feat: [BPM 工作流] Simple 模型图浏览模式
							parent
							
								
									da308e80aa
								
							
						
					
					
						commit
						4cc6cc45b1
					
				|  | @ -249,7 +249,7 @@ onMounted(() => { | ||||||
|       /> |       /> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|   <!-- TODO 这个好像暂时没有用到。保存失败弹窗 --> | 
 | ||||||
|   <Modal |   <Modal | ||||||
|     v-model:open="errorDialogVisible" |     v-model:open="errorDialogVisible" | ||||||
|     title="保存失败" |     title="保存失败" | ||||||
|  |  | ||||||
|  | @ -0,0 +1,45 @@ | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import type { SimpleFlowNode } from '../consts'; | ||||||
|  | 
 | ||||||
|  | import { provide, ref, watch } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { useWatchNode } from '../helpers'; | ||||||
|  | import SimpleProcessModel from './simple-process-model.vue'; | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'SimpleProcessViewer' }); | ||||||
|  | 
 | ||||||
|  | const props = withDefaults( | ||||||
|  |   defineProps<{ | ||||||
|  |     flowNode: SimpleFlowNode; | ||||||
|  |     // 流程实例 | ||||||
|  |     processInstance?: any; | ||||||
|  |     // 流程任务 | ||||||
|  |     tasks?: any[]; | ||||||
|  |   }>(), | ||||||
|  |   { | ||||||
|  |     processInstance: undefined, | ||||||
|  |     tasks: () => [] as any[], | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | const approveTasks = ref<any[]>(props.tasks); | ||||||
|  | const currentProcessInstance = ref(props.processInstance); | ||||||
|  | const simpleModel = useWatchNode(props); | ||||||
|  | watch( | ||||||
|  |   () => props.tasks, | ||||||
|  |   (newValue) => { | ||||||
|  |     approveTasks.value = newValue; | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | watch( | ||||||
|  |   () => props.processInstance, | ||||||
|  |   (newValue) => { | ||||||
|  |     currentProcessInstance.value = newValue; | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | // 提供给后代组件使用 | ||||||
|  | provide('tasks', approveTasks); | ||||||
|  | provide('processInstance', currentProcessInstance); | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  |   <SimpleProcessModel :flow-node="simpleModel" :readonly="true" /> | ||||||
|  | </template> | ||||||
|  | @ -4,4 +4,8 @@ export { default as HttpRequestSetting } from './components/nodes-config/modules | ||||||
| 
 | 
 | ||||||
| export { default as SimpleProcessDesigner } from './components/simple-process-designer.vue'; | export { default as SimpleProcessDesigner } from './components/simple-process-designer.vue'; | ||||||
| 
 | 
 | ||||||
|  | export { default as SimpleProcessViewer } from './components/simple-process-viewer.vue'; | ||||||
|  | 
 | ||||||
|  | export type { SimpleFlowNode } from './consts'; | ||||||
|  | 
 | ||||||
| export { parseFormFields } from './helpers'; | export { parseFormFields } from './helpers'; | ||||||
|  |  | ||||||
|  | @ -346,7 +346,12 @@ onMounted(async () => { | ||||||
|               </Row> |               </Row> | ||||||
|             </TabPane> |             </TabPane> | ||||||
| 
 | 
 | ||||||
|             <TabPane tab="流程图" key="diagram" class="tab-pane-content"> |             <TabPane | ||||||
|  |               tab="流程图" | ||||||
|  |               key="diagram" | ||||||
|  |               class="tab-pane-content" | ||||||
|  |               :force-render="true" | ||||||
|  |             > | ||||||
|               <div class="h-full"> |               <div class="h-full"> | ||||||
|                 <ProcessInstanceSimpleViewer |                 <ProcessInstanceSimpleViewer | ||||||
|                   v-show=" |                   v-show=" | ||||||
|  |  | ||||||
|  | @ -1,9 +1,180 @@ | ||||||
| <script setup lang="ts"> | <script lang="ts" setup> | ||||||
| defineOptions({ name: 'ProcessInstanceSimpleViewer' }); | import type { SimpleFlowNode } from '#/components/simple-process-design'; | ||||||
| </script> |  | ||||||
| 
 | 
 | ||||||
|  | import { ref, watch } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { SimpleProcessViewer } from '#/components/simple-process-design'; | ||||||
|  | import { BpmNodeTypeEnum, BpmTaskStatusEnum } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | defineOptions({ name: 'BpmProcessInstanceSimpleViewer' }); | ||||||
|  | 
 | ||||||
|  | const props = withDefaults( | ||||||
|  |   defineProps<{ | ||||||
|  |     loading?: boolean; // 是否加载中 | ||||||
|  |     modelView?: any; | ||||||
|  |     simpleJson?: string; // Simple 模型结构数据 (json 格式) | ||||||
|  |   }>(), | ||||||
|  |   { | ||||||
|  |     loading: false, | ||||||
|  |     modelView: () => ({}), | ||||||
|  |     simpleJson: '', | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | const simpleModel = ref<any>({}); | ||||||
|  | // 用户任务 | ||||||
|  | const tasks = ref([]); | ||||||
|  | // 流程实例 | ||||||
|  | const processInstance = ref(); | ||||||
|  | 
 | ||||||
|  | /** 监控模型视图 包括任务列表、进行中的活动节点编号等 */ | ||||||
|  | watch( | ||||||
|  |   () => props.modelView, | ||||||
|  |   async (newModelView) => { | ||||||
|  |     if (newModelView) { | ||||||
|  |       tasks.value = newModelView.tasks; | ||||||
|  |       processInstance.value = newModelView.processInstance; | ||||||
|  |       // 已经拒绝的活动节点编号集合,只包括 UserTask | ||||||
|  |       const rejectedTaskActivityIds: string[] = | ||||||
|  |         newModelView.rejectedTaskActivityIds; | ||||||
|  |       // 进行中的活动节点编号集合, 只包括 UserTask | ||||||
|  |       const unfinishedTaskActivityIds: string[] = | ||||||
|  |         newModelView.unfinishedTaskActivityIds; | ||||||
|  |       // 已经完成的活动节点编号集合, 包括 UserTask、Gateway 等 | ||||||
|  |       const finishedActivityIds: string[] = | ||||||
|  |         newModelView.finishedTaskActivityIds; | ||||||
|  |       // 已经完成的连线节点编号集合,只包括 SequenceFlow | ||||||
|  |       const finishedSequenceFlowActivityIds: string[] = | ||||||
|  |         newModelView.finishedSequenceFlowActivityIds; | ||||||
|  |       setSimpleModelNodeTaskStatus( | ||||||
|  |         newModelView.simpleModel, | ||||||
|  |         newModelView.processInstance?.status, | ||||||
|  |         rejectedTaskActivityIds, | ||||||
|  |         unfinishedTaskActivityIds, | ||||||
|  |         finishedActivityIds, | ||||||
|  |         finishedSequenceFlowActivityIds, | ||||||
|  |       ); | ||||||
|  |       simpleModel.value = newModelView.simpleModel || {}; | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | /** 监控模型结构数据 */ | ||||||
|  | watch( | ||||||
|  |   () => props.simpleJson, | ||||||
|  |   async (value) => { | ||||||
|  |     if (value) { | ||||||
|  |       simpleModel.value = JSON.parse(value); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | ); | ||||||
|  | const setSimpleModelNodeTaskStatus = ( | ||||||
|  |   simpleModel: SimpleFlowNode | undefined, | ||||||
|  |   processStatus: number, | ||||||
|  |   rejectedTaskActivityIds: string[], | ||||||
|  |   unfinishedTaskActivityIds: string[], | ||||||
|  |   finishedActivityIds: string[], | ||||||
|  |   finishedSequenceFlowActivityIds: string[], | ||||||
|  | ) => { | ||||||
|  |   if (!simpleModel) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   // 结束节点 | ||||||
|  |   if (simpleModel.type === BpmNodeTypeEnum.END_EVENT_NODE) { | ||||||
|  |     simpleModel.activityStatus = finishedActivityIds.includes(simpleModel.id) | ||||||
|  |       ? processStatus | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   // 审批节点 | ||||||
|  |   if ( | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.START_USER_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.USER_TASK_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.TRANSACTOR_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.CHILD_PROCESS_NODE | ||||||
|  |   ) { | ||||||
|  |     simpleModel.activityStatus = BpmTaskStatusEnum.NOT_START; | ||||||
|  |     if (rejectedTaskActivityIds.includes(simpleModel.id)) { | ||||||
|  |       simpleModel.activityStatus = BpmTaskStatusEnum.REJECT; | ||||||
|  |     } else if (unfinishedTaskActivityIds.includes(simpleModel.id)) { | ||||||
|  |       simpleModel.activityStatus = BpmTaskStatusEnum.RUNNING; | ||||||
|  |     } else if (finishedActivityIds.includes(simpleModel.id)) { | ||||||
|  |       simpleModel.activityStatus = BpmTaskStatusEnum.APPROVE; | ||||||
|  |     } | ||||||
|  |     // TODO 是不是还缺一个 cancel 的状态 | ||||||
|  |   } | ||||||
|  |   // 抄送节点 | ||||||
|  |   if (simpleModel.type === BpmNodeTypeEnum.COPY_TASK_NODE) { | ||||||
|  |     // 抄送节点,只有通过和未执行状态 | ||||||
|  |     simpleModel.activityStatus = finishedActivityIds.includes(simpleModel.id) | ||||||
|  |       ? BpmTaskStatusEnum.APPROVE | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |   } | ||||||
|  |   // 延迟器节点 | ||||||
|  |   if (simpleModel.type === BpmNodeTypeEnum.DELAY_TIMER_NODE) { | ||||||
|  |     // 延迟器节点,只有通过和未执行状态 | ||||||
|  |     simpleModel.activityStatus = finishedActivityIds.includes(simpleModel.id) | ||||||
|  |       ? BpmTaskStatusEnum.APPROVE | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |   } | ||||||
|  |   // 触发器节点 | ||||||
|  |   if (simpleModel.type === BpmNodeTypeEnum.TRIGGER_NODE) { | ||||||
|  |     // 触发器节点,只有通过和未执行状态 | ||||||
|  |     simpleModel.activityStatus = finishedActivityIds.includes(simpleModel.id) | ||||||
|  |       ? BpmTaskStatusEnum.APPROVE | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // 条件节点对应 SequenceFlow | ||||||
|  |   if (simpleModel.type === BpmNodeTypeEnum.CONDITION_NODE) { | ||||||
|  |     // 条件节点,只有通过和未执行状态 | ||||||
|  |     simpleModel.activityStatus = finishedSequenceFlowActivityIds.includes( | ||||||
|  |       simpleModel.id, | ||||||
|  |     ) | ||||||
|  |       ? BpmTaskStatusEnum.APPROVE | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |   } | ||||||
|  |   // 网关节点 | ||||||
|  |   if ( | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.CONDITION_BRANCH_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.PARALLEL_BRANCH_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.INCLUSIVE_BRANCH_NODE || | ||||||
|  |     simpleModel.type === BpmNodeTypeEnum.ROUTER_BRANCH_NODE | ||||||
|  |   ) { | ||||||
|  |     // 网关节点。只有通过和未执行状态 | ||||||
|  |     simpleModel.activityStatus = finishedActivityIds.includes(simpleModel.id) | ||||||
|  |       ? BpmTaskStatusEnum.APPROVE | ||||||
|  |       : BpmTaskStatusEnum.NOT_START; | ||||||
|  |     simpleModel.conditionNodes?.forEach((node) => { | ||||||
|  |       setSimpleModelNodeTaskStatus( | ||||||
|  |         node, | ||||||
|  |         processStatus, | ||||||
|  |         rejectedTaskActivityIds, | ||||||
|  |         unfinishedTaskActivityIds, | ||||||
|  |         finishedActivityIds, | ||||||
|  |         finishedSequenceFlowActivityIds, | ||||||
|  |       ); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setSimpleModelNodeTaskStatus( | ||||||
|  |     simpleModel.childNode, | ||||||
|  |     processStatus, | ||||||
|  |     rejectedTaskActivityIds, | ||||||
|  |     unfinishedTaskActivityIds, | ||||||
|  |     finishedActivityIds, | ||||||
|  |     finishedSequenceFlowActivityIds, | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  | </script> | ||||||
| <template> | <template> | ||||||
|   <div> |   <div v-loading="loading"> | ||||||
|     <h1>Simple BPM Viewer</h1> |     <SimpleProcessViewer | ||||||
|  |       :flow-node="simpleModel" | ||||||
|  |       :tasks="tasks" | ||||||
|  |       :process-instance="processInstance" | ||||||
|  |     /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" scoped></style> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 jason
						jason