This commit is contained in:
Jerry
2020-04-12 09:32:34 +08:00
parent be4a132ddf
commit c2a5f9d394
305 changed files with 33137 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
module.exports = {
baseUrl: 'http://localhost:8080/',
projectName: '橙单生成器项目'
}

View File

@@ -0,0 +1,12 @@
const projectConfig = require('../config/' + process.env.NODE_ENV);
export const globalConfig = {
httpOption: {
showMask: true,
showError: true
},
axiosOption: {
}
};
export default projectConfig;

View File

@@ -0,0 +1,4 @@
module.exports = {
baseUrl: 'http://localhost:8080/',
projectName: '橙单生成器项目'
}

View File

@@ -0,0 +1,14 @@
import Vue from 'vue'
import { SortableData } from './sortableData';
/**
* 拖拽排序指令
*/
Vue.directive('sortable', {
inserted: function (el, binding, vnode) {
let sortableData = binding.value;
if (sortableData == null || !(sortableData instanceof SortableData)) return;
sortableData.init(vnode.elm);
}
});

View File

@@ -0,0 +1,60 @@
import sortable from 'sortablejs'
/**
* 拖拽排序对象
* expample
* <ul v-sortable="new SortableData(data)">
* <li>A</li>
* <li>B</li>
* <li>C</li>
* <li>D</li>
* </ul>
*/
export class SortableData {
constructor (data, group) {
this.list = data;
this.group = group;
this.ghostClass = 'sortable-ghost';
this.sortable = null;
this.disabled = false;
};
setData (list) {
this.list = list;
}
getElement (el) {
return el;
};
onEnd (oldIndex, newIndex) {
if (oldIndex === newIndex || this.list == null) return;
let targetRow = this.list.splice(oldIndex, 1)[0]
this.list.splice(newIndex, 0, targetRow);
};
init (el) {
var _this = this;
var _option = {};
if (this.ghostClass != null) _option.ghostClass = this.ghostClass;
if (this.group != null) _option.group = this.group;
if (this.disabled != null) _option.disabled = this.disabled;
// 列表中能拖动的dom的选择器例如.drag-item
if (this.draggable != null) _option.draggable = this.draggable;
// 列表中拖动项拖动把柄的选择器只有点击这个选择出来的dom才可以开始拖动例如.drag-handle
if (this.handle != null) _option.handle = this.handle;
_option.setData = function (dataTransfer) {
dataTransfer.setData('Text', '');
};
_option.onEnd = function (evt) {
_this.onEnd(evt.oldIndex, evt.newIndex);
};
this.sortable = sortable.create(_this.getElement(el), _option);
};
release () {
if (this.sortable != null) this.sortable.destroy();
this.sortable = null;
}
};

View File

