diff --git a/.env b/.env new file mode 100644 index 0000000..4fcd55c --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +//统一配置 +VITE_APP_PORT = 17777 +VITE_APP_TITLE = '管理平台' +VITE_APP_SYSTEM_KEY = 'hengxingaokeApp1' +VITE_APP_CSS_URL = '/public/' diff --git a/.env.development b/.env.development index fbad522..7770b1d 100644 --- a/.env.development +++ b/.env.development @@ -14,3 +14,4 @@ VITE_ONLYOFFICE_HOST = 'http://myvuetest.net/onlyoffice' VITE_DEFAULT_AI_AGENT = '5bd9b0e9-d3f4-4089-670a-880009e925a8' #流程制度 VITE_REGUL_AI_AGENT = 'e3be1378-3915-4e5c-b526-9f5447df39ea' +VITE_APP_SM4_APP_KEY = '04TzMuvkHm_EZnHm' diff --git a/.env.production b/.env.production index 8c8549c..e2cf8c6 100644 --- a/.env.production +++ b/.env.production @@ -9,4 +9,5 @@ VITE_OFFICE_HOST='https://gyhlw.hxgk.group/kkapi' VITE_ONLYOFFICE_HOST = 'https://gyhlw.hxgk.group/onlyoffice' VITE_DEFAULT_AI_AGENT = '74938263-ffe5-43c5-90af-25e62d34a51f' #流程制度 -VITE_REGUL_AI_AGENT = 'e3be1378-3915-4e5c-b526-9f5447df39ea' \ No newline at end of file +VITE_REGUL_AI_AGENT = 'e3be1378-3915-4e5c-b526-9f5447df39ea' +VITE_APP_SM4_APP_KEY = '04TzMuvkHm_EZnHm' diff --git a/package.json b/package.json index c9343e0..f0a69e9 100644 --- a/package.json +++ b/package.json @@ -52,15 +52,16 @@ "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "5.1.10", "@wecom/jssdk": "^1.3.2", - "appsys": "file:", "axios": "^1.10.0", "clipboard": "^2.0.11", "compressorjs": "^1.2.1", + "crypto-js": "^4.2.0", "dayjs": "^1.11.11", "echarts": "^5.6.0", "element-plus": "^2.3.4", "element-resize-detector": "^1.2.4", "font-awesome": "^4.7.0", + "gm-crypto": "^0.1.12", "html2canvas": "^1.4.1", "install": "^0.13.0", "js-beautify": "^1.14.8", @@ -105,6 +106,7 @@ "@commitlint/cli": "^17.6.3", "@commitlint/config-conventional": "^17.6.3", "@iconify-json/ep": "^1.1.10", + "@types/crypto-js": "^4.2.2", "@types/jquery": "^3.5.29", "@types/md5": "^2.3.2", "@types/nprogress": "^0.2.0", diff --git a/src/assets/icons/aiRoboot.svg b/src/assets/icons/aiRoboot.svg new file mode 100644 index 0000000..5282ed3 --- /dev/null +++ b/src/assets/icons/aiRoboot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/DesignForm/app/index.vue b/src/components/DesignForm/app/index.vue index aa1b2d0..04e277e 100644 --- a/src/components/DesignForm/app/index.vue +++ b/src/components/DesignForm/app/index.vue @@ -50,6 +50,11 @@ import {printHtmlPage} from '../printHtmlRender.ts' //引入组件 import FormPageCont from "@/components/DesignForm/tableListPage/formPageCont.vue"; import TableFlow from "@/views/sysworkflow/lowcodepage/pageFlow/appTableFlow.vue"; + +import NewTableFlow from "@/views/sysworkflow/lowcodepage/pageFlow/newTableFlow.vue"; + + + import TimeAxisPage from "@/components/DesignForm/app/timeAxis.vue"; import CardPage from "@/components/DesignForm/app/cardPage.vue"; import GanttPageIng from "@/components/DesignForm/app/gannttPage.vue"; @@ -2149,6 +2154,7 @@ const isObject = (obj: any) => { + { border @selection-change="selectionChange" > - + + + + + + + + { @click="submitApproval(scope.row)" /> - { @click="afreshSendFlow(scope.row)" /> - { @click="editInfo(scope.row)" /> - { - { @click="editFormSendFlow(scope.row)" /> - - - - - - - - - + - { + @@ -2559,13 +2561,21 @@ const isObject = (obj: any) => { :dprt="rangedDatePickerInTables1" @get-page-data="getPageData" /> - --> + diff --git a/src/components/DesignForm/assembly/index.ts b/src/components/DesignForm/assembly/index.ts index 408fb92..098fc2d 100644 --- a/src/components/DesignForm/assembly/index.ts +++ b/src/components/DesignForm/assembly/index.ts @@ -306,97 +306,97 @@ export default [ inputStyle: {} } }, - { - type: 'select', - label: '下拉选择框', - unitName: '下拉选择框', - icon: 'select', - iconFont: 'fa-toggle-down', - control: { - modelValue: '', - appendToBody: true, - glxxsz: [], - zdtcsz: { - tbx: '', - tby: '' - }, - optionsValue3Formid:'', - optionsValue3Field:'', - }, - options: selectOption, - config: config, - styles: { - divStyle: { - marginBot: "15" - }, - labelStyle: { - //paddingLeft: "7", - }, - inputStyle: {} - } - }, - { - type: 'cascader', - label: '级联选择器', - unitName: '级联选择器', - icon: 'cascader', - iconFont: 'fa-sitemap', - control: { - modelValue: [] - }, - options: [], - config: config, - styles: { - divStyle: { - marginBot: "15" - }, - labelStyle: { - //paddingLeft: "7", - }, - inputStyle: {} - } - }, - { - type: 'datePicker', - label: '日期选择器', - unitName: '日期选择器', - icon: 'todo', - iconFont: 'fa-calendar', - control: { - modelValue: '', - type: 'date' - }, - config: {}, - styles: { - divStyle: { - marginBot: "15" - }, - labelStyle: { - //paddingLeft: "7", - }, - inputStyle: {} - } - }, - { - type: 'timePicker', - label: '时间选择器', - unitName: '时间选择器', - icon: 'time', - iconFont: 'fa-clock-o', - control: { - modelValue: '' - }, - config: {}, - styles: { - divStyle: { - marginBot: "15" - }, - labelStyle: { - //paddingLeft: "7", - }, - inputStyle: {} - } - }, + // { + // type: 'select', + // label: '下拉选择框', + // unitName: '下拉选择框', + // icon: 'select', + // iconFont: 'fa-toggle-down', + // control: { + // modelValue: '', + // appendToBody: true, + // glxxsz: [], + // zdtcsz: { + // tbx: '', + // tby: '' + // }, + // optionsValue3Formid:'', + // optionsValue3Field:'', + // }, + // options: selectOption, + // config: config, + // styles: { + // divStyle: { + // marginBot: "15" + // }, + // labelStyle: { + // //paddingLeft: "7", + // }, + // inputStyle: {} + // } + // }, + // { + // type: 'cascader', + // label: '级联选择器', + // unitName: '级联选择器', + // icon: 'cascader', + // iconFont: 'fa-sitemap', + // control: { + // modelValue: [] + // }, + // options: [], + // config: config, + // styles: { + // divStyle: { + // marginBot: "15" + // }, + // labelStyle: { + // //paddingLeft: "7", + // }, + // inputStyle: {} + // } + // }, + // { + // type: 'datePicker', + // label: '日期选择器', + // unitName: '日期选择器', + // icon: 'todo', + // iconFont: 'fa-calendar', + // control: { + // modelValue: '', + // type: 'date' + // }, + // config: {}, + // styles: { + // divStyle: { + // marginBot: "15" + // }, + // labelStyle: { + // //paddingLeft: "7", + // }, + // inputStyle: {} + // } + // }, + // { + // type: 'timePicker', + // label: '时间选择器', + // unitName: '时间选择器', + // icon: 'time', + // iconFont: 'fa-clock-o', + // control: { + // modelValue: '' + // }, + // config: {}, + // styles: { + // divStyle: { + // marginBot: "15" + // }, + // labelStyle: { + // //paddingLeft: "7", + // }, + // inputStyle: {} + // } + // }, { type: 'txt', label: '文字描述', @@ -988,28 +988,28 @@ export default [ inputStyle: {} } }, - { - type: 'component', - label: '自定义组件', - unitName: '自定义组件', - icon: 'component', - iconFont: 'fa-cubes', - control: { - modelValue: '' - }, - config: {}, - styles: { - divStyle: { - marginBot: "15" - }, - labelStyle: { - //paddingLeft: "7", - }, - inputStyle: {} - } - /*template: '', // 组件模板名称 - component: '' // 根据template注入的组件*/ - }, + // { + // type: 'component', + // label: '自定义组件', + // unitName: '自定义组件', + // icon: 'component', + // iconFont: 'fa-cubes', + // control: { + // modelValue: '' + // }, + // config: {}, + // styles: { + // divStyle: { + // marginBot: "15" + // }, + // labelStyle: { + // //paddingLeft: "7", + // }, + // inputStyle: {} + // } + // /*template: '', // 组件模板名称 + // component: '' // 根据template注入的组件*/ + // }, diff --git a/src/store/modules/orgMember.ts b/src/store/modules/orgMember.ts index 48f4e0b..6a5c853 100644 --- a/src/store/modules/orgMember.ts +++ b/src/store/modules/orgMember.ts @@ -13,10 +13,10 @@ export const useOrgMemberStore = defineStore('orgMember', () => { const listMap = ref>({}) const dataTree = ref({ id: '', name: '', child: [] }) - async function init() { + async function havueOrgTree() { await request({ - url: "/systemapi/app/get_org_everyone_people",//"172.20.2.87:39168", + url: "/systemapi/app/get_org_everyone_people",//"172.20 .2.87:39168", method: "post", data:{id:"313",all: 1} }).then((response) => { @@ -38,6 +38,7 @@ export const useOrgMemberStore = defineStore('orgMember', () => { }); } } - init() - return { listMap,dataTree } + // havueOrgTree() + // init() + return { listMap,dataTree,havueOrgTree } }) diff --git a/src/utils/encryptionAndDecryption/randNumber.ts b/src/utils/encryptionAndDecryption/randNumber.ts new file mode 100644 index 0000000..d1c74a4 --- /dev/null +++ b/src/utils/encryptionAndDecryption/randNumber.ts @@ -0,0 +1,63 @@ +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 11:07:32 +@ 备注: 创建任意位数的随机字符串 +*/ +const generateRandomString = (length: number = 16): string => { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + const array = new Uint8Array(length) + crypto.getRandomValues(array) + return Array.from(array, byte => characters[byte % characters.length]).join('') + // let randomString = ''; + // for (let i = 0; i < length; i++) { + // const randomIndex = Math.floor(Math.random() * characters.length); + // randomString += characters.charAt(randomIndex); + // } + // return randomString; +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-08 16:15:12 +@ 功能: 获取UUID +*/ +const uuid = () => { + const s: string[] = [] + const hexDigits = '123456789abcdef' + for (let i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1) + } + s[14] = '4' // bits 12-15 of the time_hi_and_version field to 0010 + s[19] = hexDigits.substr((parseInt(s[19]!, 16) & 0x3) | 0x8, 1) // bits 6-7 of the clock_seq_hi_and_reserved to 01 + s[8] = s[13] = s[18] = s[23] = '-' + const uuid = s.join('') + return uuid +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-08 16:15:48 +@ 功能: 获取简单随机数 +*/ +const randomString = (length: number) => { + var str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + var result = '' + for (var i = length; i > 0; --i) { + result += str[Math.floor(Math.random() * str.length)] + } + return result +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-08 16:16:12 +@ 功能: 中间画线驼峰 +*/ +const toHump = (str: string) => { + if (!str) return str + return str + .replace(/\-(\w)/g, function (all: string, letter: string) { + return letter.toUpperCase() + }) + .replace(/(\s|^)[a-z]/g, function (char: string) { + return char.toUpperCase() + }) +} +export { generateRandomString, uuid, randomString, toHump } diff --git a/src/utils/encryptionAndDecryption/shiliu.ts b/src/utils/encryptionAndDecryption/shiliu.ts new file mode 100644 index 0000000..811ac2c --- /dev/null +++ b/src/utils/encryptionAndDecryption/shiliu.ts @@ -0,0 +1,7 @@ +import * as CryptoJS from 'crypto-js' + +const strToHexSub = (str: string): string => { + return CryptoJS.enc.Utf8.parse(str).toString(CryptoJS.enc.Hex) +} + +export { strToHexSub } diff --git a/src/utils/encryptionAndDecryption/sm4Utils.ts b/src/utils/encryptionAndDecryption/sm4Utils.ts new file mode 100644 index 0000000..6ea8840 --- /dev/null +++ b/src/utils/encryptionAndDecryption/sm4Utils.ts @@ -0,0 +1,79 @@ +import { SM4 as sm4 } from 'gm-crypto' +import * as CryptoJS from 'crypto-js' +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 10:26:51 +@ 备注: 将字符串转换成16进制 +*/ +const strToHexMethod = (str: string): string => { + return CryptoJS.enc.Utf8.parse(str).toString(CryptoJS.enc.Hex) +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 10:29:48 +@ 备注: 判断是不是12位16进制参数 +*/ +const isValidHex32 = (str: string): boolean => { + return /^[0-9a-fA-F]{32}$/.test(str) +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 10:28:33 +@ 备注: 初始化SM4密钥参数 +*/ +const appSystemKey = strToHexMethod(import.meta.env.VITE_APP_SYSTEM_KEY) +const sm4TokenKey = strToHexMethod(import.meta.env.VITE_APP_SM4_APP_KEY) + +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 10:30:40 +@ 备注: SM4加密方法 +*/ +const sm4EncryptMethod = (data: string, customKey: string): string => { + let ivSetup = sm4TokenKey + if (customKey) { + ivSetup = strToHexMethod(customKey) + if (!isValidHex32(ivSetup)) { + ivSetup = sm4TokenKey + } + } + return sm4.encrypt(data, appSystemKey, { + iv: ivSetup, + mode: sm4.constants.CBC, + inputEncoding: 'utf8', + outputEncoding: 'hex', + padding: 1 + } as never) +} +/** +@ 作者: 秦东 +@ 时间: 2025-12-07 10:31:22 +@ 备注: SM4解密方法 +*/ +const sm4DecryptMethod = (data: string, customKey: string): string => { + let ivSetup = sm4TokenKey + if (customKey) { + ivSetup = strToHexMethod(customKey) + if (!isValidHex32(ivSetup)) { + ivSetup = sm4TokenKey + } + } + // console.log('SM4解密方法----解密结构---data--->', data) + console.log('SM4解密方法----解密结构----customKey-->', customKey) + console.log('SM4解密方法----解密结构--ivSetup---->', ivSetup) + console.log('SM4解密方法----解密结构---sm4TokenKey--->', sm4TokenKey) + console.log('SM4解密方法----解密结构---appSystemKey--->', appSystemKey) + + console.log('SM4解密方法----解密结构---appSystemKey.length--->', appSystemKey.length) + console.log('SM4解密方法----解密结构---ivSetup.length--->', ivSetup.length) + + + return sm4.decrypt(data, appSystemKey, { + iv: ivSetup, + mode: sm4.constants.CBC, + inputEncoding: 'hex', + outputEncoding: 'utf8', + padding: 1 + } as never) +} +export { sm4EncryptMethod, sm4DecryptMethod } diff --git a/src/utils/encryptionAndDecryption/tongyong.ts b/src/utils/encryptionAndDecryption/tongyong.ts new file mode 100644 index 0000000..184ed87 --- /dev/null +++ b/src/utils/encryptionAndDecryption/tongyong.ts @@ -0,0 +1,347 @@ +/** + * 数字 + */ +const REG_NUMBER: string = '.*\\d+.*' +/** + * 小写字母 + */ +const REG_UPPERCASE: string = '.*[A-Z]+.*' +/** + * 大写字母 + */ +const REG_LOWERCASE: string = '.*[a-z]+.*' +/** + * 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\) + */ +const REG_SYMBOL: string = '.*[~!@#$%^&*()_+|<>,.?/:;\'\\[\\]{}]+".*' +/** + * 键盘字符表(小写) + * 非shift键盘字符表 + */ +const CHAR_TABLE1: string[][] = [ + ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\0'], + ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'], + ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '\0', '\0'], + ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0'] +] +/** + * shift键盘的字符表 + */ +const CHAR_TABLE2: string[][] = [ + ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\0'], + ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'], + ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"', '\0', '\0'], + ['z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?', '\0', '\0', '\0'] +] + +/** + * 校验密码是否符合条件 + * @param password 密码 + * @param username 用户名 + */ +export const checkPasswordRule = (password: string, username: string) => { + if (password === '' || password.length < 8 || password.length > 32) { + // console.log("长度小于8,或大于32"); + return '密码长度应大于8小于32' + } + if (password.indexOf(username) !== -1) { + // console.log("包含用户名"); + return '请勿包含用户名' + } + if (isContinuousChar(password)) { + // console.log("包含3个及以上相同或字典连续字符"); + return '请勿包含3个及以上相同或连续的字符' + } + if (isKeyBoardContinuousChar(password)) { + // console.log("包含3个及以上键盘连续字符"); + return '请勿包含3个及以上键盘连续字符' + } + let i: number = 0 + if (password.match(REG_NUMBER)) i++ + if (password.match(REG_LOWERCASE)) i++ + if (password.match(REG_UPPERCASE)) i++ + if (password.match(REG_SYMBOL)) i++ + if (i < 2) { + // console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种")); + return '数字、小写字母、大写字母、特殊字符,至少包含两种' + } + // console.log(i); + return '校验通过' +} + +/** + * 是否包含3个及以上相同或字典连续字符 + */ +const isContinuousChar = (password: string) => { + const chars: string[] = password.split('') + + // 遍历所有可能的三个连续字符组合 + for (let i = 0; i < chars.length - 2; i++) { + // 添加类型断言,确保字符不是undefined + const char1 = chars[i] as string + const char2 = chars[i + 1] as string + const char3 = chars[i + 2] as string + + // 获取字符的ASCII码 + const n1 = char1.charCodeAt(0) + const n2 = char2.charCodeAt(0) + const n3 = char3.charCodeAt(0) + + // 判断重复字符 + if (n1 === n2 && n1 === n3) { + return true + } + + // 判断连续字符: 正序(如abc)和倒序(如cba) + if ((n1 + 1 === n2 && n2 + 1 === n3) || (n1 - 1 === n2 && n2 - 1 === n3)) { + return true + } + } + + return false +} +/** + * 是否包含3个及以上键盘连续字符 + * @param password 待匹配的字符串 + */ +const isKeyBoardContinuousChar = (password: string) => { + if (password === '') { + return false + } + //考虑大小写,都转换成小写字母 + const lpStrChars: string[] = password.toLowerCase().split('') + // 获取字符串长度 + const nStrLen: number = lpStrChars.length + // 定义位置数组:row - 行,col - column 列,初始化为-1 + const pRowCharPos: number[] = new Array(nStrLen).fill(-1) + const pColCharPos: number[] = new Array(nStrLen).fill(-1) + + for (let i = 0; i < nStrLen; i++) { + // 添加类型断言,确保字符不是undefined + const chLower: string = lpStrChars[i] as string + + // 检索在表1中的位置,构建位置数组 + for (let nRowTable1Idx = 0; nRowTable1Idx < 4; nRowTable1Idx++) { + for (let nColTable1Idx = 0; nColTable1Idx < 13; nColTable1Idx++) { + // 获取当前字符,跳过\0字符,使用可选链和空值合并确保类型安全 + const tableChar = CHAR_TABLE1[nRowTable1Idx]?.[nColTable1Idx] ?? '' + if (tableChar && tableChar !== '\0' && chLower === tableChar) { + pRowCharPos[i] = nRowTable1Idx + pColCharPos[i] = nColTable1Idx + break + } + } + } + + // 在表1中没找到,到表二中去找,找到则continue + // 添加非空检查 + const currentColPos = pColCharPos[i] + if (currentColPos !== undefined && currentColPos >= 0) { + continue + } + + // 检索在表2中的位置,构建位置数组 + for (let nRowTable2Idx = 0; nRowTable2Idx < 4; nRowTable2Idx++) { + for (let nColTable2Idx = 0; nColTable2Idx < 13; nColTable2Idx++) { + // 获取当前字符,跳过\0字符,使用可选链和空值合并确保类型安全 + const tableChar = CHAR_TABLE2[nRowTable2Idx]?.[nColTable2Idx] ?? '' + if (tableChar && tableChar !== '\0' && chLower === tableChar) { + pRowCharPos[i] = nRowTable2Idx + pColCharPos[i] = nColTable2Idx + break + } + } + } + } + + // 匹配坐标连线 + for (let j = 1; j <= nStrLen - 2; j++) { + // 获取当前三个字符的位置,添加类型断言 + const row1 = pRowCharPos[j - 1] as number + const row2 = pRowCharPos[j] as number + const row3 = pRowCharPos[j + 1] as number + const col1 = pColCharPos[j - 1] as number + const col2 = pColCharPos[j] as number + const col3 = pColCharPos[j + 1] as number + + //同一行 + if (row1 === row2 && row2 === row3) { + // 键盘行正向连续(asd)或者键盘行反向连续(dsa) + if ( + (col1 + 1 === col2 && col2 + 1 === col3) || + (col3 + 1 === col2 && col2 + 1 === col1) + ) { + return true + } + } + + //同一列 + if (col1 === col2 && col2 === col3) { + //键盘列连续(qaz)或者键盘列反向连续(zaq) + if ( + (row1 + 1 === row2 && row2 + 1 === row3) || + (row1 - 1 === row2 && row2 - 1 === row3) + ) { + return true + } + } + } + + return false +} + +/** + * 密码强度校验 + */ +/** + * 长度 + * @param str + */ +const length = (str: string) => { + if (str.length < 5) { + return 5 + } else if (str.length < 8) { + return 10 + } else { + return 25 + } +} +/** + * 字母 + * @param str + */ +const letters = (str: string) => { + let count1 = 0, + count2 = 0 + for (let i = 0; i < str.length; i++) { + if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') { + count1++ + } + if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') { + count2++ + } + } + if (count1 === 0 && count2 === 0) { + return 0 + } + if (count1 !== 0 && count2 !== 0) { + return 20 + } + return 10 +} + +/** + * 数字 + * @param str + */ +const numbers = (str: string) => { + let count = 0 + for (let i = 0; i < str.length; i++) { + if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { + count++ + } + } + if (count === 0) { + return 0 + } + if (count === 1) { + return 10 + } + return 20 +} +/** + * 符号 + * @param str + */ +const symbols = (str: string) => { + let count = 0 + for (let i = 0; i < str.length; i++) { + if ( + (str.charCodeAt(i) >= 0x21 && str.charCodeAt(i) <= 0x2f) || + (str.charCodeAt(i) >= 0x3a && str.charCodeAt(i) <= 0x40) || + (str.charCodeAt(i) >= 0x5b && str.charCodeAt(i) <= 0x60) || + (str.charCodeAt(i) >= 0x7b && str.charCodeAt(i) <= 0x7e) + ) { + count++ + } + } + if (count === 0) { + return 0 + } + if (count === 1) { + return 10 + } + return 25 +} +/** + * 得分机制 + * @param str + */ +const rewards = (str: string) => { + let letter = letters(str) //字母 + let number = numbers(str) //数字 + let symbol = symbols(str) //符号 + if (letter > 0 && number > 0 && symbol === 0) { + //字母和数字 + return 2 + } + if (letter === 10 && number > 0 && symbol > 0) { + //字母、数字和符号 + return 3 + } + if (letter === 20 && number > 0 && symbol > 0) { + //大小写字母、数字和符号 + return 5 + } + return 0 +} +/** + * 最终评分 + * @param str + */ +export const level = (str: string) => { + let lengths = length(str) //长度 + let letter = letters(str) //字母 + let number = numbers(str) //数字 + let symbol = symbols(str) //符号 + let reward = rewards(str) //奖励 + let sum = lengths + letter + number + symbol + reward + console.log(sum) + if (sum >= 80) { + return '非常强' //非常安全 + } else if (sum >= 60) { + return '强' //非常强 + } else if (sum >= 40) { + return '一般' //一般 + } else if (sum >= 25) { + return '弱' //弱 + } else { + return '非常弱' //非常弱 + } +} + +export const checkPwdRule = (password: string) => { + if (password === '' || password.length < 8 || password.length > 32) { + // console.log("长度小于8,或大于32"); + return '密码长度应大于8小于32' + } + if (isContinuousChar(password)) { + // console.log("包含3个及以上相同或字典连续字符"); + return '请勿包含3个及以上相同或连续的字符' + } + if (isKeyBoardContinuousChar(password)) { + // console.log("包含3个及以上键盘连续字符"); + return '请勿包含3个及以上键盘连续字符' + } + let i: number = 0 + if (password.match(REG_NUMBER)) i++ + if (password.match(REG_LOWERCASE)) i++ + if (password.match(REG_UPPERCASE)) i++ + if (password.match(REG_SYMBOL)) i++ + if (i < 2) { + // console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种")); + return '数字、小写字母、大写字母、特殊字符,至少包含两种' + } + // console.log(i); + return '校验通过' +} diff --git a/src/utils/request.ts b/src/utils/request.ts index 9566003..73dc9da 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,96 +1,159 @@ -import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios'; +/** +@ 作者: 秦东 +@ 时间: 2025-12-09 10:57:37 +@ 功能: 封装axios请求 +*/ +import axios, { AxiosError, type InternalAxiosRequestConfig } from 'axios' +import { ElMessage, ElMessageBox } from 'element-plus' +import { generateRandomString } from '@/utils/encryptionAndDecryption/randNumber' +import { sm4DecryptMethod, sm4EncryptMethod } from '@/utils/encryptionAndDecryption/sm4Utils' import { useUserStoreHook } from '@/store/modules/user'; -import { ElMessage, ElMessageBox } from 'element-plus'; -import router from '@/router'; import { useRouter } from 'vue-router' - const routerPinia = useRouter() -// 创建 axios 实例 +/** +@ 作者: 秦东 +@ 时间: 2025-12-09 10:58:34 +@ 功能: 创建axios实例 +*/ const service = axios.create({ baseURL: import.meta.env.VITE_APP_BASE_API, timeout: 50000, headers: { 'Content-Type': 'application/json;charset=utf-8' } }); -// 请求拦截器 +/** +@ 作者: 秦东 +@ 时间: 2025-12-09 11:00:05 +@ 功能: 请求拦截 +*/ service.interceptors.request.use( - (config: InternalAxiosRequestConfig) => { - const userStore = useUserStoreHook(); - //config.headers["Content-Type"] = "application/json;charset=utf-8"; - if (userStore.tokenIng) { - config.headers.Authorization = userStore.tokenIng; - } - if (userStore.userKey) { - config.headers["user-key"] = userStore.userKey; - } - if (userStore.userToken) { - config.headers["user-token"] = userStore.userToken; - } - return config; - }, - (error: any) => { - return Promise.reject(error); - } -); + (config: InternalAxiosRequestConfig) => { + const userStore = useUserStoreHook(); -// 响应拦截器 -service.interceptors.response.use( - (response: AxiosResponse) => { - const { code, msg } = response.data; - if (code === 0 || code === 200 || code === 10001) { - return response.data; + if (userStore.tokenIng) { + config.headers.Authorization = userStore.tokenIng; + } + if (userStore.userKey) { + config.headers["user-key"] = userStore.userKey; + } + if (userStore.userToken) { + config.headers["user-token"] = userStore.userToken; + } + + // if (config.headers['content-type'] === 'application/json') { + let { data, headers } = config + //获取16位随机数 + let randomString = generateRandomString(16) + config.headers['Auth-key'] = randomString + if (data) { + // 加密请求数据 + config.data = { + data: sm4EncryptMethod(JSON.stringify(data), randomString) + } + } + console.log('请求拦截---------->', randomString) + console.log('请求拦截----headers------>', headers) + console.log('请求拦截----data------>', config.data) + console.log('请求拦截----config------>', config) + // } + + // console.log('请求拦截----content-type------>', config.headers['Content-Type']) + // console.log('请求拦截----config------>', config.headers) + return config + }, + (error: AxiosError) => { + return Promise.reject(error) } - if (code === 7 || code === 300 || code === 301 || code === 302){ - ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示5", { +) +/** +@ 作者: 秦东 +@ 时间: 2025-12-09 21:00:20 +@ 备注: 响应拦截 +*/ +service.interceptors.response.use( + response => { + + let { data, headers } = response + let authKey = headers['auth-key'] + console.log('行营结果----authKey------>', authKey) + // 解密响应数据 + if (authKey) { + let jsonData = sm4DecryptMethod(data.data, authKey) + response.data.data = JSON.parse(jsonData) + } + console.log('行营结果----解密结构------>', headers['auth-key'], response) + const { code, msg } = response.data; + if (code === 0 || code === 200 || code === 10001) { + return response.data; + } + if (code === 7 || code === 300 || code === 301 || code === 302){ + ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示5", { confirmButtonText: "确定", type: "warning", }).then(() => { localStorage.clear(); - // window.location.href = "/login"; - routerPinia.push({path:"/login"}) + window.location.href = "/login"; + // routerPinia.push({path:"/login"}) }); return response.data; - } - // 响应数据为二进制流处理(Excel导出) - if (response.data instanceof ArrayBuffer) { - return response; - } - - // ElMessage.error(msg || '系统出错'); - return Promise.reject(new Error(msg || 'Error')); - }, - (error: any) => { - if (error.response.data) { - const { code, msg } = error.response.data; - // token 过期,重新登录 - if (code === 'A0230') { - ElMessageBox.confirm('当前页面已失效,请重新登录', '提示6', { - confirmButtonText: '确定', - type: 'warning' - }).then(() => { - localStorage.clear(); - // window.location.href = '/login'; - router.push({path:"/login"}) - }); - }else if(code === 7 || code === 300 || code === 301 || code === 302){ - ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示7", { - confirmButtonText: "确定", - type: "warning", - }).then(() => { - localStorage.clear(); - // window.location.href = "/login"; - routerPinia.push({path:"/login"}) - }); - }else if (code === 10001 || code === 10002 || code === 10003) { - return Promise.reject(error.message); - } else { + } + // 响应数据为二进制流处理(Excel导出) + if (response.data instanceof ArrayBuffer) { + return response; + } // ElMessage.error(msg || '系统出错'); - } + return Promise.reject(new Error(msg || 'Error')); + }, + (error: any) => { + if (error.response) { + const status = error.response.status + switch (status) { + case 401: + // 处理401错误,例如跳转到登录页 + break + case 403: + // 处理403错误,例如提示无权限 + break + case 404: + // 处理404错误,例如提示资源不存在 + break + case 500: + // 处理500错误,例如提示服务器错误 + break + default: + // 处理其他错误 + break + } + } + if (error.response.data) { + const { code, msg } = error.response?.data; + // token 过期,重新登录 + if (code === 'A0230') { + ElMessageBox.confirm('当前页面已失效,请重新登录', '提示6', { + confirmButtonText: '确定', + type: 'warning' + }).then(() => { + localStorage.clear(); + window.location.href = '/login'; + // router.push({path:"/login"}) + }); + }else if(code === 7 || code === 300 || code === 301 || code === 302){ + ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示7", { + confirmButtonText: "确定", + type: "warning", + }).then(() => { + localStorage.clear(); + window.location.href = "/login"; + // routerPinia.push({path:"/login"}) + }); + }else if (code === 10001 || code === 10002 || code === 10003) { + return Promise.reject(error.message); + } else { + // ElMessage.error(msg || '系统出错'); + } + } + return Promise.reject(error.message); } - return Promise.reject(error.message); - } -); - -// 导出 axios 实例 -export default service; +) +export default service diff --git a/src/utils/request123.ts b/src/utils/request123.ts new file mode 100644 index 0000000..9e950b0 --- /dev/null +++ b/src/utils/request123.ts @@ -0,0 +1,130 @@ +import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios'; +import { useUserStoreHook } from '@/store/modules/user'; +import { ElMessage, ElMessageBox } from 'element-plus'; +import router from '@/router'; +import { useRouter } from 'vue-router' +import { generateRandomString } from '@/utils/encryptionAndDecryption/randNumber' + + +const routerPinia = useRouter() +// 创建 axios 实例 +const service = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_API, + timeout: 50000, + headers: { 'Content-Type': 'application/json;charset=utf-8' } +}); + +// 请求拦截器 +service.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + const userStore = useUserStoreHook(); + //config.headers["Content-Type"] = "application/json;charset=utf-8"; + if (userStore.tokenIng) { + config.headers.Authorization = userStore.tokenIng; + } + if (userStore.userKey) { + config.headers["user-key"] = userStore.userKey; + } + if (userStore.userToken) { + config.headers["user-token"] = userStore.userToken; + } + + let { data, headers } = config + console.log('请求拦截----data---1--->', data) + + //获取16位随机数 + let randomString = generateRandomString(16) + config.headers['Auth-key'] = randomString + if (data) { + console.log('请求拦截----data---2--->', data) + // 加密请求数据 + config.data = { + data: sm4EncryptMethod(JSON.stringify(data), randomString) + } + } + + console.log('请求拦截---------->', randomString) + console.log('请求拦截----headers------>', headers) + console.log('请求拦截----data---3--->', data) + console.log('请求拦截----data------>', config.data) + console.log('请求拦截----config------>', config) + + + return config; + }, + (error: any) => { + return Promise.reject(error); + } +); + +// 响应拦截器 +service.interceptors.response.use( + (response: AxiosResponse) => { + + let { data, headers } = response + let authKey = headers['auth-key'] + console.log('行营结果----authKey------>', authKey) + if (authKey) { + let jsonData = sm4DecryptMethod(data.data, authKey) + response.data.data = JSON.parse(jsonData) + } + const { code, msg } = response.data; + console.log('行营结果----解密结构------>', headers['auth-key'], response) + // console.error("--------code--------->",code) + // console.error("--------msg--------->",msg) + if (code === 0 || code === 200 || code === 10001) { + return response.data; + } + if (code === 7 || code === 300 || code === 301 || code === 302){ + ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示5", { + confirmButtonText: "确定", + type: "warning", + }).then(() => { + localStorage.clear(); + window.location.href = "/login"; + // routerPinia.push({path:"/login"}) + }); + return response.data; + } + // 响应数据为二进制流处理(Excel导出) + if (response.data instanceof ArrayBuffer) { + return response; + } + + // ElMessage.error(msg || '系统出错'); + return Promise.reject(new Error(msg || 'Error')); + }, + (error: any) => { + if (error.response.data) { + const { code, msg } = error.response.data; + // token 过期,重新登录 + if (code === 'A0230') { + ElMessageBox.confirm('当前页面已失效,请重新登录', '提示6', { + confirmButtonText: '确定', + type: 'warning' + }).then(() => { + localStorage.clear(); + window.location.href = '/login'; + // router.push({path:"/login"}) + }); + }else if(code === 7 || code === 300 || code === 301 || code === 302){ + ElMessageBox.confirm("身份令牌已失效!请重新登录!", "提示7", { + confirmButtonText: "确定", + type: "warning", + }).then(() => { + localStorage.clear(); + window.location.href = "/login"; + // routerPinia.push({path:"/login"}) + }); + }else if (code === 10001 || code === 10002 || code === 10003) { + return Promise.reject(error.message); + } else { + // ElMessage.error(msg || '系统出错'); + } + } + return Promise.reject(error.message); + } +); + +// 导出 axios 实例 +export default service; diff --git a/src/views/doc/spacePermission.vue b/src/views/doc/spacePermission.vue index 37b79bf..9d581b3 100644 --- a/src/views/doc/spacePermission.vue +++ b/src/views/doc/spacePermission.vue @@ -196,11 +196,12 @@ function refreshSpaceData(){ {space:props.spaceid,matter:props.uuid} ).then(resp=>{ resp.data?.dprts?.forEach(item=>{ + orgMembers.havueOrgTree() for(let data of dataSource.value){ if (data.id==item) return; if (checkNode(item,data)) return; } - + addNode(item,orgMembers.dataTree) }); @@ -272,6 +273,7 @@ function checkNode(key:string,node:Tree):boolean{ onMounted(()=>{ refreshSpaceData() + orgMembers.havueOrgTree() }) diff --git a/src/views/sysworkflow/lowcodepage/appPage/createAppFormPage.vue b/src/views/sysworkflow/lowcodepage/appPage/createAppFormPage.vue index e796ca6..50af6fc 100644 --- a/src/views/sysworkflow/lowcodepage/appPage/createAppFormPage.vue +++ b/src/views/sysworkflow/lowcodepage/appPage/createAppFormPage.vue @@ -241,7 +241,7 @@ onBeforeMount(() => { - +
diff --git a/src/views/sysworkflow/lowcodepage/pageFlow/appTableFlow.vue b/src/views/sysworkflow/lowcodepage/pageFlow/appTableFlow.vue index c684ad0..55acc07 100644 --- a/src/views/sysworkflow/lowcodepage/pageFlow/appTableFlow.vue +++ b/src/views/sysworkflow/lowcodepage/pageFlow/appTableFlow.vue @@ -638,6 +638,7 @@ function optionsValue3Get3(data: any, fieldName: string) { provide('flowNodePower', currterNodePower) provide('currentNodeKey', nodeKey) + diff --git a/src/views/sysworkflow/lowcodepage/pageFlow/newTableFlow.vue b/src/views/sysworkflow/lowcodepage/pageFlow/newTableFlow.vue new file mode 100644 index 0000000..e0e167e --- /dev/null +++ b/src/views/sysworkflow/lowcodepage/pageFlow/newTableFlow.vue @@ -0,0 +1,659 @@ + + + + + diff --git a/src/views/sysworkflow/lowcodepage/pageFlow/tableFlow.vue b/src/views/sysworkflow/lowcodepage/pageFlow/tableFlow.vue index 96662bd..f74fa14 100644 --- a/src/views/sysworkflow/lowcodepage/pageFlow/tableFlow.vue +++ b/src/views/sysworkflow/lowcodepage/pageFlow/tableFlow.vue @@ -543,6 +543,7 @@ provide('currentNodeKey', nodeKey) :destroy-on-close="true" :size="drawbox" class="drawerClass" + > @@ -557,7 +558,7 @@ provide('currentNodeKey', nodeKey) {{ versiontitle }}
扫码填单扫码填单123
@@ -677,6 +678,7 @@ provide('currentNodeKey', nodeKey) .drawer-close { cursor: pointer; //margin-left: 8px; + } } diff --git a/src/views/sysworkflow/lowcodepage/runApp/regularPage.vue b/src/views/sysworkflow/lowcodepage/runApp/regularPage.vue index 9b3e97b..6f11f1c 100644 --- a/src/views/sysworkflow/lowcodepage/runApp/regularPage.vue +++ b/src/views/sysworkflow/lowcodepage/runApp/regularPage.vue @@ -51,7 +51,7 @@ const resetQueryTd = () => { };