diff --git a/src/api/bpm/task/index.ts b/src/api/bpm/task/index.ts index a818ae5a..713400fc 100644 --- a/src/api/bpm/task/index.ts +++ b/src/api/bpm/task/index.ts @@ -106,6 +106,11 @@ export const copyTask = async (data: any) => { return await request.put({ url: '/bpm/task/copy', data }) } +// 撤回 +export const withdrawTask = async (taskId: string) => { + return await request.put({ url: '/bpm/task/withdraw', params: { taskId } }) +} + // 获取我的待办任务 export const myTodoTask = async (processInstanceId: string) => { return await request.get({ url: '/bpm/task/my-todo?processInstanceId=' + processInstanceId }) diff --git a/src/api/system/mail/log/index.ts b/src/api/system/mail/log/index.ts index d891db07..409ced63 100644 --- a/src/api/system/mail/log/index.ts +++ b/src/api/system/mail/log/index.ts @@ -4,7 +4,9 @@ export interface MailLogVO { id: number userId: number userType: number - toMail: string + toMails: string[] + ccMails?: string[] + bccMails?: string[] accountId: number fromMail: string templateId: number diff --git a/src/api/system/mail/template/index.ts b/src/api/system/mail/template/index.ts index c6dae688..6e1d083f 100644 --- a/src/api/system/mail/template/index.ts +++ b/src/api/system/mail/template/index.ts @@ -14,7 +14,9 @@ export interface MailTemplateVO { } export interface MailSendReqVO { - mail: string + toMails: string[] + ccMails?: string[] + bccMails?: string[] templateCode: string templateParams: Map } @@ -46,7 +48,10 @@ export const deleteMailTemplate = async (id: number) => { // 批量删除邮件模版 export const deleteMailTemplateList = async (ids: number[]) => { - return await request.delete({ url: '/system/mail-template/delete-list', params: { ids: ids.join(',') } }) + return await request.delete({ + url: '/system/mail-template/delete-list', + params: { ids: ids.join(',') } + }) } // 发送邮件 diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue index fdb0b1de..06f23128 100644 --- a/src/components/DiyEditor/components/ComponentLibrary.vue +++ b/src/components/DiyEditor/components/ComponentLibrary.vue @@ -17,7 +17,7 @@ :group="{ name: 'component', pull: 'clone', put: false }" :clone="handleCloneComponent" :animation="200" - :force-fallback="true" + :force-fallback="false" > @@ -467,6 +467,13 @@ const saveConfig = async () => { return true } +/** 取消配置 */ +const cancelConfig = () => { + // 恢复原来的配置 + currentNode.value.triggerSetting = originalSetting + closeDrawer() +} + /** 获取节点展示内容 */ const getShowText = (): string => { let showText = '' @@ -498,7 +505,7 @@ const getShowText = (): string => { /** 显示触发器节点配置, 由父组件传过来 */ const showTriggerNodeConfig = (node: SimpleFlowNode) => { nodeName.value = node.name - originalSetting = node.triggerSetting ? JSON.parse(JSON.stringify(node.triggerSetting)) : {} + originalSetting = cloneDeep(node.triggerSetting) if (node.triggerSetting) { configForm.value = { type: node.triggerSetting.type, diff --git a/src/components/Verifition/src/Verify.vue b/src/components/Verifition/src/Verify.vue index b7b50486..930d0e72 100644 --- a/src/components/Verifition/src/Verify.vue +++ b/src/components/Verifition/src/Verify.vue @@ -36,14 +36,15 @@ * Verify 验证码组件 * @description 分发验证码使用 * */ -import { VerifyPoints, VerifySlide } from './Verify' +import {VerifyPictureWord, VerifyPoints, VerifySlide} from './Verify' import { computed, ref, toRefs, watchEffect } from 'vue' export default { name: 'Vue3Verify', components: { VerifySlide, - VerifyPoints + VerifyPoints, + VerifyPictureWord }, props: { captchaType: { @@ -118,6 +119,10 @@ export default { } watchEffect(() => { switch (captchaType.value) { + case 'pictureWord': + verifyType.value = '3' + componentType.value = 'VerifyPictureWord' + break case 'blockPuzzle': verifyType.value = '2' componentType.value = 'VerifySlide' @@ -438,4 +443,4 @@ export default { content: ' '; inset: 0; } - + \ No newline at end of file diff --git a/src/components/Verifition/src/Verify/VerifyPictureWord.vue b/src/components/Verifition/src/Verify/VerifyPictureWord.vue new file mode 100644 index 00000000..e1725f89 --- /dev/null +++ b/src/components/Verifition/src/Verify/VerifyPictureWord.vue @@ -0,0 +1,196 @@ + + diff --git a/src/components/Verifition/src/Verify/index.ts b/src/components/Verifition/src/Verify/index.ts index 0daa63a5..e027ab3f 100644 --- a/src/components/Verifition/src/Verify/index.ts +++ b/src/components/Verifition/src/Verify/index.ts @@ -1,4 +1,5 @@ import VerifySlide from './VerifySlide.vue' import VerifyPoints from './VerifyPoints.vue' +import VerifyPictureWord from './VerifyPictureWord.vue' -export { VerifySlide, VerifyPoints } +export { VerifySlide, VerifyPoints, VerifyPictureWord } \ No newline at end of file diff --git a/src/locales/en.ts b/src/locales/en.ts index 505cfd80..bd4c0b42 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -146,9 +146,11 @@ export default { invalidTenantName:"Invalid Tenant Name" }, captcha: { + verify: 'Verify', verification: 'Please complete security verification', slide: 'Swipe right to complete verification', point: 'Please click', + code: 'Please enter the verification code', success: 'Verification succeeded', fail: 'verification failed' }, @@ -457,4 +459,4 @@ export default { btn_zoom_out: 'Zoom out', preview: 'Preivew' } -} +} \ No newline at end of file diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 768b5879..3b6c2e90 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -147,9 +147,11 @@ export default { invalidTenantName: '无效的租户名称' }, captcha: { + verify: '验证', verification: '请完成安全验证', slide: '向右滑动完成验证', point: '请依次点击', + code: '请输入验证码', success: '验证成功', fail: '验证失败' }, @@ -453,4 +455,4 @@ export default { preview: '预览' }, 'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错 -} +} \ No newline at end of file diff --git a/src/utils/formCreate.ts b/src/utils/formCreate.ts index 19862f57..f3f005ea 100644 --- a/src/utils/formCreate.ts +++ b/src/utils/formCreate.ts @@ -2,6 +2,7 @@ * 针对 https://github.com/xaboy/form-create-designer 封装的工具类 */ import { isRef } from 'vue' +import formCreate from '@form-create/element-ui' // 编码表单 Conf export const encodeConf = (designerRef: object) => { @@ -24,7 +25,7 @@ export const encodeFields = (designerRef: object) => { export const decodeFields = (fields: string[]) => { const rule: object[] = [] fields.forEach((item) => { - rule.push(JSON.parse(item)) + rule.push(formCreate.parseJson(item)) }) return rule } @@ -32,7 +33,7 @@ export const decodeFields = (fields: string[]) => { // 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 export const setConfAndFields = (designerRef: object, conf: string, fields: string) => { // @ts-ignore - designerRef.value.setOption(JSON.parse(conf)) + designerRef.value.setOption(formCreate.parseJson(conf)) // @ts-ignore designerRef.value.setRule(decodeFields(fields)) } @@ -49,154 +50,10 @@ export const setConfAndFields2 = ( detailPreview = detailPreview.value } - // 修复所有函数类型(解决设计器保存后函数变成字符串的问题)。例如说: - // https://t.zsxq.com/rADff - // https://t.zsxq.com/ZfbGt - // https://t.zsxq.com/mHOoj - // https://t.zsxq.com/BSylB - const option = JSON.parse(conf) - const rule = decodeFields(fields) - // 🔧 修复所有函数类型 - 解决设计器保存后函数变成字符串的问题 - const fixFunctions = (obj: any) => { - if (obj && typeof obj === 'object') { - Object.keys(obj).forEach((key) => { - // 检查是否是函数相关的属性 - if (isFunctionProperty(key)) { - // 如果不是函数类型,重新构建为函数 - if (typeof obj[key] !== 'function') { - obj[key] = createDefaultFunction(key) - } - } else if (typeof obj[key] === 'object' && obj[key] !== null) { - // 递归处理嵌套对象 - fixFunctions(obj[key]) - } - }) - } - } - // 判断是否是函数属性 - const isFunctionProperty = (key: string): boolean => { - const functionKeys = [ - 'beforeFetch', // 请求前处理 - 'afterFetch', // 请求后处理 - 'onSubmit', // 表单提交 - 'onReset', // 表单重置 - 'onChange', // 值变化 - 'onInput', // 输入事件 - 'onClick', // 点击事件 - 'onFocus', // 获取焦点 - 'onBlur', // 失去焦点 - 'onMounted', // 组件挂载 - 'onCreated', // 组件创建 - 'onReload', // 重新加载 - 'remoteMethod', // 远程搜索方法 - 'parseFunc', // 解析函数 - 'validator', // 验证器 - 'asyncValidator', // 异步验证器 - 'formatter', // 格式化函数 - 'parser', // 解析函数 - 'beforeUpload', // 上传前处理 - 'onSuccess', // 成功回调 - 'onError', // 错误回调 - 'onProgress', // 进度回调 - 'onPreview', // 预览回调 - 'onRemove', // 移除回调 - 'onExceed', // 超出限制回调 - 'filterMethod', // 过滤方法 - 'sortMethod', // 排序方法 - 'loadData', // 加载数据 - 'renderContent', // 渲染内容 - 'render' // 渲染函数 - ] - // 检查是否以函数相关前缀开头 - const functionPrefixes = ['on', 'before', 'after', 'handle'] - return functionKeys.includes(key) || functionPrefixes.some((prefix) => key.startsWith(prefix)) - } - // 根据函数名创建默认函数 - const createDefaultFunction = (key: string): Function => { - switch (key) { - case 'beforeFetch': - return (config: any) => { - // 添加 Token 认证头。例如说: - // https://t.zsxq.com/hK3FO - const token = localStorage.getItem('token') - if (token) { - config.headers = { - ...config.headers, - Authorization: 'Bearer ' + token - } - } - // 添加通用请求头 - config.headers = { - ...config.headers, - 'Content-Type': 'application/json', - 'X-Requested-With': 'XMLHttpRequest' - } - // 添加时间戳防止缓存 - config.params = { - ...config.params, - _t: Date.now() - } - return config - } - case 'afterFetch': - return (data: any) => { - return data - } - case 'onSubmit': - return (_formData: any) => { - return true - } - case 'onReset': - return () => { - return true - } - case 'onChange': - return (_value: any, _oldValue: any) => {} - case 'remoteMethod': - return (query: string) => { - console.log('remoteMethod被调用:', query) - } - case 'parseFunc': - return (data: any) => { - // 默认解析逻辑:如果是数组直接返回,否则尝试获取list属性 - if (Array.isArray(data)) { - return data - } - return data?.list || data?.data || [] - } - case 'validator': - return (_rule: any, _value: any, callback: Function) => { - callback() - } - case 'beforeUpload': - return (_file: any) => { - return true - } - default: - // 通用默认函数 - return (...args: any[]) => { - // 对于事件处理函数,返回true表示继续执行 - if (key.startsWith('on') || key.startsWith('handle')) { - return true - } - // 对于其他函数,返回第一个参数(通常是数据传递) - return args[0] - } - } - } - // 修复 option 中的所有函数 - fixFunctions(option) - // 修复 rule 中的所有函数(包括组件的 props) - if (Array.isArray(rule)) { - rule.forEach((item: any) => { - fixFunctions(item) - }) - } - // @ts-ignore - detailPreview.option = option + detailPreview.option = formCreate.parseJson(conf) // @ts-ignore - detailPreview.rule = rule + detailPreview.rule = decodeFields(fields) if (value) { // @ts-ignore diff --git a/src/views/Login/SocialLogin.vue b/src/views/Login/SocialLogin.vue index e0caace8..961f4ddb 100644 --- a/src/views/Login/SocialLogin.vue +++ b/src/views/Login/SocialLogin.vue @@ -185,7 +185,7 @@ const { push } = useRouter() const permissionStore = usePermissionStore() const loginLoading = ref(false) const verify = ref() -const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 +const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码 const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN) diff --git a/src/views/Login/components/ForgetPasswordForm.vue b/src/views/Login/components/ForgetPasswordForm.vue index 0c3b2e04..f47b2299 100644 --- a/src/views/Login/components/ForgetPasswordForm.vue +++ b/src/views/Login/components/ForgetPasswordForm.vue @@ -143,7 +143,7 @@ const iconCircleCheck = useIcon({ icon: 'ep:circle-check' }) const { validForm } = useFormValid(formSmsResetPassword) const { handleBackLogin, getLoginState, setLoginState } = useLoginState() const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD) -const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 +const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码 const validatePass2 = (_rule, value, callback) => { if (value === '') { diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 3c4e1d1a..1bb5173d 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -47,10 +47,7 @@ /> - + @@ -177,7 +174,7 @@ const permissionStore = usePermissionStore() const redirect = ref('') const loginLoading = ref(false) const verify = ref() -const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 +const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码 const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN) diff --git a/src/views/Login/components/RegisterForm.vue b/src/views/Login/components/RegisterForm.vue index 6a77cfbf..514dd0de 100644 --- a/src/views/Login/components/RegisterForm.vue +++ b/src/views/Login/components/RegisterForm.vue @@ -120,7 +120,7 @@ const permissionStore = usePermissionStore() const redirect = ref('') const loginLoading = ref(false) const verify = ref() -const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 +const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码 const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER) diff --git a/src/views/bpm/model/form/ExtraSettings.vue b/src/views/bpm/model/form/ExtraSettings.vue index 9c5beaf6..b75fbbd0 100644 --- a/src/views/bpm/model/form/ExtraSettings.vue +++ b/src/views/bpm/model/form/ExtraSettings.vue @@ -11,6 +11,17 @@ + + +
+ +
+ 审批人可撤回正在审批节点的前一节点 +
+
+