@@ -0,0 +1,185 @@
import Vue from 'vue';
import { Loading, Message } from 'element-ui';
import request from './request';
import requestUrl from './requestUrl';
import merge from 'lodash/merge';
import { globalConfig } from '@/core/config';
/**
* 遮罩管理,多次调用支持引用计数
*/
class LoadingManager {
constructor (options) {
this.options = options;
this.refCount = 0;
this.loading = undefined;
}
showMask () {
this.loading = Loading.service(this.options);
this.refCount++;
}
hideMask () {
if (this.refCount <= 1 && this.loading != null) {
this.loading.close();
this.loading = null;
}
this.refCount--;
this.refCount = Math.max(0, this.refCount);
}
}
const loadingManager = new LoadingManager({
fullscreen: true,
background: 'rgba(0, 0, 0, 0.1)'
});
/**
* post请求
* @param {String} url 请求的url
* @param {Object} params 请求参数
* @param {Object} options axios设置项
* @returns {Promise}
*/
const fetchPost = function (url, params, options) {
if (options == null) return {};
let tempOptions = {
...options,
method: 'post',
url: requestUrl(url),
data: params
};
return request(tempOptions);
};
/**
* get请求
* @param {String} url 请求的url
* @param {Object} params 请求参数
* @param {Object} options axios设置项
* @returns {Promise}
*/
const fetchGet = function (url, params, options) {
if (options == null) return {};
let tempOptions = {
...options,
method: 'get',
url: requestUrl(url),
params
};
return request(tempOptions);
};
/**
* 下载请求
* @param {String} url 请求的url
* @param {Object} params 请求参数
* @param {String} fileName 下载后保存的文件名
* @returns {Promise}
*/
const fetchDownload = function (url, params, fileName) {
return new Promise((resolve, reject) => {
request({
url: requestUrl(url),
method: 'post',
data: params,
responseType: 'blob',
transformResponse: function (data) {
return (data instanceof Blob && data.size > 0) ? data : undefined;
}
}).then(res => {
if (res.data == null) {
reject(new Error('下载文件失败'));
} else {
let blobData = new Blob([res.data], { type: 'application/octet-stream' });
let blobUrl = window.URL.createObjectURL(blobData);
let linkDom = document.createElement('a');
linkDom.style.display = 'none';
linkDom.href = blobUrl;
linkDom.setAttribute('download', fileName);
if (typeof linkDom.download === 'undefined') {
linkDom.setAttribute('target', '_blank');
}
document.body.appendChild(linkDom);
linkDom.click();
document.body.removeChild(linkDom);
window.URL.revokeObjectURL(blobData);
resolve();
}
}).catch(e => {
if (e instanceof Blob) {
let reader = new FileReader();
reader.onload = function () {
let jsonObj = JSON.parse(reader.result);
reject((jsonObj || {}).errorMessage || '下载文件失败');
}
reader.readAsText(e);
} else {
reject(e);
}
});
});
}
/**
* 数据请求
* @param {String} url 请求的url
* @param {String} type 请求类型getpost
* @param {Object} params 请求参数
* @param {Object} axiosOption axios设置
* @param {Object} options 显示设置
*/
const doUrl = function (url, type, params, axiosOption, options) {
options = merge(globalConfig.httpOption, options);
axiosOption = merge(globalConfig.axiosOption, axiosOption);
if (type == null || type === '') type = 'post';
return new Promise((resolve, reject) => {
if (options.showMask) loadingManager.showMask();
let ajaxCall = null;
if (type.toLowerCase() === 'get') {
ajaxCall = fetchGet(url, params, axiosOption);
} else if (type.toLowerCase() === 'post') {
ajaxCall = fetchPost(url, params, axiosOption);
}
if (ajaxCall != null) {
ajaxCall.then(res => {
if (options.showMask) loadingManager.hideMask();
if (res.data && res.data.success) {
resolve(res.data);
} else {
if (options.showError) {
Message.error({
showClose: true,
message: res.data.errorMessage ? res.data.errorMessage : '数据请求失败'
});
}
reject(res.data);
}
}).catch(e => {
if (options.showMask) loadingManager.hideMask();
if (options.showError) {
Message.error({
showClose: true,
message: e.errorMessage ? e.errorMessage : '网络请求错误'
});
}
reject(e);
});
} else {
if (options.showMask) loadingManager.hideMask();
reject(new Error('错误的请求类型 - ' + type));
}
});
};
Vue.prototype.download = fetchDownload;
Vue.prototype.doUrl = doUrl;
Vue.prototype.loadingManager = loadingManager;
export default {
doUrl,
fetchPost,
fetchGet,
fetchDownload
}

View File

