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 @@
-
-
-
-
-
- {{ category.name }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ category.name }}
+
-
-
-
- {{ categoryActive.name }}
-
-
-
-
-
-
{{ definition.name }}
+
+
+
+
+
{{ title }}
+
+
+
+
+
+
+ {{ definition.name }}
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
{
loading.value = true
try {
- // 流程分类
- categoryList.value = await CategoryApi.getCategorySimpleList()
- if (categoryList.value.length > 0) {
- categoryActive.value = categoryList.value[0]
- }
- // 流程定义
- processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({
- suspensionState: 1
- })
+ // 所有流程分类数据
+ await getCategoryList()
+ // 所有流程定义数据
+ await getDefinitionList()
// 如果 processInstanceId 非空,说明是重新发起
if (processInstanceId?.length > 0) {
@@ -102,11 +127,149 @@ const getList = async () => {
}
}
-/** 选中分类对应的流程定义列表 */
-const categoryProcessDefinitionList: any = computed(() => {
- return processDefinitionList.value.filter(
- (item: any) => item.category == categoryActive.value.code
- )
+// 获取所有流程分类数据
+const getCategoryList = async () => {
+ try {
+ // 流程分类
+ categoryList.value = await CategoryApi.getCategorySimpleList()
+ if (categoryList.value.length > 0) {
+ categoryActive.value = categoryList.value[0]
+ }
+ } finally {
+ }
+}
+
+// 获取所有流程定义数据
+const getDefinitionList = async () => {
+ try {
+ // 流程定义
+ processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({
+ suspensionState: 1
+ })
+ /* 测试数据 */
+ // processDefinitionList.value = [
+ // {
+ // id: 'business:3:fab1dceb-95be-11ef-8c7d-00a6181404fd',
+ // version: 3,
+ // name: '商务管理',
+ // key: 'business',
+ // icon: 'https://picsum.photos/200?r=2',
+ // description: '商务管理',
+ // category: 'test0',
+ // categoryName: '分类0',
+ // formType: 10,
+ // formId: 27,
+ // formName: null,
+ // formConf:
+ // '{"form":{"inline":false,"hideRequiredAsterisk":false,"labelPosition":"right","size":"default","labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"重置"},"submitBtn":{"show":false,"innerText":"提交"}}',
+ // formFields: [
+ // '{"type":"input","field":"F1yrm2sosxgeabc","title":"请假原因","info":"","$required":false,"props":{"type":"text","placeholder":"请输入123"},"_fc_id":"id_Fhrbm2sosxgeacc","name":"ref_Festm2sosxgeadc","display":true,"hidden":false,"_fc_drag_tag":"input"}',
+ // '{"type":"radio","field":"F9r3m2sp1b34aec","title":"请假类型","info":"","$required":false,"props":{"_optionType":2},"_fc_id":"id_F4nwm2sp1b34afc","name":"ref_Fkodm2sp1b34agc","display":true,"hidden":false,"_fc_drag_tag":"radio","options":[{"label":"事假","value":"1"},{"label":"婚假","value":"2"},{"label":"丧假","value":"3"}]}',
+ // '{"type":"datePicker","field":"Finom2tsbwbpadc","title":"请假时间段","info":"","$required":false,"props":{"type":"datetimerange"},"_fc_id":"id_F028m2tsbwbpaec","name":"ref_F0okm2tsbwbpafc","display":true,"hidden":false,"_fc_drag_tag":"dateRange"}'
+ // ],
+ // formCustomCreatePath: '',
+ // formCustomViewPath: '',
+ // suspensionState: 1,
+ // deploymentTime: null,
+ // bpmnXml: null,
+ // startUserSelectTasks: null
+ // },
+ // {
+ // id: 'oa_leave:1:6e5ac269-5f87-11ef-bdb6-00a6181404fd',
+ // version: 1,
+ // name: 'oa_leave',
+ // key: 'oa_leave',
+ // icon: null,
+ // description: 'oa_leave',
+ // category: 'etst',
+ // categoryName: '分类1',
+ // formType: 20,
+ // formId: null,
+ // formName: null,
+ // formConf: null,
+ // formFields: null,
+ // formCustomCreatePath: '/bpm/oa/leave/create',
+ // formCustomViewPath: '/bpm/oa/leave/detail',
+ // suspensionState: 1,
+ // deploymentTime: null,
+ // bpmnXml: null,
+ // startUserSelectTasks: null
+ // },
+ // {
+ // id: 'oa_leave:3:c9d06889-94fd-11ef-bf08-00a6181404fd',
+ // version: 3,
+ // name: '请假流程',
+ // key: 'oa_leave',
+ // icon: 'https://picsum.photos/200?r=1',
+ // description: '请假流程',
+ // category: 'test3',
+ // categoryName: '分类3',
+ // formType: 10,
+ // formId: 27,
+ // formName: null,
+ // formConf:
+ // '{"form":{"inline":false,"hideRequiredAsterisk":false,"labelPosition":"right","size":"default","labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"重置"},"submitBtn":{"show":true,"innerText":"提交"}}',
+ // formFields: [
+ // '{"type":"input","field":"F1yrm2sosxgeabc","title":"请假原因","info":"","$required":false,"props":{"type":"text","placeholder":"请输入123"},"_fc_id":"id_Fhrbm2sosxgeacc","name":"ref_Festm2sosxgeadc","display":true,"hidden":false,"_fc_drag_tag":"input"}',
+ // '{"type":"radio","field":"F9r3m2sp1b34aec","title":"请假类型","info":"","$required":false,"props":{"_optionType":2},"_fc_id":"id_F4nwm2sp1b34afc","name":"ref_Fkodm2sp1b34agc","display":true,"hidden":false,"_fc_drag_tag":"radio","options":[{"label":"事假","value":"1"},{"label":"婚假","value":"2"},{"label":"丧假","value":"3"}]}'
+ // ],
+ // formCustomCreatePath: 'bpm/oa/leave/create',
+ // formCustomViewPath: 'bpm/oa/leave/create',
+ // suspensionState: 1,
+ // deploymentTime: null,
+ // bpmnXml: null,
+ // startUserSelectTasks: null
+ // }
+ // ]
+ /* 测试数据 */
+ // processDefinitionList.value = [
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value,
+ // ...processDefinitionList.value
+ // ]
+ // 初始化过滤列表为全部流程定义
+ filteredProcessDefinitionList.value = processDefinitionList.value
+ } finally {
+ }
+}
+
+const filteredProcessDefinitionList = ref([]) // 用于存储搜索过滤后的流程定义
+// 直接进行前端搜索
+const handleQuery = () => {
+ if (currentSearchKey.value.trim()) {
+ // 如果有搜索关键字,进行过滤
+ filteredProcessDefinitionList.value = processDefinitionList.value.filter(
+ (definition: any) =>
+ definition.name.toLowerCase().includes(currentSearchKey.value.toLowerCase()) // 假设搜索依据是流程定义的名称
+ )
+ } else {
+ // 如果没有搜索关键字,恢复所有数据
+ filteredProcessDefinitionList.value = processDefinitionList.value
+ }
+}
+
+// 监听input `clearable` 事件
+const handleClear = () => {
+ filteredProcessDefinitionList.value = processDefinitionList.value
+}
+
+// 流程定义的分组
+const processDefinitionGroup: any = computed(() => {
+ if (!processDefinitionList.value?.length) return {}
+ return groupBy(filteredProcessDefinitionList.value, 'categoryName')
})
// ========== 表单相关 ==========
@@ -122,8 +285,16 @@ const handleSelect = async (row, formVariables?) => {
processDefinitionDetailRef.value?.initProcessInfo(row, formVariables)
}
// 左侧分类切换
-const handleCategoryClick = (val: number) => {
- categoryActive.value = val
+const handleCategoryClick = (category) => {
+ categoryActive.value = category
+ const categoryRef = proxy.$refs[`category-${category.name}`] // 获取点击分类对应的 DOM 元素
+ if (categoryRef?.length) {
+ const scrollWrapper = proxy.$refs.scrollWrapper // 获取右侧滚动容器
+ const categoryOffsetTop = categoryRef[0].offsetTop
+
+ // 滚动到对应位置
+ scrollWrapper.scrollTo({ top: categoryOffsetTop, behavior: 'smooth' })
+ }
}
/** 初始化 */
From 0fbd98291e293421a3a6e17f195492eb2767a2e1 Mon Sep 17 00:00:00 2001
From: GoldenZqqq <1361001127@qq.com>
Date: Wed, 6 Nov 2024 15:55:48 +0800
Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=97=B6=E9=97=B4?=
=?UTF-8?q?=E7=BA=BF=E7=BB=84=E4=BB=B6=E4=B8=AD=E5=AD=98=E5=9C=A8=E5=AE=A1?=
=?UTF-8?q?=E6=89=B9=E6=84=8F=E8=A7=81=E6=97=B6=EF=BC=8C=E5=80=99=E9=80=89?=
=?UTF-8?q?=E4=BA=BA=E5=90=8D=E7=A7=B0=E5=A4=B4=E5=83=8F=E6=A0=B7=E5=BC=8F?=
=?UTF-8?q?=E5=B8=83=E5=B1=80=E9=94=99=E4=BD=8D=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../bpm/processInstance/create/index.vue | 94 -------------------
.../detail/ProcessInstanceTimeline.vue | 84 ++++++++---------
2 files changed, 42 insertions(+), 136 deletions(-)
diff --git a/src/views/bpm/processInstance/create/index.vue b/src/views/bpm/processInstance/create/index.vue
index 4909f3f7..5daa22d8 100644
--- a/src/views/bpm/processInstance/create/index.vue
+++ b/src/views/bpm/processInstance/create/index.vue
@@ -146,100 +146,6 @@ const getDefinitionList = async () => {
processDefinitionList.value = await DefinitionApi.getProcessDefinitionList({
suspensionState: 1
})
- /* 测试数据 */
- // processDefinitionList.value = [
- // {
- // id: 'business:3:fab1dceb-95be-11ef-8c7d-00a6181404fd',
- // version: 3,
- // name: '商务管理',
- // key: 'business',
- // icon: 'https://picsum.photos/200?r=2',
- // description: '商务管理',
- // category: 'test0',
- // categoryName: '分类0',
- // formType: 10,
- // formId: 27,
- // formName: null,
- // formConf:
- // '{"form":{"inline":false,"hideRequiredAsterisk":false,"labelPosition":"right","size":"default","labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"重置"},"submitBtn":{"show":false,"innerText":"提交"}}',
- // formFields: [
- // '{"type":"input","field":"F1yrm2sosxgeabc","title":"请假原因","info":"","$required":false,"props":{"type":"text","placeholder":"请输入123"},"_fc_id":"id_Fhrbm2sosxgeacc","name":"ref_Festm2sosxgeadc","display":true,"hidden":false,"_fc_drag_tag":"input"}',
- // '{"type":"radio","field":"F9r3m2sp1b34aec","title":"请假类型","info":"","$required":false,"props":{"_optionType":2},"_fc_id":"id_F4nwm2sp1b34afc","name":"ref_Fkodm2sp1b34agc","display":true,"hidden":false,"_fc_drag_tag":"radio","options":[{"label":"事假","value":"1"},{"label":"婚假","value":"2"},{"label":"丧假","value":"3"}]}',
- // '{"type":"datePicker","field":"Finom2tsbwbpadc","title":"请假时间段","info":"","$required":false,"props":{"type":"datetimerange"},"_fc_id":"id_F028m2tsbwbpaec","name":"ref_F0okm2tsbwbpafc","display":true,"hidden":false,"_fc_drag_tag":"dateRange"}'
- // ],
- // formCustomCreatePath: '',
- // formCustomViewPath: '',
- // suspensionState: 1,
- // deploymentTime: null,
- // bpmnXml: null,
- // startUserSelectTasks: null
- // },
- // {
- // id: 'oa_leave:1:6e5ac269-5f87-11ef-bdb6-00a6181404fd',
- // version: 1,
- // name: 'oa_leave',
- // key: 'oa_leave',
- // icon: null,
- // description: 'oa_leave',
- // category: 'etst',
- // categoryName: '分类1',
- // formType: 20,
- // formId: null,
- // formName: null,
- // formConf: null,
- // formFields: null,
- // formCustomCreatePath: '/bpm/oa/leave/create',
- // formCustomViewPath: '/bpm/oa/leave/detail',
- // suspensionState: 1,
- // deploymentTime: null,
- // bpmnXml: null,
- // startUserSelectTasks: null
- // },
- // {
- // id: 'oa_leave:3:c9d06889-94fd-11ef-bf08-00a6181404fd',
- // version: 3,
- // name: '请假流程',
- // key: 'oa_leave',
- // icon: 'https://picsum.photos/200?r=1',
- // description: '请假流程',
- // category: 'test3',
- // categoryName: '分类3',
- // formType: 10,
- // formId: 27,
- // formName: null,
- // formConf:
- // '{"form":{"inline":false,"hideRequiredAsterisk":false,"labelPosition":"right","size":"default","labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"重置"},"submitBtn":{"show":true,"innerText":"提交"}}',
- // formFields: [
- // '{"type":"input","field":"F1yrm2sosxgeabc","title":"请假原因","info":"","$required":false,"props":{"type":"text","placeholder":"请输入123"},"_fc_id":"id_Fhrbm2sosxgeacc","name":"ref_Festm2sosxgeadc","display":true,"hidden":false,"_fc_drag_tag":"input"}',
- // '{"type":"radio","field":"F9r3m2sp1b34aec","title":"请假类型","info":"","$required":false,"props":{"_optionType":2},"_fc_id":"id_F4nwm2sp1b34afc","name":"ref_Fkodm2sp1b34agc","display":true,"hidden":false,"_fc_drag_tag":"radio","options":[{"label":"事假","value":"1"},{"label":"婚假","value":"2"},{"label":"丧假","value":"3"}]}'
- // ],
- // formCustomCreatePath: 'bpm/oa/leave/create',
- // formCustomViewPath: 'bpm/oa/leave/create',
- // suspensionState: 1,
- // deploymentTime: null,
- // bpmnXml: null,
- // startUserSelectTasks: null
- // }
- // ]
- /* 测试数据 */
- // processDefinitionList.value = [
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value,
- // ...processDefinitionList.value
- // ]
// 初始化过滤列表为全部流程定义
filteredProcessDefinitionList.value = processDefinitionList.value
} finally {
diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
index 8415a2b1..3eb071ed 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
@@ -24,7 +24,7 @@
-
+
{{ activity.name }}
@@ -36,53 +36,53 @@
{{ getApprovalNodeTime(activity) }}
-
+
-
-
+
+
+
-
+
+
+
+ {{ task.assigneeUser?.nickname.substring(0, 1) }}
+
+ {{ task.assigneeUser?.nickname }}
+
+
+
+
+ {{ task.ownerUser?.nickname.substring(0, 1) }}
+
+ {{ task.ownerUser?.nickname }}
+
+
-
-
-
- {{ task.assigneeUser?.nickname.substring(0, 1) }}
-
- {{ task.assigneeUser?.nickname }}
-
-
-
-
- {{ task.ownerUser?.nickname.substring(0, 1) }}
-
- {{ task.ownerUser?.nickname }}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ 确 定
+ 取 消
+
+
+
+
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"
>
-
+
@@ -61,7 +61,7 @@
ref="timelineRef"
:activity-nodes="activityNodes"
:show-status-icon="false"
- candidateField="candidateUserList"
+ :startUserSelectTasks="startUserSelectTasks"
/>
@@ -104,7 +104,8 @@ 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 * as UserApi from '@/api/system/user'
+import { activityNodes as aN, startUserSelectTasks as sUs } from './mock'
defineOptions({ name: 'ProcessDefinitionDetail' })
const props = defineProps<{
@@ -125,7 +126,7 @@ const startUserSelectAssigneesFormRef = ref() // 发起人选择审批人的表
const startUserSelectTasks: any = ref([]) // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref({}) // 发起人选择审批人的数据
const startUserSelectAssigneesFormRules = ref({}) // 发起人选择审批人的表单 Rules
-const userList = ref([]) // 用户列表
+// const userList = ref([]) // 用户列表
const bpmnXML: any = ref(null) // BPMN 数据
/** 当前的Tab */
const activeTab = ref('form')
@@ -163,25 +164,25 @@ 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) {
+ // 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()
+ // }
}
// 情况二:业务表单
} else if (row.formCustomCreatePath) {
@@ -205,6 +206,7 @@ const getApprovalDetail = async (row: any) => {
}
// 获取审批节点,显示 Timeline 的数据
activityNodes.value = data.activityNodes
+ activityNodes.value = aN
} finally {
}
}
@@ -250,7 +252,7 @@ defineExpose({ initProcessInfo })
$wrap-padding-height: 20px;
$wrap-margin-height: 15px;
$button-height: 51px;
-$process-header-height: 194px;
+$process-header-height: 105px;
.processInstance-wrap-main {
height: calc(
diff --git a/src/views/bpm/processInstance/create/mock.ts b/src/views/bpm/processInstance/create/mock.ts
new file mode 100644
index 00000000..2cb1394c
--- /dev/null
+++ b/src/views/bpm/processInstance/create/mock.ts
@@ -0,0 +1,86 @@
+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 3eb071ed..1d3e7a1c 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
@@ -36,7 +36,15 @@
{{ getApprovalNodeTime(activity) }}
-
+
+
+
+
+
+
+
+
+
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<{