init
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
import HttpRequest from '@/libs/axios'
|
||||
import config from '@/config'
|
||||
const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro
|
||||
|
||||
const axios = new HttpRequest(baseUrl)
|
||||
export default axios
|
||||
@@ -0,0 +1,29 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @description 判断列表1中是否包含了列表2中的某一项
|
||||
* 因为用户权限 access 为数组,includes 方法无法直接得出结论
|
||||
* */
|
||||
function includeArray (list1, list2) {
|
||||
let status = false
|
||||
if (list1 === true) {
|
||||
return true
|
||||
} else {
|
||||
if (typeof list2 !== 'object') {
|
||||
return false
|
||||
}
|
||||
list2.forEach(item => {
|
||||
if (list1.includes(item)) status = true
|
||||
})
|
||||
return status
|
||||
}
|
||||
}
|
||||
export { includeArray }
|
||||
@@ -0,0 +1,86 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
import axios from 'axios'
|
||||
import store from '@/store'
|
||||
// import { Spin } from 'iview'
|
||||
const addErrorLog = errorInfo => {
|
||||
const { statusText, status, request: { responseURL } } = errorInfo
|
||||
let info = {
|
||||
type: 'ajax',
|
||||
code: status,
|
||||
mes: statusText,
|
||||
url: responseURL
|
||||
}
|
||||
if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
|
||||
}
|
||||
|
||||
class HttpRequest {
|
||||
constructor (baseUrl = baseURL) {
|
||||
this.baseUrl = 'http://admin.crmeb.net/adminapi'
|
||||
this.queue = {}
|
||||
}
|
||||
getInsideConfig () {
|
||||
const config = {
|
||||
baseURL: this.baseUrl,
|
||||
headers: {
|
||||
//
|
||||
}
|
||||
}
|
||||
return config
|
||||
}
|
||||
destroy (url) {
|
||||
delete this.queue[url]
|
||||
if (!Object.keys(this.queue).length) {
|
||||
// Spin.hide()
|
||||
}
|
||||
}
|
||||
interceptors (instance, url) {
|
||||
// 请求拦截
|
||||
instance.interceptors.request.use(config => {
|
||||
// 添加全局的loading...
|
||||
if (!Object.keys(this.queue).length) {
|
||||
// Spin.show() // 不建议开启,因为界面不友好
|
||||
}
|
||||
this.queue[url] = true
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
// 响应拦截
|
||||
instance.interceptors.response.use(res => {
|
||||
console.log('red');
|
||||
console.log(res);
|
||||
this.destroy(url)
|
||||
const { data, status } = res
|
||||
return { data, status }
|
||||
}, error => {
|
||||
this.destroy(url)
|
||||
let errorInfo = error.response
|
||||
if (!errorInfo) {
|
||||
const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
|
||||
errorInfo = {
|
||||
statusText,
|
||||
status,
|
||||
request: { responseURL: config.url }
|
||||
}
|
||||
}
|
||||
addErrorLog(errorInfo)
|
||||
return Promise.reject(error)
|
||||
})
|
||||
}
|
||||
request (options) {
|
||||
const instance = axios.create()
|
||||
options = Object.assign(this.getInsideConfig(), options)
|
||||
this.interceptors(instance, options.url)
|
||||
return instance(options)
|
||||
}
|
||||
}
|
||||
export default HttpRequest
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,66 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
import {
|
||||
Confirm as confirm,
|
||||
Alert as alert,
|
||||
Toast as toast,
|
||||
Notify as notify,
|
||||
Loading as loading
|
||||
} from "vue-ydui/dist/lib.rem/dialog";
|
||||
|
||||
const dialog = {
|
||||
confirm,
|
||||
alert,
|
||||
toast,
|
||||
notify,
|
||||
loading
|
||||
};
|
||||
|
||||
const icons = { error: "操作失败", success: "操作成功" };
|
||||
Object.keys(icons).reduce((dialog, key) => {
|
||||
dialog[key] = (mes, obj = {}) => {
|
||||
return new Promise(function(resolve) {
|
||||
toast({
|
||||
mes: mes || icons[key],
|
||||
timeout: 1000,
|
||||
icon: key,
|
||||
callback: () => {
|
||||
resolve();
|
||||
},
|
||||
...obj
|
||||
});
|
||||
});
|
||||
};
|
||||
return dialog;
|
||||
}, dialog);
|
||||
|
||||
dialog.message = (mes = "操作失败", obj = {}) => {
|
||||
return new Promise(function(resolve) {
|
||||
toast({
|
||||
mes,
|
||||
timeout: 1000,
|
||||
callback: () => {
|
||||
resolve();
|
||||
},
|
||||
...obj
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
dialog.validateError = (...args) => {
|
||||
validatorDefaultCatch(...args);
|
||||
};
|
||||
|
||||
export function validatorDefaultCatch(err, type = "message") {
|
||||
return dialog[type](err.errors[0].message);
|
||||
}
|
||||
|
||||
export default dialog;
|
||||
@@ -0,0 +1,123 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
/* eslint-disable */
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
function auto_width(ws, data){
|
||||
/*set worksheet max width per col*/
|
||||
const colWidth = data.map(row => row.map(val => {
|
||||
/*if null/undefined*/
|
||||
if (val == null) {
|
||||
return {'wch': 10};
|
||||
}
|
||||
/*if chinese*/
|
||||
else if (val.toString().charCodeAt(0) > 255) {
|
||||
return {'wch': val.toString().length * 2};
|
||||
} else {
|
||||
return {'wch': val.toString().length};
|
||||
}
|
||||
}));
|
||||
/*start in the first row*/
|
||||
let result = colWidth[0];
|
||||
for (let i = 1; i < colWidth.length; i++) {
|
||||
for (let j = 0; j < colWidth[i].length; j++) {
|
||||
if (result[j]['wch'] < colWidth[i][j]['wch']) {
|
||||
result[j]['wch'] = colWidth[i][j]['wch'];
|
||||
}
|
||||
}
|
||||
}
|
||||
ws['!cols'] = result;
|
||||
}
|
||||
|
||||
function json_to_array(key, jsonData){
|
||||
return jsonData.map(v => key.map(j => { return v[j] }));
|
||||
}
|
||||
|
||||
// fix data,return string
|
||||
function fixdata(data) {
|
||||
let o = '';
|
||||
let l = 0;
|
||||
const w = 10240;
|
||||
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
|
||||
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
|
||||
return o
|
||||
}
|
||||
|
||||
// get head from excel file,return array
|
||||
function get_header_row(sheet) {
|
||||
const headers = [];
|
||||
const range = XLSX.utils.decode_range(sheet['!ref']);
|
||||
let C;
|
||||
const R = range.s.r; /* start in the first row */
|
||||
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
|
||||
var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]; /* find the cell in the first row */
|
||||
var hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
|
||||
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
|
||||
headers.push(hdr)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
export const export_table_to_excel= (id, filename) => {
|
||||
const table = document.getElementById(id);
|
||||
const wb = XLSX.utils.table_to_book(table);
|
||||
XLSX.writeFile(wb, filename);
|
||||
|
||||
/* the second way */
|
||||
// const table = document.getElementById(id);
|
||||
// const wb = XLSX.utils.book_new();
|
||||
// const ws = XLSX.utils.table_to_sheet(table);
|
||||
// XLSX.utils.book_append_sheet(wb, ws, filename);
|
||||
// XLSX.writeFile(wb, filename);
|
||||
};
|
||||
|
||||
export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => {
|
||||
const wb = XLSX.utils.book_new();
|
||||
data.unshift(title);
|
||||
const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true});
|
||||
if(autoWidth){
|
||||
const arr = json_to_array(key, data);
|
||||
auto_width(ws, arr);
|
||||
}
|
||||
XLSX.utils.book_append_sheet(wb, ws, filename);
|
||||
XLSX.writeFile(wb, filename + '.xlsx');
|
||||
};
|
||||
|
||||
export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => {
|
||||
const wb = XLSX.utils.book_new();
|
||||
const arr = json_to_array(key, data);
|
||||
arr.unshift(title);
|
||||
const ws = XLSX.utils.aoa_to_sheet(arr);
|
||||
if(autoWidth){
|
||||
auto_width(ws, arr);
|
||||
}
|
||||
XLSX.utils.book_append_sheet(wb, ws, filename);
|
||||
XLSX.writeFile(wb, filename + '.xlsx');
|
||||
};
|
||||
|
||||
export const read = (data, type) => {
|
||||
/* if type == 'base64' must fix data first */
|
||||
// const fixedData = fixdata(data)
|
||||
// const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
|
||||
const workbook = XLSX.read(data, { type: type });
|
||||
const firstSheetName = workbook.SheetNames[0];
|
||||
const worksheet = workbook.Sheets[firstSheetName];
|
||||
const header = get_header_row(worksheet);
|
||||
const results = XLSX.utils.sheet_to_json(worksheet);
|
||||
return {header, results};
|
||||
};
|
||||
|
||||
export default {
|
||||
export_table_to_excel,
|
||||
export_array_to_excel,
|
||||
export_json_to_excel,
|
||||
read
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
const events = [];
|
||||
|
||||
const $scroll = function(dom, fn) {
|
||||
events.push({ dom, fn });
|
||||
fn._index = events.length - 1;
|
||||
};
|
||||
|
||||
$scroll.remove = function(fn) {
|
||||
fn._index && events.splice(fn._index, 1);
|
||||
};
|
||||
|
||||
//上拉加载;
|
||||
const Scroll = {
|
||||
addHandler: function(element, type, handler) {
|
||||
if (element.addEventListener)
|
||||
element.addEventListener(type, handler, false);
|
||||
else if (element.attachEvent) element.attachEvent("on" + type, handler);
|
||||
else element["on" + type] = handler;
|
||||
},
|
||||
listenTouchDirection: function() {
|
||||
this.addHandler(window, "scroll", function() {
|
||||
const wh = window.innerHeight,
|
||||
st = window.scrollY;
|
||||
events
|
||||
.filter(e => e.dom.scrollHeight && e.dom.scrollHeight > 0)
|
||||
.forEach(e => {
|
||||
var dh = e.dom.scrollHeight;
|
||||
var s = Math.ceil((st / (dh - wh)) * 100);
|
||||
if (s > 85) e.fn();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Scroll.listenTouchDirection();
|
||||
|
||||
export default $scroll;
|
||||
export { Scroll };
|
||||
@@ -0,0 +1,20 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
export default {
|
||||
name: 'RenderDom',
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function
|
||||
},
|
||||
render: (h, ctx) => {
|
||||
return ctx.props.render(h)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
import axios from 'axios'
|
||||
import { Message } from 'iview'
|
||||
import { getCookies, removeCookies, getSen, getLoc } from '@/libs/util'
|
||||
import Setting from '@/setting'
|
||||
import router from '@/router';
|
||||
const service = axios.create({
|
||||
baseURL: Setting.apiBaseURL,
|
||||
timeout: 10000 // 请求超时时间
|
||||
})
|
||||
|
||||
axios.defaults.withCredentials = true// 携带cookie
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
let baseUrl;
|
||||
if(config.kefu) {
|
||||
baseUrl = Setting.apiBaseURL.replace(/admin/, "kefu")
|
||||
config.baseURL = baseUrl
|
||||
} else if(config.mobile) {
|
||||
baseUrl = Setting.apiBaseURL.replace(/admin/, "mobile");
|
||||
config.baseURL = baseUrl
|
||||
} else {
|
||||
config.baseURL = Setting.apiBaseURL
|
||||
}
|
||||
const token = getCookies('token')
|
||||
const kefuToken = getCookies('kefu_token');
|
||||
const mobileToken = getLoc('mobile_token');
|
||||
|
||||
if(token || kefuToken || mobileToken) {
|
||||
config.headers['Authori-zation'] = config.mobile ? 'Bearer ' + mobileToken : config.kefu ? 'Bearer ' + kefuToken : 'Bearer ' + token;
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
|
||||
response => {
|
||||
let status = response.data ? response.data.status : 0
|
||||
const code = status
|
||||
switch(code) {
|
||||
case 200:
|
||||
return response.data
|
||||
case 400: case 400011: case 400012:
|
||||
return Promise.reject(response.data || { msg: '未知错误' })
|
||||
case 410000:
|
||||
case 410001:
|
||||
case 410002:
|
||||
console.log(code);
|
||||
localStorage.clear()
|
||||
removeCookies('token')
|
||||
removeCookies('expires_time')
|
||||
removeCookies('uuid')
|
||||
router.replace({ path: '/admin/login' })
|
||||
break
|
||||
case 410003:
|
||||
removeCookies('kefuInfo')
|
||||
removeCookies('kefu_token')
|
||||
removeCookies('kefu_expires_time')
|
||||
removeCookies('kefu_uuid')
|
||||
router.replace({ path: '/kefu' })
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
error => {
|
||||
Message.error(error.msg)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
@@ -0,0 +1,269 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +----------------------------------------------------------------------
|
||||
import {wss} from '@/libs/util';
|
||||
import {netWorkPing} from '@/api/kefu';
|
||||
import Setting from '@/setting';
|
||||
import Cookies from "js-cookie";
|
||||
import Vue from 'vue';
|
||||
|
||||
|
||||
let reconneTimer = {};
|
||||
let reconneCount = {};
|
||||
let connectGuid = {};
|
||||
let NetWork = null;
|
||||
|
||||
class wsSocket {
|
||||
constructor(opt) {
|
||||
this.vm = new Vue;
|
||||
this.ws = null;
|
||||
this.opt = opt || {};
|
||||
this.networkStatus = true;
|
||||
this.reconneMax = 100;
|
||||
this.connectLing = false;
|
||||
reconneTimer[this.opt.key] = null;
|
||||
reconneCount[this.opt.key] = 0;
|
||||
this.init(opt);
|
||||
this.networkWath();
|
||||
this.defaultEvenv();
|
||||
}
|
||||
|
||||
defaultEvenv() {
|
||||
this.vm.$on('timeout', this.timeoutEvent.bind(this));
|
||||
}
|
||||
|
||||
timeoutEvent() {
|
||||
this.reconne();
|
||||
}
|
||||
|
||||
guid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = Math.random() * 16 | 0,
|
||||
v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
addHandler(element, type, handler) {
|
||||
if (element.addEventListener) {
|
||||
element.addEventListener(type, handler, false);
|
||||
} else if (element.attachEvent) {
|
||||
element.attachEvent("on" + type, handler);
|
||||
} else {
|
||||
element["on" + type] = handler;
|
||||
}
|
||||
}
|
||||
|
||||
networkStatusFn(onlineFun, offlineFun) {
|
||||
this.addHandler(window, 'online', () => {
|
||||
onlineFun()
|
||||
})
|
||||
this.addHandler(window, 'offline', () => {
|
||||
offlineFun()
|
||||
});
|
||||
}
|
||||
|
||||
networkStatusFnv2(onlineFun, offlineFun) {
|
||||
if (NetWork) {
|
||||
clearInterval(NetWork);
|
||||
NetWork = null;
|
||||
}
|
||||
let online = null,
|
||||
offline = null;
|
||||
NetWork = setInterval(() => {
|
||||
netWorkPing().then(res => {
|
||||
if (online === null) {
|
||||
onlineFun();
|
||||
online = true;
|
||||
}
|
||||
offline = null;
|
||||
}).catch(() => {
|
||||
if (offline === null) {
|
||||
offlineFun();
|
||||
offline = true;
|
||||
}
|
||||
online = null;
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
networkWath() {
|
||||
this.networkStatusFn(() => {
|
||||
this.networkStatus = true;
|
||||
console.log('联网了')
|
||||
this.vm.$on('timeout', this.timeoutEvent);
|
||||
}, () => {
|
||||
this.networkStatus = false;
|
||||
this.socketStatus = false;
|
||||
this.timer && clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.ws.close();
|
||||
console.log('断网了')
|
||||
});
|
||||
}
|
||||
|
||||
reconne() {
|
||||
|
||||
if (reconneCount[this.opt.key] > this.reconneMax) {
|
||||
//重连次数超过限制不再重连
|
||||
if (reconneTimer[this.opt.key]) {
|
||||
clearInterval(reconneTimer[this.opt.key]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (reconneTimer[this.opt.key] || this.socketStatus) {
|
||||
return;
|
||||
}
|
||||
reconneTimer[this.opt.key] = setInterval(() => {
|
||||
//断线连接中发现状态为真就不用再连接
|
||||
if (this.socketStatus) {
|
||||
return;
|
||||
}
|
||||
//正在连接中也不需要在连接了
|
||||
if (!this.connectLing) {
|
||||
console.log('重新连接')
|
||||
this.init(this.opt);
|
||||
reconneCount[this.opt.key]++;
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
onOpen(key = false) {
|
||||
//关闭断线重连定时器
|
||||
clearInterval(reconneTimer[this.opt.key]);
|
||||
reconneTimer[this.opt.key] = null;
|
||||
|
||||
this.connectLing = false;
|
||||
this.opt.open && this.opt.open();
|
||||
reconneCount[this.opt.key] = 0
|
||||
this.socketStatus = true;
|
||||
this.ping();
|
||||
}
|
||||
|
||||
init(opt) {
|
||||
if (this.socketStatus) {
|
||||
return;
|
||||
}
|
||||
let wsUrl = ''
|
||||
let hostUrl = wss(Setting.wsSocketUrl);
|
||||
|
||||
hostUrl = hostUrl + '/ws';
|
||||
|
||||
if (opt.key == 1) {
|
||||
wsUrl = hostUrl + '?type=admin' + '&token=' + util.cookies.get("token")
|
||||
}
|
||||
if (opt.key == 2) {
|
||||
wsUrl = hostUrl + `?type=kefu` + '&token=' + `${Cookies.get("kefu_token")}`;
|
||||
}
|
||||
if (opt.key == 3) {
|
||||
wsUrl = `${hostUrl}?type=user&form=${opt.form}&token=${opt.token}`;
|
||||
}
|
||||
if (opt.tourist_uid) {
|
||||
wsUrl += '&tourist_uid=' + opt.tourist_uid
|
||||
}
|
||||
if (wsUrl) {
|
||||
this.connectLing = true;
|
||||
// connectGuid[opt.key] = this.guid();
|
||||
this.ws = new WebSocket(wsUrl);
|
||||
this.ws.onopen = this.onOpen.bind(this);
|
||||
this.ws.onerror = this.onError.bind(this);
|
||||
this.ws.onmessage = this.onMessage.bind(this);
|
||||
this.ws.onclose = this.onClose.bind(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ping() {
|
||||
var that = this;
|
||||
this.timer = setInterval(() => {
|
||||
that.send({type: 'ping'});
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
send(data) {
|
||||
if (!this.socketStatus || this.ws.readyState === 0 || !this.networkStatus) {
|
||||
this.reconne();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
this.ws.send(JSON.stringify(data));
|
||||
resolve({status: true});
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
reject({status: false, socketStatus: this.socketStatus, networkStatus: this.networkStatus})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMessage(res) {
|
||||
this.opt.message && this.opt.message(res);
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.connectLing = false;
|
||||
this.timer && clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.opt.close && this.opt.close();
|
||||
this.socketStatus = false;
|
||||
this.reconne();
|
||||
}
|
||||
|
||||
onError(e) {
|
||||
this.connectLing = false;
|
||||
this.timer && clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.opt.error && this.opt.error(e);
|
||||
this.socketStatus = false;
|
||||
this.reconne();
|
||||
}
|
||||
|
||||
$on(...args) {
|
||||
this.vm.$on(...args);
|
||||
}
|
||||
|
||||
$off(...args) {
|
||||
this.vm.$off(...args);
|
||||
}
|
||||
}
|
||||
|
||||
let promises = {};
|
||||
|
||||
function createSocket(key, flag, token, tourist_uid, type, form) {
|
||||
if (flag) promises[key] = null;
|
||||
if (!promises[key])
|
||||
promises[key] = new Promise((resolve, reject) => {
|
||||
const ws = new wsSocket({
|
||||
key,
|
||||
token,
|
||||
tourist_uid,
|
||||
type,
|
||||
form,
|
||||
open() {
|
||||
resolve(ws);
|
||||
},
|
||||
error(e) {
|
||||
reject(e)
|
||||
},
|
||||
message(res) {
|
||||
const {type, data = {}} = JSON.parse(res.data);
|
||||
ws.vm.$emit(type, data);
|
||||
},
|
||||
close(e) {
|
||||
ws.vm.$emit('close', e);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return promises[key];
|
||||
}
|
||||
|
||||
|
||||
export const adminSocket = (flag, token) => createSocket(1, flag, token);
|
||||
export const Socket = (flag, token, tourist_uid, type) => createSocket(2, flag, token, tourist_uid, type);
|
||||
export const mobileScoket = (flag, token, form, tourist_uid, type,) => createSocket(3, flag, token, tourist_uid, type, form);
|
||||
@@ -0,0 +1,69 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
export default {
|
||||
shortcuts: [
|
||||
{
|
||||
text: '今天',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()))
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '昨天',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() - 1)))
|
||||
end.setTime(end.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() -1 )))
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '最近7天',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() - 6)))
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '最近30天',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() - 29)))
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '本月',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), new Date().getMonth(), 1)))
|
||||
return [start, end]
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '本年',
|
||||
value () {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.setTime(new Date(new Date().getFullYear(), 0, 1)))
|
||||
return [start, end]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
export const forEach = (arr, fn) => {
|
||||
if (!arr.length || !fn) return
|
||||
let i = -1
|
||||
let len = arr.length
|
||||
while (++i < len) {
|
||||
let item = arr[i]
|
||||
fn(item, i, arr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的交集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getIntersection = (arr1, arr2) => {
|
||||
let len = Math.min(arr1.length, arr2.length)
|
||||
let i = -1
|
||||
let res = []
|
||||
while (++i < len) {
|
||||
const item = arr2[i]
|
||||
if (arr1.indexOf(item) > -1) res.push(item)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的并集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getUnion = (arr1, arr2) => {
|
||||
return Array.from(new Set([...arr1, ...arr2]))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} target 目标数组
|
||||
* @param {Array} arr 需要查询的数组
|
||||
* @description 判断要查询的数组是否至少有一个元素包含在目标数组中
|
||||
*/
|
||||
export const hasOneOf = (targetarr, arr) => {
|
||||
return targetarr.some(_ => arr.indexOf(_) > -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String|Number} value 要验证的字符串或数值
|
||||
* @param {*} validList 用来验证的列表
|
||||
*/
|
||||
export function oneOf (value, validList) {
|
||||
for (let i = 0; i < validList.length; i++) {
|
||||
if (value === validList[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 判断时间戳格式是否是毫秒
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
const isMillisecond = timeStamp => {
|
||||
const timeStr = String(timeStamp)
|
||||
return timeStr.length > 10
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} currentTime 当前时间时间戳
|
||||
* @returns {Boolean} 传入的时间戳是否早于当前时间戳
|
||||
*/
|
||||
const isEarly = (timeStamp, currentTime) => {
|
||||
return timeStamp < currentTime
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} num 数值
|
||||
* @returns {String} 处理后的字符串
|
||||
* @description 如果传入的数值小于10,即位数只有1位,则在前面补充0
|
||||
*/
|
||||
const getHandledValue = num => {
|
||||
return num < 10 ? '0' + num : num
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间
|
||||
*/
|
||||
const getDate = (timeStamp, startType) => {
|
||||
const d = new Date(timeStamp * 1000)
|
||||
const year = d.getFullYear()
|
||||
const month = getHandledValue(d.getMonth() + 1)
|
||||
const date = getHandledValue(d.getDate())
|
||||
const hours = getHandledValue(d.getHours())
|
||||
const minutes = getHandledValue(d.getMinutes())
|
||||
const second = getHandledValue(d.getSeconds())
|
||||
let resStr = ''
|
||||
if (startType === 'year') resStr = year + '-' + month + '-' + date + ' ' + hours + ':' + minutes + ':' + second
|
||||
else resStr = month + '-' + date + ' ' + hours + ':' + minutes
|
||||
return resStr
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String|Number} timeStamp 时间戳
|
||||
* @returns {String} 相对时间字符串
|
||||
*/
|
||||
export const getRelativeTime = timeStamp => {
|
||||
// 判断当前传入的时间戳是秒格式还是毫秒
|
||||
const IS_MILLISECOND = isMillisecond(timeStamp)
|
||||
// 如果是毫秒格式则转为秒格式
|
||||
if (IS_MILLISECOND) Math.floor(timeStamp /= 1000)
|
||||
// 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
|
||||
timeStamp = Number(timeStamp)
|
||||
// 获取当前时间时间戳
|
||||
const currentTime = Math.floor(Date.parse(new Date()) / 1000)
|
||||
// 判断传入时间戳是否早于当前时间戳
|
||||
const IS_EARLY = isEarly(timeStamp, currentTime)
|
||||
// 获取两个时间戳差值
|
||||
let diff = currentTime - timeStamp
|
||||
// 如果IS_EARLY为false则差值取反
|
||||
if (!IS_EARLY) diff = -diff
|
||||
let resStr = ''
|
||||
const dirStr = IS_EARLY ? '前' : '后'
|
||||
// 少于等于59秒
|
||||
if (diff <= 59) resStr = diff + '秒' + dirStr
|
||||
// 多于59秒,少于等于59分钟59秒
|
||||
else if (diff > 59 && diff <= 3599) resStr = Math.floor(diff / 60) + '分钟' + dirStr
|
||||
// 多于59分钟59秒,少于等于23小时59分钟59秒
|
||||
else if (diff > 3599 && diff <= 86399) resStr = Math.floor(diff / 3600) + '小时' + dirStr
|
||||
// 多于23小时59分钟59秒,少于等于29天59分钟59秒
|
||||
else if (diff > 86399 && diff <= 2623859) resStr = Math.floor(diff / 86400) + '天' + dirStr
|
||||
// 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
|
||||
else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) resStr = getDate(timeStamp)
|
||||
else resStr = getDate(timeStamp, 'year')
|
||||
return resStr
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String} 当前浏览器名称
|
||||
*/
|
||||
export const getExplorer = () => {
|
||||
const ua = window.navigator.userAgent
|
||||
const isExplorer = (exp) => {
|
||||
return ua.indexOf(exp) > -1
|
||||
}
|
||||
if (isExplorer('MSIE')) return 'IE'
|
||||
else if (isExplorer('Firefox')) return 'Firefox'
|
||||
else if (isExplorer('Chrome')) return 'Chrome'
|
||||
else if (isExplorer('Opera')) return 'Opera'
|
||||
else if (isExplorer('Safari')) return 'Safari'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绑定事件 on(element, event, handler)
|
||||
*/
|
||||
export const on = (function () {
|
||||
if (document.addEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.addEventListener(event, handler, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.attachEvent('on' + event, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* @description 解绑事件 off(element, event, handler)
|
||||
*/
|
||||
export const off = (function () {
|
||||
if (document.removeEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.removeEventListener(event, handler, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.detachEvent('on' + event, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性
|
||||
* 如果没有传入key这个参数,则判断obj对象是否有键值对
|
||||
*/
|
||||
export const hasKey = (obj, key) => {
|
||||
if (key) return key in obj
|
||||
else {
|
||||
let keysArr = Object.keys(obj)
|
||||
return keysArr.length
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} obj1 对象
|
||||
* @param {*} obj2 对象
|
||||
* @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
|
||||
*/
|
||||
export const objEqual = (obj1, obj2) => {
|
||||
const keysArr1 = Object.keys(obj1)
|
||||
const keysArr2 = Object.keys(obj2)
|
||||
if (keysArr1.length !== keysArr2.length) return false
|
||||
else if (keysArr1.length === 0 && keysArr2.length === 0) return true
|
||||
/* eslint-disable-next-line */
|
||||
else return !keysArr1.some(key => obj1[key] != obj2[key])
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除乘法计算出现多位小数
|
||||
* @param arg1返回值,arg2乘以的参数
|
||||
*/
|
||||
export const accMul = (arg1, arg2) => {
|
||||
var m=0,s1=arg1.toString(),s2=arg2.toString();
|
||||
try{m+=s1.split(".")[1].length}catch(e){}
|
||||
try{m+=s2.split(".")[1].length}catch(e){}
|
||||
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
import Cookies from 'js-cookie'
|
||||
// cookie保存的天数
|
||||
import config from '@/config'
|
||||
import {forEach, hasOneOf, objEqual} from '@/libs/tools'
|
||||
import {cloneDeep} from 'lodash'
|
||||
|
||||
const {title, useI18n} = config
|
||||
|
||||
// 设置setCookies;
|
||||
// setToken
|
||||
export const setCookies = (key, val, cookieExpires) => {
|
||||
Cookies.set(key, val, {expires: cookieExpires || 1})
|
||||
}
|
||||
// 获取getCookies;
|
||||
// getToken
|
||||
export const getCookies = (key) => {
|
||||
return Cookies.get(key)
|
||||
}
|
||||
|
||||
export const removeCookies = (key) => {
|
||||
return Cookies.remove(key)
|
||||
}
|
||||
|
||||
export const hasChild = (item) => {
|
||||
return item.children && item.children.length !== 0
|
||||
}
|
||||
|
||||
const showThisMenuEle = (item, access) => {
|
||||
if (item.meta && item.meta.access && item.meta.access.length) {
|
||||
if (hasOneOf(item.meta.access, access)) return true
|
||||
else return false
|
||||
} else return true
|
||||
}
|
||||
/**
|
||||
* @param {Array} list 通过路由列表得到菜单列表
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getMenuByRouter = (list, access) => {
|
||||
let res = []
|
||||
forEach(list, item => {
|
||||
if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
meta: item.meta
|
||||
}
|
||||
if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
|
||||
obj.children = getMenuByRouter(item.children, access)
|
||||
}
|
||||
if (item.meta && item.meta.href) obj.href = item.meta.href
|
||||
if (showThisMenuEle(item, access)) res.push(obj)
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} routeMetched 当前路由metched
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getBreadCrumbList = (route, homeRoute) => {
|
||||
let homeItem = {...homeRoute, icon: homeRoute.meta.icon}
|
||||
let routeMetched = route.matched
|
||||
if (routeMetched.some(item => item.name === homeRoute.name)) return [homeItem]
|
||||
let res = routeMetched.filter(item => {
|
||||
return item.meta === undefined || !item.meta.hideInBread
|
||||
}).map(item => {
|
||||
let meta = {...item.meta}
|
||||
if (meta.title && typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true
|
||||
meta.title = meta.title(route)
|
||||
}
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
meta: meta
|
||||
}
|
||||
return obj
|
||||
})
|
||||
res = res.filter(item => {
|
||||
return !item.meta.hideInMenu
|
||||
})
|
||||
return [{...homeItem, to: homeRoute.path}, ...res]
|
||||
}
|
||||
|
||||
export const getRouteTitleHandled = (route) => {
|
||||
let router = {...route}
|
||||
let meta = {...route.meta}
|
||||
let title = ''
|
||||
if (meta.title) {
|
||||
if (typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true
|
||||
title = meta.title(router)
|
||||
} else title = meta.title
|
||||
}
|
||||
meta.title = title
|
||||
router.meta = meta
|
||||
return router
|
||||
}
|
||||
|
||||
export const showTitle = (item, vm) => {
|
||||
let {title, __titleIsFunction__} = item.meta
|
||||
if (!title) return
|
||||
if (useI18n) {
|
||||
if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))
|
||||
else if (__titleIsFunction__) title = item.meta.title
|
||||
else title = vm.$t(item.name)
|
||||
} else title = (item.meta && item.meta.title) || item.name
|
||||
return title
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 本地存储和获取标签导航列表
|
||||
*/
|
||||
export const setTagNavListInLocalstorage = list => {
|
||||
localStorage.tagNaveList = JSON.stringify(list)
|
||||
}
|
||||
/**
|
||||
* @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
|
||||
*/
|
||||
export const getTagNavListFromLocalstorage = () => {
|
||||
const list = localStorage.tagNaveList
|
||||
return list ? JSON.parse(list) : []
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} routers 路由列表数组
|
||||
* @description 用于找到路由列表中name为home的对象
|
||||
*/
|
||||
export const getHomeRoute = (routers, homeName = 'home') => {
|
||||
let i = -1
|
||||
let len = routers.length
|
||||
let homeRoute = {}
|
||||
while (++i < len) {
|
||||
let item = routers[i]
|
||||
if (item.children && item.children.length) {
|
||||
let res = getHomeRoute(item.children, homeName)
|
||||
if (res.name) return res
|
||||
} else {
|
||||
if (item.name === homeName) homeRoute = item
|
||||
}
|
||||
}
|
||||
return homeRoute
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} list 现有标签导航列表
|
||||
* @param {*} newRoute 新添加的路由原信息对象
|
||||
* @description 如果该newRoute已经存在则不再添加
|
||||
*/
|
||||
export const getNewTagList = (list, newRoute) => {
|
||||
const {name, path, meta} = newRoute
|
||||
let newList = [...list]
|
||||
if (newList.findIndex(item => item.name === name) >= 0) return newList
|
||||
else newList.push({name, path, meta})
|
||||
return newList
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} access 用户权限数组,如 ['super_admin', 'admin']
|
||||
* @param {*} route 路由列表
|
||||
*/
|
||||
const hasAccess = (access, route) => {
|
||||
if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access)
|
||||
else return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 权鉴
|
||||
* @param {*} name 即将跳转的路由name
|
||||
* @param {*} access 用户权限数组
|
||||
* @param {*} routes 路由列表
|
||||
* @description 用户是否可跳转到该页
|
||||
*/
|
||||
export const canTurnTo = (name, access, routes) => {
|
||||
const routePermissionJudge = (list) => {
|
||||
return list.some(item => {
|
||||
if (item.children && item.children.length) {
|
||||
return routePermissionJudge(item.children)
|
||||
} else if (item.name === name) {
|
||||
return hasAccess(access, item)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return routePermissionJudge(routes)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} url
|
||||
* @description 从URL中解析参数
|
||||
*/
|
||||
export const getParams = url => {
|
||||
const keyValueArr = url.split('?')[1].split('&')
|
||||
let paramObj = {}
|
||||
keyValueArr.forEach(item => {
|
||||
const keyValue = item.split('=')
|
||||
paramObj[keyValue[0]] = keyValue[1]
|
||||
})
|
||||
return paramObj
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} list 标签列表
|
||||
* @param {String} name 当前关闭的标签的name
|
||||
*/
|
||||
export const getNextRoute = (list, route) => {
|
||||
let res = {}
|
||||
if (list.length === 2) {
|
||||
res = getHomeRoute(list)
|
||||
} else {
|
||||
const index = list.findIndex(item => routeEqual(item, route))
|
||||
if (index === list.length - 1) res = list[list.length - 2]
|
||||
else res = list[index + 1]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} times 回调函数需要执行的次数
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
export const doCustomTimes = (times, callback) => {
|
||||
let i = -1
|
||||
while (++i < times) {
|
||||
callback(i)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} file 从上传组件得到的文件对象
|
||||
* @returns {Promise} resolve参数是解析后的二维数组
|
||||
* @description 从Csv文件中解析出表格,解析成二维数组
|
||||
*/
|
||||
export const getArrayFromFile = (file) => {
|
||||
let nameSplit = file.name.split('.')
|
||||
let format = nameSplit[nameSplit.length - 1]
|
||||
return new Promise((resolve, reject) => {
|
||||
let reader = new FileReader()
|
||||
reader.readAsText(file) // 以文本格式读取
|
||||
let arr = []
|
||||
reader.onload = function (evt) {
|
||||
let data = evt.target.result // 读到的数据
|
||||
let pasteData = data.trim()
|
||||
arr = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => {
|
||||
return row.split('\t')
|
||||
}).map(item => {
|
||||
return item[0].split(',')
|
||||
})
|
||||
if (format === 'csv') resolve(arr)
|
||||
else reject(new Error('[Format Error]:你上传的不是Csv文件'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} array 表格数据二维数组
|
||||
* @returns {Object} { columns, tableData }
|
||||
* @description 从二维数组中获取表头和表格数据,将第一行作为表头,用于在iView的表格中展示数据
|
||||
*/
|
||||
export const getTableDataFromArray = (array) => {
|
||||
let columns = []
|
||||
let tableData = []
|
||||
if (array.length > 1) {
|
||||
let titles = array.shift()
|
||||
columns = titles.map(item => {
|
||||
return {
|
||||
title: item,
|
||||
key: item
|
||||
}
|
||||
})
|
||||
tableData = array.map(item => {
|
||||
let res = {}
|
||||
item.forEach((col, i) => {
|
||||
res[titles[i]] = col
|
||||
})
|
||||
return res
|
||||
})
|
||||
}
|
||||
return {
|
||||
columns,
|
||||
tableData
|
||||
}
|
||||
}
|
||||
|
||||
export const findNodeUpper = (ele, tag) => {
|
||||
if (ele.parentNode) {
|
||||
if (ele.parentNode.tagName === tag.toUpperCase()) {
|
||||
return ele.parentNode
|
||||
} else {
|
||||
return findNodeUpper(ele.parentNode, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const findNodeUpperByClasses = (ele, classes) => {
|
||||
let parentNode = ele.parentNode
|
||||
if (parentNode) {
|
||||
let classList = parentNode.classList
|
||||
if (classList && classes.every(className => classList.contains(className))) {
|
||||
return parentNode
|
||||
} else {
|
||||
return findNodeUpperByClasses(parentNode, classes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const findNodeDownward = (ele, tag) => {
|
||||
const tagName = tag.toUpperCase()
|
||||
if (ele.childNodes.length) {
|
||||
let i = -1
|
||||
let len = ele.childNodes.length
|
||||
while (++i < len) {
|
||||
let child = ele.childNodes[i]
|
||||
if (child.tagName === tagName) return child
|
||||
else return findNodeDownward(child, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const showByAccess = (access, canViewAccess) => {
|
||||
return hasOneOf(canViewAccess, access)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据name/params/query判断两个路由对象是否相等
|
||||
* @param {*} route1 路由对象
|
||||
* @param {*} route2 路由对象
|
||||
*/
|
||||
export const routeEqual = (route1, route2) => {
|
||||
const params1 = route1.params || {}
|
||||
const params2 = route2.params || {}
|
||||
const query1 = route1.query || {}
|
||||
const query2 = route2.query || {}
|
||||
return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2)
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断打开的标签列表里是否已存在这个新添加的路由对象
|
||||
*/
|
||||
export const routeHasExist = (tagNavList, routeItem) => {
|
||||
let len = tagNavList.length
|
||||
let res = false
|
||||
doCustomTimes(len, (index) => {
|
||||
if (routeEqual(tagNavList[index], routeItem)) res = true
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
export const localSave = (key, value) => {
|
||||
localStorage.setItem(key, value)
|
||||
}
|
||||
|
||||
export const localRead = (key) => {
|
||||
return localStorage.getItem(key) || ''
|
||||
}
|
||||
|
||||
// scrollTop animation
|
||||
export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame = (
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
return window.setTimeout(callback, 1000 / 60)
|
||||
}
|
||||
)
|
||||
}
|
||||
const difference = Math.abs(from - to)
|
||||
const step = Math.ceil(difference / duration * 50)
|
||||
|
||||
const scroll = (start, end, step) => {
|
||||
if (start === end) {
|
||||
endCallback && endCallback()
|
||||
return
|
||||
}
|
||||
|
||||
let d = (start + step > end) ? end : start + step
|
||||
if (start > end) {
|
||||
d = (start - step < end) ? end : start - step
|
||||
}
|
||||
|
||||
if (el === window) {
|
||||
window.scrollTo(d, d)
|
||||
} else {
|
||||
el.scrollTop = d
|
||||
}
|
||||
window.requestAnimationFrame(() => scroll(d, end, step))
|
||||
}
|
||||
scroll(from, to, step)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据当前跳转的路由设置显示在浏览器标签的title
|
||||
* @param {Object} routeItem 路由对象
|
||||
* @param {Object} vm Vue实例
|
||||
*/
|
||||
export const setTitle = (routeItem, vm) => {
|
||||
const handledRoute = getRouteTitleHandled(routeItem)
|
||||
const pageTitle = showTitle(handledRoute, vm)
|
||||
let pageTitleCooke = getCookies('pageTitle')
|
||||
let title1 = pageTitleCooke === undefined ? title : pageTitleCooke;
|
||||
const resTitle = pageTitle ? `${title1} - ${pageTitle}` : title1
|
||||
window.document.title = resTitle
|
||||
}
|
||||
|
||||
export const R = (menuList, newOpenMenus) => {
|
||||
menuList.forEach(item => {
|
||||
let newMenu = {}
|
||||
for (let i in item) {
|
||||
if (i !== 'children') newMenu[i] = cloneDeep(item[i])
|
||||
}
|
||||
newOpenMenus.push(newMenu)
|
||||
item.children && R(item.children, newOpenMenus)
|
||||
})
|
||||
return newOpenMenus
|
||||
}
|
||||
|
||||
export function getMenuopen(to, menuList) {
|
||||
const allMenus = []
|
||||
menuList.forEach(menu => {
|
||||
const menus = transMenu(menu, [])
|
||||
allMenus.push({
|
||||
path: menu.path,
|
||||
openNames: []
|
||||
})
|
||||
menus.forEach(item => allMenus.push(item))
|
||||
})
|
||||
const currentMenu = allMenus.find(item => item.path === to.path)
|
||||
return currentMenu ? currentMenu.openNames : []
|
||||
}
|
||||
|
||||
function transMenu(menu, openNames) {
|
||||
if (menu.children && menu.children.length) {
|
||||
const itemOpenNames = openNames.concat([menu.path])
|
||||
return menu.children.reduce((all, item) => {
|
||||
all.push({
|
||||
path: item.path,
|
||||
openNames: itemOpenNames
|
||||
})
|
||||
const foundChildren = transMenu(item, itemOpenNames)
|
||||
return all.concat(foundChildren)
|
||||
}, [])
|
||||
} else {
|
||||
return [menu].map(item => {
|
||||
return {
|
||||
path: item.path,
|
||||
openNames: openNames
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function wss(wsSocketUrl) {
|
||||
let ishttps = document.location.protocol == 'https:';
|
||||
if (ishttps) {
|
||||
return wsSocketUrl.replace('ws:', 'wss:');
|
||||
} else {
|
||||
return wsSocketUrl.replace('wss:', 'ws:');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//set session
|
||||
export function setSen(k, val) {
|
||||
if (typeof val == 'string') {
|
||||
sessionStorage.setItem(k, val);
|
||||
return val;
|
||||
}
|
||||
sessionStorage.setItem(k, JSON.stringify(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
//get session
|
||||
export function getSen(k) {
|
||||
let uu = sessionStorage.getItem(k);
|
||||
|
||||
try {
|
||||
if (typeof JSON.parse(uu) != 'number') {
|
||||
uu = JSON.parse(uu);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return uu;
|
||||
}
|
||||
|
||||
//set local
|
||||
export function setLoc(k, val) {
|
||||
if (typeof val == 'string') {
|
||||
localStorage.setItem(k, val);
|
||||
return val;
|
||||
}
|
||||
localStorage.setItem(k, JSON.stringify(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
//get local
|
||||
export function getLoc(k) {
|
||||
let uu = localStorage.getItem(k);
|
||||
|
||||
try {
|
||||
if (typeof JSON.parse(uu) != 'number') {
|
||||
uu = JSON.parse(uu);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return uu;
|
||||
}
|
||||
|
||||
export function getGuid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = Math.random() * 16 | 0,
|
||||
v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// +---------------------------------------------------------------------
|
||||
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
|
||||
// +---------------------------------------------------------------------
|
||||
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
|
||||
// +---------------------------------------------------------------------
|
||||
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
|
||||
// +---------------------------------------------------------------------
|
||||
// | Author: CRMEB Team <admin@crmeb.com>
|
||||
// +---------------------------------------------------------------------
|
||||
|
||||
class AuthWechat {
|
||||
/**
|
||||
* 是否是微信
|
||||
*/
|
||||
isWeixin() {
|
||||
return navigator.userAgent.toLowerCase().indexOf("micromessenger") !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是手机端
|
||||
*/
|
||||
_isMobile() {
|
||||
let flag = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
export default new AuthWechat();
|
||||
Reference in New Issue
Block a user