@@ -0,0 +1,73 @@
import axios from 'axios';
import router from '@/router';
import dialog from '@/components/Dialog';
import JSONbig from 'json-bigint';
// 创建axios实例
const service = axios.create({
timeout: 1000 * 30,
withCredentials: true,
headers: {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
'Content-Type': 'application/json; charset=utf-8'
},
transformResponse: [
function (data) {
if (typeof data === 'string') {
const JSONbigString = new JSONbig({storeAsString: true});
return JSONbigString.parse(data);
} else {
return data;
}
}
]
})
// request拦截器
service.interceptors.request.use(
config => {
let token = window.sessionStorage.getItem('token');
let menuIdJsonStr = window.sessionStorage.getItem('currentMenuId');
let currentMenuId;
if (menuIdJsonStr != null) {
currentMenuId = (JSON.parse(menuIdJsonStr) || {}).data;
}
if (token != null) config.headers['Authorization'] = token;
if (currentMenuId != null) config.headers['MenuId'] = currentMenuId;
return config
}, error => {
return Promise.reject(error)
}
);
// response拦截器
service.interceptors.response.use(
response => {
if (response.data && response.data.errorCode === 'UNAUTHORIZED_LOGIN') { // 401, token失效
dialog.closeAll();
router.push({ name: 'login' })
} else {
if (response.headers['refreshedtoken'] != null) {
window.sessionStorage.setItem('token', response.headers['refreshedtoken']);
}
}
return response
}, error => {
let response = error.response;
if (response && response.data) {
if (response.data.errorCode === 'UNAUTHORIZED_LOGIN') {
dialog.closeAll();
router.push({ name: 'login' });
}
return Promise.reject(response.data);
} else {
return Promise.reject(new Error({
errorMessage: '数据获取失败,请稍后再试'
}));
}
}
);
export default service

View File

@@ -0,0 +1,27 @@
import projectConfig from '@/core/config';
import { objectToQueryString } from '@/utils';
console.log(process.env.NODE_ENV, projectConfig);
/**
* 请求地址统一处理/组装
* @param actionName action方法名称
*/
export default function (actionName) {
if (actionName != null && actionName !== '') {
if (actionName.substr(0, 1) === '/') actionName = actionName.substr(1);
}
return projectConfig.baseUrl + actionName;
}
export function buildGetUrl (actionName, params) {
let queryString = objectToQueryString(params);
if (actionName != null && actionName !== '') {
if (actionName.substr(0, 1) === '/') actionName = actionName.substr(1);
}
return projectConfig.baseUrl + actionName + (queryString == null ? '' : ('?' + queryString));
}
export {
projectConfig
}

View File

@@ -0,0 +1,120 @@
import Vue from 'vue';
import Request from '@/core/http/request.js';
import { mapMutations, mapGetters } from 'vuex';
// 全局mixin对象
const globalMixin = {
data () {
return {
isHttpLoading: false
}
},
methods: {
/**
* 是否显示遮罩
* @param {Boolean} isShow 是否显示
*/
showMask (isShow) {
isShow ? this.loadingManager.showMask() : this.loadingManager.hideMask();
},
/**
* 判读用户是否有权限
* @param {String} permCode 权限字
*/
checkPermCodeExist (permCode) {
if (this.getUserInfo.permCodeSet != null) {
return this.getUserInfo.permCodeSet.has(permCode);
} else {
return this.getUserInfo.isAdmin;
}
},
/**
* 将输入的值转换成指定的类型
* @param {Any} value
* @param {String} type 要转换的类型integer、float、boolean、string
*/
parseParams (value, type = 'string') {
if (value == null) return value;
switch (type) {
case 'integer': return Number.parseInt(value);
case 'float': return Number.parseFloat(value);
case 'boolean': return (value === 'true' || value);
default: return String(value);
}
},
/**
* 将输入值转换为执行的类型数组
* @param {Array} value 输入数组
* @param {String} type 要转换的类型integer、float、boolean、string
*/
parseArrayParams (value, type = 'string') {
if (Array.isArray(value)) {
return value.map((item) => {
switch (type) {
case 'integer': return Number.parseInt(item);
case 'float': return Number.parseFloat(item);
case 'boolean': return (item === 'true' || item);
default: return String(item);
}
});
} else {
return [];
}
},
/**
* 下载上传的文件
* @param {*} url 下载文件的url
* @param {*} fileName 下载文件名
*/
downloadFile (url, fileName) {
console.log(fileName);
Request({
url: url,
method: 'get',
responseType: 'blob',
transformResponse: function (data) {
console.log(data);
return data;
}
}).then(res => {
console.log(res);
let data = res.data;
if (res.status === 200 && data instanceof Blob) {
let url = window.URL.createObjectURL(data);
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
this.$message.error('下载文件失败');
}
}).catch(e => {
let reader = new FileReader();
reader.onload = () => {
let jsonObj = JSON.parse(reader.result);
this.$message.error((jsonObj || {}).errorMessage || '下载文件失败');
}
reader.readAsText(e);
});
},
...mapMutations(['setLoadingStatus'])
},
computed: {
getPageHeight () {
return this.getClientHeight - 130;
},
...mapGetters(['getUserInfo', 'getClientHeight'])
},
watch: {
'loadingManager.loading': {
handler: function (newValue) {
this.isHttpLoading = (newValue != null);
}
}
}
}
Vue.mixin(globalMixin);

