From cd69659c93ab8cf58f331afe9a1357b0882176a0 Mon Sep 17 00:00:00 2001 From: GoldenZqqq <1361001127@qq.com> Date: Tue, 5 Nov 2024 17:22:12 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E5=8F=91=E8=B5=B7=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E9=A1=B5=E9=9D=A2-=E5=A2=9E=E5=8A=A0=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=A1=86=E3=80=81=E5=89=8D=E7=AB=AF=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=8C=E6=88=90=EF=BC=9B=E5=8F=B3=E4=BE=A7?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=89=80=E6=9C=89=E6=B5=81=E7=A8=8B=EF=BC=8C?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=BB=9A=E5=8A=A8=E6=88=96=E8=80=85=E7=82=B9?= =?UTF-8?q?=E5=87=BB=EF=BC=8C=E5=8F=AF=E4=BB=A5=E5=88=87=E6=8D=A2=E5=88=86?= =?UTF-8?q?=E7=B1=BB=EF=BC=9B=E9=BC=A0=E6=A0=87hover=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/processInstance/create/index.vue | 283 ++++++++++++++---- 1 file changed, 227 insertions(+), 56 deletions(-) diff --git a/src/views/bpm/processInstance/create/index.vue b/src/views/bpm/processInstance/create/index.vue index 9e6fcb48..4909f3f7 100644 --- a/src/views/bpm/processInstance/create/index.vue +++ b/src/views/bpm/processInstance/create/index.vue @@ -1,46 +1,74 @@ -
+
{{ activity.name }}
@@ -36,53 +36,53 @@ {{ getApprovalNodeTime(activity) }}
-
+
-
-
+
+
+
- + + +
- - - -
- -
+
+
+
+ + + + + + + + + + + + diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue index 35044965..442cfffc 100644 --- a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue +++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue @@ -20,7 +20,7 @@ :option="detailForm.option" @submit="submitForm" > - From 8b5740d05c908f8e23925c07570f2a73d99fd54a Mon Sep 17 00:00:00 2001 From: GoldenZqqq <1361001127@qq.com> Date: Thu, 7 Nov 2024 13:21:04 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E9=A1=B5=E9=9D=A2-=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E9=80=89=E6=8B=A9=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E8=8A=82=E7=82=B9=E6=94=B9=E4=B8=BA=E5=9C=A8?= =?UTF-8?q?=E5=8F=B3=E4=BE=A7timeline=E7=BB=84=E4=BB=B6=E4=B8=AD=E8=B7=B3?= =?UTF-8?q?=E5=87=BA=E5=BC=B9=E7=AA=97=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/UserSelectForm/index.vue | 24 ++++-- .../create/ProcessDefinitionDetail.vue | 82 +++++------------- src/views/bpm/processInstance/create/mock.ts | 86 ------------------- .../detail/ProcessInstanceTimeline.vue | 39 +++++++-- 4 files changed, 69 insertions(+), 162 deletions(-) delete mode 100644 src/views/bpm/processInstance/create/mock.ts diff --git a/src/components/UserSelectForm/index.vue b/src/components/UserSelectForm/index.vue index 2dc94587..d4cf6f2b 100644 --- a/src/components/UserSelectForm/index.vue +++ b/src/components/UserSelectForm/index.vue @@ -15,7 +15,7 @@ @@ -36,21 +41,24 @@ import * as UserApi from '@/api/system/user' defineOptions({ name: 'UserSelectForm' }) const emit = defineEmits<{ - confirm: [userList: any[]] + confirm: [id: any, userList: any[]] }>() const { t } = useI18n() // 国际 const deptList = ref([]) // 部门树形结构化 const userList: any = ref([]) // 用户列表 const message = useMessage() // 消息弹窗 -const selectedUserList: any = ref([]) // 选中的用户列表 +const selectedUserIdList: any = ref([]) // 选中的用户列表 const dialogVisible = ref(false) // 弹窗的是否展示 const formLoading = ref(false) // 表单的加载中 +const activityId = ref() // 主键id /** 打开弹窗 */ -const open = async () => { +const open = async (id, selectedList?) => { + activityId.value = id resetForm() deptList.value = handleTree(await DeptApi.getSimpleDeptList()) await getUserList() + selectedUserIdList.value = selectedList?.map((item) => item.id) // 修改时,设置数据 dialogVisible.value = true } @@ -71,8 +79,9 @@ const submitForm = async () => { try { message.success(t('common.updateSuccess')) dialogVisible.value = false + const emitUserList = userList.value.filter((user) => selectedUserIdList.value.includes(user.id)) // 发送操作成功的事件 - emit('confirm', selectedUserList.value) + emit('confirm', activityId.value, emitUserList) } finally { formLoading.value = false } @@ -80,13 +89,12 @@ const submitForm = async () => { const resetForm = () => { deptList.value = [] userList.value = [] - selectedUserList.value = [] + selectedUserIdList.value = [] } /** 处理部门被点击 */ const handleNodeClick = async (row: { [key: string]: any }) => { getUserList(row.id) } - defineExpose({ open }) // 提供 open 方法,用于打开弹窗 diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue index 442cfffc..18a3ba72 100644 --- a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue +++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue @@ -19,40 +19,7 @@ v-model="detailForm.value" :option="detailForm.option" @submit="submitForm" - > - - + /> @@ -62,6 +29,8 @@ :activity-nodes="activityNodes" :show-status-icon="false" :startUserSelectTasks="startUserSelectTasks" + :startUserSelectAssignees="startUserSelectAssignees" + @select-user-confirm="selectUserConfirm" /> @@ -104,8 +73,7 @@ import type { ApiAttrs } from '@form-create/element-ui/types/config' import { useTagsViewStore } from '@/store/modules/tagsView' import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as DefinitionApi from '@/api/bpm/definition' -// import * as UserApi from '@/api/system/user' -import { activityNodes as aN, startUserSelectTasks as sUs } from './mock' +// import { activityNodes as aN, startUserSelectTasks as sUs } from './mock' defineOptions({ name: 'ProcessDefinitionDetail' }) const props = defineProps<{ @@ -122,11 +90,8 @@ const detailForm: any = ref({ }) // 流程表单详情 const fApi = ref() // 指定审批人 -const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表单 Ref const startUserSelectTasks: any = ref([]) // 发起人需要选择审批人的用户任务列表 const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据 -const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules -// const userList = ref([]) // 用户列表 const bpmnXML: any = ref(null) // BPMN 数据 /** 当前的Tab */ const activeTab = ref('form') @@ -139,7 +104,6 @@ const initProcessInfo = async (row: any, formVariables?: any) => { // 重置指定审批人 startUserSelectTasks.value = [] startUserSelectAssignees.value = {} - startUserSelectAssigneesFormRules.value = {} // 情况一:流程表单 if (row.formType == 10) { @@ -164,25 +128,13 @@ const initProcessInfo = async (row: any, formVariables?: any) => { if (processDefinitionDetail) { bpmnXML.value = processDefinitionDetail.bpmnXml startUserSelectTasks.value = processDefinitionDetail.startUserSelectTasks - startUserSelectTasks.value = sUs // 设置指定审批人 - // if (startUserSelectTasks.value?.length > 0) { - // detailForm.value.rule.push({ - // type: 'startUserSelect', - // props: { - // title: '指定审批人' - // } - // }) - // // 设置校验规则 - // for (const userTask of startUserSelectTasks.value) { - // startUserSelectAssignees.value[userTask.id] = [] - // startUserSelectAssigneesFormRules.value[userTask.id] = [ - // { required: true, message: '请选择审批人', trigger: 'blur' } - // ] - // } - // // 加载用户列表 - // userList.value = await UserApi.getSimpleUserList() - // } + if (startUserSelectTasks.value?.length > 0) { + for (const userTask of startUserSelectTasks.value) { + // 初始化数据 + startUserSelectAssignees.value[userTask.id] = [] + } + } } // 情况二:业务表单 } else if (row.formCustomCreatePath) { @@ -206,19 +158,23 @@ const getApprovalDetail = async (row: any) => { } // 获取审批节点,显示 Timeline 的数据 activityNodes.value = data.activityNodes - activityNodes.value = aN } finally { } } /** 提交按钮 */ const submitForm = async (formData: any) => { - debugger if (!fApi.value || !props.selectProcessDefinition) { return } // 如果有指定审批人,需要校验 if (startUserSelectTasks.value?.length > 0) { - await startUserSelectAssigneesFormRef.value.validate() + for (const userTask of startUserSelectTasks.value) { + if ( + Array.isArray(startUserSelectAssignees.value[userTask.id]) && + startUserSelectAssignees.value[userTask.id].length === 0 + ) + return message.warning(`请选择${userTask.name}的审批人`) + } } // 提交请求 @@ -245,6 +201,10 @@ const handleCancel = () => { emit('cancel') } +const selectUserConfirm = (id, userList) => { + startUserSelectAssignees.value[id] = userList?.map((item) => item.id) +} + defineExpose({ initProcessInfo }) diff --git a/src/views/bpm/processInstance/create/mock.ts b/src/views/bpm/processInstance/create/mock.ts deleted file mode 100644 index 2cb1394c..00000000 --- a/src/views/bpm/processInstance/create/mock.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { ProcessInstanceVO, User, ApprovalTaskInfo, ApprovalNodeInfo } from '@/api/bpm/processInstance'; -import { NodeType } from '@/components/SimpleProcessDesignerV2/src/consts' - -const users: User[] = [ - { id: 1, nickname: 'Alice', avatar: 'https://picsum.photos/200?r=1' }, - { id: 2, nickname: 'Bob', avatar: 'https://picsum.photos/200?r=2' }, - { id: 3, nickname: 'Charlie', avatar: 'https://picsum.photos/200?r=3' }, - { id: 4, nickname: 'David', avatar: 'https://picsum.photos/200?r=4' } -]; - -const approvalTask1: ApprovalTaskInfo = { - id: 1, - ownerUser: users[0], // Alice is the owner (initiator) - assigneeUser: users[1], // Bob is the assignee - status: 1, // In Progress - reason: 'Please review and approve the request.' -}; - -const approvalTask2: ApprovalTaskInfo = { - id: 2, - ownerUser: users[1], // Bob is the owner (approver) - assigneeUser: users[2], // Charlie is the assignee - status: 0, // Pending approval - reason: 'Awaiting Bob’s decision.' -}; - -const approvalTask3: ApprovalTaskInfo = { - id: 3, - ownerUser: users[2], // Charlie is the owner (approver) - assigneeUser: users[3], // David is the assignee - status: 0, // Pending approval - reason: 'Awaiting Charlie’s decision.' -}; - -const approvalNode1: ApprovalNodeInfo = { - id: 101, - name: 'Start Review', - nodeType: NodeType.START_USER_NODE, - status: 1, // In Progress - startTime: new Date('2024-11-01T10:00:00Z'), - tasks: [approvalTask1] -}; - -const approvalNode2: ApprovalNodeInfo = { - id: 102, - name: 'First Review', - nodeType: NodeType.USER_TASK_NODE, - status: 0, // Pending approval - startTime: new Date('2024-11-01T11:00:00Z'), - tasks: [approvalTask2], - candidateUsers: [users[2], users[3]] // Candidate users: Charlie and David -}; - -const approvalNode3: ApprovalNodeInfo = { - id: 103, - name: 'Second Review', - nodeType: NodeType.USER_TASK_NODE, - status: 0, // Pending approval - startTime: new Date('2024-11-01T12:00:00Z'), - tasks: [approvalTask3], - candidateUsers: [users[1], users[3]] // Candidate users: Bob and David -}; - -const processInstance: ProcessInstanceVO = { - id: 1001, - name: 'Request Approval Process', - processDefinitionId: 'proc-2024-001', - category: 'Approval Process', - result: 0, // Ongoing - tasks: [{ id: '1', name: 'Start Review' }, { id: '2', name: 'First Review' }, { id: '3', name: 'Second Review' }], - fields: ['field1', 'field2'], - status: 1, // In Progress - remark: 'This is a sample approval process.', - businessKey: 'BUS-12345', - createTime: '2024-11-01T09:00:00Z', - endTime: '', - processDefinition: undefined // Not populated in this example -}; - -// 模拟的 activityNodes 数据,传递给 ProcessInstanceTimeline 组件 -const activityNodes: ApprovalNodeInfo[] = [approvalNode1, approvalNode2, approvalNode3]; - -export { processInstance, activityNodes, users }; - - -export const startUserSelectTasks = users.map(user => ({id: user.id,name:user.nickname})) diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue index 1d3e7a1c..10993735 100644 --- a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue +++ b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue @@ -38,11 +38,29 @@
- + + +
+ + + {{ user.nickname.substring(0, 1) }} + + {{ user.nickname }} +
@@ -152,10 +170,12 @@ withDefaults( activityNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息 showStatusIcon?: boolean // 是否显示头像右下角状态图标 startUserSelectTasks?: any[] // 发起人需要选择审批人的用户任务列表 + startUserSelectAssignees?: any // 发起人选择审批人的数据 }>(), { showStatusIcon: true, // 默认值为 true - startUserSelectTasks: () => [] // 默认值为空数组 + startUserSelectTasks: () => [], // 默认值为空数组 + startUserSelectAssignees: () => {} } ) @@ -256,11 +276,16 @@ const getApprovalNodeTime = (node: ProcessInstanceApi.ApprovalNodeInfo) => { // 选择自定义审批人 const userSelectFormRef = ref() -const handleSelectUser = () => { - userSelectFormRef.value.open() +const handleSelectUser = (activityId, selectedList) => { + userSelectFormRef.value.open(activityId, selectedList) } +const emit = defineEmits<{ + selectUserConfirm: [id: any, userList: any[]] +}>() +const customApprover: any = ref({}) // 选择完成 -const handleUserSelectConfirm = (userList) => { - console.log('[ userList ] >', userList) +const handleUserSelectConfirm = (activityId, userList) => { + customApprover.value[activityId] = userList || [] + emit('selectUserConfirm', activityId, userList) } From 8df599194036a02925b3ede3eeecf105b140d0ec Mon Sep 17 00:00:00 2001 From: GoldenZqqq <1361001127@qq.com> Date: Thu, 7 Nov 2024 13:49:18 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=E6=B5=81=E7=A8=8B=E5=8F=91=E8=B5=B7?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2-=E4=BF=AE=E5=A4=8D=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E6=97=B6=E8=A1=A8=E5=8D=95=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9C=AA=E5=9B=9E=E6=98=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/processInstance/create/ProcessDefinitionDetail.vue | 4 ++-- src/views/bpm/processInstance/index.vue | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue index 18a3ba72..6bdad332 100644 --- a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue +++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue @@ -162,7 +162,7 @@ const getApprovalDetail = async (row: any) => { } } /** 提交按钮 */ -const submitForm = async (formData: any) => { +const submitForm = async () => { if (!fApi.value || !props.selectProcessDefinition) { return } @@ -182,7 +182,7 @@ const submitForm = async (formData: any) => { try { await ProcessInstanceApi.createProcessInstance({ processDefinitionId: props.selectProcessDefinition.id, - variables: formData || detailForm.value.value, + variables: detailForm.value.value, startUserSelectAssignees: startUserSelectAssignees.value }) // 提示 diff --git a/src/views/bpm/processInstance/index.vue b/src/views/bpm/processInstance/index.vue index 4b72e395..f3b7439b 100644 --- a/src/views/bpm/processInstance/index.vue +++ b/src/views/bpm/processInstance/index.vue @@ -222,7 +222,6 @@ const handleCreate = async (row?: ProcessInstanceVO) => { const processDefinitionDetail = await DefinitionApi.getProcessDefinition( row.processDefinitionId ) - debugger if (processDefinitionDetail.formType === 20) { message.error('重新发起流程失败,原因:该流程使用业务表单,不支持重新发起') return From 6dd6f9c2a5e5a02579e3cde7f71a6ec0f3a5da36 Mon Sep 17 00:00:00 2001 From: GoldenZqqq <1361001127@qq.com> Date: Thu, 7 Nov 2024 13:57:57 +0800 Subject: [PATCH 6/6] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=E6=A8=A1?= =?UTF-8?q?=E6=8B=9F=E5=81=87=E6=95=B0=E6=8D=AE=E5=BC=95=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue index 6bdad332..4ab280b5 100644 --- a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue +++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue @@ -73,7 +73,6 @@ import type { ApiAttrs } from '@form-create/element-ui/types/config' import { useTagsViewStore } from '@/store/modules/tagsView' import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as DefinitionApi from '@/api/bpm/definition' -// import { activityNodes as aN, startUserSelectTasks as sUs } from './mock' defineOptions({ name: 'ProcessDefinitionDetail' }) const props = defineProps<{