UNPKG

vmf

Version:

vue micro service frame

1,768 lines (1,749 loc) 78.5 kB
import Vue from 'vue'; export { default as Vue } from 'vue'; import Moment from 'dayjs'; import Md5 from 'md5'; import Router from 'vue-router'; import Vuex from 'vuex'; import VueMeta from 'vue-meta'; import Axios from 'axios'; export { default as Axios } from 'axios'; import Qs from 'qs'; import { MessageBox, Message, Loading } from 'element-ui'; async function getQRCode() { const { default: qrcode } = await import(/* webpackChunkName: "qrcode" */ 'qrcode'); return qrcode; } async function toDataURL(...arg) { const qrcode = await getQRCode(); if (arg.length <= 1) { arg.push({ margin: 2, scale: 30, errorCorrectionLevel: 'H', }); } return qrcode.toDataURL.apply(null, arg); } var QRCode = { getQRCode, toDataURL, }; /** * Created by henian.xu on 2019/2/28. * 字符串解码 */ /* eslint-disable*/ const t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const a = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, ]; function uniEncode(t) { const e = []; for (let n = 0; n < t.length; n++) e[n] = (`00${t.charCodeAt(n).toString(16)}`).slice(-4); return `\\u${e.join('\\u')}`; } function uniDecode(t) { t = t = t.replace(/(\\)?\\u/gi, '%u').replace('%u0025', '%25'); const e = (t = unescape(t.toString().replace(/%2B/g, '+'))).match(/(%u00([0-9A-F]{2}))/gi); if (e) { for (let n = 0; n < e.length; n++) { const a = e[n].substring(1, 3); Number(`0x${a}`) >= 128 && (t = t.replace(e[n], a)); } } return (t = unescape(t.toString().replace(/%2B/g, '+'))); } function base64Encode(e) { let n; let a; let i; let r; let s; let o; for (i = e.length, a = 0, n = ''; a < i;) { if (((r = 255 & e.charCodeAt(a++)), a == i)) { (n += t.charAt(r >> 2)), (n += t.charAt((3 & r) << 4)), (n += '=='); break; } if (((s = e.charCodeAt(a++)), a == i)) { (n += t.charAt(r >> 2)), (n += t.charAt(((3 & r) << 4) | ((240 & s) >> 4))), (n += t.charAt((15 & s) << 2)), (n += '='); break; } (o = e.charCodeAt(a++)), (n += t.charAt(r >> 2)), (n += t.charAt(((3 & r) << 4) | ((240 & s) >> 4))), (n += t.charAt(((15 & s) << 2) | ((192 & o) >> 6))), (n += t.charAt(63 & o)); } return n; } function base64Decode(t) { let e; let n; let i; let r; let s; let o; let l; for (o = t.length, s = 0, l = ''; s < o;) { do { e = a[255 & t.charCodeAt(s++)]; } while (s < o && e == -1); if (e == -1) break; do { n = a[255 & t.charCodeAt(s++)]; } while (s < o && n == -1); if (n == -1) break; l += String.fromCharCode((e << 2) | ((48 & n) >> 4)); do { if ((i = 255 & t.charCodeAt(s++)) == 61) return l; i = a[i]; } while (s < o && i == -1); if (i == -1) break; l += String.fromCharCode(((15 & n) << 4) | ((60 & i) >> 2)); do { if ((r = 255 & t.charCodeAt(s++)) == 61) return l; r = a[r]; } while (s < o && r == -1); if (r == -1) break; l += String.fromCharCode(((3 & i) << 6) | r); } return l; } function utf8Encode(t) { let e; let n; let a; let i; for (e = '', a = t.length, n = 0; n < a; n++) { (i = t.charCodeAt(n)) >= 1 && i <= 127 ? (e += t.charAt(n)) : i > 2047 ? ((e += String.fromCharCode(224 | ((i >> 12) & 15))), (e += String.fromCharCode(128 | ((i >> 6) & 63))), (e += String.fromCharCode(128 | ((i >> 0) & 63)))) : ((e += String.fromCharCode(192 | ((i >> 6) & 31))), (e += String.fromCharCode(128 | ((i >> 0) & 63)))); } return e; } function utf8Decode(t) { let e; let n; let a; let i; let r; let s; for (e = '', a = t.length, n = 0; n < a;) { switch ((i = t.charCodeAt(n++)) >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: e += t.charAt(n - 1); break; case 12: case 13: (r = t.charCodeAt(n++)), (e += String.fromCharCode(((31 & i) << 6) | (63 & r))); break; case 14: (r = t.charCodeAt(n++)), (s = t.charCodeAt(n++)), (e += String.fromCharCode(((15 & i) << 12) | ((63 & r) << 6) | ((63 & s) << 0))); } } return e; } function utf16to8(t) { return t.replace(/\\x/g, '%'); } function utf8to16(t) { return t.replace(/%/g, '\\x'); } var Decode = { uniEncode, uniDecode, base64Encode, base64Decode, utf8Encode, utf8Decode, utf16to8, utf8to16, }; /** * Created by henian.xu on 2019/11/1. * */ function sortAtOrderNum(list) { list.sort((prev, next) => prev.orderNum - next.orderNum || prev.id - next.id); } function sortTreeData(list) { if (!Array.isArray(list) && typeof list !== 'object') return; list.forEach(item => { if (item.children && item.children.length) { sortTreeData(item.children); } }); sortAtOrderNum(list); } function listToTree(list, lv) { // console.log('convertListToTree'); const res = []; const parentNodeMap = {}; let minLv = 9999999; list.forEach(item => { // item.id 有值时才可能是父节点 (这个有数据问题 id 不应该不存在) if (item.id) { parentNodeMap[item.id] = item; minLv = lv || (item.lv < minLv ? item.lv : minLv); } }); list.forEach(item => { // item.lv = minLv 时是根节点 if (item.lv === minLv) { res.push(item); } else { const parentNode = parentNodeMap[item.parentId]; if (parentNode) { parentNode.children = parentNode.children || []; parentNode.children.push(item); } else { console.error('此节点数据有问题', item); } } }); // console.log(res); sortTreeData(res); // console.log(res); return res; } var Convert = { listToTree, sortAtOrderNum, sortTreeData, }; const pickerOptions = { shortcuts: [ { text: '今天', onClick(picker) { const now = new Date(); picker.$emit('pick', [now, now]); }, }, { text: '昨天', onClick(picker) { const now = new Date(); now.setTime(now.getTime() - 3600 * 1000 * 24); picker.$emit('pick', [now, now]); }, }, { text: '近一周', onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); picker.$emit('pick', [start, end]); }, }, { text: '近一个月', onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); picker.$emit('pick', [start, end]); }, }, { text: '近三个月', onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); picker.$emit('pick', [start, end]); }, }, ], }; var CommonConfig = { pickerOptions, }; /** * Created by henian.xu on 2019/3/19. * */ const Device = (function Device() { const { platform } = window.navigator; const ua = window.navigator.userAgent; const device = { ua, ios: false, android: false, androidChrome: false, desktop: false, windowsPhone: false, iphone: false, iphoneX: false, ipod: false, ipad: false, edge: false, ie: false, firefox: false, macos: false, windows: false, cordova: !!(window.cordova || window.phonegap), phonegap: !!(window.cordova || window.phonegap), electron: false, webview: false, standalone: false, statusbar: false, weixin: false, pixelRatio: 1, os: '', osVersion: null, needsStatusbarOverlay: () => false, }; const screenWidth = window.screen.width; const screenHeight = window.screen.height; const windowsPhone = ua.match(/(Windows Phone);?[\s\/]+([\d.]+)?/); // eslint-disable-line const android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // eslint-disable-line const ipad = ua.match(/(iPad).*OS\s([\d_]+)/); const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); const iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/); const iphoneX = iphone && ((screenWidth === 375 && screenHeight === 812) || // X/XS (screenWidth === 414 && screenHeight === 896)); // XR / XS Max const ie = ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0; const edge = ua.indexOf('Edge/') >= 0; const firefox = ua.indexOf('Gecko/') >= 0 && ua.indexOf('Firefox/') >= 0; const macos = platform === 'MacIntel'; const windows = platform === 'Win32'; const electron = ua.toLowerCase().indexOf('electron') >= 0; const weixin = !!ua.match(/MicroMessenger/); device.ie = ie; device.edge = edge; device.firefox = firefox; device.weixin = weixin; /* eslint-disable prefer-destructuring */ // Windows if (windowsPhone) { device.os = 'windowsPhone'; device.osVersion = windowsPhone[2]; device.windowsPhone = true; } // Android if (android && !windows) { device.os = 'android'; device.osVersion = android[2]; device.android = true; device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0; } if (ipad || iphone || ipod) { device.os = 'ios'; device.ios = true; } // iOS if (iphone && !ipod) { device.osVersion = iphone[2].replace(/_/g, '.'); device.iphone = true; device.iphoneX = !!iphoneX; } if (ipad) { device.osVersion = ipad[2].replace(/_/g, '.'); device.ipad = true; } if (ipod) { device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null; device.iphone = true; } // iOS 8+ changed UA if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) { if (device.osVersion.split('.')[0] === '10') { device.osVersion = ua .toLowerCase() .split('version/')[1] .split(' ')[0]; } } // Webview const webView = !!((iphone || ipad || ipod) && (ua.match(/.*AppleWebKit(?!.*Safari)/i) || window.navigator.standalone)) || (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); device.webview = webView; device.standalone = webView; // Desktop device.desktop = !(device.ios || device.android || device.windowsPhone) || electron; if (device.desktop) { device.electron = electron; device.macos = macos; device.windows = windows; } // Meta statusbar const metaStatusbar = document.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]'); // Check for status bar and fullscreen app mode device.needsStatusbarOverlay = function needsStatusbarOverlay() { if (device.desktop) return false; if (device.standalone && device.ios && metaStatusbar && metaStatusbar.content === 'black-translucent') { return true; } if ((webView || (device.android && device.cordova)) && window.innerWidth * window.innerHeight === window.screen.width * window.screen.height) { if (device.iphoneX && (window.orientation === 90 || window.orientation === -90)) { return false; } return true; } return false; }; device.statusbar = device.needsStatusbarOverlay(); // Pixel Ratio device.pixelRatio = window.devicePixelRatio || 1; // Export object return device; })(); /** * Created by henian.xu on 2020/5/22. * */ const NOOP = () => { }; const getType = (obj) => Object.prototype.toString.call(obj).slice(8, -1); const { isArray } = Array; const isFunction = (val) => typeof val === 'function'; const isString = (val) => typeof val === 'string'; const isBoolean = (val) => typeof val === 'boolean'; const isObject = (val) => val !== null && typeof val === 'object'; // const urlReg = new RegExp(/[a-zA-z]+:\/\/[^\s]*/); const isUrl = (url) => /[a-zA-z]+:\/\/[^\s]*/.test(url); function assert(condition, msg, module = 'vmf') { if (!condition) throw new Error(`[${module}] ${msg}`); } const isDef = (val) => val !== undefined; const getUniqueId = (() => { let autoIncrement = 0; return (prefix = '') => { autoIncrement += 1; const cDate = new Date().getTime(); const offDate = new Date(2010, 1, 1).getTime(); const offset = cDate - offDate; return prefix + parseFloat(`${offset}`).toString(16) + autoIncrement; }; })(); function getKey() { // const t = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' const t = 'xxxxxxxx'; return t.replace(/[xy]/g, c => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } /** * 检查对象是否具有该属性。 */ const hasOwn = (() => { const { hasOwnProperty } = Object.prototype; return (obj, key) => hasOwnProperty.call(obj, key); })(); /** * 是否 VNode * @param node */ const isVNode = (node) => node !== null && typeof node === 'object' && hasOwn(node, 'componentOptions'); /** * 防抖 * (与underscore 不同的是 immediate 为 true 时仅仅只是第一次触发会立即调用, * 而 underscore immediate 为 true 时会把调用前置,既:触发会立即调用且在 delay 内再触发触发的不调用。 * 与 underscore 的不同导致不会严格按照 delay 时间间隔调用,因为正好在 delay 调用后触发会立即调用) * @param func * @param delay * @param immediate */ function debounce(func, delay = 200, immediate = false) { let timeout = null; function debounced(...args) { let callback; const promise = new Promise(resolve => { callback = resolve; }); if (timeout) clearTimeout(timeout); if (immediate) { const callNow = !timeout; // 如果 timeout 为 false 立即调用,侧 setTimeout 就无需重复调用,否侧相反 timeout = setTimeout((now) => { timeout = null; if (now) callback(func.apply(this, args)); }, delay, !callNow); if (callNow) callback(func.apply(this, args)); } else { timeout = setTimeout(() => callback(func.apply(this, args)), delay); } return promise; } debounced.cancel = () => { clearTimeout(timeout); timeout = null; }; return debounced; } /** * 节流 * underscore的实现 * @param func * @param delay * @param options */ function throttle(func, delay = 200, options = { leading: true, trailing: true }) { let timeout; let context; let _args; let previous = 0; if (!options) options = {}; const later = (resolve) => { previous = options.leading === false ? 0 : new Date().getTime(); timeout = null; resolve(func.apply(context, _args)); if (!timeout) { context = null; _args = null; } }; function throttled(...args) { let callback; const promise = new Promise(resolve => { callback = resolve; }); const now = new Date().getTime(); if (!previous && options.leading === false) previous = now; const remaining = delay - (now - previous); context = this; _args = args; if (remaining <= 0 || remaining > delay) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; callback(func.apply(context, _args)); if (!timeout) { context = null; _args = null; } } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining, callback); } return promise; } throttled.cancel = () => { clearTimeout(timeout); previous = 0; timeout = null; context = null; _args = null; }; return throttled; } /** * 整合异步 * @param func */ function integrateAsync(func) { const promisesMap = {}; return async function integrate(...args) { let options = [...Array.from(args)].pop(); if (!isObject(options)) options = {}; const groupKey = `${options.groupKey || 'default'}`; const promises = promisesMap[groupKey]; if (promises) { return new Promise((resolve, reject) => { promises.push({ resolve, reject }); }); } promisesMap[groupKey] = []; let res = null; try { res = await func.apply(this, args); } catch (e) { res = Promise.reject(e); } promisesMap[groupKey].forEach(({ resolve, reject }) => { if (res instanceof Promise) { res.then(r => { resolve(r); }).catch(e => { reject(e); }); } else { resolve(res); } }); delete promisesMap[groupKey]; return res; }; } function delayRun(func, delay, ...args) { return setTimeout(() => func.apply(this, args), delay); } // 加载图片 function loadImg(src) { return new Promise((resolve, reject) => { const img = new Image(); // 当为线上图片时,需要设置 crossOrigin 属性; if (src.indexOf('http') === 0) img.crossOrigin = '*'; img.onload = () => { resolve(img); }; img.onerror = () => { reject(img); }; img.src = src; }); } function loadImgs(srcs) { const lng = srcs.length; let count = 0; const imgs = []; return new Promise((resolve, reject) => { srcs.forEach((item, index) => { loadImg(item) .then(img => { count += 1; imgs[index] = img; if (count >= lng) { resolve(imgs); } }) .catch(_err => { reject(_err); }); }); }); } // 合并表单项 function formModelMerge(formModel, obj) { Object.keys(formModel).forEach(key => { let item = obj[key]; if (typeof item === 'string') { item = item.trim(); } const isBooleanAndNumber = typeof item === 'boolean' || typeof item === 'number'; if (!(!isBooleanAndNumber && (item === undefined || (Array.isArray(item) && !item.length) || JSON.stringify(item) === '{}'))) { formModel[key] = item; } }); } /** * 数值格式化 * @param value * @param length * @param strict */ function filterNumber(value = 0, length = 2, strict = false) { if (value === null) return ''; let numberList = []; if (Number.isNaN(+value)) { numberList = `${value}`.split('-'); } else { numberList = [`${value}`]; } return numberList .reduce((pre, cur) => { let item = ''; if (!Number.isNaN(+cur) && cur !== '') { item = (+cur).toFixed(length); if (!strict) { item = `${+item}`; } } pre.push(item); return pre; }, []) .join('-'); } // 获取当前月份第一天 function getSysMonthFirstDayDate() { const date = new Date(); return `${date.getFullYear()}-${(Array(2).join('0') + (date.getMonth() + 1)).slice(-2)}-01`; } // 获取当前年月日 function getSysDayDate() { const date = new Date(); return `${date.getFullYear()}-${(Array(2).join('0') + (date.getMonth() + 1)).slice(-2)}-${(Array(2).join('0') + date.getDate()).slice(-2)}`; } // 获取当年第一个月 function getSysYearFirstMonthDate() { const date = new Date(); return `${date.getFullYear()}-01`; } // 获取当前年月 function getSysMonthDate() { const date = new Date(); return `${date.getFullYear()}-${(Array(2).join('0') + (date.getMonth() + 1)).slice(-2)}`; } // 表单校验 function validateForm(forms, showFirstErrorField = true) { forms = forms.filter(form => form._isVue && form.validate); let callback; let count = 0; const len = forms.length; const invalidFields = []; const formsMap = {}; let resultValid = true; if (!forms.length) return Promise.resolve(true); const promise = new Promise((resolve, reject) => { callback = (valid, invalidFieldMap, _uid) => { if (!valid) resultValid = false; Object.keys(invalidFieldMap || {}).forEach(field => { invalidFields.push(formsMap[_uid].fieldsMap[field]); }); count += 1; if (count !== len) return; if (!resultValid) { if (showFirstErrorField && invalidFields.length) { invalidFields[0].scrollIntoView(true); } // eslint-disable-next-line prefer-promise-reject-errors reject({ errorField: invalidFields }); } else { resolve(true); } }; }); forms.forEach(form => { formsMap[form._uid] = { fieldsMap: form.fields.reduce((prev, curr) => { prev[curr.prop] = curr.$el; return prev; }, {}), }; form.validate((valid, invalidFieldMap) => callback(valid, invalidFieldMap, form._uid)); }); return promise; } // 取出对象中的深层属性 function pluckDeep(path, data, isCreate = false) { const pathArr = `${path}`.split('.'); const lng = pathArr.length; return pathArr.reduce((prev, next, index) => { const now = prev[next]; if (now !== null && typeof now === 'object' && !Array.isArray(now)) { return now; } if (!isCreate) { if (index + 1 === lng) { return now; } throw new Error(`${path}超出对像范围`); } prev[next] = {}; return prev[next]; }, data); } /* 转换 css 的值 */ function transformCssValue(val, unit = 'px') { const int = parseFloat(val); if (!int) return ''; if (!+val) return val; return int + unit; } function makeEnum(obj) { if (!isObject(obj)) throw new Error(`构建枚举的对象必须是 array 或 object`); let list = obj; if (!isArray(list)) { list = Object.entries(obj).reduce((pre, cur) => { const [code, key] = cur; pre.push({ key, code }); return pre; }, []); } const result = {}; Object.defineProperty(result, '_rawList', { get() { return list; }, }); return list.reduce((pre, cur) => { const { key, code, name } = cur; if (!key || (!code && !name)) { throw new Error(`构建枚举的数组项必须包含{key,[code|name]}`); } if (code) { if (hasOwn(pre, code)) throw new Error(`有重复 code:${code} 值`); Object.defineProperty(pre, code, { get: () => key }); } else if (name) { if (hasOwn(pre, name)) throw new Error(`有重复 name:${name} 值`); Object.defineProperty(pre, name, { get: () => key }); } if (hasOwn(pre, key)) throw new Error(`有重复 key:${key} 值`); Object.defineProperty(pre, key, { get() { const res = { ...cur }; if (code) res.code = code; if (name || code) res.name = name || code; return res; }, enumerable: true, }); return pre; }, result); } function dataURLtoBlob(dataurl, fileName = '') { const arr = dataurl.split(','); const mime = (arr[0].match(/:(.*?);/) || [])[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while (n) { n -= 1; u8arr[n] = bstr.charCodeAt(n); } const blob = new Blob([u8arr], { type: mime }); if (fileName) { // ios 某些版本不支持 new File // return new File([u8arr], fileName, { type: mime }); blob.name = fileName; blob.lastModifiedDate = new Date(); } return blob; } const createObjectURL = (() => { const { createObjectURL: createUrl } = (window || {}).URL || {}; return (obj) => createUrl && createUrl(obj); })(); function formatDuration(ms) { if (ms < 0) ms = -ms; const time = { day: Math.floor(ms / 86400000), hour: Math.floor(ms / 3600000) % 24, minute: Math.floor(ms / 60000) % 60, second: Math.floor(ms / 1000) % 60, }; const splitMap = { day: ' ', hour: ':', minute: ':', second: '', }; return Object.entries(time) .filter(val => val[1] !== 0 || val[0] === 'second' || val[0] === 'minute') .map(([key, val]) => `${`${val}`.padStart(2, '0')}${splitMap[key]}`) .join(''); } const startCountdown = (() => { let heartbeatId = null; const timestampMap = {}; function heartbeat() { heartbeatId = setInterval(() => { const timestampList = Object.values(timestampMap); if (heartbeatId && (!timestampList || !timestampList.length)) { clearInterval(heartbeatId); heartbeatId = null; return; } timestampList.forEach(item => { const { uid, active, callBack, finish } = item; if (!active) { delete timestampMap[uid]; return; } item.timestamp -= 1000; if (item.timestamp > 0) { callBack(formatDuration(item.timestamp), item.timestamp); } else { item.active = false; callBack(formatDuration(0), 0); finish(0); } }); }, 1000); } function stop(uid) { const item = timestampMap[uid]; if (!item) return; item.active = false; } return function handler(timestamp, callBack = NOOP, finish = NOOP) { const uid = getUniqueId('countdown-'); timestampMap[uid] = { uid, active: true, timestamp, callBack, finish, }; if (!heartbeatId) heartbeat(); return () => stop(uid); }; })(); function addScript(src) { if (!src) return null; const script = document.createElement('script'); script.type = 'text/javascript'; script.src = src; document.body.appendChild(script); return () => { document.body.removeChild(script); }; } async function loadExternalScript(src, check, delay = 500) { if (!src) return Promise.reject(new Error('src 不能为空')); if (isFunction(check)) { const res = check(); if (res) return res; } let checkCount = 0; return new Promise((resolve, reject) => { const unload = addScript(src); if (!unload) { reject(new Error('加载脚本失败')); return; } if (isFunction(check)) { const timerId = setInterval(() => { const res = check(); if (res) { resolve(res); clearInterval(timerId); } else if (checkCount > 5) { clearInterval(timerId); unload(); reject(new Error(`已检查 5遍了,脚本未加载成功!`)); } checkCount += 1; }, delay); } }); } const sizeMap = { b: 0, kb: 1, mb: 2, gb: 3 }; function fileSize(value = 0, format, isUpperCase = false) { let val = +value || 0; let unit = `${format || ''}`.toLocaleLowerCase(); if (val) { if (unit) { val = Array(sizeMap[unit] || 0) .fill(null) .reduce(pre => { pre /= 1024; return pre; }, val); } else if (~~(val / 1024 ** 3)) { val /= 1024 ** 3; unit = 'gb'; } else if (~~(val / 1024 ** 2)) { val /= 1024 ** 2; unit = 'mb'; } else if (~~(val / 1024 ** 1)) { val /= 1024 ** 1; unit = 'kb'; } else { unit = 'b'; } } if (isUpperCase) unit = unit.toLocaleUpperCase(); return `${+val.toFixed(2)}${unit}`; } /** * Created by henian.xu on 2018/7/24. * 常用校验类 */ const emailReg = /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/; // const mobileReg = /(^((166|198|199)|(15[^4])|(14[5-9])|17[0-3]|(17[5-8])|((13|18)[0-9]))\d{8}$)|(^(1749)\d{7}$)/; const mobileReg = /^1\d{10}$/; /** * 确认密码验证 * @param rule * @param value * @param callback */ function againPassword(rule, value, callback /* , source, options */) { if (value !== this.formModel.password) { callback(new Error(rule.message)); } else { callback(); } } /** * 邮箱验证 * @param rule * @param value * @param callback * @param source * @param options */ function email(rule, value, callback /* , source, options */) { if (!emailReg.test(value)) { callback(new Error(rule.message)); } else { callback(); } } /** * 手机验证 * @param rule * @param value * @param callback * @param source * @param options */ function mobile(rule, value, callback /* , source, options */) { if (!mobileReg.test(value)) { callback(new Error(rule.message)); } else { callback(); } } /** * 账号验证(手机号与邮箱) * @param rule * @param value * @param callback */ function account(rule, value, callback) { if (!emailReg.test(value) && !mobileReg.test(value)) { callback(new Error(rule.message)); } else { callback(); } } function strictRequired(rule, value, callback) { const { key = 'id', message } = rule; let val = value; if (isArray(value)) { val = value.length; } else if (isObject(value)) { val = value[key]; } else if (isBoolean(value)) { val = true; } if (val) { callback(); } else { callback(new Error(message)); } } var Valid = { againPassword, email, mobile, account, strictRequired, }; /** * Created by henian.xu on 2019/11/24. * */ const $bus = new Vue(); let _router; function setRouter(router) { _router = router; } function getRouter() { return _router; } var Runtime = { setRouter, getRouter, }; /** * Created by henian.xu on 2019/10/12. * */ const GlobalVar = window.__GLOBAL_VAR__ || {}; GlobalVar.docTitle = document.title; // 默认页面标题 GlobalVar.isDev = process.env.NODE_ENV === 'development'; function mergeConfig(config) { // TODO 写一个配置合并方法 GlobalVar.appConfig = { ...GlobalVar.appConfig, ...config, }; } const requireConfig = require.context('@', true, /\.(\/.[^/]*)?\/(config|config\/index)\.js$/); requireConfig.keys().forEach((fileName) => { const config = requireConfig(fileName); if (!config) return; mergeConfig(config); // console.log(config); }); // console.log('config', requireConfig.keys()); var GlobalVar$1 = Vue.observable(GlobalVar); /** * Created by henian.xu on 2019/11/18. * */ var Utils = /*#__PURE__*/Object.freeze({ __proto__: null, QRCode: QRCode, Decode: Decode, Convert: Convert, CommonConfig: CommonConfig, Device: Device, Valid: Valid, Runtime: Runtime, $bus: $bus, GlobalVar: GlobalVar$1, Md5: Md5, NOOP: NOOP, getType: getType, isArray: isArray, isFunction: isFunction, isString: isString, isBoolean: isBoolean, isObject: isObject, isUrl: isUrl, assert: assert, isDef: isDef, getUniqueId: getUniqueId, getKey: getKey, hasOwn: hasOwn, isVNode: isVNode, debounce: debounce, throttle: throttle, integrateAsync: integrateAsync, delayRun: delayRun, loadImg: loadImg, loadImgs: loadImgs, formModelMerge: formModelMerge, filterNumber: filterNumber, getSysMonthFirstDayDate: getSysMonthFirstDayDate, getSysDayDate: getSysDayDate, getSysYearFirstMonthDate: getSysYearFirstMonthDate, getSysMonthDate: getSysMonthDate, validateForm: validateForm, pluckDeep: pluckDeep, transformCssValue: transformCssValue, makeEnum: makeEnum, dataURLtoBlob: dataURLtoBlob, createObjectURL: createObjectURL, formatDuration: formatDuration, startCountdown: startCountdown, addScript: addScript, loadExternalScript: loadExternalScript, fileSize: fileSize }); Moment.extend(require('dayjs/plugin/duration')); var Filter = (vue) => { vue.filter('moment', (value, format = 'YYYY-MM-DD') => { if (!value) return ''; return Moment(value).format(format); }); vue.filter('number', (value = 0, length = 2, strict = true) => { const res = filterNumber(value, length, strict); return strict ? res : +res; }); vue.filter('price', (value = 0, length = 0, strict) => { const amountFormat = `${GlobalVar$1.moduleConfig.amountFormat}`; const signStrict = amountFormat.charAt(0) !== '+'; const arr = amountFormat.split('.'); const len = arr.length < 2 ? 0 : arr[1].length; return filterNumber(value, length || len, isDef(strict) ? strict : signStrict); }); /** * imgCropping * mini: 100 * small: 200 * little: 375 * normal: 750 * big: 900 * more: 1200 * super: 1920 */ vue.filter('imgCropping', (value, params) => { value += ''; const { moduleConfig: { imgCropping } = {} } = GlobalVar$1; if (!value || !imgCropping || !params) return value; const imgCroppingList = isArray(imgCropping) ? imgCropping : [imgCropping]; const available = imgCroppingList.some(val => isString(val) && value.indexOf(val) === 0); // console.log(available, params); if (!available) return value; if (params && isString(params)) return `${value}_${params}`; if (params && isObject(params)) { // doc: https://help.aliyun.com/document_detail/44688.html?spm=a2c4g.11186623.6.1372.11313168wqiX8s const keyMap = { mode: 'm', width: 'w', height: 'h', long: 'l', short: 's', limit: 'limit', color: 'color', }; const query = Object.entries(params) .reduce((pre, [key, val]) => { const k = keyMap[key]; if (k) pre.push(`${k}_${val}`); return pre; }, ['image/resize']) .join(','); const fn = '?x-oss-process='; return `${value}${fn}${query}`; } return `${value}_normal`; }); vue.filter('fileSize', (value = 0, format, isUpperCase = false) => { return fileSize(value, format, isUpperCase); }); vue.filter('moneyFormat', (value = 0) => { let val = value; if (val === 0) val = '0'; return `${val || ''}`.replace(/(?<!\.\d*)(\d)(?=(\d{3})+($|\.))/g, '$1,'); }); }; /** * Created by henian.xu on 2023/6/12. * */ function create$$t(vue) { const old$t = vue.prototype.$t; const { $i18n } = vue.prototype; return function func(key, defaultValue, ...values) { let res = ''; if (old$t) { res = old$t.call(this, key, ...values); } else if ($i18n) { res = $i18n._t(key, $i18n.locale, $i18n._getMessages(), this, ...values); } return res || defaultValue || ''; }; } const $$t = create$$t(Vue); var I18n = (vue) => { vue.prototype.$$t = create$$t(vue); }; let powerMap = null; // 添加权限 function addPower(list = [], isClear = true) { if (!powerMap || isClear) { powerMap = {}; } list.reduce((pre, cur) => { pre[cur] = true; return pre; }, powerMap); } const hasPower = (value, bitAnd) => { if (!powerMap || powerMap['*']) return true; let result = false; // eslint-disable-next-line no-cond-assign for (let i = 0, item; (item = value[i]); i += 1) { result = powerMap[item]; if (!result) { const itemArr = item.split(':'); const itemLen = itemArr.length - 1; for (let n = 0; n < itemLen; n += 1) { itemArr.length -= 1; const key = `${itemArr.join(':')}*`; result = powerMap[key]; if (result) break; } } // 处理关系 if (bitAnd) { if (!result) break; } else if (result) break; } return result; }; hasPower.addPower = addPower; var Power = (vue) => { Object.defineProperty(vue, '$power', { get() { return hasPower; }, }); Object.defineProperty(vue.prototype, '$power', { get() { return hasPower; }, }); }; /** * Created by henian.xu on 2019/10/12. * */ Vue.use(Router); const initialMethodMap = {}; const routes = []; async function initAppData(to) { const { meta: { uniqueId }, } = to; const initialMethod = initialMethodMap[uniqueId]; let res; if (!initialMethod || initialMethod.isCalled) return res; res = await initialMethod(); console.log('初始路由数据完成', 222222); initialMethod.isCalled = true; return res; } const router = new Router({ mode: 'hash', linkActiveClass: 'active', linkExactActiveClass: 'exact-active', ...(GlobalVar$1.appConfig && GlobalVar$1.appConfig.ROUTER_DEFAULT_CONFIG), }); router.beforeEach((to, from, next) => { if (to.path === '/login') { next(); return; } initAppData(to) .then(() => { next(); }) .catch(() => { next(); }) .finally(() => { // noop }); }); // eslint-disable-next-line no-shadow function markRoutes(routes, uniqueId) { return routes.map(route => { const res = { ...route, meta: { ...route.meta, uniqueId, }, }; if (route.children && route.children.length) res.children = markRoutes(route.children, uniqueId); return res; }); } // TODO 检验重复的 route function addRoutes(routesList, beforeEach) { const uniqueId = getUniqueId('router-'); const routeList = markRoutes(routesList, uniqueId); if (isFunction(beforeEach)) { initialMethodMap[uniqueId] = beforeEach; } routes.splice(routes.length, 0, ...routeList); router.addRoutes(routeList); } // 设置运行时 router Runtime.setRouter(router); /** * Created by henian.xu on 2020/2/6. * 该插件使 getters 中的方法 this 指向 {store,dispatch,commit} * store: 当前根 store 实例 * dispatch: 当前模块 dispatch 方法 * commit: 当前模块 commit 方法 */ function forEachModules(store, modules, path = []) { Object.keys(modules).forEach(moduleKey => { const module = modules[moduleKey]; const { namespaced, _rawModule: rawModule, _children: children, context, } = module; const newPath = namespaced ? path.concat(moduleKey) : path; const { getters = {} } = rawModule; Object.keys(getters).forEach(key => { const methodsKey = newPath.concat(key).join('/'); const { _vm: { _computedWatchers: computedWatchers = {} } = {} } = store; if (computedWatchers[methodsKey]) { computedWatchers[methodsKey].getter = () => { return getters[key].call({ store, dispatch: context.dispatch, commit: context.commit, }, // local context context.state, // local state context.getters, // local getters store.state, // root state store.getters); }; } }); forEachModules(store, children, newPath); }); } var gettersPlugin = (store) => forEachModules(store, store._modules); /** * Created by henian.xu on 2019/10/13. * */ // import Global from './Global'; // 移到 vmf 模块下 Vue.use(Vuex); function assertModule(store, path) { const pathList = Array.isArray(path) ? path : [path]; for (let i = 0, len = pathList.length; i < len; i += 1) { const key = pathList[i]; if (!hasOwn(store, key)) return; store = store[key]; } assert(false, `${pathList.join('.')} 模块/属性已经存在,所以不能注册!`, '@vmf/vuex'); } const store = new Vuex.Store({ plugins: [gettersPlugin], // 原始默认状态(是无法被 unregisterModule 注销的) modules: {}, state: {}, getters: {}, mutations: {}, actions: {}, }); function registerModule(path, module, options) { assertModule(store.state, path); store.registerModule(path, module, options); const rootModule = store._modules.root; const { plugins } = rootModule._rawModule; // apply plugins plugins.forEach((plugin) => plugin(store)); } function unregisterModule(path) { store.unregisterModule(path); } /** * Created by henian.xu on 2019/11/24. * */ var Plugin = (vue) => { const { appConfig = {} } = GlobalVar$1; vue.prototype.$defaultImg = appConfig.DEFAULT_IMG; vue.use(VueMeta, appConfig.VUE_META); }; const recordRequestMap = {}; const recordLoadingMap = {}; let loadingInstance = null; const vm = new Vue(); // 获取取消请求配置 function getExtendConfig(config) { const { cancelToken } = config; if (!cancelToken || !cancelToken.extendConfig) return null; return cancelToken.extendConfig; } // 记录请求用于处理重复请求 function recordRequest(config) { const extendConfig = getExtendConfig(config); if (!extendConfig) return; const { isRepeat, isCancelBefore, cancelSource } = extendConfig; if (isRepeat) return; // 可重复的请求不记录 const { url, baseURL } = config; const recordKey = `${baseURL}${url}`; const oldCancelSource = recordRequestMap[recordKey]; if (!oldCancelSource) { // requestMap 无记录说明是新的请求 recordRequestMap[recordKey] = cancelSource; } else if (isCancelBefore) { oldCancelSource.cancel(`因重复而取消之前的请求:${recordKey}`); recordRequestMap[recordKey] = cancelSource; // 更新取消令牌 } else { cancelSource.cancel(`因重复而取消当前的请求:${recordKey}`); } } // 删除已记录的请求 function removeRequestRecord(response) { const { config } = response; if (!config || !config.url) return; const { url, baseURL } = config; const recordKey = new RegExp(`^${baseURL}`).test(url) ? url : `${baseURL}${url}`; delete recordRequestMap[recordKey]; } // 请求提示处理 function promptHandler(response) { const { config, data: reslut } = response; const extendConfig = getExtendConfig(config); if (!extendConfig) return Promise.resolve(response); const { isHandleError, isSuccessTip } = extendConfig; if (!reslut.success) { if (isHandleError) return Promise.resolve(response); if (!isHandleError) { // 统一处理失败请求提示 MessageBox.alert(reslut.msg || '', vm.$$t('vmf_friendly_reminder', '温馨提示'), { type: 'error', confirmButtonText: vm.$$t('vmf_confirm', '确定'), }); } return Promise.reject(response); } if (isSuccessTip) { // 统一处理成功请求提示 Message.success({ message: reslut.msg || '', offset: 70 }); } return Promise.resolve(response); } // loading处理 function recordRequestLoading(config) { const extendConfig = getExtendConfig(config); if (!extendConfig) return; const { isLoading } = extendConfig; if (!isLoading) return; const { url, baseURL } = config; const recordKey = `${baseURL}${url}`; recordLoadingMap[recordKey] = true; loadingInstance = Loading.service({ lock: true, text: isString(isLoading) ? isLoading : vm.$$t('vmf_please_wait', '请稍候...'), spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)', customClass: 'loading-show-ani', }); // vm.$nprogress.start(); } function removeRequestLoading(response) { const { config } = response; if (!config || !config.url) return; const { url, baseURL } = config; const recordKey = new RegExp(`^${baseURL}`).test(url) ? url : `${baseURL}${url}`; delete recordLoadingMap[recordKey]; const { length } = Object.keys(recordLoadingMap); if (length || !loadingInstance) return; loadingInstance.close(); loadingInstance = null; // vm.$nprogress.done(); } const httpStatusHandler = { isStatusProcessing: { 401: false, }, 401() { console.log(401); const router = Runtime.getRouter(); const { currentRoute } = router; const query = {}; if (currentRoute.name === null && currentRoute.path === '/') { const hash = (window.location.hash || '').replace(/^#/, ''); const [matchedComponent] = router.getMatchedComponents(hash); if (matchedComponent.name !== 'ErrorPage') { query.backUrl = hash; } } if (this.isStatusProcessing[401] || currentRoute.name === 'login') return; this.isStatusProcessing[401] = true; router .replace({ path: '/login', query, }) .finally(() => { this.isStatusProcessing[401] = false; }); }, 404( /* response */) { /* console.log('404'); */ }, }; // http状态处理 function httpStatusCodeHandler(error) { const { resp