View File

@@ -0,0 +1,282 @@
import projectConfig from '@/core/config';
import { buildGetUrl } from '@/core/http/requestUrl.js';
import { formatDate, parseDate } from 'element-ui/src/utils/date-util';
import { mapMutations } from 'vuex';
/**
* 上传文件组件相关方法
*/
const uploadMixin = {
methods: {
/**
* 解析返回的上传文件数据
* @param {String} jsonData 上传文件数据,[{name, downloadUri, filename}]
* @param {Object} params 上传文件的参数
* @returns {Array} 上传文件信息,[{name, downloadUri, filename, url}]
*/
parseUploadData (jsonData, params) {
let pathList = [];
if (jsonData != null) {
try {
pathList = JSON.parse(jsonData);
} catch (e) {
console.error(e);
}
}
return pathList.map((item) => {
let downloadParams = {...params};
downloadParams.filename = item.filename;
return {
...item,
url: this.getUploadFileUrl(item, downloadParams)
}
});
},
/**
* 获得上传文件url列表
* @param {*} jsonData 上传文件数据,[{name, downloadUri, filename}]
* @param {*} params 上传文件的参数
* @returns {Array} 文件url列表
*/
getPictureList (jsonData, params) {
let tempList = this.parseUploadData(jsonData, params);
if (Array.isArray(tempList)) {
return tempList.map(item => item.url);
} else {
return [];
}
},
/**
* 将选中文件信息格式化成json信息
* @param {Array} fileList 上传文件列表,[{name, fileUrl, data}]
*/
fileListToJson (fileList) {
if (Array.isArray(fileList)) {
return JSON.stringify(fileList.map((item) => {
return {
name: item.name,
downloadUri: item.downloadUri || item.response.data.downloadUri,
filename: item.filename || item.response.data.filename
}
}));
} else {
return undefined;
}
},
/**
* 获得上传文件url
* @param {*} item 上传文件
* @param {*} params 上传文件的参数
*/
getUploadFileUrl (item, params) {
if (item == null || item.downloadUri == null) {
return null;
} else {
let menuIdJsonStr = window.sessionStorage.getItem('currentMenuId');
let currentMenuId;
if (menuIdJsonStr != null) {
currentMenuId = (JSON.parse(menuIdJsonStr) || {}).data;
}
params.Authorization = window.sessionStorage.getItem('token');
params.MenuId = currentMenuId;
return buildGetUrl(item.downloadUri, params);
}
},
/**
* 获得上传接口
* @param {*} url 上传路径
*/
getUploadActionUrl (url) {
if (url != null && url[0] === '/') {
url = url.substr(1);
}
return projectConfig.baseUrl + url;
},
/**
* 上传文件是否图片文件
* @param {*} file 上传文件
*/
pictureFile (file) {
if (['image/jpeg', 'image/jpg', 'image/png'].indexOf(file.type) !== -1) {
return true;
} else {
this.$message.error('图片文件格式不正确,请重新选择');
return false;
}
}
},
computed: {
getUploadHeaders () {
let token = window.sessionStorage.getItem('token');
return {
Authorization: token
}
}
}
};
const allowStatsType = [
'time',
'datetime',
'day',
'month',
'year'
];
/**
* 日期相关方法
*/
const statsDateRangeMixin = {
methods: {
/**
* 根据输入的日期获得日期范围例如输入2019-12-12输出['2019-12-12 00:00:00', '2019-12-12 23:59:59']
* @param {Date|String} date 要转换的日期
* @param {String} statsType 转换类型day, month, year
* @param {String} format 输出格式
*/
getDateRangeFilter (date, statsType = 'day', format = 'yyyy-MM-dd HH:mm:ss') {
if (date == null) return [];
statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType;
let tempDate = new Date(date);
tempDate.setHours(0, 0, 0, 0);
let retDate;
switch (statsType) {
case 'day':
retDate = [
new Date(tempDate),
new Date(tempDate.setDate(tempDate.getDate() + 1))
];
break;
case 'month':
tempDate.setDate(1);
retDate = [
new Date(tempDate),
new Date(tempDate.setMonth(tempDate.getMonth() + 1))
];
break;
case 'year':
tempDate.setDate(1);
tempDate.setMonth(0);
retDate = [
new Date(tempDate),
new Date(tempDate.setFullYear(tempDate.getFullYear() + 1))
]
}
retDate[1] = new Date(retDate[1].getTime() - 1);
return [
formatDate(retDate[0], format),
formatDate(retDate[1], format)
];
},
/**
* 格式化日期
* @param {Date|String} date 要格式化的日期
* @param {String} statsType 输出日期类型
* @param {String} format 输入日期的格式
*/
formatDateByStatsType (date, statsType = 'day', format = 'yyyy-MM-dd') {
if (date == null) return undefined;
statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType;
if (statsType === 'datetime') format = 'yyyy-MM-dd HH:mm:ss';
let tempDate = ((date instanceof Date) ? date : parseDate(date, format));
if (!tempDate) return undefined;
switch (statsType) {
case 'time':
return formatDate(tempDate, 'HH:mm:ss');
case 'datetime':
return formatDate(tempDate, 'yyyy-MM-dd HH:mm:ss');
case 'day':
return formatDate(tempDate, 'yyyy-MM-dd');
case 'month':
return formatDate(tempDate, 'yyyy-MM');
case 'year':
return formatDate(tempDate, 'yyyy');
default:
return formatDate(tempDate, 'yyyy-MM-dd');
}
},
/**
* 获得统计类型中文名称
* @param {String} statsType 统计类型day, month, year
*/
getStatsTypeShowName (statsType) {
statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType;
switch (statsType) {
case 'day': return '日统计';
case 'month': return '月统计';
case 'year': return '年统计';
}
},
/**
* 获取统计类型字典列表
* @param {Array} statsTypeList 统计类型列表
*/
getAllowStatsTypeList (statsTypeList) {
if (Array.isArray(statsTypeList) && statsTypeList.length > 0) {
return statsTypeList.map((item) => {
return {
id: item,
name: this.getStatsTypeShowName(item)
}
});
} else {
return [];
}
}
}
}
/**
* 页面缓存相关方法
*/
const cachePageMixin = {
methods: {
/**
* 移除缓存页面
* @param {*} name 缓存组件的名称
*/
removeCachePage (name) {
this.removeCachePage(name);
},
/**
* 从跳转页面返回并且刷新当前页面时调用
*/
onResume () {
},
...mapMutations(['addCachePage', 'removeCachePage'])
},
created () {
this.addCachePage(this.$options.name);
},
activated () {
if (this.$route && this.$route.meta && this.$route.meta.refresh) {
this.onResume();
this.$route.meta.refresh = false;
}
}
}
/**
* 缓存页面跳转页面相关方法
*/
const cachedPageChildMixin = {
data () {
return {
// 是否刷新父页面
refreshParentCachedPage: false
}
},
beforeRouteLeave (to, from, next) {
if (to.meta == null) to.meta = {};
to.meta.refresh = this.refreshParentCachedPage;
next();
}
}
export {
uploadMixin,
statsDateRangeMixin,
cachePageMixin,
cachedPageChildMixin
}