diff --git a/.eslintrc.js b/.eslintrc.js index 70c91784..b28255ca 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -68,6 +68,8 @@ module.exports = defineConfig({ ], 'vue/multi-word-component-names': 'off', 'vue/no-v-html': 'off', - 'prettier/prettier': 'off' // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件 + 'prettier/prettier': 'off', // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件 + '@unocss/order': 'off', // 芋艿:禁用 unocss 【css】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐 + '@unocss/order-attributify': 'off' // 芋艿:禁用 unocss 【属性】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐 } }) diff --git a/.image/common/bpm-feature.png b/.image/common/bpm-feature.png new file mode 100644 index 00000000..23787fb4 Binary files /dev/null and b/.image/common/bpm-feature.png differ diff --git a/.image/common/infra-feature.png b/.image/common/infra-feature.png new file mode 100644 index 00000000..f5cef50c Binary files /dev/null and b/.image/common/infra-feature.png differ diff --git a/.image/common/system-feature.png b/.image/common/system-feature.png new file mode 100644 index 00000000..366087ce Binary files /dev/null and b/.image/common/system-feature.png differ diff --git a/README.md b/README.md index f78b0cba..7bac2225 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,8 @@ | 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 | | 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 | +![功能图](/.image/common/system-feature.png) + ### 工作流程 | | 功能 | 描述 | @@ -129,6 +131,8 @@ | 🚀 | 已办任务 | 查看自己【已】审批的工作任务,未来会支持回退操作 | | 🚀 | OA 请假 | 作为业务自定义接入工作流的使用示例,只需创建请求对应的工作流程,即可进行审批 | +![功能图](/.image/common/bpm-feature.png) + ### 支付系统 | | 功能 | 描述 | @@ -164,6 +168,8 @@ ps:核心功能已经实现,正在对接微信小程序中... | 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 | | 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 | +![功能图](/.image/common/infra-feature.png) + ### 数据报表 | | 功能 | 描述 | diff --git a/package.json b/package.json index bafdf048..58460358 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yudao-ui-admin-vue3", - "version": "2.0.0-snapshot", + "version": "2.0.1-snapshot", "description": "基于vue3、vite4、element-plus、typesScript", "author": "xingyu", "private": false, @@ -30,12 +30,12 @@ "@form-create/element-ui": "^3.1.24", "@iconify/iconify": "^3.1.1", "@videojs-player/vue": "^1.0.0", - "@vueuse/core": "^10.6.1", + "@vueuse/core": "^10.9.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10", "@zxcvbn-ts/core": "^3.0.4", "animate.css": "^4.1.1", - "axios": "^1.6.1", + "axios": "^1.6.7", "benz-amr-recorder": "^1.1.5", "bpmn-js-token-simulation": "^0.10.0", "camunda-bpmn-moddle": "^7.0.1", @@ -44,9 +44,9 @@ "dayjs": "^1.11.10", "diagram-js": "^12.8.0", "driver.js": "^1.3.1", - "echarts": "^5.4.3", + "echarts": "^5.5.0", "echarts-wordcloud": "^2.1.0", - "element-plus": "2.4.2", + "element-plus": "2.5.3", "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", "jsencrypt": "^3.3.2", @@ -55,77 +55,78 @@ "mitt": "^3.0.1", "nprogress": "^0.2.0", "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.0", "qrcode": "^1.5.3", "qs": "^6.11.2", "steady-xml": "^0.1.0", "url": "^0.11.3", "video.js": "^7.21.5", - "vue": "^3.3.8", + "vue": "3.4.20", "vue-dompurify-html": "^4.1.4", - "vue-i18n": "^9.6.5", - "vue-router": "^4.2.5", + "vue-i18n": "9.9.1", + "vue-router": "^4.3.0", "vue-types": "^5.1.1", "vuedraggable": "^4.1.0", "web-storage-cache": "^1.1.1", "xml-js": "^1.6.11" }, "devDependencies": { - "@commitlint/cli": "^18.4.1", - "@commitlint/config-conventional": "^18.4.0", - "@iconify/json": "^2.2.142", - "@intlify/unplugin-vue-i18n": "^1.5.0", + "@commitlint/cli": "^19.0.1", + "@commitlint/config-conventional": "^19.0.0", + "@iconify/json": "^2.2.187", + "@intlify/unplugin-vue-i18n": "^2.0.0", "@purge-icons/generated": "^0.9.0", - "@types/lodash-es": "^4.17.11", - "@types/node": "^20.9.0", + "@types/lodash-es": "^4.17.12", + "@types/node": "^20.11.21", "@types/nprogress": "^0.2.3", "@types/qrcode": "^1.5.5", - "@types/qs": "^6.9.10", - "@typescript-eslint/eslint-plugin": "^6.11.0", - "@typescript-eslint/parser": "^6.11.0", - "@unocss/transformer-variant-group": "^0.57.4", + "@types/qs": "^6.9.12", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", + "@unocss/transformer-variant-group": "^0.58.5", "@unocss/eslint-config": "^0.57.4", - "@vitejs/plugin-legacy": "^4.1.1", - "@vitejs/plugin-vue": "^4.4.1", - "@vitejs/plugin-vue-jsx": "^3.0.2", - "autoprefixer": "^10.4.16", + "@vitejs/plugin-legacy": "^5.3.1", + "@vitejs/plugin-vue": "^5.0.4", + "@vitejs/plugin-vue-jsx": "^3.1.0", + "autoprefixer": "^10.4.17", "bpmn-js": "8.9.0", "bpmn-js-properties-panel": "0.46.0", "consola": "^3.2.3", - "eslint": "^8.53.0", - "eslint-config-prettier": "^9.0.0", - "eslint-define-config": "^1.24.1", - "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-vue": "^9.18.1", - "lint-staged": "^15.1.0", - "postcss": "^8.4.31", - "postcss-html": "^1.5.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-define-config": "^2.1.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-vue": "^9.22.0", + "lint-staged": "^15.2.2", + "postcss": "^8.4.35", + "postcss-html": "^1.6.0", "postcss-scss": "^4.0.9", - "prettier": "^3.1.0", + "prettier": "^3.2.5", "prettier-eslint": "^16.3.0", "rimraf": "^5.0.5", - "rollup": "^4.4.1", + "rollup": "^4.12.0", "sass": "^1.69.5", - "stylelint": "^15.11.0", + "stylelint": "^16.2.1", "stylelint-config-html": "^1.1.0", - "stylelint-config-recommended": "^13.0.0", - "stylelint-config-standard": "^34.0.0", - "stylelint-order": "^6.0.3", - "terser": "^5.24.0", - "typescript": "5.2.2", - "unocss": "^0.57.4", + "stylelint-config-recommended": "^14.0.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-order": "^6.0.4", + "terser": "^5.28.1", + "typescript": "5.3.3", + "unocss": "^0.58.5", "unplugin-auto-import": "^0.16.7", "unplugin-element-plus": "^0.8.0", "unplugin-vue-components": "^0.25.2", - "vite": "4.5.0", + "vite": "5.1.4", "vite-plugin-compression": "^0.5.1", - "vite-plugin-ejs": "^1.6.4", + "vite-plugin-ejs": "^1.7.0", "vite-plugin-eslint": "^1.8.1", "vite-plugin-progress": "^0.0.7", - "vite-plugin-purge-icons": "^0.9.2", + "vite-plugin-purge-icons": "^0.10.0", "vite-plugin-svg-icons": "^2.0.1", "vite-plugin-top-level-await": "^1.3.1", "vue-eslint-parser": "^9.3.2", - "vue-tsc": "^1.8.22" + "vue-tsc": "^1.8.27" }, "license": "MIT", "repository": { diff --git a/src/api/bpm/category/index.ts b/src/api/bpm/category/index.ts new file mode 100644 index 00000000..d1e109cb --- /dev/null +++ b/src/api/bpm/category/index.ts @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +// BPM 流程分类 VO +export interface CategoryVO { + id: number // 分类编号 + name: string // 分类名 + code: string // 分类标志 + status: number // 分类状态 + sort: number // 分类排序 +} + +// BPM 流程分类 API +export const CategoryApi = { + // 查询流程分类分页 + getCategoryPage: async (params: any) => { + return await request.get({ url: `/bpm/category/page`, params }) + }, + + // 查询流程分类列表 + getCategorySimpleList: async () => { + return await request.get({ url: `/bpm/category/simple-list` }) + }, + + // 查询流程分类详情 + getCategory: async (id: number) => { + return await request.get({ url: `/bpm/category/get?id=` + id }) + }, + + // 新增流程分类 + createCategory: async (data: CategoryVO) => { + return await request.post({ url: `/bpm/category/create`, data }) + }, + + // 修改流程分类 + updateCategory: async (data: CategoryVO) => { + return await request.put({ url: `/bpm/category/update`, data }) + }, + + // 删除流程分类 + deleteCategory: async (id: number) => { + return await request.delete({ url: `/bpm/category/delete?id=` + id }) + } +} diff --git a/src/api/bpm/definition/index.ts b/src/api/bpm/definition/index.ts index c0e51fab..cb6d4271 100644 --- a/src/api/bpm/definition/index.ts +++ b/src/api/bpm/definition/index.ts @@ -1,8 +1,9 @@ import request from '@/config/axios' -export const getProcessDefinitionBpmnXML = async (id: number) => { +export const getProcessDefinition = async (id: number, key: string) => { return await request.get({ - url: '/bpm/process-definition/get-bpmn-xml?id=' + id + url: '/bpm/process-definition/get', + params: { id, key } }) } diff --git a/src/api/bpm/form/index.ts b/src/api/bpm/form/index.ts index 142ed24c..7fce11fc 100644 --- a/src/api/bpm/form/index.ts +++ b/src/api/bpm/form/index.ts @@ -49,8 +49,8 @@ export const getFormPage = async (params) => { } // 获得动态表单的精简列表 -export const getSimpleFormList = async () => { +export const getFormSimpleList = async () => { return await request.get({ - url: '/bpm/form/list-all-simple' + url: '/bpm/form/simple-list' }) } diff --git a/src/api/bpm/leave/index.ts b/src/api/bpm/leave/index.ts index d4fe8d58..4f374b2f 100644 --- a/src/api/bpm/leave/index.ts +++ b/src/api/bpm/leave/index.ts @@ -2,7 +2,7 @@ import request from '@/config/axios' export type LeaveVO = { id: number - result: number + status: number type: number reason: string processInstanceId: string diff --git a/src/api/bpm/processExpression/index.ts b/src/api/bpm/processExpression/index.ts new file mode 100644 index 00000000..af6a7372 --- /dev/null +++ b/src/api/bpm/processExpression/index.ts @@ -0,0 +1,42 @@ +import request from '@/config/axios' + +// BPM 流程表达式 VO +export interface ProcessExpressionVO { + id: number // 编号 + name: string // 表达式名字 + status: number // 表达式状态 + expression: string // 表达式 +} + +// BPM 流程表达式 API +export const ProcessExpressionApi = { + // 查询BPM 流程表达式分页 + getProcessExpressionPage: async (params: any) => { + return await request.get({ url: `/bpm/process-expression/page`, params }) + }, + + // 查询BPM 流程表达式详情 + getProcessExpression: async (id: number) => { + return await request.get({ url: `/bpm/process-expression/get?id=` + id }) + }, + + // 新增BPM 流程表达式 + createProcessExpression: async (data: ProcessExpressionVO) => { + return await request.post({ url: `/bpm/process-expression/create`, data }) + }, + + // 修改BPM 流程表达式 + updateProcessExpression: async (data: ProcessExpressionVO) => { + return await request.put({ url: `/bpm/process-expression/update`, data }) + }, + + // 删除BPM 流程表达式 + deleteProcessExpression: async (id: number) => { + return await request.delete({ url: `/bpm/process-expression/delete?id=` + id }) + }, + + // 导出BPM 流程表达式 Excel + exportProcessExpression: async (params) => { + return await request.download({ url: `/bpm/process-expression/export-excel`, params }) + } +} \ No newline at end of file diff --git a/src/api/bpm/processInstance/index.ts b/src/api/bpm/processInstance/index.ts index a937eae2..81640625 100644 --- a/src/api/bpm/processInstance/index.ts +++ b/src/api/bpm/processInstance/index.ts @@ -20,51 +20,49 @@ export type ProcessInstanceVO = { endTime: string } -export type ProcessInstanceCCVO = { - type: number, - taskName: string, - taskKey: string, - processInstanceName: string, - processInstanceKey: string, - startUserId: string, - options:string [], +export type ProcessInstanceCopyVO = { + type: number + taskName: string + taskKey: string + processInstanceName: string + processInstanceKey: string + startUserId: string + options: string[] reason: string } -export const getMyProcessInstancePage = async (params) => { +export const getProcessInstanceMyPage = async (params: any) => { return await request.get({ url: '/bpm/process-instance/my-page', params }) } +export const getProcessInstanceManagerPage = async (params: any) => { + return await request.get({ url: '/bpm/process-instance/manager-page', params }) +} + export const createProcessInstance = async (data) => { return await request.post({ url: '/bpm/process-instance/create', data: data }) } -export const cancelProcessInstance = async (id: number, reason: string) => { +export const cancelProcessInstanceByStartUser = async (id: number, reason: string) => { const data = { id: id, reason: reason } - return await request.delete({ url: '/bpm/process-instance/cancel', data: data }) + return await request.delete({ url: '/bpm/process-instance/cancel-by-start-user', data: data }) } -export const getProcessInstance = async (id: number) => { +export const cancelProcessInstanceByAdmin = async (id: number, reason: string) => { + const data = { + id: id, + reason: reason + } + return await request.delete({ url: '/bpm/process-instance/cancel-by-admin', data: data }) +} + +export const getProcessInstance = async (id: string) => { return await request.get({ url: '/bpm/process-instance/get?id=' + id }) } -/** - * 抄送 - * @param data 抄送数据 - * @returns 是否抄送成功 - */ -export const createProcessInstanceCC = async (data) => { - return await request.post({ url: '/bpm/process-instance/cc/create', data: data }) +export const getProcessInstanceCopyPage = async (params: any) => { + return await request.get({ url: '/bpm/process-instance/copy/page', params }) } - -/** - * 抄送列表 - * @param params - * @returns - */ -export const getProcessInstanceCCPage = async (params) => { - return await request.get({ url: '/bpm/process-instance/cc/my-page', params }) -} \ No newline at end of file diff --git a/src/api/bpm/processListener/index.ts b/src/api/bpm/processListener/index.ts new file mode 100644 index 00000000..dabaa476 --- /dev/null +++ b/src/api/bpm/processListener/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +// BPM 流程监听器 VO +export interface ProcessListenerVO { + id: number // 编号 + name: string // 监听器名字 + type: string // 监听器类型 + status: number // 监听器状态 + event: string // 监听事件 + valueType: string // 监听器值类型 + value: string // 监听器值 +} + +// BPM 流程监听器 API +export const ProcessListenerApi = { + // 查询流程监听器分页 + getProcessListenerPage: async (params: any) => { + return await request.get({ url: `/bpm/process-listener/page`, params }) + }, + + // 查询流程监听器详情 + getProcessListener: async (id: number) => { + return await request.get({ url: `/bpm/process-listener/get?id=` + id }) + }, + + // 新增流程监听器 + createProcessListener: async (data: ProcessListenerVO) => { + return await request.post({ url: `/bpm/process-listener/create`, data }) + }, + + // 修改流程监听器 + updateProcessListener: async (data: ProcessListenerVO) => { + return await request.put({ url: `/bpm/process-listener/update`, data }) + }, + + // 删除流程监听器 + deleteProcessListener: async (id: number) => { + return await request.delete({ url: `/bpm/process-listener/delete?id=` + id }) + } +} diff --git a/src/api/bpm/task/index.ts b/src/api/bpm/task/index.ts index df6d8160..f3cda9f7 100644 --- a/src/api/bpm/task/index.ts +++ b/src/api/bpm/task/index.ts @@ -4,78 +4,63 @@ export type TaskVO = { id: number } -export const getTodoTaskPage = async (params) => { +export const getTaskTodoPage = async (params: any) => { return await request.get({ url: '/bpm/task/todo-page', params }) } -export const getDoneTaskPage = async (params) => { +export const getTaskDonePage = async (params: any) => { return await request.get({ url: '/bpm/task/done-page', params }) } -export const completeTask = async (data) => { - return await request.put({ url: '/bpm/task/complete', data }) +export const getTaskManagerPage = async (params: any) => { + return await request.get({ url: '/bpm/task/manager-page', params }) } -export const approveTask = async (data) => { +export const approveTask = async (data: any) => { return await request.put({ url: '/bpm/task/approve', data }) } -export const rejectTask = async (data) => { +export const rejectTask = async (data: any) => { return await request.put({ url: '/bpm/task/reject', data }) } -export const backTask = async (data) => { - return await request.put({ url: '/bpm/task/back', data }) -} -export const updateTaskAssignee = async (data) => { - return await request.put({ url: '/bpm/task/update-assignee', data }) -} - -export const getTaskListByProcessInstanceId = async (processInstanceId) => { +export const getTaskListByProcessInstanceId = async (processInstanceId: string) => { return await request.get({ url: '/bpm/task/list-by-process-instance-id?processInstanceId=' + processInstanceId }) } -// 导出任务 -export const exportTask = async (params) => { - return await request.download({ url: '/bpm/task/export', params }) -} - // 获取所有可回退的节点 -export const getReturnList = async (params) => { - return await request.get({ url: '/bpm/task/return-list', params }) +export const getTaskListByReturn = async (id: string) => { + return await request.get({ url: '/bpm/task/list-by-return', params: { id } }) } // 回退 -export const returnTask = async (data) => { +export const returnTask = async (data: any) => { return await request.put({ url: '/bpm/task/return', data }) } -/** - * 委派 - */ -export const delegateTask = async (data) => { +// 委派 +export const delegateTask = async (data: any) => { return await request.put({ url: '/bpm/task/delegate', data }) } -/** - * 加签 - */ -export const taskAddSign = async (data) => { +// 转派 +export const transferTask = async (data: any) => { + return await request.put({ url: '/bpm/task/transfer', data }) +} + +// 加签 +export const signCreateTask = async (data: any) => { return await request.put({ url: '/bpm/task/create-sign', data }) } -/** - * 获取减签任务列表 - */ -export const getChildrenTaskList = async (id: string) => { - return await request.get({ url: '/bpm/task/children-list?taskId=' + id }) -} - -/** - * 减签 - */ -export const taskSubSign = async (data) => { +// 减签 +export const signDeleteTask = async (data: any) => { return await request.delete({ url: '/bpm/task/delete-sign', data }) } + +// 获取减签任务列表 +export const getChildrenTaskList = async (id: string) => { + return await request.get({ url: '/bpm/task/list-by-parent-task-id?parentTaskId=' + id }) +} diff --git a/src/api/bpm/taskAssignRule/index.ts b/src/api/bpm/taskAssignRule/index.ts deleted file mode 100644 index 5fbe342d..00000000 --- a/src/api/bpm/taskAssignRule/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import request from '@/config/axios' - -export type TaskAssignVO = { - id: number - modelId: string - processDefinitionId: string - taskDefinitionKey: string - taskDefinitionName: string - options: string[] - type: number -} - -export const getTaskAssignRuleList = async (params) => { - return await request.get({ url: '/bpm/task-assign-rule/list', params }) -} - -export const createTaskAssignRule = async (data: TaskAssignVO) => { - return await request.post({ - url: '/bpm/task-assign-rule/create', - data: data - }) -} - -export const updateTaskAssignRule = async (data: TaskAssignVO) => { - return await request.put({ - url: '/bpm/task-assign-rule/update', - data: data - }) -} diff --git a/src/api/bpm/userGroup/index.ts b/src/api/bpm/userGroup/index.ts index 035762bf..7d12755e 100644 --- a/src/api/bpm/userGroup/index.ts +++ b/src/api/bpm/userGroup/index.ts @@ -4,7 +4,7 @@ export type UserGroupVO = { id: number name: string description: string - memberUserIds: number[] + userIds: number[] status: number remark: string createTime: string @@ -42,6 +42,6 @@ export const getUserGroupPage = async (params) => { } // 获取用户组精简信息列表 -export const getSimpleUserGroupList = async (): Promise => { - return await request.get({ url: '/bpm/user-group/list-all-simple' }) +export const getUserGroupSimpleList = async (): Promise => { + return await request.get({ url: '/bpm/user-group/simple-list' }) } diff --git a/src/assets/imgs/avatar.jpg b/src/assets/imgs/avatar.jpg new file mode 100644 index 00000000..d46a70a4 Binary files /dev/null and b/src/assets/imgs/avatar.jpg differ diff --git a/src/components/ContentWrap/src/ContentWrap.vue b/src/components/ContentWrap/src/ContentWrap.vue index e3bd5972..454e95c9 100644 --- a/src/components/ContentWrap/src/ContentWrap.vue +++ b/src/components/ContentWrap/src/ContentWrap.vue @@ -25,6 +25,9 @@ defineProps({ +
+ +
diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue index ec40bca2..eff82745 100644 --- a/src/components/Editor/src/Editor.vue +++ b/src/components/Editor/src/Editor.vue @@ -180,12 +180,12 @@ defineExpose({ + + diff --git a/src/components/SimpleProcessDesigner/src/nodeWrap.vue b/src/components/SimpleProcessDesigner/src/nodeWrap.vue new file mode 100644 index 00000000..3c9d5eb1 --- /dev/null +++ b/src/components/SimpleProcessDesigner/src/nodeWrap.vue @@ -0,0 +1,297 @@ + + + + diff --git a/src/components/SimpleProcessDesigner/src/util.ts b/src/components/SimpleProcessDesigner/src/util.ts new file mode 100644 index 00000000..f4acd76c --- /dev/null +++ b/src/components/SimpleProcessDesigner/src/util.ts @@ -0,0 +1,165 @@ +/** + * todo + */ +export const arrToStr = (arr?: [{ name: string }]) => { + if (arr) { + return arr + .map((item) => { + return item.name + }) + .toString() + } +} + +export const setApproverStr = (nodeConfig: any) => { + if (nodeConfig.settype == 1) { + if (nodeConfig.nodeUserList.length == 1) { + return nodeConfig.nodeUserList[0].name + } else if (nodeConfig.nodeUserList.length > 1) { + if (nodeConfig.examineMode == 1) { + return arrToStr(nodeConfig.nodeUserList) + } else if (nodeConfig.examineMode == 2) { + return nodeConfig.nodeUserList.length + '人会签' + } + } + } else if (nodeConfig.settype == 2) { + const level = + nodeConfig.directorLevel == 1 ? '直接主管' : '第' + nodeConfig.directorLevel + '级主管' + if (nodeConfig.examineMode == 1) { + return level + } else if (nodeConfig.examineMode == 2) { + return level + '会签' + } + } else if (nodeConfig.settype == 4) { + if (nodeConfig.selectRange == 1) { + return '发起人自选' + } else { + if (nodeConfig.nodeUserList.length > 0) { + if (nodeConfig.selectRange == 2) { + return '发起人自选' + } else { + return '发起人从' + nodeConfig.nodeUserList[0].name + '中自选' + } + } else { + return '' + } + } + } else if (nodeConfig.settype == 5) { + return '发起人自己' + } else if (nodeConfig.settype == 7) { + return '从直接主管到通讯录中级别最高的第' + nodeConfig.examineEndDirectorLevel + '个层级主管' + } +} + +export const copyerStr = (nodeConfig: any) => { + if (nodeConfig.nodeUserList.length != 0) { + return arrToStr(nodeConfig.nodeUserList) + } else { + if (nodeConfig.ccSelfSelectFlag == 1) { + return '发起人自选' + } + } +} +export const conditionStr = (nodeConfig, index) => { + const { conditionList, nodeUserList } = nodeConfig.conditionNodes[index] + if (conditionList.length == 0) { + return index == nodeConfig.conditionNodes.length - 1 && + nodeConfig.conditionNodes[0].conditionList.length != 0 + ? '其他条件进入此流程' + : '请设置条件' + } else { + let str = '' + for (let i = 0; i < conditionList.length; i++) { + const { + columnId, + columnType, + showType, + showName, + optType, + zdy1, + opt1, + zdy2, + opt2, + fixedDownBoxValue + } = conditionList[i] + if (columnId == 0) { + if (nodeUserList.length != 0) { + str += '发起人属于:' + str += + nodeUserList + .map((item) => { + return item.name + }) + .join('或') + ' 并且 ' + } + } + if (columnType == 'String' && showType == '3') { + if (zdy1) { + str += showName + '属于:' + dealStr(zdy1, JSON.parse(fixedDownBoxValue)) + ' 并且 ' + } + } + if (columnType == 'Double') { + if (optType != 6 && zdy1) { + const optTypeStr = ['', '<', '>', '≤', '=', '≥'][optType] + str += `${showName} ${optTypeStr} ${zdy1} 并且 ` + } else if (optType == 6 && zdy1 && zdy2) { + str += `${zdy1} ${opt1} ${showName} ${opt2} ${zdy2} 并且 ` + } + } + } + return str ? str.substring(0, str.length - 4) : '请设置条件' + } +} + +export const dealStr = (str: string, obj) => { + const arr = [] + const list = str.split(',') + for (const elem in obj) { + list.map((item) => { + if (item == elem) { + arr.push(obj[elem].value) + } + }) + } + return arr.join('或') +} + +export const removeEle = (arr, elem, key = 'id') => { + let includesIndex + arr.map((item, index) => { + if (item[key] == elem[key]) { + includesIndex = index + } + }) + arr.splice(includesIndex, 1) +} + +export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250'] +export const placeholderList = ['发起人', '审核人', '抄送人'] +export const setTypes = [ + { value: 1, label: '指定成员' }, + { value: 2, label: '主管' }, + { value: 4, label: '发起人自选' }, + { value: 5, label: '发起人自己' }, + { value: 7, label: '连续多级主管' } +] + +export const selectModes = [ + { value: 1, label: '选一个人' }, + { value: 2, label: '选多个人' } +] + +export const selectRanges = [ + { value: 1, label: '全公司' }, + { value: 2, label: '指定成员' }, + { value: 3, label: '指定角色' } +] + +export const optTypes = [ + { value: '1', label: '小于' }, + { value: '2', label: '大于' }, + { value: '3', label: '小于等于' }, + { value: '4', label: '等于' }, + { value: '5', label: '大于等于' }, + { value: '6', label: '介于两个数之间' } +] diff --git a/src/components/SimpleProcessDesigner/theme/workflow.css b/src/components/SimpleProcessDesigner/theme/workflow.css new file mode 100644 index 00000000..888b1a82 --- /dev/null +++ b/src/components/SimpleProcessDesigner/theme/workflow.css @@ -0,0 +1,1292 @@ + +.clearfix { + zoom: 1 +} + +.clearfix:after, +.clearfix:before { + content: ""; + display: table +} + +.clearfix:after { + clear: both +} + +@font-face { + font-family: anticon; + font-display: fallback; + src: url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.eot"); + src: url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.woff") format("woff"), url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.ttf") format("truetype"), url("https://at.alicdn.com/t/font_148784_v4ggb6wrjmkotj4i.svg#iconfont") format("svg") +} + +.anticon { + display: inline-block; + font-style: normal; + vertical-align: baseline; + text-align: center; + text-transform: none; + line-height: 1; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.anticon:before { + display: block; + font-family: anticon!important +} +.anticon-close:before { + content: "\E633" +} +.anticon-right:before { + content: "\E61F" +} +.anticon-exclamation-circle{ + color: rgb(242, 86, 67) +} +.anticon-exclamation-circle:before { + content: "\E62C" +} + +.anticon-left:before { + content: "\E620" +} + +.anticon-close-circle:before { + content: "\E62E" +} + +.ant-btn { + line-height: 1.5; + display: inline-block; + font-weight: 400; + text-align: center; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 0 15px; + font-size: 14px; + border-radius: 4px; + height: 32px; + user-select: none; + transition: all .3s cubic-bezier(.645, .045, .355, 1); + position: relative; + color: rgba(0, 0, 0, .65); + background-color: #fff; + border-color: #d9d9d9 +} + +.ant-btn>.anticon { + line-height: 1 +} + +.ant-btn, +.ant-btn:active, +.ant-btn:focus { + outline: 0 +} + +.ant-btn>a:only-child { + color: currentColor +} + +.ant-btn>a:only-child:after { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: transparent +} + +.ant-btn:focus, +.ant-btn:hover { + color: #40a9ff; + background-color: #fff; + border-color: #40a9ff +} + +.ant-btn:focus>a:only-child, +.ant-btn:hover>a:only-child { + color: currentColor +} + +.ant-btn:focus>a:only-child:after, +.ant-btn:hover>a:only-child:after { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: transparent +} + +.ant-btn.active, +.ant-btn:active { + color: #096dd9; + background-color: #fff; + border-color: #096dd9 +} + +.ant-btn.active>a:only-child, +.ant-btn:active>a:only-child { + color: currentColor +} + +.ant-btn.active>a:only-child:after, +.ant-btn:active>a:only-child:after { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: transparent +} + +.ant-btn.active, +.ant-btn:active, +.ant-btn:focus, +.ant-btn:hover { + background: #fff; + text-decoration: none +} + +.ant-btn>i, +.ant-btn>span { + pointer-events: none +} + +.ant-btn:before { + position: absolute; + top: -1px; + left: -1px; + bottom: -1px; + right: -1px; + background: #fff; + opacity: .35; + content: ""; + border-radius: inherit; + z-index: 1; + transition: opacity .2s; + pointer-events: none; + display: none +} + +.ant-btn .anticon { + transition: margin-left .3s cubic-bezier(.645, .045, .355, 1) +} + +.ant-btn:active>span, +.ant-btn:focus>span { + position: relative +} + +.ant-btn>.anticon+span, +.ant-btn>span+.anticon { + margin-left: 8px +} + +.ant-input { + font-family: Chinese Quote, -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif; + font-variant: tabular-nums; + box-sizing: border-box; + margin: 0; + padding: 0; + list-style: none; + position: relative; + display: inline-block; + padding: 4px 11px; + width: 100%; + height: 32px; + font-size: 14px; + line-height: 1.5; + color: rgba(0, 0, 0, .65); + background-color: #fff; + background-image: none; + border: 1px solid #d9d9d9; + border-radius: 4px; + transition: all .3s +} + +.ant-input::-moz-placeholder { + color: #bfbfbf; + opacity: 1 +} + +.ant-input:-ms-input-placeholder { + color: #bfbfbf +} + +.ant-input::-webkit-input-placeholder { + color: #bfbfbf +} + +.ant-input:focus, +.ant-input:hover { + border-color: #40a9ff; + border-right-width: 1px!important +} + +.ant-input:focus { + outline: 0; + box-shadow: 0 0 0 2px rgba(24, 144, 255, .2) +} + +textarea.ant-input { + max-width: 100%; + height: auto; + vertical-align: bottom; + transition: all .3s, height 0s; + min-height: 32px +} + +a, +abbr, +acronym, +address, +applet, +article, +aside, +audio, +b, +big, +blockquote, +body, +canvas, +caption, +center, +cite, +code, +dd, +del, +details, +dfn, +div, +dl, +dt, +em, +fieldset, +figcaption, +figure, +footer, +form, +h1, +h2, +h3, +h4, +h5, +h6, +header, +hgroup, +html, +i, +iframe, +img, +ins, +kbd, +label, +legend, +li, +mark, +menu, +nav, +object, +ol, +p, +pre, +q, +s, +samp, +section, +small, +span, +strike, +strong, +sub, +summary, +sup, +table, +tbody, +td, +tfoot, +th, +thead, +time, +tr, +tt, +u, +ul, +var, +video { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline +} + +*, +:after, +:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box +} + +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100% +} + +body, +html { + font-size: 14px +} + +body { + font-family: Microsoft Yahei, Lucida Grande, Lucida Sans Unicode, Helvetica, Arial, Verdana, sans-serif; + line-height: 1.6; + background-color: #fff; + position: static!important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0) +} + +ol, +ul { + list-style-type: none +} + +b, +strong { + font-weight: 700 +} + +img { + border: 0 +} + +button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + margin: 0 +} + +textarea { + overflow: auto; + vertical-align: top; + -webkit-appearance: none +} + +button, +input { + line-height: normal +} + +button, +select { + text-transform: none +} + +button, +html input[type=button], +input[type=reset], +input[type=submit] { + -webkit-appearance: button; + cursor: pointer +} + +input[type=search] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box +} + +input[type=search]::-webkit-search-cancel-button, +input[type=search]::-webkit-search-decoration { + -webkit-appearance: none +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0 +} + +table { + width: 100%; + border-spacing: 0; + border-collapse: collapse +} + +table, +td, +th { + border: 0 +} + +td, +th { + padding: 0; + vertical-align: top +} + +th { + font-weight: 700; + text-align: left +} + +thead th { + white-space: nowrap +} + +a { + text-decoration: none; + cursor: pointer; + color: #3296fa +} + +a:active, +a:hover { + outline: 0; + color: #3296fa +} + +small { + font-size: 80% +} + +body, +html { + font-size: 12px!important; + color: #191f25!important; + background: #f6f6f6!important +} + +.wrap { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + height: 100% +} + +@font-face { + font-family: IconFont; + src: url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.eot"); + src: url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.eot?#iefix") format("embedded-opentype"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.woff") format("woff"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.ttf") format("truetype"), url("//at.alicdn.com/t/font_135284_ph2thxxbzgf.svg#IconFont") format("svg") +} + +.iconfont { + font-family: IconFont!important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -webkit-text-stroke-width: .2px; + -moz-osx-font-smoothing: grayscale +} + +.fd-nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 997; + width: 100%; + height: 60px; + font-size: 14px; + color: #fff; + background: #3296fa; + display: flex; + align-items: center +} + +.fd-nav>* { + flex: 1; + width: 100% +} + +.fd-nav .fd-nav-left { + display: -webkit-box; + display: flex; + align-items: center +} + +.fd-nav .fd-nav-center { + flex: none; + width: 600px; + text-align: center +} + +.fd-nav .fd-nav-right { + display: flex; + align-items: center; + justify-content: flex-end; + text-align: right +} + +.fd-nav .fd-nav-back { + display: inline-block; + width: 60px; + height: 60px; + font-size: 22px; + border-right: 1px solid #1583f2; + text-align: center; + cursor: pointer +} + +.fd-nav .fd-nav-back:hover { + background: #5af +} + +.fd-nav .fd-nav-back:active { + background: #1583f2 +} + +.fd-nav .fd-nav-back .anticon { + line-height: 60px +} + +.fd-nav .fd-nav-title { + width: 0; + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + padding: 0 15px +} + +.fd-nav a { + color: #fff; + margin-left: 12px +} + +.fd-nav .button-publish { + min-width: 80px; + margin-left: 4px; + margin-right: 15px; + color: #3296fa; + border-color: #fff +} + +.fd-nav .button-publish.ant-btn:focus, +.fd-nav .button-publish.ant-btn:hover { + color: #3296fa; + border-color: #fff; + box-shadow: 0 10px 20px 0 rgba(0, 0, 0, .3) +} + +.fd-nav .button-publish.ant-btn:active { + color: #3296fa; + background: #d6eaff; + box-shadow: none +} + +.fd-nav .button-preview { + min-width: 80px; + margin-left: 16px; + margin-right: 4px; + color: #fff; + border-color: #fff; + background: transparent +} + +.fd-nav .button-preview.ant-btn:focus, +.fd-nav .button-preview.ant-btn:hover { + color: #fff; + border-color: #fff; + background: #59acfc +} + +.fd-nav .button-preview.ant-btn:active { + color: #fff; + border-color: #fff; + background: #2186ef +} + +.fd-nav-content { + position: fixed; + top: 60px; + left: 0; + right: 0; + bottom: 0; + z-index: 1; + overflow-x: hidden; + overflow-y: auto; + padding-bottom: 30px +} + +.error-modal-desc { + font-size: 13px; + color: rgba(25, 31, 37, .56); + line-height: 22px; + margin-bottom: 14px +} + +.error-modal-list { + height: 200px; + overflow-y: auto; + margin-right: -25px; + padding-right: 25px +} + +.error-modal-item { + padding: 10px 20px; + line-height: 21px; + background: #f6f6f6; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + border-radius: 4px +} + +.error-modal-item-label { + flex: none; + font-size: 15px; + color: rgba(25, 31, 37, .56); + padding-right: 10px +} + +.error-modal-item-content { + text-align: right; + flex: 1; + font-size: 13px; + color: #191f25 +} + +#body.blur { + -webkit-filter: blur(3px); + filter: blur(3px) +} + +.zoom { + display: flex; + position: fixed; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + height: 40px; + width: 125px; + right: 40px; + margin-top: 30px; + z-index: 10 +} + +.zoom .zoom-in, +.zoom .zoom-out { + width: 30px; + height: 30px; + background: #fff; + color: #c1c1cd; + cursor: pointer; + background-size: 100%; + background-repeat: no-repeat +} + +.zoom .zoom-out { + background-image: url(https://gw.alicdn.com/tfs/TB1s0qhBHGYBuNjy0FoXXciBFXa-90-90.png) +} + +.zoom .zoom-out.disabled { + opacity: .5 +} + +.zoom .zoom-in { + background-image: url(https://gw.alicdn.com/tfs/TB1UIgJBTtYBeNjy1XdXXXXyVXa-90-90.png) +} + +.zoom .zoom-in.disabled { + opacity: .5 +} + +.auto-judge:hover .editable-title, +.node-wrap-box:hover .editable-title { + border-bottom: 1px dashed #fff +} + +.auto-judge:hover .editable-title.editing, +.node-wrap-box:hover .editable-title.editing { + text-decoration: none; + border: 1px solid #d9d9d9 +} + +.auto-judge:hover .editable-title { + border-color: #15bc83 +} + +.editable-title { + line-height: 15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + border-bottom: 1px dashed transparent +} + +.editable-title:before { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 40px +} + +.editable-title:hover { + border-bottom: 1px dashed #fff +} + +.editable-title-input { + flex: none; + height: 18px; + padding-left: 4px; + text-indent: 0; + font-size: 12px; + line-height: 18px; + z-index: 1 +} + +.editable-title-input:hover { + text-decoration: none +} + +.ant-btn { + position: relative +} + +.node-wrap-box { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + width: 220px; + min-height: 72px; + -ms-flex-negative: 0; + flex-shrink: 0; + background: #fff; + border-radius: 4px; + cursor: pointer +} + +.node-wrap-box:after { + pointer-events: none; + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 2; + border-radius: 4px; + border: 1px solid transparent; + transition: all .1s cubic-bezier(.645, .045, .355, 1); + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.node-wrap-box.active:after, +.node-wrap-box:active:after, +.node-wrap-box:hover:after { + border: 1px solid #3296fa; + box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3) +} + +.node-wrap-box.active .close, +.node-wrap-box:active .close, +.node-wrap-box:hover .close { + display: block +} + +.node-wrap-box.error:after { + border: 1px solid #f25643; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.node-wrap-box .title { + position: relative; + display: flex; + align-items: center; + padding-left: 16px; + padding-right: 30px; + width: 100%; + height: 24px; + line-height: 24px; + font-size: 12px; + color: #fff; + text-align: left; + background: #576a95; + border-radius: 4px 4px 0 0 +} + +.node-wrap-box .title .iconfont { + font-size: 12px; + margin-right: 5px +} + +.node-wrap-box .placeholder { + color: #bfbfbf +} + +.node-wrap-box .close { + display: none; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + font-size: 14px; + color: #fff; + border-radius: 50%; + text-align: center; + line-height: 20px +} + +.node-wrap-box .content { + position: relative; + font-size: 14px; + padding: 16px; + padding-right: 30px +} + +.node-wrap-box .content .text { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical +} + +.node-wrap-box .content .arrow { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 14px; + font-size: 14px; + color: #979797 +} + +.start-node.node-wrap-box .content .text { + display: block; + white-space: nowrap +} + +.node-wrap-box:before { + content: ""; + position: absolute; + top: -12px; + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + width: 0; + height: 4px; + border-style: solid; + border-width: 8px 6px 4px; + border-color: #cacaca transparent transparent; + background: #f5f5f7 +} + +.node-wrap-box.start-node:before { + content: none +} + +.top-left-cover-line { + left: -1px +} + +.top-left-cover-line, +.top-right-cover-line { + position: absolute; + height: 8px; + width: 50%; + background-color: #f5f5f7; + top: -4px +} + +.top-right-cover-line { + right: -1px +} + +.bottom-left-cover-line { + left: -1px +} + +.bottom-left-cover-line, +.bottom-right-cover-line { + position: absolute; + height: 8px; + width: 50%; + background-color: #f5f5f7; + bottom: -4px +} + +.bottom-right-cover-line { + right: -1px +} + +.dingflow-design { + width: 100%; + background-color: #f5f5f7; + overflow: auto; + position: absolute; + bottom: 0; + left: 0; + right: 0; + top: 0 +} + +.dingflow-design .box-scale { + transform: scale(1); + display: inline-block; + position: relative; + width: 100%; + padding: 54.5px 0; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + min-width: -webkit-min-content; + min-width: -moz-min-content; + min-width: min-content; + background-color: #f5f5f7; + transform-origin: 50% 0px 0px; +} + +.dingflow-design .node-wrap { + flex-direction: column; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + padding: 0 50px; + position: relative +} + +.dingflow-design .branch-wrap, +.dingflow-design .node-wrap { + display: inline-flex; + width: 100% +} + +.dingflow-design .branch-box-wrap { + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-height: 270px; + width: 100%; + -ms-flex-negative: 0; + flex-shrink: 0 +} + +.dingflow-design .branch-box { + display: flex; + overflow: visible; + min-height: 180px; + height: auto; + border-bottom: 2px solid #ccc; + border-top: 2px solid #ccc; + position: relative; + margin-top: 15px +} + +.dingflow-design .branch-box .col-box { + background: #f5f5f7 +} + +.dingflow-design .branch-box .col-box:before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 0; + margin: auto; + width: 2px; + height: 100%; + background-color: #cacaca +} + +.dingflow-design .add-branch { + border: none; + outline: none; + user-select: none; + justify-content: center; + font-size: 12px; + padding: 0 10px; + height: 30px; + line-height: 30px; + border-radius: 15px; + color: #3296fa; + background: #fff; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1); + position: absolute; + top: -16px; + left: 50%; + transform: translateX(-50%); + transform-origin: center center; + cursor: pointer; + z-index: 1; + display: inline-flex; + align-items: center; + -webkit-transition: all .3s cubic-bezier(.645, .045, .355, 1); + transition: all .3s cubic-bezier(.645, .045, .355, 1) +} + +.dingflow-design .add-branch:hover { + transform: translateX(-50%) scale(1.1); + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, .1) +} + +.dingflow-design .add-branch:active { + transform: translateX(-50%); + box-shadow: none +} + +.dingflow-design .col-box { + display: inline-flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-align: center; + align-items: center; + position: relative +} + +.dingflow-design .condition-node { + min-height: 220px +} + +.dingflow-design .condition-node, +.dingflow-design .condition-node-box { + display: inline-flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-flex: 1 +} + +.dingflow-design .condition-node-box { + padding-top: 30px; + padding-right: 50px; + padding-left: 50px; + -webkit-box-pack: center; + justify-content: center; + -webkit-box-align: center; + align-items: center; + flex-grow: 1; + position: relative +} + +.dingflow-design .condition-node-box:before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 2px; + height: 100%; + background-color: #cacaca +} + +.dingflow-design .auto-judge { + position: relative; + width: 220px; + min-height: 72px; + background: #fff; + border-radius: 4px; + padding: 14px 19px; + cursor: pointer +} + +.dingflow-design .auto-judge:after { + pointer-events: none; + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 2; + border-radius: 4px; + border: 1px solid transparent; + transition: all .1s cubic-bezier(.645, .045, .355, 1); + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.dingflow-design .auto-judge.active:after, +.dingflow-design .auto-judge:active:after, +.dingflow-design .auto-judge:hover:after { + border: 1px solid #3296fa; + box-shadow: 0 0 6px 0 rgba(50, 150, 250, .3) +} + +.dingflow-design .auto-judge.active .close, +.dingflow-design .auto-judge:active .close, +.dingflow-design .auto-judge:hover .close { + display: block +} + +.dingflow-design .auto-judge.error:after { + border: 1px solid #f25643; + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.dingflow-design .auto-judge .title-wrapper { + position: relative; + font-size: 12px; + color: #15bc83; + text-align: left; + line-height: 16px +} + +.dingflow-design .auto-judge .title-wrapper .editable-title { + display: inline-block; + max-width: 120px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis +} + +.dingflow-design .auto-judge .title-wrapper .priority-title { + display: inline-block; + float: right; + margin-right: 10px; + color: rgba(25, 31, 37, .56) +} + +.dingflow-design .auto-judge .placeholder { + color: #bfbfbf +} + +.dingflow-design .auto-judge .close { + display: none; + position: absolute; + right: -10px; + top: -10px; + width: 20px; + height: 20px; + font-size: 14px; + color: rgba(0, 0, 0, .25); + border-radius: 50%; + text-align: center; + line-height: 20px; + z-index: 2 +} + +.dingflow-design .auto-judge .content { + font-size: 14px; + color: #191f25; + text-align: left; + margin-top: 6px; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical +} + +.dingflow-design .auto-judge .sort-left, +.dingflow-design .auto-judge .sort-right { + position: absolute; + top: 0; + bottom: 0; + display: none; + z-index: 1 +} + +.dingflow-design .auto-judge .sort-left { + left: 0; + border-right: 1px solid #f6f6f6 +} + +.dingflow-design .auto-judge .sort-right { + right: 0; + border-left: 1px solid #f6f6f6 +} + +.dingflow-design .auto-judge:hover .sort-left, +.dingflow-design .auto-judge:hover .sort-right { + display: flex; + align-items: center +} + +.dingflow-design .auto-judge .sort-left:hover, +.dingflow-design .auto-judge .sort-right:hover { + background: #efefef +} + +.dingflow-design .end-node { + border-radius: 50%; + font-size: 14px; + color: rgba(25, 31, 37, .4); + text-align: left +} + +.dingflow-design .end-node .end-node-circle { + width: 10px; + height: 10px; + margin: auto; + border-radius: 50%; + background: #dbdcdc +} + +.dingflow-design .end-node .end-node-text { + margin-top: 5px; + text-align: center +} + +.approval-setting { + border-radius: 2px; + margin: 20px 0; + position: relative; + background: #fff +} + +.ant-btn { + position: relative +} + + diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue index 3fe21944..6cbe11fa 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue @@ -436,7 +436,7 @@ const initBpmnModeler = () => { // bpmnModeler.createDiagram() - console.log(bpmnModeler, 'bpmnModeler111111') + // console.log(bpmnModeler, 'bpmnModeler111111') emit('init-finished', bpmnModeler) initModelListeners() } @@ -666,10 +666,10 @@ const previewProcessJson = () => { } /* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */ const processSave = async () => { - console.log(bpmnModeler, 'bpmnModelerbpmnModelerbpmnModelerbpmnModeler') + // console.log(bpmnModeler, 'bpmnModelerbpmnModelerbpmnModelerbpmnModeler') const { err, xml } = await bpmnModeler.saveXML() - console.log(err, 'errerrerrerrerr') - console.log(xml, 'xmlxmlxmlxmlxml') + // console.log(err, 'errerrerrerrerr') + // console.log(xml, 'xmlxmlxmlxmlxml') // 读取异常时抛出异常 if (err) { // this.$modal.msgError('保存模型失败,请重试!') diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue index a7958adb..485b9795 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessViewer.vue @@ -115,19 +115,19 @@ const highlightDiagram = async () => { if (!task) { return } - //进行中的任务已经高亮过了,则不高亮后面的任务了 + // 进行中的任务已经高亮过了,则不高亮后面的任务了 if (findProcessTask) { removeTaskDefinitionKeyList.push(n.id) return } // 高亮任务 - canvas.addMarker(n.id, getResultCss(task.result)) + canvas.addMarker(n.id, getResultCss(task.status)) //标记是否高亮了进行中任务 - if (task.result === 1) { + if (task.status === 1) { findProcessTask = true } // 如果非通过,就不走后面的线条了 - if (task.result !== 2) { + if (task.status !== 2) { return } // 处理 outgoing 出线 @@ -194,6 +194,7 @@ const highlightDiagram = async () => { }) } else if (n.$type === 'bpmn:StartEvent') { // 开始节点 + canvas.addMarker(n.id, 'highlight') n.outgoing?.forEach((nn) => { // outgoing 例如说【bpmn:SequenceFlow】连线 // 获得连线是否有指向目标。如果有,则进行高亮 @@ -205,10 +206,10 @@ const highlightDiagram = async () => { }) } else if (n.$type === 'bpmn:EndEvent') { // 结束节点 - if (!processInstance.value || processInstance.value.result === 1) { + if (!processInstance.value || processInstance.value.status === 1) { return } - canvas.addMarker(n.id, getResultCss(processInstance.value.result)) + canvas.addMarker(n.id, getResultCss(processInstance.value.status)) } else if (n.$type === 'bpmn:ServiceTask') { //服务任务 if (activity.startTime > 0 && activity.endTime === 0) { @@ -223,39 +224,49 @@ const highlightDiagram = async () => { canvas.addMarker(out.id, getResultCss(2)) }) } + } else if (n.$type === 'bpmn:SequenceFlow') { + let targetActivity = activityList.find((m: any) => m.key === n.targetRef.id) + if (targetActivity) { + canvas.addMarker(n.id, getActivityHighlightCss(targetActivity)) + } } }) if (!isEmpty(removeTaskDefinitionKeyList)) { taskList.value = taskList.value.filter( - (item) => !removeTaskDefinitionKeyList.includes(item.definitionKey) + (item) => !removeTaskDefinitionKeyList.includes(item.taskDefinitionKey) ) } } + const getActivityHighlightCss = (activity) => { return activity.endTime ? 'highlight' : 'highlight-todo' } -const getResultCss = (result) => { - if (result === 1) { + +const getResultCss = (status) => { + if (status === 1) { // 审批中 return 'highlight-todo' - } else if (result === 2) { + } else if (status === 2) { // 已通过 return 'highlight' - } else if (result === 3) { + } else if (status === 3) { // 不通过 return 'highlight-reject' - } else if (result === 4) { + } else if (status === 4) { // 已取消 return 'highlight-cancel' - } else if (result === 5) { + } else if (status === 5) { // 退回 return 'highlight-return' - } else if (result === 6) { + } else if (status === 6) { // 委派 - return 'highlight-return' - } else if (result === 7 || result === 8 || result === 9) { - // 待后加签任务完成/待前加签任务完成/待前置任务完成 - return 'highlight-return' + return 'highlight-todo' + } else if (status === 7) { + // 审批通过中 + return 'highlight-todo' + } else if (status === 0) { + // 待审批 + return 'highlight-todo' } return '' } @@ -296,10 +307,10 @@ const elementHover = (element) => { !elementOverlayIds.value && (elementOverlayIds.value = {}) !overlays.value && (overlays.value = bpmnModeler.get('overlays')) // 展示信息 - console.log(activityLists.value, 'activityLists.value') - console.log(element.value, 'element.value') + // console.log(activityLists.value, 'activityLists.value') + // console.log(element.value, 'element.value') const activity = activityLists.value.find((m) => m.key === element.value.id) - console.log(activity, 'activityactivityactivityactivity') + // console.log(activity, 'activityactivityactivityactivity') if (!activity) { return } @@ -313,15 +324,14 @@ const elementHover = (element) => {

部门:${processInstance.value.startUser.deptName}

创建时间:${formatDate(processInstance.value.createTime)}` } else if (element.value.type === 'bpmn:UserTask') { - // debugger let task = taskList.value.find((m) => m.id === activity.taskId) // 找到活动对应的 taskId if (!task) { return } - let optionData = getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT) + let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS) let dataResult = '' optionData.forEach((element) => { - if (element.value == task.result) { + if (element.value == task.status) { dataResult = element.label } }) @@ -333,7 +343,7 @@ const elementHover = (element) => { //

部门:${task.assigneeUser.deptName}

//

结果:${getIntDictOptions( // DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, - // task.result + // task.status // )}

//

创建时间:${formatDate(task.createTime)}

` if (task.endTime) { @@ -351,29 +361,30 @@ const elementHover = (element) => { } console.log(html) } else if (element.value.type === 'bpmn:EndEvent' && processInstance.value) { - let optionData = getIntDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT) + let optionData = getIntDictOptions(DICT_TYPE.BPM_TASK_STATUS) let dataResult = '' optionData.forEach((element) => { - if (element.value == processInstance.value.result) { + if (element.value == processInstance.value.status) { dataResult = element.label } }) html = `

结果:${dataResult}

` // html = `

结果:${getIntDictOptions( // DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, - // processInstance.value.result + // processInstance.value.status // )}

` if (processInstance.value.endTime) { html += `

结束时间:${formatDate(processInstance.value.endTime)}

` } } - console.log(html, 'html111111111111111') + // console.log(html, 'html111111111111111') elementOverlayIds.value[element.value.id] = toRaw(overlays.value)?.add(element.value, { position: { left: 0, bottom: 0 }, html: `
${html}
` }) } } + // 流程图的元素被 out const elementOut = (element) => { toRaw(overlays.value).remove({ element }) @@ -389,6 +400,7 @@ onMounted(() => { // 初始模型的监听器 initModelListeners() }) + onBeforeUnmount(() => { // this.$once('hook:beforeDestroy', () => { // }) @@ -427,7 +439,7 @@ watch( ) - diff --git a/src/layout/components/Menu/src/components/useRenderMenuItem.tsx b/src/layout/components/Menu/src/components/useRenderMenuItem.tsx index 17a520a6..301313fe 100644 --- a/src/layout/components/Menu/src/components/useRenderMenuItem.tsx +++ b/src/layout/components/Menu/src/components/useRenderMenuItem.tsx @@ -1,59 +1,50 @@ import { ElSubMenu, ElMenuItem } from 'element-plus' -import type { RouteMeta } from 'vue-router' import { hasOneShowingChild } from '../helper' import { isUrl } from '@/utils/is' import { useRenderMenuTitle } from './useRenderMenuTitle' -import { useDesign } from '@/hooks/web/useDesign' import { pathResolve } from '@/utils/routerHelper' -export const useRenderMenuItem = ( +const { renderMenuTitle } = useRenderMenuTitle() + +export const useRenderMenuItem = () => // allRouters: AppRouteRecordRaw[] = [], - menuMode: 'vertical' | 'horizontal' -) => { - const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => { - return routers.map((v) => { - const meta = (v.meta ?? {}) as RouteMeta - if (!meta.hidden) { - const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v) - const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath(allRouters, v.path).join('/') + { + const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => { + return routers + .filter((v) => !v.meta?.hidden) + .map((v) => { + const meta = v.meta ?? {} + const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v) + const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath(allRouters, v.path).join('/') - const { renderMenuTitle } = useRenderMenuTitle() + if ( + oneShowingChild && + (!onlyOneChild?.children || onlyOneChild?.noShowingChildren) && + !meta?.alwaysShow + ) { + return ( + + {{ + default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta) + }} + + ) + } else { + return ( + + {{ + title: () => renderMenuTitle(meta), + default: () => renderMenuItem(v.children!, fullPath) + }} + + ) + } + }) + } - if ( - oneShowingChild && - (!onlyOneChild?.children || onlyOneChild?.noShowingChildren) && - !meta?.alwaysShow - ) { - return ( - - {{ - default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta) - }} - - ) - } else { - const { getPrefixCls } = useDesign() - - const preFixCls = getPrefixCls('menu-popper') - return ( - - {{ - title: () => renderMenuTitle(meta), - default: () => renderMenuItem(v.children!, fullPath) - }} - - ) - } - } - }) + return { + renderMenuItem + } } - - return { - renderMenuItem - } -} diff --git a/src/layout/components/Menu/src/components/useRenderMenuTitle.tsx b/src/layout/components/Menu/src/components/useRenderMenuTitle.tsx index fc30b900..8941d9d7 100644 --- a/src/layout/components/Menu/src/components/useRenderMenuTitle.tsx +++ b/src/layout/components/Menu/src/components/useRenderMenuTitle.tsx @@ -1,5 +1,6 @@ import type { RouteMeta } from 'vue-router' import { Icon } from '@/components/Icon' +import { useI18n } from '@/hooks/web/useI18n' export const useRenderMenuTitle = () => { const renderMenuTitle = (meta: RouteMeta) => { @@ -9,10 +10,14 @@ export const useRenderMenuTitle = () => { return icon ? ( <> - {t(title as string)} + + {t(title as string)} + ) : ( - {t(title as string)} + + {t(title as string)} + ) } diff --git a/src/layout/components/TabMenu/src/TabMenu.vue b/src/layout/components/TabMenu/src/TabMenu.vue index c4f63a3f..055a6aff 100644 --- a/src/layout/components/TabMenu/src/TabMenu.vue +++ b/src/layout/components/TabMenu/src/TabMenu.vue @@ -139,7 +139,7 @@ export default defineComponent({ id={`${variables.namespace}-menu`} class={[ prefixCls, - 'relative bg-[var(--left-menu-bg-color)] top-1px z-3000 layout-border__right', + 'relative bg-[var(--left-menu-bg-color)] top-1px layout-border__right', { 'w-[var(--tab-menu-max-width)]': !unref(collapse), 'w-[var(--tab-menu-min-width)]': unref(collapse) diff --git a/src/layout/components/UserInfo/src/UserInfo.vue b/src/layout/components/UserInfo/src/UserInfo.vue index 22acfd13..5c5e3732 100644 --- a/src/layout/components/UserInfo/src/UserInfo.vue +++ b/src/layout/components/UserInfo/src/UserInfo.vue @@ -5,6 +5,9 @@ import avatarImg from '@/assets/imgs/avatar.gif' import { useDesign } from '@/hooks/web/useDesign' import { useTagsViewStore } from '@/store/modules/tagsView' import { useUserStore } from '@/store/modules/user' +import LockDialog from './components/LockDialog.vue' +import LockPage from './components/LockPage.vue' +import { useLockStore } from '@/store/modules/lock' defineOptions({ name: 'UserInfo' }) @@ -23,6 +26,14 @@ const prefixCls = getPrefixCls('user-info') const avatar = computed(() => userStore.user.avatar ?? avatarImg) const userName = computed(() => userStore.user.nickname ?? 'Admin') +// 锁定屏幕 +const lockStore = useLockStore() +const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false) +const dialogVisible = ref(false) +const lockScreen = () => { + dialogVisible.value = true +} + const loginOut = async () => { try { await ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), { @@ -33,8 +44,7 @@ const loginOut = async () => { await userStore.loginOut() tagsViewStore.delAllViews() replace('/login?redirect=/index') - } - catch { } + } catch {} } const toProfile = async () => { push('/user/profile') @@ -62,6 +72,10 @@ const toDocument = () => {
{{ t('common.document') }}
+ + +
{{ t('lock.lockScreen') }}
+
{{ t('common.loginOut') }}
@@ -69,4 +83,31 @@ const toDocument = () => { + + + + + + + + + + diff --git a/src/layout/components/UserInfo/src/components/LockDialog.vue b/src/layout/components/UserInfo/src/components/LockDialog.vue new file mode 100644 index 00000000..f4ab7d4f --- /dev/null +++ b/src/layout/components/UserInfo/src/components/LockDialog.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/layout/components/UserInfo/src/components/LockPage.vue b/src/layout/components/UserInfo/src/components/LockPage.vue new file mode 100644 index 00000000..497dd37b --- /dev/null +++ b/src/layout/components/UserInfo/src/components/LockPage.vue @@ -0,0 +1,270 @@ + + + + + diff --git a/src/locales/en.ts b/src/locales/en.ts index 4f4d4895..6562c9b7 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -56,6 +56,16 @@ export default { copySuccess: 'Copy Success', copyError: 'Copy Error' }, + lock: { + lockScreen: 'Lock screen', + lock: 'Lock', + lockPassword: 'Lock screen password', + unlock: 'Click to unlock', + backToLogin: 'Back to login', + entrySystem: 'Entry the system', + placeholder: 'Please enter the lock screen password', + message: 'Lock screen password error' + }, error: { noPermission: `Sorry, you don't have permission to access this page.`, pageError: 'Sorry, the page you visited does not exist.', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 6346a3d3..0721651d 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -56,6 +56,16 @@ export default { copySuccess: '复制成功', copyError: '复制失败' }, + lock: { + lockScreen: '锁定屏幕', + lock: '锁定', + lockPassword: '锁屏密码', + unlock: '点击解锁', + backToLogin: '返回登录', + entrySystem: '进入系统', + placeholder: '请输入锁屏密码', + message: '锁屏密码错误' + }, error: { noPermission: `抱歉,您无权访问此页面。`, pageError: '抱歉,您访问的页面不存在。', diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index f63bee6e..bc62a3c4 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -243,7 +243,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ }, children: [ { - path: '/manager/form/edit', + path: 'manager/form/edit', component: () => import('@/views/bpm/form/editor/index.vue'), name: 'BpmFormEditor', meta: { @@ -255,7 +255,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: '/manager/model/edit', + path: 'manager/model/edit', component: () => import('@/views/bpm/model/editor/index.vue'), name: 'BpmModelEditor', meta: { @@ -267,7 +267,19 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: '/manager/definition', + path: 'manager/simple/workflow/model/edit', + component: () => import('@/views/bpm/simpleWorkflow/index.vue'), + name: 'SimpleWorkflowDesignEditor', + meta: { + noCache: true, + hidden: true, + canTo: true, + title: '仿钉钉设计流程', + activeMenu: '/bpm/manager/model' + } + }, + { + path: 'manager/definition', component: () => import('@/views/bpm/definition/index.vue'), name: 'BpmProcessDefinition', meta: { @@ -279,30 +291,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: '/manager/task-assign-rule', - component: () => import('@/views/bpm/taskAssignRule/index.vue'), - name: 'BpmTaskAssignRuleList', - meta: { - noCache: true, - hidden: true, - canTo: true, - title: '任务分配规则' - } - }, - { - path: '/process-instance/create', - component: () => import('@/views/bpm/processInstance/create/index.vue'), - name: 'BpmProcessInstanceCreate', - meta: { - noCache: true, - hidden: true, - canTo: true, - title: '发起流程', - activeMenu: 'bpm/processInstance/create' - } - }, - { - path: '/process-instance/detail', + path: 'process-instance/detail', component: () => import('@/views/bpm/processInstance/detail/index.vue'), name: 'BpmProcessInstanceDetail', meta: { @@ -310,11 +299,11 @@ const remainingRouter: AppRouteRecordRaw[] = [ hidden: true, canTo: true, title: '流程详情', - activeMenu: 'bpm/processInstance/detail' + activeMenu: '/bpm/task/my' } }, { - path: '/bpm/oa/leave/create', + path: 'oa/leave/create', component: () => import('@/views/bpm/oa/leave/create.vue'), name: 'OALeaveCreate', meta: { @@ -326,7 +315,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: '/bpm/oa/leave/detail', + path: 'oa/leave/detail', component: () => import('@/views/bpm/oa/leave/detail.vue'), name: 'OALeaveDetail', meta: { diff --git a/src/store/index.ts b/src/store/index.ts index 65964ea8..63f00452 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,7 +1,9 @@ import type { App } from 'vue' import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const store = createPinia() +store.use(piniaPluginPersistedstate) export const setupStore = (app: App) => { app.use(store) diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 1d0c797a..87336181 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -268,7 +268,8 @@ export const useAppStore = defineStore('app', { setFooter(footer: boolean) { this.footer = footer } - } + }, + persist: false }) export const useAppStoreWithOut = () => { diff --git a/src/store/modules/lock.ts b/src/store/modules/lock.ts new file mode 100644 index 00000000..68ae1d7d --- /dev/null +++ b/src/store/modules/lock.ts @@ -0,0 +1,48 @@ +import { defineStore } from 'pinia' +import { store } from '@/store' + +interface lockInfo { + isLock?: boolean + password?: string +} + +interface LockState { + lockInfo: lockInfo +} + +export const useLockStore = defineStore('lock', { + state: (): LockState => { + return { + lockInfo: { + // isLock: false, // 是否锁定屏幕 + // password: '' // 锁屏密码 + } + } + }, + getters: { + getLockInfo(): lockInfo { + return this.lockInfo + } + }, + actions: { + setLockInfo(lockInfo: lockInfo) { + this.lockInfo = lockInfo + }, + resetLockInfo() { + this.lockInfo = {} + }, + unLock(password: string) { + if (this.lockInfo?.password === password) { + this.resetLockInfo() + return true + } else { + return false + } + } + }, + persist: true +}) + +export const useLockStoreWithOut = () => { + return useLockStore(store) +} diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index c729cea0..5e3287a7 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia' -import { store } from '../index' +import { store } from '@/store' import { cloneDeep } from 'lodash-es' import remainingRouter from '@/router/modules/remaining' import { flatMultiLevelRoutes, generateRoute } from '@/utils/routerHelper' @@ -59,7 +59,8 @@ export const usePermissionStore = defineStore('permission', { setMenuTabRouters(routers: AppRouteRecordRaw[]): void { this.menuTabRouters = routers } - } + }, + persist: false }) export const usePermissionStoreWithOut = () => { diff --git a/src/store/modules/simpleWorkflow.ts b/src/store/modules/simpleWorkflow.ts new file mode 100644 index 00000000..cf98538d --- /dev/null +++ b/src/store/modules/simpleWorkflow.ts @@ -0,0 +1,55 @@ +import { store } from '../index' +import { defineStore } from 'pinia' + +export const useWorkFlowStore = defineStore('simpleWorkflow', { + state: () => ({ + tableId: '', + isTried: false, + promoterDrawer: false, + flowPermission1: {}, + approverDrawer: false, + approverConfig1: {}, + copyerDrawer: false, + copyerConfig1: {}, + conditionDrawer: false, + conditionsConfig1: { + conditionNodes: [] + } + }), + actions: { + setTableId(payload) { + this.tableId = payload + }, + setIsTried(payload) { + this.isTried = payload + }, + setPromoter(payload) { + this.promoterDrawer = payload + }, + setFlowPermission(payload) { + this.flowPermission1 = payload + }, + setApprover(payload) { + this.approverDrawer = payload + }, + setApproverConfig(payload) { + this.approverConfig1 = payload + }, + setCopyer(payload) { + this.copyerDrawer = payload + }, + setCopyerConfig(payload) { + this.copyerConfig1 = payload + }, + setCondition(payload) { + this.conditionDrawer = payload + }, + setConditionsConfig(payload) { + this.conditionsConfig1 = payload + } + } +}) + +export const useWorkFlowStoreWithOut = () => { + return useWorkFlowStore(store) +} diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index a60d0e45..25a3a1fd 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -132,7 +132,8 @@ export const useTagsViewStore = defineStore('tagsView', { } } } - } + }, + persist: false }) export const useTagsViewStoreWithOut = () => { diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index cb71a1a4..b3861809 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,7 +1,7 @@ -import { store } from '../index' +import { store } from '@/store' import { defineStore } from 'pinia' import { getAccessToken, removeToken } from '@/utils/auth' -import { CACHE_KEY, useCache } from '@/hooks/web/useCache' +import { CACHE_KEY, useCache, deleteUserCache } from '@/hooks/web/useCache' import { getInfo, loginOut } from '@/api/login' const { wsCache } = useCache() @@ -14,6 +14,7 @@ interface UserVO { } interface UserInfoVO { + // USER 缓存 permissions: string[] roles: string[] isSetUser: boolean @@ -80,7 +81,7 @@ export const useUserStore = defineStore('admin-user', { async loginOut() { await loginOut() removeToken() - wsCache.clear() + deleteUserCache() // 删除用户缓存 this.resetState() }, resetState() { diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 7da49b08..c68a67a9 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,4 +1,4 @@ -import { useCache } from '@/hooks/web/useCache' +import { useCache, CACHE_KEY } from '@/hooks/web/useCache' import { TokenType } from '@/api/login/types' import { decrypt, encrypt } from '@/utils/jsencrypt' @@ -36,8 +36,6 @@ export const formatToken = (token: string): string => { } // ========== 账号相关 ========== -const LoginFormKey = 'LOGINFORM' - export type LoginFormType = { tenantName: string username: string @@ -46,7 +44,7 @@ export type LoginFormType = { } export const getLoginForm = () => { - const loginForm: LoginFormType = wsCache.get(LoginFormKey) + const loginForm: LoginFormType = wsCache.get(CACHE_KEY.LoginForm) if (loginForm) { loginForm.password = decrypt(loginForm.password) as string } @@ -55,38 +53,19 @@ export const getLoginForm = () => { export const setLoginForm = (loginForm: LoginFormType) => { loginForm.password = encrypt(loginForm.password) as string - wsCache.set(LoginFormKey, loginForm, { exp: 30 * 24 * 60 * 60 }) + wsCache.set(CACHE_KEY.LoginForm, loginForm, { exp: 30 * 24 * 60 * 60 }) } export const removeLoginForm = () => { - wsCache.delete(LoginFormKey) + wsCache.delete(CACHE_KEY.LoginForm) } // ========== 租户相关 ========== -const TenantIdKey = 'TENANT_ID' -const TenantNameKey = 'TENANT_NAME' - -export const getTenantName = () => { - return wsCache.get(TenantNameKey) -} - -export const setTenantName = (username: string) => { - wsCache.set(TenantNameKey, username, { exp: 30 * 24 * 60 * 60 }) -} - -export const removeTenantName = () => { - wsCache.delete(TenantNameKey) -} - export const getTenantId = () => { - return wsCache.get(TenantIdKey) + return wsCache.get(CACHE_KEY.TenantId) } export const setTenantId = (username: string) => { - wsCache.set(TenantIdKey, username) -} - -export const removeTenantId = () => { - wsCache.delete(TenantIdKey) + wsCache.set(CACHE_KEY.TenantId, username) } diff --git a/src/utils/dateUtil.ts b/src/utils/dateUtil.ts new file mode 100644 index 00000000..316b870b --- /dev/null +++ b/src/utils/dateUtil.ts @@ -0,0 +1,18 @@ +/** + * Independent time operation tool to facilitate subsequent switch to dayjs + */ +// TODO 芋艿:【锁屏】可能后面删除掉 +import dayjs from 'dayjs' + +const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' +const DATE_FORMAT = 'YYYY-MM-DD' + +export function formatToDateTime(date?: dayjs.ConfigType, format = DATE_TIME_FORMAT): string { + return dayjs(date).format(format) +} + +export function formatToDate(date?: dayjs.ConfigType, format = DATE_FORMAT): string { + return dayjs(date).format(format) +} + +export const dateUtil = dayjs diff --git a/src/utils/dict.ts b/src/utils/dict.ts index cc1774b3..2284ff13 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -136,13 +136,13 @@ export enum DICT_TYPE { INFRA_FILE_STORAGE = 'infra_file_storage', // ========== BPM 模块 ========== - BPM_MODEL_CATEGORY = 'bpm_model_category', BPM_MODEL_FORM_TYPE = 'bpm_model_form_type', - BPM_TASK_ASSIGN_RULE_TYPE = 'bpm_task_assign_rule_type', + BPM_TASK_CANDIDATE_STRATEGY = 'bpm_task_candidate_strategy', BPM_PROCESS_INSTANCE_STATUS = 'bpm_process_instance_status', - BPM_PROCESS_INSTANCE_RESULT = 'bpm_process_instance_result', - BPM_TASK_ASSIGN_SCRIPT = 'bpm_task_assign_script', + BPM_TASK_STATUS = 'bpm_task_status', BPM_OA_LEAVE_TYPE = 'bpm_oa_leave_type', + BPM_PROCESS_LISTENER_TYPE = 'bpm_process_listener_type', + BPM_PROCESS_LISTENER_VALUE_TYPE = 'bpm_process_listener_value_type', // ========== PAY 模块 ========== PAY_CHANNEL_CODE = 'pay_channel_code', // 支付渠道编码类型 @@ -157,7 +157,7 @@ export enum DICT_TYPE { MP_AUTO_REPLY_REQUEST_MATCH = 'mp_auto_reply_request_match', // 自动回复请求匹配类型 MP_MESSAGE_TYPE = 'mp_message_type', // 消息类型 - // ========== MALL - 会员模块 ========== + // ========== Member 会员模块 ========== MEMBER_POINT_BIZ_TYPE = 'member_point_biz_type', // 积分的业务类型 MEMBER_EXPERIENCE_BIZ_TYPE = 'member_experience_biz_type', // 会员经验业务类型 diff --git a/src/utils/formCreate.ts b/src/utils/formCreate.ts index 6d7dbc7f..b9644d6f 100644 --- a/src/utils/formCreate.ts +++ b/src/utils/formCreate.ts @@ -28,7 +28,7 @@ export const decodeFields = (fields: string[]) => { return rule } -// 设置表单的 Conf 和 Fields +// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 export const setConfAndFields = (designerRef: object, conf: string, fields: string) => { // @ts-ignore designerRef.value.setOption(JSON.parse(conf)) @@ -36,19 +36,22 @@ export const setConfAndFields = (designerRef: object, conf: string, fields: stri designerRef.value.setRule(decodeFields(fields)) } -// 设置表单的 Conf 和 Fields +// 设置表单的 Conf 和 Fields,适用 form-create 场景 export const setConfAndFields2 = ( detailPreview: object, conf: string, fields: string, value?: object ) => { + if (isRef(detailPreview)) { + detailPreview = detailPreview.value + } // @ts-ignore - detailPreview.value.option = JSON.parse(conf) + detailPreview.option = JSON.parse(conf) // @ts-ignore - detailPreview.value.rule = decodeFields(fields) + detailPreview.rule = decodeFields(fields) if (value) { // @ts-ignore - detailPreview.value.value = value + detailPreview.value = value } } diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts index ed434cb0..134a986e 100644 --- a/src/utils/formatTime.ts +++ b/src/utils/formatTime.ts @@ -175,18 +175,18 @@ export function formatPast2(ms: number): string { const minute = Math.floor(ms / (60 * 1000) - day * 24 * 60 - hour * 60) const second = Math.floor(ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60) if (day > 0) { - return day + '天' + hour + '小时' + minute + '分钟' + return day + ' 天' + hour + ' 小时 ' + minute + ' 分钟' } if (hour > 0) { - return hour + '小时' + minute + '分钟' + return hour + ' 小时 ' + minute + ' 分钟' } if (minute > 0) { - return minute + '分钟' + return minute + ' 分钟' } if (second > 0) { - return second + '秒' + return second + ' 秒' } else { - return 0 + '秒' + return 0 + ' 秒' } } diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index e8e618dd..e61ccbe9 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -188,7 +188,7 @@ const loginData = reactive({ username: 'admin', password: 'admin123', captchaVerification: '', - rememberMe: false + rememberMe: true // 默认记录我。如果不需要,可手动修改 } }) @@ -218,14 +218,14 @@ const getTenantId = async () => { } } // 记住我 -const getCookie = () => { +const getLoginFormCache = () => { const loginForm = authUtil.getLoginForm() if (loginForm) { loginData.loginForm = { ...loginData.loginForm, username: loginForm.username ? loginForm.username : loginData.loginForm.username, password: loginForm.password ? loginForm.password : loginData.loginForm.password, - rememberMe: loginForm.rememberMe ? true : false, + rememberMe: loginForm.rememberMe, tenantName: loginForm.tenantName ? loginForm.tenantName : loginData.loginForm.tenantName } } @@ -326,7 +326,7 @@ watch( } ) onMounted(() => { - getCookie() + getLoginFormCache() getTenantByWebsite() }) diff --git a/src/views/bpm/category/CategoryForm.vue b/src/views/bpm/category/CategoryForm.vue new file mode 100644 index 00000000..5b771537 --- /dev/null +++ b/src/views/bpm/category/CategoryForm.vue @@ -0,0 +1,124 @@ + + diff --git a/src/views/bpm/category/index.vue b/src/views/bpm/category/index.vue new file mode 100644 index 00000000..46fa6cf1 --- /dev/null +++ b/src/views/bpm/category/index.vue @@ -0,0 +1,200 @@ + + + diff --git a/src/views/bpm/definition/index.vue b/src/views/bpm/definition/index.vue index 31ed8413..1e7794b3 100644 --- a/src/views/bpm/definition/index.vue +++ b/src/views/bpm/definition/index.vue @@ -11,11 +11,7 @@ - - - + \ No newline at end of file diff --git a/src/views/bpm/task/cc/index.vue b/src/views/bpm/task/copy/index.vue similarity index 74% rename from src/views/bpm/task/cc/index.vue rename to src/views/bpm/task/copy/index.vue index 50ddf889..adc1fe32 100644 --- a/src/views/bpm/task/cc/index.vue +++ b/src/views/bpm/task/copy/index.vue @@ -1,5 +1,10 @@