feat: [BPM 工作流] Simple 模型图浏览模式

pull/154/head
jason 2025-06-21 16:53:33 +08:00
parent da308e80aa
commit 4cc6cc45b1
5 changed files with 232 additions and 7 deletions

View File

@ -249,7 +249,7 @@ onMounted(() => {
/> />
</div> </div>
</div> </div>
<!-- TODO 这个好像暂时没有用到保存失败弹窗 -->
<Modal <Modal
v-model:open="errorDialogVisible" v-model:open="errorDialogVisible"
title="保存失败" title="保存失败"

View File

@ -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>

View File

@ -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';

View File

@ -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="

View File

@ -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;
// UserTaskGateway
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>