From 97b4eef342effb892622d2834658dbf489254590 Mon Sep 17 00:00:00 2001
From: LiuHao <liuhaoai545@gmail.com>
Date: 星期五, 08 三月 2024 16:02:08 +0800
Subject: [PATCH] update 使用bpmnjs流程预览
---
src/components/BpmnView/index.vue | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 361 insertions(+), 0 deletions(-)
diff --git a/src/components/BpmnView/index.vue b/src/components/BpmnView/index.vue
new file mode 100644
index 0000000..ee0eaa6
--- /dev/null
+++ b/src/components/BpmnView/index.vue
@@ -0,0 +1,361 @@
+<template>
+ <el-dialog v-if="bpmnVisible" v-model="bpmnVisible" title="娴佺▼杩涘害" append-to-body width="90%" @opened="init(undefined)">
+ <div v-loading="loading" class="bpmnDialogContainers">
+ <el-header style="border-bottom: 1px solid rgb(218 218 218); height: auto">
+ <div class="header-div">
+ <div>
+ <el-tooltip effect="dark" content="鑷�傚簲灞忓箷" placement="bottom">
+ <el-button size="small" icon="Rank" @click="fitViewport" />
+ </el-tooltip>
+ <el-tooltip effect="dark" content="鏀惧ぇ" placement="bottom">
+ <el-button size="small" icon="ZoomIn" @click="zoomViewport(true)" />
+ </el-tooltip>
+ <el-tooltip effect="dark" content="缂╁皬" placement="bottom">
+ <el-button size="small" icon="ZoomOut" @click="zoomViewport(false)" />
+ </el-tooltip>
+ </div>
+ <div>
+ <div class="tips-label">
+ <div class="un-complete">鏈畬鎴�</div>
+ <div class="in-progress">杩涜涓�</div>
+ <div class="complete">宸插畬鎴�</div>
+ </div>
+ </div>
+ </div>
+ </el-header>
+ <div class="flow-containers">
+ <el-container class="bpmn-el-container" style="align-items: stretch">
+ <el-main style="padding: 0">
+ <div ref="canvas" class="canvas" />
+ </el-main>
+ </el-container>
+ </div>
+ </div>
+ </el-dialog>
+</template>
+
+<script lang="ts" setup>
+import BpmnViewer from 'bpmn-js/lib/Viewer';
+import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
+import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';
+import { ModuleDeclaration } from 'didi';
+import { Canvas, ModdleElement } from 'bpmn';
+import defaultXML from '@/components/BpmnDesign/assets/defaultXML';
+import EventBus from 'diagram-js/lib/core/EventBus';
+import Overlays from 'diagram-js/lib/features/overlays/Overlays';
+import processApi from '@/api/workflow/processInstance/index';
+
+const canvas = ref<HTMLElement>();
+const modeler = ref<BpmnViewer>();
+const taskList = ref([]);
+const zoom = ref(1);
+const xml = ref('');
+const loading = ref(false);
+const bpmnVisible = ref(true);
+const historyList = ref([]);
+const init = (instanceId) => {
+ loading.value = true;
+ bpmnVisible.value = true;
+ nextTick(() => {
+ if (modeler.value) modeler.value.destroy();
+ modeler.value = new BpmnViewer({
+ container: canvas.value,
+ additionalModules: [
+ {
+ //绂佹婊氳疆婊氬姩
+ zoomScroll: ['value', '']
+ },
+ ZoomScrollModule,
+ MoveCanvasModule
+ ] as ModuleDeclaration[]
+ });
+ processApi.getHistoryList(instanceId).then((resp) => {
+ xml.value = resp.data.xml;
+ taskList.value = resp.data.taskList;
+ historyList.value = resp.data.historyList;
+ // createDiagram(xml);
+ console.log(resp);
+ });
+ createDiagram(defaultXML);
+ loading.value = false;
+ });
+};
+
+const createDiagram = async (data) => {
+ try {
+ await modeler.value.importXML(data);
+ fitViewport();
+ fillColor();
+ loading.value = false;
+ addEventBusListener();
+ } catch (err) {
+ //console.error(err.message, err.warnings)
+ }
+};
+const addEventBusListener = () => {
+ const eventBus = modeler.value.get<EventBus>('eventBus');
+ const overlays = modeler.value.get<Overlays>('overlays');
+ eventBus.on<ModdleElement>('element.hover', (e) => {
+ let data = historyList.value.find((t) => t.taskDefinitionKey === e.element.id);
+ if (e.element.type === 'bpmn:UserTask' && data) {
+ setTimeout(() => {
+ genNodeDetailBox(e, overlays, data);
+ }, 10);
+ }
+ });
+ eventBus.on('element.out', (e) => {
+ overlays.clear();
+ });
+};
+const genNodeDetailBox = (e, overlays, data) => {
+ overlays.add(e.element.id, {
+ position: { top: e.element.height, left: 0 },
+ html: `<div class="verlays">
+ <p>瀹℃壒浜哄憳: ${data.nickName || ''}<p/>
+ <p>鑺傜偣鐘舵�侊細${data.status || ''}</p>
+ <p>寮�濮嬫椂闂达細${data.startTime || ''}</p>
+ <p>缁撴潫鏃堕棿锛�${data.endTime || ''}</p>
+ <p>瀹℃壒鑰楁椂锛�${data.runDuration || ''}</p>
+ </div>`
+ });
+};
+// 璁╁浘鑳借嚜閫傚簲灞忓箷
+const fitViewport = () => {
+ zoom.value = modeler.value.get<Canvas>('canvas').zoom('fit-viewport');
+ const bbox = document.querySelector<SVGGElement>('.flow-containers .viewport').getBBox();
+ const currentViewBox = modeler.value.get('canvas').viewbox();
+ const elementMid = {
+ x: bbox.x + bbox.width / 2 - 65,
+ y: bbox.y + bbox.height / 2
+ };
+ modeler.value.get<Canvas>('canvas').viewbox({
+ x: elementMid.x - currentViewBox.width / 2,
+ y: elementMid.y - currentViewBox.height / 2,
+ width: currentViewBox.width,
+ height: currentViewBox.height
+ });
+ zoom.value = (bbox.width / currentViewBox.width) * 1.8;
+};
+// 鏀惧ぇ缂╁皬
+const zoomViewport = (zoomIn = true) => {
+ zoom.value = modeler.value.get<Canvas>('canvas').zoom();
+ zoom.value += zoomIn ? 0.1 : -0.1;
+ modeler.value.get<Canvas>('canvas').zoom(zoom.value);
+};
+//涓婅壊
+const fillColor = () => {
+ const canvas = modeler.value.get<Canvas>('canvas');
+ bpmnNodeList(modeler.value._definitions.rootElements[0].flowElements, canvas);
+};
+//閫掑綊涓婅壊
+const bpmnNodeList = (flowElements, canvas) => {
+ flowElements.forEach((n) => {
+ if (n.$type === 'bpmn:UserTask') {
+ const completeTask = taskList.value.find((m) => m.key === n.id);
+ if (completeTask) {
+ canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ n.outgoing?.forEach((nn) => {
+ const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id);
+ if (targetTask) {
+ canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo');
+ } else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') {
+ canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ nn.targetRef.outgoing.forEach((e) => {
+ getway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed);
+ });
+ } else if (nn.targetRef.$type === 'bpmn:ParallelGateway') {
+ canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ nn.targetRef.outgoing.forEach((e) => {
+ getway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed);
+ });
+ } else if (nn.targetRef.$type === 'bpmn:InclusiveGateway') {
+ canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ nn.targetRef.outgoing.forEach((e) => {
+ getway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed);
+ });
+ }
+ });
+ }
+ } else if (n.$type === 'bpmn:ExclusiveGateway') {
+ n.outgoing.forEach((nn) => {
+ const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id);
+ if (targetTask) {
+ canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo');
+ }
+ });
+ } else if (n.$type === 'bpmn:ParallelGateway') {
+ n.outgoing.forEach((nn) => {
+ const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id);
+ if (targetTask) {
+ canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo');
+ }
+ });
+ } else if (n.$type === 'bpmn:InclusiveGateway') {
+ n.outgoing.forEach((nn) => {
+ const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id);
+ if (targetTask) {
+ canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo');
+ }
+ });
+ } else if (n.$type === 'bpmn:SubProcess') {
+ const completeTask = taskList.value.find((m) => m.key === n.id);
+ if (completeTask) {
+ canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo');
+ }
+ bpmnNodeList(n.flowElements, canvas);
+ } else if (n.$type === 'bpmn:StartEvent') {
+ n.outgoing.forEach((nn) => {
+ const completeTask = taskList.value.find((m) => m.key === nn.targetRef.id);
+ if (completeTask) {
+ canvas.addMarker(nn.id, 'highlight');
+ canvas.addMarker(n.id, 'highlight');
+ return;
+ }
+ });
+ } else if (n.$type === 'bpmn:EndEvent') {
+ const completeTask = taskList.value.find((m) => m.key === n.id);
+ if (completeTask) {
+ canvas.addMarker(completeTask.key, 'highlight');
+ canvas.addMarker(n.id, 'highlight');
+ return;
+ }
+ }
+ });
+};
+const getway = (id, targetRefType, targetRefId, canvas, completed) => {
+ if (targetRefType === 'bpmn:ExclusiveGateway') {
+ canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo');
+ }
+ if (targetRefType === 'bpmn:ParallelGateway') {
+ canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo');
+ }
+ if (targetRefType === 'bpmn:InclusiveGateway') {
+ canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo');
+ canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo');
+ }
+};
+</script>
+
+<style lang="scss">
+.canvas {
+ width: 100%;
+ height: 100%;
+}
+
+.header-div {
+ display: flex;
+ padding: 10px 0;
+ justify-content: space-between;
+
+ .tips-label {
+ display: flex;
+ div {
+ margin-right: 10px;
+ padding: 5px;
+ font-size: 12px;
+ }
+ .un-complete {
+ border: 1px dashed #000;
+ }
+ .in-progress {
+ background-color: rgb(255, 237, 204);
+ border: 1px dashed orange;
+ }
+ .complete {
+ background-color: rgb(204, 230, 204);
+ border: 1px dashed green;
+ }
+ }
+}
+
+.view-mode {
+ .el-header,
+ .el-aside,
+ .djs-palette,
+ .bjs-powered-by {
+ display: none;
+ }
+ .el-loading-mask {
+ background-color: initial;
+ }
+ .el-loading-spinner {
+ display: none;
+ }
+}
+.bpmn-el-container {
+ height: 500px;
+}
+.flow-containers {
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+ .canvas {
+ width: 100%;
+ height: 100%;
+ }
+ .load {
+ margin-right: 10px;
+ }
+ .el-form-item__label {
+ font-size: 13px;
+ }
+
+ .djs-palette {
+ left: 0 !important;
+ top: 0;
+ border-top: none;
+ }
+
+ .djs-container svg {
+ min-height: 650px;
+ }
+
+ .highlight.djs-shape .djs-visual > :nth-child(1) {
+ fill: green !important;
+ stroke: green !important;
+ fill-opacity: 0.2 !important;
+ }
+ .highlight.djs-shape .djs-visual > :nth-child(2) {
+ fill: green !important;
+ }
+ .highlight.djs-shape .djs-visual > path {
+ fill: green !important;
+ fill-opacity: 0.2 !important;
+ stroke: green !important;
+ }
+ .highlight.djs-connection > .djs-visual > path {
+ stroke: green !important;
+ }
+ .highlight-todo.djs-connection > .djs-visual > path {
+ stroke: orange !important;
+ stroke-dasharray: 4px !important;
+ fill-opacity: 0.2 !important;
+ marker-end: url(#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr);
+ }
+ .highlight-todo.djs-shape .djs-visual > :nth-child(1) {
+ fill: orange !important;
+ stroke: orange !important;
+ stroke-dasharray: 4px !important;
+ fill-opacity: 0.2 !important;
+ }
+}
+.verlays {
+ width: 250px;
+ background: rgb(102, 102, 102);
+ border-radius: 4px;
+ border: 1px solid #ebeef5;
+ //padding: 12px;
+ color: #fff;
+ padding: 15px 10px;
+ p {
+ line-height: 28px;
+ margin: 0;
+ padding: 0;
+ }
+}
+</style>
--
Gitblit v1.9.3