src/api/workflow/processInstance/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/BpmnView/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/Process/approvalRecord.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/workflow/processInstance/index.ts
@@ -41,7 +41,7 @@ /** * 通过流程实例id获取历史流程图运行中,历史等节点 */ export const getHistoryList = (instanceId: string) => { export const getHistoryList = (instanceId: string): AxiosPromise<Record<string, any>> => { return request({ url: `/workflow/processInstance/getHistoryList/${instanceId}` + '?t' + Math.random(), method: 'get' src/components/BpmnView/index.vue
@@ -1,37 +1,35 @@ <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 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> </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> </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> </el-dialog> </div> </template> <script lang="ts" setup> @@ -53,10 +51,11 @@ const loading = ref(false); const bpmnVisible = ref(true); const historyList = ref([]); const init = (instanceId) => { loading.value = true; bpmnVisible.value = true; nextTick(() => { nextTick(async () => { if (modeler.value) modeler.value.destroy(); modeler.value = new BpmnViewer({ container: canvas.value, @@ -69,14 +68,11 @@ 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); const resp = await processApi.getHistoryList(instanceId); xml.value = resp.data.xml; taskList.value = resp.data.taskList; historyList.value = resp.data.historyList; await createDiagram(xml.value); loading.value = false; }); }; @@ -89,7 +85,7 @@ loading.value = false; addEventBusListener(); } catch (err) { //console.error(err.message, err.warnings) console.log(err); } }; const addEventBusListener = () => { @@ -150,8 +146,10 @@ //递归上色 const bpmnNodeList = (flowElements, canvas) => { flowElements.forEach((n) => { console.log(n); if (n.$type === 'bpmn:UserTask') { const completeTask = taskList.value.find((m) => m.key === n.id); console.log(completeTask); if (completeTask) { canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo'); n.outgoing?.forEach((nn) => { @@ -162,19 +160,19 @@ 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); gateway(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); gateway(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); gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); }); } }); @@ -207,15 +205,19 @@ } 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; } }); canvas.addMarker(n.id, 'startEvent'); if (n.outgoing) { 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') { canvas.addMarker(n.id, 'endEvent'); const completeTask = taskList.value.find((m) => m.key === n.id); if (completeTask) { canvas.addMarker(completeTask.key, 'highlight'); @@ -225,7 +227,7 @@ } }); }; const getway = (id, targetRefType, targetRefId, canvas, completed) => { const gateway = (id, targetRefType, targetRefId, canvas, completed) => { if (targetRefType === 'bpmn:ExclusiveGateway') { canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); @@ -239,9 +241,12 @@ canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); } }; defineExpose({ init }); </script> <style lang="scss"> <style lang="scss" scoped> .canvas { width: 100%; height: 100%; @@ -260,7 +265,7 @@ font-size: 12px; } .un-complete { border: 1px dashed #000; border: 1px solid #000; } .in-progress { background-color: rgb(255, 237, 204); @@ -268,7 +273,7 @@ } .complete { background-color: rgb(204, 230, 204); border: 1px dashed green; border: 1px solid green; } } } @@ -301,55 +306,60 @@ .load { margin-right: 10px; } .el-form-item__label { :deep(.el-form-item__label) { font-size: 13px; } .djs-palette { :deep(.djs-palette) { left: 0 !important; top: 0; border-top: none; } .djs-container svg { :deep(.djs-container svg) { min-height: 650px; } .highlight.djs-shape .djs-visual > :nth-child(1) { :deep(.startEvent.djs-shape .djs-visual > :nth-child(1)) { fill: #77df6d !important; } :deep(.endEvent.djs-shape .djs-visual > :nth-child(1)) { fill: #ee7b77 !important; } :deep(.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) { :deep(.highlight.djs-shape .djs-visual > :nth-child(2)) { fill: green !important; } .highlight.djs-shape .djs-visual > path { :deep(.highlight.djs-shape .djs-visual > path) { fill: green !important; fill-opacity: 0.2 !important; stroke: green !important; } .highlight.djs-connection > .djs-visual > path { :deep(.highlight.djs-connection > .djs-visual > path) { stroke: green !important; } .highlight-todo.djs-connection > .djs-visual > path { :deep(.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) { :deep(.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 { :deep(.verlays) { width: 250px; background: rgb(102, 102, 102); border-radius: 4px; border: 1px solid #ebeef5; //padding: 12px; color: #fff; padding: 15px 10px; p { src/components/Process/approvalRecord.vue
@@ -1,86 +1,90 @@ <template> <el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" append-to-body :close-on-click-modal="false"> <el-tabs v-model="tabActiveName" class="demo-tabs"> <el-tab-pane label="流程图" name="bpmn"> <div v-loading="loading"> <div style="width: 100%; height: 300px; overflow: auto; position: relative"> <div v-for="(graphic, index) in graphicInfoVos" :key="index" :style="{ position: 'absolute', left: `${graphic.x}px`, top: `${graphic.y}px`, width: `${graphic.width}px`, height: `${graphic.height}px`, cursor: 'pointer', zIndex: 99 }" @mouseover="handleMouseOver(graphic)" @mouseleave="handleMouseLeave()" ></div> <!-- 弹出的 div 元素 --> <div v-show="popupVisible" class="triangle" :style="{ position: 'absolute', left: `${graphicX}px`, top: `${graphicY}px`, backgroundColor: '#fff', padding: '10px', zIndex: 100 }" > <p>审批人员: {{ nodeInfo.nickName }}</p> <p>节点状态:{{ nodeInfo.status }}</p> <p>开始时间:{{ nodeInfo.startTime }}</p> <p>结束时间:{{ nodeInfo.endTime }}</p> <p>审批耗时:{{ nodeInfo.runDuration }}</p> </div> <el-image :src="src" /> <div class="container"> <el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false"> <el-tabs v-model="tabActiveName" class="demo-tabs"> <el-tab-pane label="流程图" name="bpmn"> <!-- <div v-loading="loading">--> <!-- <div style="width: 100%; height: 300px; overflow: auto; position: relative">--> <!-- <div--> <!-- v-for="(graphic, index) in graphicInfoVos"--> <!-- :key="index"--> <!-- :style="{--> <!-- position: 'absolute',--> <!-- left: `${graphic.x}px`,--> <!-- top: `${graphic.y}px`,--> <!-- width: `${graphic.width}px`,--> <!-- height: `${graphic.height}px`,--> <!-- cursor: 'pointer',--> <!-- zIndex: 99--> <!-- }"--> <!-- @mouseover="handleMouseOver(graphic)"--> <!-- @mouseleave="handleMouseLeave()"--> <!-- ></div>--> <!-- <!– 弹出的 div 元素 –>--> <!-- <div--> <!-- v-show="popupVisible"--> <!-- class="triangle"--> <!-- :style="{--> <!-- position: 'absolute',--> <!-- left: `${graphicX}px`,--> <!-- top: `${graphicY}px`,--> <!-- backgroundColor: '#fff',--> <!-- padding: '10px',--> <!-- zIndex: 100--> <!-- }"--> <!-- >--> <!-- <p>审批人员: {{ nodeInfo.nickName }}</p>--> <!-- <p>节点状态:{{ nodeInfo.status }}</p>--> <!-- <p>开始时间:{{ nodeInfo.startTime }}</p>--> <!-- <p>结束时间:{{ nodeInfo.endTime }}</p>--> <!-- <p>审批耗时:{{ nodeInfo.runDuration }}</p>--> <!-- </div>--> <!-- <el-image :src="src" />--> <!-- </div>--> <!-- </div>--> <BpmnView ref="bpmnViewRef"></BpmnView> </el-tab-pane> <el-tab-pane label="审批信息" name="info"> <div> <el-table :data="historyList" style="width: 100%" border fit max-height="570"> <el-table-column type="index" label="序号" align="center" width="50"></el-table-column> <el-table-column prop="name" label="任务名称" sortable align="center"></el-table-column> <el-table-column prop="nickName" label="办理人" sortable align="center"></el-table-column> <el-table-column label="状态" sortable align="center"> <template #default="scope"> <el-tag type="success">{{ scope.row.statusName }}</el-tag> </template> </el-table-column> <el-table-column prop="comment" label="审批意见" sortable align="center"></el-table-column> <el-table-column prop="attachmentList" label="附件" sortable align="center"> <template #default="scope"> <el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click"> <template #reference> <el-button style="margin-right: 16px">附件</el-button> </template> <el-table border :data="scope.row.attachmentList"> <el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column> <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作"> <template #default="tool"> <el-button type="text" @click="handleDownload(tool.row.contentId)">下载</el-button> </template> </el-table-column> </el-table> </el-popover> </template> </el-table-column> <el-table-column prop="startTime" label="开始时间" sortable align="center"></el-table-column> <el-table-column prop="endTime" label="结束时间" sortable align="center"></el-table-column> <el-table-column prop="runDuration" label="运行时长" sortable align="center"></el-table-column> </el-table> </div> </div> </el-tab-pane> <el-tab-pane label="审批信息" name="info"> <div> <el-table :data="historyList" style="width: 100%" border fit max-height="570"> <el-table-column type="index" label="序号" align="center" width="50"></el-table-column> <el-table-column prop="name" label="任务名称" sortable align="center"></el-table-column> <el-table-column prop="nickName" label="办理人" sortable align="center"></el-table-column> <el-table-column label="状态" sortable align="center"> <template #default="scope"> <el-tag type="success">{{ scope.row.statusName }}</el-tag> </template> </el-table-column> <el-table-column prop="comment" label="审批意见" sortable align="center"></el-table-column> <el-table-column prop="attachmentList" label="附件" sortable align="center"> <template #default="scope"> <el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click"> <template #reference> <el-button style="margin-right: 16px">附件</el-button> </template> <el-table border :data="scope.row.attachmentList"> <el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column> <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作"> <template #default="tool"> <el-button type="text" @click="handleDownload(tool.row.contentId)">下载</el-button> </template> </el-table-column> </el-table> </el-popover> </template> </el-table-column> <el-table-column prop="startTime" label="开始时间" sortable align="center"></el-table-column> <el-table-column prop="endTime" label="结束时间" sortable align="center"></el-table-column> <el-table-column prop="runDuration" label="运行时长" sortable align="center"></el-table-column> </el-table> </div> </el-tab-pane> </el-tabs> </el-dialog> </el-tab-pane> </el-tabs> </el-dialog> </div> </template> <script lang="ts" setup> import BpmnView from '@/components/BpmnView/index.vue'; import processApi from '@/api/workflow/processInstance'; import { propTypes } from '@/utils/propTypes'; @@ -111,6 +115,8 @@ const graphicY = ref<number | string>(0); const tabActiveName = ref('bpmn'); const bpmnViewRef = ref<BpmnView>(); //初始化查询审批记录 const init = async (instanceId: string) => { visible.value = true; @@ -126,6 +132,9 @@ nodeListInfo.value = resp.data.nodeListInfo; deleteReason.value = resp.data.deleteReason; loading.value = false; }); await nextTick(() => { bpmnViewRef.value.init(instanceId); }); }; //悬浮事件 @@ -163,7 +172,7 @@ init }); </script> <style scoped> <style lang="scss" scoped> .triangle { box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); border-radius: 6px; @@ -177,4 +186,11 @@ border: 15px solid; border-color: transparent #fff transparent transparent; } .container { :deep(.el-dialog .el-dialog__body) { max-height: calc(100vh - 300px) !important; min-height: calc(100vh - 300px) !important; } } </style>