ui库合并版本完成
This commit is contained in:
		
							
								
								
									
										88
									
								
								ui/lib/js/area.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								ui/lib/js/area.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| import request from "./request"; | ||||
|  | ||||
|  | ||||
| export default class Area { | ||||
|   constructor(code, hash = {}) { | ||||
|     this.id = code | ||||
|     this.level = Area.getLevelByAreaId(code) | ||||
|     this.areaMap = Object.values(this.getAreaInfo(code)) | ||||
|     if (Object.keys(hash).length > 0) { | ||||
|       this.getName(this.areaMap.map(id => hash[id])) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 获取地区的行政等级 | ||||
|    * @param code 地区编码 | ||||
|    * @returns {number} | ||||
|    */ | ||||
|   static getLevelByAreaId(code) { | ||||
|     if (code) { | ||||
|       if (code.length === 2 || /0{10}$/.test(code)) return 0; | ||||
|       else if (/0{8}$/.test(code)) return 1; | ||||
|       else if (/0{6}$/.test(code)) return 2; | ||||
|       else if (/0{3}$/.test(code)) return 3; | ||||
|       else return 4 | ||||
|     } else return -1 | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 根据地区编码获取指定等级的地区编码 | ||||
|    * @param value 地区编码 | ||||
|    * @param level 指定等级 | ||||
|    * @returns {string|null|*} | ||||
|    */ | ||||
|   static getAreaCodeByLevel(value, level) { | ||||
|     if (value) { | ||||
|       const areaNumber = value.toString(); | ||||
|       switch (level) { | ||||
|         case 0: | ||||
|           return areaNumber.substring(0, 2) + '0000000000'; | ||||
|         case 1: | ||||
|           return areaNumber.substring(0, 4) + '00000000'; | ||||
|         case 2: | ||||
|           return areaNumber.substring(0, 6) + '000000'; | ||||
|         case 3: | ||||
|           return areaNumber.substring(0, 9) + '000'; | ||||
|         case 4: | ||||
|           return areaNumber | ||||
|       } | ||||
|     } else return null | ||||
|   } | ||||
|  | ||||
|   static createByAction(areaId, ins = request, action = "/admin/area/getAllParentAreaId") { | ||||
|     return ins.post(action, null, {params: {areaId}, withoutToken: 1}).then(res => res?.data?.reverse() || []) | ||||
|   } | ||||
|  | ||||
|   getAreaInfo(id) { | ||||
|     let info = {} | ||||
|     const currentLevel = Area.getLevelByAreaId(id); | ||||
|     for (let i = 0; i <= currentLevel; i++) { | ||||
|       info[i] = Area.getAreaCodeByLevel(id, i); | ||||
|     } | ||||
|     return info | ||||
|   } | ||||
|  | ||||
|   async getAreaName() { | ||||
|     const names = await Area.createByAction(this.id); | ||||
|     this.getName(names) | ||||
|   } | ||||
|  | ||||
|   getName(names) { | ||||
|     this.meta = names | ||||
|     this.nameMap = names?.map(e => e.name) || [] | ||||
|     this.name = names?.slice(-1)?.[0]?.name | ||||
|     this.fullname = this.nameMap.join('') | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 异步从数据库中获取地区信息 | ||||
|    * @returns {Promise<void>} | ||||
|    */ | ||||
|   static async init(code) { | ||||
|     const names = await Area.createByAction(code), | ||||
|         area = new Area(code) | ||||
|     area.getName(names) | ||||
|     return area | ||||
|   } | ||||
| } | ||||
							
								
								
									
										20
									
								
								ui/lib/js/coin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								ui/lib/js/coin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| export default { | ||||
|   cny(money) { | ||||
|     if (money) { | ||||
|       money.toLocaleString('zh-Hans-CN', {style: 'currency', currency: "CNY"}) | ||||
|     } | ||||
|     return money | ||||
|   }, | ||||
|   cn(money) { | ||||
|     let num = parseFloat(money), cnMoney = '', | ||||
|         units = '仟佰拾亿仟佰拾万仟佰拾元角分', | ||||
|         cnNum = '零壹贰叁肆伍陆柒捌玖' | ||||
|     num = num.toFixed(2).replace(/\./g,'') | ||||
|     units = units.substring(units.length - num.length) | ||||
|     console.log(num, units.length, num.length) | ||||
|     Array.from(num).map((e, i) => { | ||||
|       cnMoney += cnNum.charAt(e) + units.charAt(i) | ||||
|     }) | ||||
|     return cnMoney.replace(/零角零分$/, '整').replace(/零[仟佰拾]/g, '零').replace(/零{2,}/g, '零').replace(/零([亿|万])/g, '$1').replace(/零+元/, '元').replace(/亿零{0,3}万/, '亿').replace(/^元/, "零元") | ||||
|   } | ||||
| } | ||||
							
								
								
									
										77
									
								
								ui/lib/js/dict.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								ui/lib/js/dict.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| import request from "./request"; | ||||
|  | ||||
| /** | ||||
|  * 封装字典工具类 | ||||
|  */ | ||||
| const $dict = { | ||||
|   url: "/admin/dictionary/queryValsByCodeList", | ||||
|   loading: [], | ||||
|   resolves: [], | ||||
|   getStorage() { | ||||
|     const dicts = JSON.parse(localStorage.getItem('dicts') || null) | ||||
|     return dicts?.data || dicts || []; | ||||
|   }, | ||||
|   setUrl(v) { | ||||
|     this.url = v | ||||
|   }, | ||||
|   getData(codeList) { | ||||
|     codeList = [codeList].flat().filter(Boolean).toString() | ||||
|     return request.post(this.url, null, { | ||||
|       withoutToken: true, params: {codeList} | ||||
|     }).then(res => res?.data && this.setStorage(res.data)) | ||||
|   }, | ||||
|   load(...code) { | ||||
|     return new Promise(resolve => { | ||||
|       this.resolves.push(resolve) | ||||
|       if (this.loading.length == 2) { | ||||
|         const [timer, codes] = this.loading; | ||||
|         clearTimeout(timer) | ||||
|         code = Array.from(new Set([codes, code].flat())) | ||||
|       } | ||||
|       const timer = setTimeout(() => { | ||||
|         this.getData(code).then(() => Promise.all(this.resolves.map(e => e())).then(() => this.resolves = [])) | ||||
|       }, 500) | ||||
|       this.loading = [timer, code] | ||||
|     }) | ||||
|   }, | ||||
|   setStorage(data) { | ||||
|     let ds = this.getStorage() | ||||
|     data.map(p => { | ||||
|       if (ds.some(d => d.key == p.key)) { | ||||
|         const index = ds.findIndex(d => d.key == p.key) | ||||
|         ds.splice(index, 1, p) | ||||
|       } else { | ||||
|         ds.push(p) | ||||
|       } | ||||
|     }) | ||||
|     localStorage.setItem("dicts", JSON.stringify([ds].flat())) | ||||
|   }, | ||||
|   getDict(key) { | ||||
|     let dict = this.getStorage().find(e => e.key == key) | ||||
|     !dict && console.warn("字典%s缺少加载...", key) | ||||
|     return dict ? dict.values : [] | ||||
|   }, | ||||
|   getValue(key, label) { | ||||
|     let dict = this.getDict(key) | ||||
|     if (dict) { | ||||
|       let item = dict.find(v => v.dictName == label) | ||||
|       return item ? item.dictValue : label | ||||
|     } else return label | ||||
|   }, | ||||
|   getLabel(key, value) { | ||||
|     let dict = this.getDict(key) | ||||
|     if (dict) { | ||||
|       let item = dict.find(v => v.dictValue == value) | ||||
|       return item ? item.dictName : value | ||||
|     } else return value | ||||
|   }, | ||||
|   getColor(key, value) { | ||||
|     let dict = this.getDict(key) | ||||
|     if (dict) { | ||||
|       let item = dict.find(v => v.dictValue == value) | ||||
|       return item ? item.dictColor : value | ||||
|     } else return value | ||||
|   }, | ||||
| } | ||||
|  | ||||
| export default $dict | ||||
							
								
								
									
										23
									
								
								ui/lib/js/encryption.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								ui/lib/js/encryption.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import CryptoJs from  "crypto-js"; | ||||
|  | ||||
| /** | ||||
|  * 密码加密工具 | ||||
|  * @param params | ||||
|  * @param c 加载尝试计数器 | ||||
|  * @returns {string} | ||||
|  */ | ||||
| export const $encryption = (params, c = 0) => { | ||||
|   if (CryptoJs) { | ||||
|     const key = "thanks,villcloud" | ||||
|     let iv = CryptoJs.enc.Latin1.parse(key) | ||||
|     let encrypted = CryptoJs.AES.encrypt(params.password, iv, { | ||||
|       iv, | ||||
|       mode: CryptoJs.mode.CBC, | ||||
|       padding: CryptoJs.pad.ZeroPadding | ||||
|     }) | ||||
|     return encrypted.toString() | ||||
|   } else if (c < 10) { | ||||
|     setTimeout(() => $encryption(params, ++c), 200) | ||||
|   } else console.error("无法加载CryptoJs") | ||||
| } | ||||
| export default $encryption | ||||
							
								
								
									
										238
									
								
								ui/lib/js/identity.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								ui/lib/js/identity.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,238 @@ | ||||
| import dayjs from "./moment"; | ||||
|  | ||||
|  | ||||
| const PARAMS = { | ||||
|   /* 省,直辖市代码表 */ | ||||
|   provinceAndCitys: { | ||||
|     11: '北京', | ||||
|     12: '天津', | ||||
|     13: '河北', | ||||
|     14: '山西', | ||||
|     15: '内蒙古', | ||||
|     21: '辽宁', | ||||
|     22: '吉林', | ||||
|     23: '黑龙江', | ||||
|     31: '上海', | ||||
|     32: '江苏', | ||||
|     33: '浙江', | ||||
|     34: '安徽', | ||||
|     35: '福建', | ||||
|     36: '江西', | ||||
|     37: '山东', | ||||
|     41: '河南', | ||||
|     42: '湖北', | ||||
|     43: '湖南', | ||||
|     44: '广东', | ||||
|     45: '广西', | ||||
|     46: '海南', | ||||
|     50: '重庆', | ||||
|     51: '四川', | ||||
|     52: '贵州', | ||||
|     53: '云南', | ||||
|     54: '西藏', | ||||
|     61: '陕西', | ||||
|     62: '甘肃', | ||||
|     63: '青海', | ||||
|     64: '宁夏', | ||||
|     65: '新疆', | ||||
|     71: '台湾', | ||||
|     81: '香港', | ||||
|     82: '澳门', | ||||
|     91: '国外' | ||||
|   }, | ||||
|  | ||||
|   /* 每位加权因子 */ | ||||
|   powers: [ | ||||
|     '7', | ||||
|     '9', | ||||
|     '10', | ||||
|     '5', | ||||
|     '8', | ||||
|     '4', | ||||
|     '2', | ||||
|     '1', | ||||
|     '6', | ||||
|     '3', | ||||
|     '7', | ||||
|     '9', | ||||
|     '10', | ||||
|     '5', | ||||
|     '8', | ||||
|     '4', | ||||
|     '2' | ||||
|   ], | ||||
|  | ||||
|   /* 第18位校检码 */ | ||||
|   parityBit: ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'], | ||||
|  | ||||
|   /* 性别 */ | ||||
|   genders: {1: '男', 0: '女'}, | ||||
| } | ||||
|  | ||||
| const Check = { | ||||
|   /* 校验地址码 */ | ||||
|   checkAddressCode(addressCode) { | ||||
|     const check = /^[1-9]\d{5}$/.test(addressCode) | ||||
|     if (!check) return false | ||||
|     return !!PARAMS.provinceAndCitys[parseInt(addressCode.substring(0, 2))] | ||||
|   }, | ||||
|   /* 校验日期码 */ | ||||
|   checkBirthDayCode(birDayCode) { | ||||
|     const check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test( | ||||
|         birDayCode | ||||
|     ) | ||||
|     if (!check) return false | ||||
|     const yyyy = parseInt(birDayCode.substring(0, 4), 10) | ||||
|     const mm = parseInt(birDayCode.substring(4, 6), 10) | ||||
|     const dd = parseInt(birDayCode.substring(6), 10) | ||||
|     const xdata = new Date(yyyy, mm - 1, dd) | ||||
|     if (xdata > new Date()) { | ||||
|       return false // 生日不能大于当前日期 | ||||
|     } else { | ||||
|       return ( | ||||
|           xdata.getFullYear() == yyyy && | ||||
|           xdata.getMonth() == mm - 1 && | ||||
|           xdata.getDate() == dd | ||||
|       ) | ||||
|     } | ||||
|   }, | ||||
|   /* 验证校检码 */ | ||||
|   checkParityBit(idCardNo) { | ||||
|     const parityBit = idCardNo.charAt(17).toUpperCase() | ||||
|     return this.getParityBit(idCardNo) == parityBit | ||||
|   }, | ||||
| // 校验15位的身份证号码 | ||||
|   check15IdCardNo(idCardNo) { | ||||
|     // 15位身份证号码的基本校验 | ||||
|     let check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test( | ||||
|         idCardNo | ||||
|     ) | ||||
|     if (!check) return false | ||||
|     // 校验地址码 | ||||
|     const addressCode = idCardNo.substring(0, 6) | ||||
|     check = this.checkAddressCode(addressCode) | ||||
|     if (!check) return false | ||||
|     const birDayCode = '19' + idCardNo.substring(6, 12) | ||||
|     // 校验日期码 | ||||
|     return this.checkBirthDayCode(birDayCode) | ||||
|   }, | ||||
|  | ||||
| // 校验18位的身份证号码 | ||||
|   check18IdCardNo(idCardNo) { | ||||
|     // 18位身份证号码的基本格式校验 | ||||
|     let check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(\d|x|X)$/.test( | ||||
|         idCardNo | ||||
|     ) | ||||
|     if (!check) return false | ||||
|     // 校验地址码 | ||||
|     const addressCode = idCardNo.substring(0, 6) | ||||
|     check = this.checkAddressCode(addressCode) | ||||
|     if (!check) return false | ||||
|     // 校验日期码 | ||||
|     const birDayCode = idCardNo.substring(6, 14) | ||||
|     check = this.checkBirthDayCode(birDayCode) | ||||
|     if (!check) return false | ||||
|     // 验证校检码 | ||||
|     return this.checkParityBit(idCardNo) | ||||
|   }, | ||||
|   /* 计算校检码 */ | ||||
|   getParityBit(idCardNo) { | ||||
|     const id17 = idCardNo.substring(0, 17) | ||||
|     /* 加权 */ | ||||
|     let power = 0 | ||||
|     for (let i = 0; i < 17; i++) { | ||||
|       power += parseInt(id17.charAt(i), 10) * parseInt(PARAMS.powers[i]) | ||||
|     } | ||||
|     /* 取模 */ | ||||
|     const mod = power % 11 | ||||
|     return PARAMS.parityBit[mod] | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default class Identity { | ||||
|   constructor(code) { | ||||
|     this.code = this.getId18(code) | ||||
|     this.init() | ||||
|   } | ||||
|  | ||||
|   init() { | ||||
|     const {code} = this | ||||
|     if (!!code) { | ||||
|       this.hideCode = Identity.hideId(code) | ||||
|       this.getIdCardInfo(code) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static hideId(code) { | ||||
|     return code?.replace(/^(\d{10})\d{4}(.{4}$)/g, `$1${Array(5).join('*')}$2`) | ||||
|   } | ||||
|  | ||||
|   getId18(code) { | ||||
|     if (code.length == 15) { | ||||
|       const id17 = code.substring(0, 6) + '19' + code.substring(6) | ||||
|       const parityBit = Check.getParityBit(id17) | ||||
|       return id17 + parityBit | ||||
|     } else if (code.length == 18) { | ||||
|       return code | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getIdCardInfo(idCardNo) { | ||||
|     this.birthday = Identity.getBirthday(idCardNo) | ||||
|     this.sex = Identity.getSex(idCardNo) | ||||
|     this.gender = PARAMS.genders[this.sex] | ||||
|     this.age = Identity.getAge(idCardNo) | ||||
|     this.areaId = Identity.getArea(idCardNo) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 获取性别 | ||||
|    * @param code | ||||
|    * @returns {string} | ||||
|    */ | ||||
|   static getSex(code) { | ||||
|     return (Number(code.substring(16, 17)) % 2).toString() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 获取年龄 | ||||
|    * @param code | ||||
|    * @returns {number} | ||||
|    */ | ||||
|   static getAge(code) { | ||||
|     const birthday = dayjs(code.substring(6, 14), 'YYYYMMDD') | ||||
|     return Math.ceil(dayjs.duration(dayjs().unix() - dayjs(birthday).unix(), 's').asYears()) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 获取地区编码 | ||||
|    * @param code | ||||
|    */ | ||||
|   static getArea(code) { | ||||
|     return code.substring(0, 6) + new Array(7).join(0) | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 获取生日 | ||||
|    */ | ||||
|   static getBirthday(code) { | ||||
|     return dayjs(code.substring(6, 14), 'YYYYMMDD').format("YYYY-MM-DD").replace('Invalid Date', '') | ||||
|   } | ||||
|  | ||||
|   /* 校验15位或18位的身份证号码 */ | ||||
|   static check(idCardNo) { | ||||
|     // 15位和18位身份证号码的基本校验 | ||||
|     const check = /^\d{15}|(\d{17}(\d|x|X))$/.test(idCardNo) | ||||
|     if (!check) return false | ||||
|     // 判断长度为15位或18位 | ||||
|     if (idCardNo.length == 15) { | ||||
|       return Check.check15IdCardNo(idCardNo) | ||||
|     } else if (idCardNo.length == 18) { | ||||
|       return Check.check18IdCardNo(idCardNo) | ||||
|     } else { | ||||
|       return false | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										305
									
								
								ui/lib/js/modules.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								ui/lib/js/modules.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | ||||
| import http from "./request"; | ||||
| import utils from "./utils"; | ||||
| import Vue from "vue" | ||||
|  | ||||
| export const sys = { | ||||
|   state: () => ({ | ||||
|     info: {}, | ||||
|     theme: {} | ||||
|   }), | ||||
|   mutations: { | ||||
|     setSysInfo(state, info) { | ||||
|       state.info = info | ||||
|     }, | ||||
|     setTheme(state, theme) { | ||||
|       state.theme = theme | ||||
|     } | ||||
|   }, | ||||
|   actions: { | ||||
|     getSystem({commit}, info) { | ||||
|       return http.post("/app/appdvcpconfig/getSystemInfo", null, {withoutToken: true}).then(res => { | ||||
|         if (res?.data) { | ||||
|           let {systemInfo, colorScheme, enableGreyFilter} = res.data | ||||
|           systemInfo = JSON.parse(systemInfo || null) || {} | ||||
|           colorScheme = JSON.parse(colorScheme || null) || {} | ||||
|           commit("setSysInfo", {...info, ...systemInfo}) | ||||
|           commit("setTheme", {colorScheme, enableGreyFilter}) | ||||
|           return res.data | ||||
|         } else return Promise.reject() | ||||
|       }).catch(() => commit("setSysInfo", info)) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 用户信息 | ||||
|  */ | ||||
| export const user = { | ||||
|   state: () => ({ | ||||
|     token: "", | ||||
|     info: {}, | ||||
|     routes: [] | ||||
|   }), | ||||
|   mutations: { | ||||
|     setToken(state, token) { | ||||
|       state.token = token; | ||||
|     }, | ||||
|     setUserInfo(state, info) { | ||||
|       state.info = info | ||||
|     }, | ||||
|     cleanUserInfo(state) { | ||||
|       state.info = {} | ||||
|       state.token = "" | ||||
|     }, | ||||
|     setUserExtra(state, extra = {}) { | ||||
|       Object.keys(extra).map(e => Vue.set(state, e, extra[e])) | ||||
|     }, | ||||
|     setRoutes(state,routes){ | ||||
|       state.routes = routes | ||||
|     } | ||||
|   }, | ||||
|   actions: { | ||||
|     getToken({commit}, params) { | ||||
|       let action = "/auth/oauth/token" | ||||
|       if (params?.action) { | ||||
|         action = params?.action | ||||
|         delete params?.action | ||||
|       } | ||||
|       const password = utils.$encryption(params) | ||||
|       return http.post(action, null, { | ||||
|         auth: { | ||||
|           username: 'villcloud', | ||||
|           password: "villcloud" | ||||
|         }, | ||||
|         params: {grant_type: 'password', scope: 'server', ...params, password} | ||||
|       }).then(res => { | ||||
|         if (res?.access_token) { | ||||
|           const {token_type, access_token} = res, token = [token_type, access_token].join(" ") | ||||
|           return commit('setToken', token) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getUserInfo({commit, dispatch}) { | ||||
|       return http.post("/admin/user/detail-phone").then(res => { | ||||
|         if (res?.data) { | ||||
|           commit("setUserInfo", res.data) | ||||
|           return Promise.all([dispatch('getWorkflowConfigs')]).then(() => res.data) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getRouteName({state}, appName) { | ||||
|       return state.routes.find(e => e.component == appName)?.route || appName | ||||
|     } | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 企微jssdk功能 | ||||
|  */ | ||||
| let timer = {injectJWeixin: null, initOpenData: null} | ||||
| export const wxwork = { | ||||
|   state: () => ({ | ||||
|     agentSignURL: "", | ||||
|     apiList: [], | ||||
|     config: {} | ||||
|   }), | ||||
|   mutations: { | ||||
|     setConfig(state, config) { | ||||
|       state.config = config | ||||
|     }, | ||||
|     setAgentSignURL(state, url) { | ||||
|       state.agentSignURL = url | ||||
|     }, | ||||
|     setApiList(state, list) { | ||||
|       state.apiList = list | ||||
|     }, | ||||
|   }, | ||||
|   actions: { | ||||
|     agentSign({state, commit, rootState}, params) { | ||||
|       //授权jssdk在url上使用,并获取corpId | ||||
|       let url = window.location.href | ||||
|       if (state.agentSignURL == url && state.config.corpId) { | ||||
|         return Promise.resolve() | ||||
|       } else { | ||||
|         commit("setAgentSignURL", url) | ||||
|         commit("setApiList", []) | ||||
|         let action = "/app/wxcptp/portal/agentSign" | ||||
|         if (!!params?.action) { | ||||
|           action = params.action | ||||
|           delete params.action | ||||
|         } | ||||
|         const {corpId} = rootState.user.info | ||||
|         return http.post(action, null, { | ||||
|           withoutToken: true, | ||||
|           params: {corpId, ...params, url} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             let config = { | ||||
|               ...params, | ||||
|               debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 | ||||
|               beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题 | ||||
|               corpid: res.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致 | ||||
|               agentid: res.data.agentId, // 必填,企业微信的应用id (e.g. 1000247) | ||||
|               timestamp: Number(res.data.timestamp), // 必填,生成签名的时间戳 | ||||
|               nonceStr: res.data.nonceStr, // 必填,生成签名的随机串 | ||||
|               signature: res.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法 | ||||
|               ...res.data | ||||
|             } | ||||
|             commit("setConfig", config) | ||||
|             return config | ||||
|           } | ||||
|         }).catch(err => { | ||||
|           commit("setAgentSignURL", "") | ||||
|           console.error(err) | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     injectJWeixin({state, commit}, apis) { | ||||
|       const inject = (jsApiList) => new Promise((resolve, reject) => { | ||||
|         jsApiList = jsApiList || [] | ||||
|         if (timer.injectJWeixin) {//节流设置,50ms内的多次请求合并到一处 | ||||
|           clearTimeout(timer.injectJWeixin) | ||||
|           jsApiList = [...new Set([...state.apiList, ...jsApiList])] | ||||
|           commit("setApiList", jsApiList) | ||||
|         } | ||||
|         timer.injectJWeixin = setTimeout(() => { | ||||
|           const sdk = wx?.agentConfig ? wx : jWeixin | ||||
|           sdk?.agentConfig({ | ||||
|             ...state.config, jsApiList, | ||||
|             success: res => resolve(res), | ||||
|             fail: err => { | ||||
|               console.error(err) | ||||
|               reject(err) | ||||
|             } | ||||
|           }) | ||||
|         }, 50) | ||||
|       }) | ||||
|       return inject(apis) | ||||
|     }, | ||||
|     initOpenData({dispatch, commit}, params = {}) { | ||||
|       const initWOD = (count = 0) => { | ||||
|         if (!!window?.WWOpenData) { | ||||
|           const canvas = params?.canvas | ||||
|           if (canvas) delete params.canvas | ||||
|           if (timer.initOpenData) { | ||||
|             clearTimeout(timer.initOpenData) | ||||
|           } | ||||
|           const init = () => canvas ? dispatch('initCanvas') : dispatch('bindElements') | ||||
|           timer.initOpenData = setTimeout(() => { | ||||
|             window?.WWOpenData?.checkSession({ | ||||
|               success: () => init(), | ||||
|               fail: () => { | ||||
|                 dispatch('agentSign', params).then(() => dispatch("injectJWeixin")).then(() => init()) | ||||
|               } | ||||
|             }) | ||||
|           }, 50) | ||||
|         } else if (count > 10) { | ||||
|           console.log("无法获取WWOpenData") | ||||
|         } else { | ||||
|           setTimeout(() => { | ||||
|             initWOD(++count) | ||||
|           }, 200) | ||||
|         } | ||||
|       } | ||||
|       dispatch('agentSign', params).then(() => dispatch("injectJWeixin")).then(() => initWOD()) | ||||
|     }, | ||||
|     bindElements() { | ||||
|       const nodes = document.querySelectorAll('.AiOpenData') | ||||
|       window.WWOpenData?.bindAll(nodes) | ||||
|     }, | ||||
|     initCanvas() { | ||||
|       window.WWOpenData?.initCanvas() | ||||
|     }, | ||||
|     transCanvas(store, items) { | ||||
|       return new Promise((resolve, reject) => { | ||||
|         window.WWOpenData?.prefetch({items}, (err, data) => { | ||||
|           err ? reject(err) : resolve(data) | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 各种前端方案记录选择 | ||||
|  */ | ||||
| export const logs = { | ||||
|   state: () => ({ | ||||
|     closeIntro: [] | ||||
|   }), | ||||
|   mutations: { | ||||
|     addCloseIntro(state, app) { | ||||
|       state.closeIntro.push(app) | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| /** | ||||
|  * 流程信息 | ||||
|  */ | ||||
| const startProcess = (form) => { | ||||
|   const {bid, app, flows = {}} = form | ||||
|   const process = flows[app] | ||||
|   if (!!process) { | ||||
|     const {id: pid, config} = process | ||||
|     let workflowConfig = JSON.parse(config || null), nowNodeId = [], startId | ||||
|     workflowConfig?.nodes?.map(e => { | ||||
|       if (e.type == "start") { | ||||
|         e.properties.isStart = true | ||||
|         e.properties.updateTime = utils.$moment().format("YYYY-MM-DD HH:mm:ss") | ||||
|         startId = e.id | ||||
|       } | ||||
|     }) | ||||
|     workflowConfig?.edges?.map(e => { | ||||
|       if (e.sourceNodeId == startId) { | ||||
|         nowNodeId.push(e.targetNodeId) | ||||
|       } | ||||
|     }) | ||||
|     nowNodeId = nowNodeId?.toString() | ||||
|     return !!nowNodeId && http.post("/app/appworkflowlog/addOrUpdate", {bid, pid, nowNodeId, workflowConfig: JSON.stringify(workflowConfig)}) | ||||
|   } | ||||
| } | ||||
| export const workflow = { | ||||
|   state: () => ({}), | ||||
|   mutations: { | ||||
|     setWfConfigs(state, configs) { | ||||
|       configs.map(e => { | ||||
|         Vue.set(state, e.app, e) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   actions: { | ||||
|     getWorkflowConfigs({commit}) { | ||||
|       return http.post("/app/appworkflowmanage/list", null, { | ||||
|         params: {size: 999} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           return commit("setWfConfigs", res.data.records) | ||||
|         } | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     startFlow(context, form) { | ||||
|       startProcess(form) | ||||
|     }, | ||||
|     endFlow(context, form) { | ||||
|       let {workflowConfig = {}, nowNodeId} = form | ||||
|       workflowConfig?.nodes?.map(e => { | ||||
|         if (e.type == "end") { | ||||
|           e.properties.isFinished = true | ||||
|           e.properties.updateTime = utils.$moment().format("YYYY-MM-DD HH:mm:ss") | ||||
|           nowNodeId = "nowNodeId" | ||||
|         } | ||||
|       }) | ||||
|       return http.post("/app/appworkflowlog/addOrUpdate", {...form, nowNodeId, workflowConfig: JSON.stringify(workflowConfig)}) | ||||
|     } | ||||
|   }, | ||||
|   processAdapter(config) {//流程业务拦截器 | ||||
|     if (/addOrUpdate/.test(config.url)) { | ||||
|       let app = config.url.replace(/.+(app[^\\\/]+).+/g, '$1') | ||||
|       if (/appapplicationinfo/.test(app)) {//动态台账表单 | ||||
|         app = config.params?.appId | ||||
|       } else if (/appcontentinfo/.test(app)) {//内容发布 | ||||
|         app = config.data?.moduleId | ||||
|       } | ||||
|       config.workflow = app | ||||
|     } | ||||
|     return config | ||||
|   }, | ||||
|   startProcess | ||||
| } | ||||
							
								
								
									
										35
									
								
								ui/lib/js/moment.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								ui/lib/js/moment.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import moment from 'dayjs' | ||||
| import duration from 'dayjs/plugin/duration' | ||||
| import updateLocale from 'dayjs/plugin/updateLocale' | ||||
| import customParseFormat from 'dayjs/plugin/customParseFormat' | ||||
| import 'dayjs/locale/zh-cn' | ||||
|  | ||||
| moment.locale('zh-cn') | ||||
| moment.extend(updateLocale) | ||||
| moment.extend(customParseFormat) | ||||
| moment.extend(duration) | ||||
| moment.updateLocale('zh-cn', { | ||||
|   weekdays: "星期日|星期一|星期二|星期三|星期四|星期五|星期六".split("|"), | ||||
|   meridiem(hour) { | ||||
|     let word = "" | ||||
|     if (hour < 6) { | ||||
|       word = "凌晨" | ||||
|     } else if (hour < 9) { | ||||
|       word = "早上" | ||||
|     } else if (hour < 12) { | ||||
|       word = "上午" | ||||
|     } else if (hour < 14) { | ||||
|       word = "中午" | ||||
|     } else if (hour < 17) { | ||||
|       word = "下午" | ||||
|     } else if (hour < 19) { | ||||
|       word = "傍晚" | ||||
|     } else if (hour < 22) { | ||||
|       word = "晚上" | ||||
|     } else { | ||||
|       word = "夜里" | ||||
|     } | ||||
|     return word; | ||||
|   } | ||||
| }) | ||||
| export default moment | ||||
							
								
								
									
										15
									
								
								ui/lib/js/regular.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ui/lib/js/regular.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| export default { | ||||
|   phone: /^((0\d{2,3}-\d{7,8})|((13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}))$/, | ||||
|   password: /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^&*,.?_-])[\da-zA-Z~!@#$%^&*,.?_-]{8,16}$/, | ||||
|   money: /^([1-9]\d*|0)(\.\d{1,2})?$/, | ||||
|   area: { | ||||
|     village: /^\d{9}[^0]0{0,2}$/, | ||||
|     town: /^\d{6}[^0]0{0,2}000$/, | ||||
|     country: /^\d{4}[^0]0?0{6}$/, | ||||
|     city: /^\d{2}[^0]0?0{8}$/, | ||||
|     province: /^[^0]0?0{10}$/, | ||||
|   }, | ||||
|   zh: /^[\u4e00-\u9fa5]+$/, | ||||
|   email: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/, | ||||
|   ip: /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/ | ||||
| } | ||||
							
								
								
									
										83
									
								
								ui/lib/js/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								ui/lib/js/request.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| /* eslint-disable */ | ||||
| import axios from 'axios' | ||||
| import {Message} from "element-ui"; | ||||
| import {workflow} from "./modules"; | ||||
|  | ||||
| const instance = axios.create({ | ||||
|   baseURL: process.env.NODE_ENV === "production" ? "/" : "/lan", | ||||
|   timeout: 600000, | ||||
|   withCredentials: true, | ||||
| }) | ||||
|  | ||||
| const getStore = () => JSON.parse(localStorage.getItem("vuex") || null) || {} | ||||
|  | ||||
| const getToken = () => getStore().user?.token | ||||
| /** | ||||
|  * 节流工具 | ||||
|  */ | ||||
| let throttleMap = {} | ||||
| const source = axios.CancelToken.source(); | ||||
| instance.interceptors.request.use(config => { | ||||
|   if (config.throttle) {// 节流处理 | ||||
|     let timer = throttleMap[config.url] | ||||
|     if (!!timer) { | ||||
|       config.cancelToken = source.token | ||||
|       source.cancel("节流控制,取消请求:" + config.url) | ||||
|     } | ||||
|     throttleMap[config.url] = setTimeout(() => { | ||||
|       throttleMap[config.url] = null | ||||
|     }, config.throttle) | ||||
|   } | ||||
|   if (!config.withoutToken && getToken()) { | ||||
|     config.headers["Authorization"] = getToken() | ||||
|   } | ||||
|   //BUG 9456 去除传参空格 | ||||
|   if (config.params) { | ||||
|     Object.keys(config.params).map(e => { | ||||
|       if (typeof config.params[e] == "string") config.params[e] = config.params[e].trim() | ||||
|     }) | ||||
|   } | ||||
|   config = workflow.processAdapter(config) | ||||
|   return config | ||||
| }, err => { | ||||
|   console.error(err) | ||||
| }) | ||||
| instance.interceptors.response.use(res => { | ||||
|   if (res && !!res.config.workflow) { | ||||
|     const {config: {workflow: app}, data: {data: bid}} = res | ||||
|     bid && workflow.startProcess({app, bid, flows: getStore().workflow}) | ||||
|   } | ||||
|   if (res && res.data) { | ||||
|     if (!!res.data.code?.toString()) { | ||||
|       if (res.data.code == 0) { | ||||
|         return res.data | ||||
|       } else if (!!res.config.pureBack) { | ||||
|         return res.data | ||||
|       } else if (res.data.code == 401) { | ||||
|         console.error("安全令牌验证无法通过!") | ||||
|         return Promise.reject(res.data) | ||||
|       } else { | ||||
|         Message.error(res.data.msg || "请求失败!") | ||||
|         return !!res.config.returnError ? res.data : Promise.reject(res.data.msg) | ||||
|       } | ||||
|     } else return res.data | ||||
|   } else { | ||||
|     Message.error("服务器异常,请联系管理员!") | ||||
|   } | ||||
| }, err => { | ||||
|   if (err) { | ||||
|     if (err.response) { | ||||
|       if (err.response.status == 401) { | ||||
|         console.error("安全令牌验证无法通过!") | ||||
|       } else { | ||||
|         console.error(err.response.statusText) | ||||
|       } | ||||
|     } else { | ||||
|       console.error(err) | ||||
|     } | ||||
|   } else { | ||||
|     console.error("通信异常,请联系管理员!") | ||||
|   } | ||||
| }) | ||||
|  | ||||
| export default instance | ||||
							
								
								
									
										215
									
								
								ui/lib/js/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								ui/lib/js/utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| import {MessageBox} from 'element-ui' | ||||
| import $moment from './moment' | ||||
| import $dict from './dict' | ||||
| import $encryption from './encryption' | ||||
| import $coin from './coin' | ||||
| import Area from "./area" | ||||
| import ID from "./identity" | ||||
| import $reg from "./regular" | ||||
|  | ||||
| /** | ||||
|  * 生成子节点的递归方法 | ||||
|  * @param parent 父元素 | ||||
|  * @param pending 待递归的数组 | ||||
|  * @param config 配置 | ||||
|  */ | ||||
| const addChild = (parent, pending, config) => { | ||||
|   let conf = { | ||||
|         key: 'id', | ||||
|         parent: 'parentId', | ||||
|         children: 'children', | ||||
|         ...config | ||||
|       }, | ||||
|       doBeforeCount = pending.length | ||||
|   for (let i = pending.length - 1; i >= 0; i--) { | ||||
|     let e = pending[i] | ||||
|     if (e[conf.parent] == parent[conf.key]) { | ||||
|       parent[conf.children] = [...(parent[conf.children] || []), e] | ||||
|       pending.splice(i, 1) | ||||
|     } | ||||
|   } | ||||
|   parent[conf.children] && | ||||
|   (parent[conf.children] = parent[conf.children].reverse()) | ||||
|   if (pending.length > 0 && doBeforeCount > pending.length) { | ||||
|     parent[conf.children].map(c => addChild(c, pending, conf)) | ||||
|   } | ||||
| } | ||||
| /** | ||||
|  * 数组转tree | ||||
|  * @param list 待转化的数组 | ||||
|  * @param config 配置 | ||||
|  */ | ||||
| const $arr2tree = (list, config = {}) => { | ||||
|   const {key = 'id', parent = 'parentId', children = 'children'} = config, result = [], itemMap = {}, ids = list?.map(e => `${e[key]}`)?.toString() | ||||
|   for (const e of list) { | ||||
|     const id = e[key], pid = e[parent] | ||||
|     itemMap[id] = {...e, [children]: [itemMap[id]?.[children]].flat().filter(Boolean)} | ||||
|     const treeItem = itemMap[id] | ||||
|     if (!!pid && ids.indexOf(pid) > -1) { | ||||
|       if (!itemMap[pid]) { | ||||
|         itemMap[pid] = { | ||||
|           children: [], | ||||
|         } | ||||
|       } | ||||
|       itemMap[pid].children.push(treeItem) | ||||
|     } else result.push(treeItem) | ||||
|   } | ||||
|   return result | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 封装提示框 | ||||
|  */ | ||||
| const $confirm = (content, options) => { | ||||
|   return MessageBox.confirm(content, { | ||||
|     type: 'warning', | ||||
|     confirmButtonText: '确认', | ||||
|     center: true, | ||||
|     title: '提示', | ||||
|     dangerouslyUseHTMLString: true, | ||||
|     customClass: "AiConfirm", | ||||
|     ...options | ||||
|   }).catch(() => 0) | ||||
| } | ||||
|  | ||||
|  | ||||
| const $decimalCalc = (...arr) => { | ||||
|   // 确认提升精度 | ||||
|   let decimalLengthes = arr.map(e => { | ||||
|     let index = ('' + e).indexOf('.') | ||||
|     return ('' + e).length - index | ||||
|   }) | ||||
|   let maxDecimal = Math.max(...decimalLengthes), | ||||
|       precision = Math.pow(10, maxDecimal) | ||||
|   // 计算 | ||||
|   let intArr = arr.map(e => (Number(e) || 0) * precision) | ||||
|   // 返回计算值 | ||||
|   return intArr.reduce((t, a) => t + a) / precision | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 封装权限判断方法 | ||||
|  */ | ||||
| const $permissions = flag => { | ||||
|   let buttons = [] | ||||
|   if (localStorage.getItem('vuex')) { | ||||
|     const vuex = JSON.parse(localStorage.getItem('vuex')) | ||||
|     buttons = vuex.user.info.buttons | ||||
|   } | ||||
|   if (buttons && buttons.length > 0) { | ||||
|     return buttons.some(b => b.id == flag || b.permission == flag) | ||||
|   } else return false | ||||
| } | ||||
|  | ||||
| const $colorUtils = { | ||||
|   Hex2RGBA(color, alpha = 1) { | ||||
|     let hex = 0 | ||||
|     if (color.charAt(0) == '#') { | ||||
|       if (color.length == 4) { | ||||
|         // 检测诸如#FFF简写格式 | ||||
|         color = | ||||
|             '#' + | ||||
|             color.charAt(1).repeat(2) + | ||||
|             color.charAt(2).repeat(2) + | ||||
|             color.charAt(3).repeat(2) | ||||
|       } | ||||
|       hex = parseInt(color.slice(1), 16) | ||||
|     } | ||||
|     let r = (hex >> 16) & 0xff | ||||
|     let g = (hex >> 8) & 0xff | ||||
|     let b = hex & 0xff | ||||
|     return `rgba(${r},${g},${b},${alpha})` | ||||
|   }, | ||||
|   RGBtoHex(r, g, b) { | ||||
|     let hex = (r << 16) | (g << 8) | b | ||||
|     return '#' + hex.toString(16) | ||||
|   } | ||||
| } | ||||
| export const $copy = any => { | ||||
|   if (any) { | ||||
|     return JSON.parse(JSON.stringify(any)) | ||||
|   } else return any | ||||
| } | ||||
| let debounceWait = null | ||||
| export const $debounce = (fn, wait) => { | ||||
|   if (debounceWait !== null) clearTimeout(debounceWait); | ||||
|   debounceWait = setTimeout(function () { | ||||
|     typeof fn === 'function' && fn(); | ||||
|   }, wait); | ||||
| } | ||||
| export const $checkJson = str => { | ||||
|   if (typeof str == 'string') { | ||||
|     try { | ||||
|       let obj = JSON.parse(str); | ||||
|       return !!(typeof obj == 'object' && obj); | ||||
|     } catch (e) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| const $load = (sdk, interval = 200, name = "", c = 0) => { | ||||
|   if (!!sdk) { | ||||
|     return Promise.resolve() | ||||
|   } else if (c < 10) { | ||||
|     return new Promise(resolve => setTimeout(() => resolve($load(sdk, interval, name, ++c)), interval)) | ||||
|   } else return Promise.reject("无法加载" + name) | ||||
| } | ||||
|  | ||||
| export {Area, ID} | ||||
|  | ||||
| export default { | ||||
|   addChild, | ||||
|   $confirm, | ||||
|   $decimalCalc, | ||||
|   $dict, | ||||
|   $permissions, | ||||
|   $colorUtils, | ||||
|   $moment, | ||||
|   $encryption, | ||||
|   $coin, | ||||
|   $injectLib: (url, cb = () => 0) => { | ||||
|     const scriptList = document.body.querySelectorAll('script') | ||||
|     if (Object.values(scriptList || {}).findIndex(e => e.src == url) == -1) { | ||||
|       const script = document.createElement('script') | ||||
|       script.type = 'text/javascript' | ||||
|       script.src = url | ||||
|       script.addEventListener('load', () => cb()) | ||||
|       document.body.appendChild(script) | ||||
|     } else cb() | ||||
|   }, | ||||
|   $injectCss: (url, cb = () => 0) => { | ||||
|     const linkList = document.body.querySelectorAll('link') | ||||
|     if (Object.values(linkList || {}).findIndex(e => e.href == url) == -1) { | ||||
|       const link = document.createElement('link') | ||||
|       link.rel = "stylesheet" | ||||
|       link.type = "text/css" | ||||
|       link.href = url | ||||
|       link.addEventListener('load', () => cb()) | ||||
|       document.head.appendChild(link) | ||||
|     } else cb() | ||||
|   }, | ||||
|   $dateFormat: (time, format) => { | ||||
|     return $moment(time) | ||||
|     .format(format || 'YYYY-MM-DD') | ||||
|     .replace('Invalid Date', '') | ||||
|   }, | ||||
|   $copy, | ||||
|   $download: url => { | ||||
|     fetch(url).then(res => res.blob()).then(blob => { | ||||
|       const link = document.createElement('a') | ||||
|       link.style.display = 'none' | ||||
|       link.href = URL.createObjectURL(blob) | ||||
|       document.body.appendChild(link) | ||||
|       link.click() | ||||
|       document.body.removeChild(link) | ||||
|     }) | ||||
|   }, | ||||
|   $debounce, | ||||
|   $checkJson, | ||||
|   $arr2tree, | ||||
|   $load, | ||||
|   $reg, | ||||
|   Area, | ||||
|   ID | ||||
| } | ||||
		Reference in New Issue
	
	Block a user