因为这个项目license问题无法开源,更多技术支持与服务请加入我的知识星球。
1、因为之前ProcessViewer是vue2的组件版本,平时显示也还正常,但在历史记录的时候老是出现下面的问题。
就是第一次进去在panel点击流程图的时候不会出现,拖拉一下就会出现,看了一下代码也没有任何问题,但就是这个情况,或者放大缩小一下也可以出现,找了半天找不到原因。
2、在没有办法只好修改成vue3看看效果,修改成如下:
javascript
<template>
<div class="process-viewer">
<div class="process-canvas" style="height: 100%;" ref="processCanvas" v-show="!isLoading" />
<!-- 自定义箭头样式,用于已完成状态下流程连线箭头 -->
<defs ref="customDefs">
<marker id="sequenceflow-end-white-success" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto">
<path class="success-arrow" d="M 1 5 L 11 10 L 1 15 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
</marker>
<marker id="conditional-flow-marker-white-success" viewBox="0 0 20 20" refX="-1" refY="10" markerWidth="10" markerHeight="10" orient="auto">
<path class="success-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
</marker>
</defs>
<!-- 自定义箭头样式,用于失败状态下流程连线箭头 -->
<defs ref="customFailDefs">
<marker id="sequenceflow-end-white-fail" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto">
<path class="fail-arrow" d="M 1 5 L 11 10 L 1 15 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
</marker>
<marker id="conditional-flow-marker-white-fail" viewBox="0 0 20 20" refX="-1" refY="10" markerWidth="10" markerHeight="10" orient="auto">
<path class="fail-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z" style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;"></path>
</marker>
</defs>
<!-- 已完成节点悬浮弹窗 -->
<el-dialog class="comment-dialog" :title="dlgTitle || '审批记录'" v-model="dialogVisible">
<el-row>
<el-table :data="taskCommentList" border header-cell-class-name="table-header-gray">
<el-table-column label="序号" header-align="center" align="center" type="index" width="55px" />
<el-table-column label="候选办理" prop="candidate" width="150px" align="center" />
<el-table-column label="实际办理" prop="assigneeName" width="100px" align="center" />
<el-table-column label="处理时间" prop="createTime" width="140px" align="center" />
<el-table-column label="办结时间" prop="endTime" width="140px" align="center" />
<el-table-column label="耗时" prop="duration" width="100px" align="center" />
<el-table-column label="审批意见" align="center">
<template #default="scope">
{{scope.row.commentList&&scope.row.commentList[0]?scope.row.commentList[0].fullMessage:''}}
</template>
</el-table-column>
</el-table>
</el-row>
</el-dialog>
<div style="position: absolute; top: 0; left: 0; width: 100%;">
<el-row type="flex" justify="end">
<el-button-group key="scale-control">
<el-button :plain="true" :disabled="defaultZoom <= 0.3" icon="ZoomOut" @click="processZoomOut()" />
<el-button style="width: 90px;">{{ Math.floor(defaultZoom * 10 * 10) + "%" }}</el-button>
<el-button :plain="true" :disabled="defaultZoom >= 3.9" icon="ZoomIn" @click="processZoomIn()" />
<el-button icon="ScaleToOriginal" @click="processReZoom()" />
<slot />
</el-button-group>
</el-row>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, toRaw, watch, onBeforeUnmount } from 'vue';
import '@/package/theme/index.scss';
import BpmnViewer from 'bpmn-js/lib/Viewer';
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
defineOptions({ name: 'ProcessViewer' })
const props = defineProps({
xml: {
type: String
},
finishedInfo: {
type: Object
},
// 所有节点审批记录
allCommentList: {
type: Array
}
})
const processCanvas = ref(null)
const customDefs = ref(null)
const dialogVisible = ref(false)
const dlgTitle = ref(undefined)
const defaultZoom = ref(1)
// 是否正在加载流程图
const isLoading = ref(false)
const bpmnViewer = ref(undefined)
// 已完成流程元素
const processNodeInfo = ref(undefined)
// 当前任务id
const selectTaskId = ref(undefined)
// 任务节点审批记录
const taskCommentList = ref([])
// 已完成任务悬浮延迟Timer
const hoverTimer = ref(null)
const SysFlowTaskOperationType =ref('')
const processReZoom = () => {
defaultZoom.value = 1;
bpmnViewer.value.get('canvas').zoom('fit-viewport', 'auto');
}
const processZoomIn = (zoomStep = 0.1) => {
let newZoom = Math.floor(defaultZoom.value * 100 + zoomStep * 100) / 100;
if (newZoom > 4) {
throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4');
}
defaultZoom.value = newZoom;
bpmnViewer.value.get('canvas').zoom(defaultZoom.value);
}
const processZoomOut = (zoomStep = 0.1) => {
let newZoom = Math.floor(defaultZoom.value * 100 - zoomStep * 100) / 100;
if (newZoom < 0.2) {
throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2');
}
defaultZoom.value = newZoom;
bpmnViewer.value.get('canvas').zoom(defaultZoom.value);
}
// 流程图预览清空
const clearViewer = () => {
if (processCanvas.value) processCanvas.value.innerHTML = '';
if (bpmnViewer.value) bpmnViewer.value.destroy();
bpmnViewer.value = null;
}
// 添加自定义箭头
const addCustomDefs = () => {
const canvas = bpmnViewer.value.get('canvas');
const svg = canvas._svg;
svg.appendChild(customDefs.value);
}
// 任务悬浮弹窗
const onSelectElement = (element) => {
selectTaskId.value = undefined;
dlgTitle.value = undefined;
if (processNodeInfo.value == null || processNodeInfo.value.finishedTaskSet == null) return;
if (element == null || processNodeInfo.value.finishedTaskSet.indexOf(element.id) === -1) {
return;
}
if (props.allCommentList == null) {//临时解决,以后可以传入
return;
}
selectTaskId.value = element.id;
dlgTitle.value = element.businessObject ? element.businessObject.name : undefined;
// 计算当前悬浮任务审批记录,如果记录为空不显示弹窗
console.log("props.allCommentList",props.allCommentList)
taskCommentList.value = (toRaw(props.allCommentList)).filter(item => {
console.log("item",item)
console.log("selectTaskId.value",selectTaskId.value)
return item.activityId === selectTaskId.value;
});
console.log("taskCommentList.value ",taskCommentList.value)
dialogVisible.value = true;
}
// 显示流程图
const importXML = async (xml) => {
clearViewer();
if (xml != null && xml !== '') {
try {
bpmnViewer.value = new BpmnViewer({
additionalModules: [
// 支持移动拖动整个画布
MoveCanvasModule
],
container: processCanvas.value,
});
// 任务节点悬浮事件
bpmnViewer.value.on('element.click', ({ element }) => {
onSelectElement(element);
});
// 注册需要的监听事件
bpmnViewer.value.on('element.hover', ({ element }) => {
elementHover(element);
});
bpmnViewer.value.on('element.out', ({ element }) => {
elementOut(element);
});
isLoading.value = true;
await bpmnViewer.value.importXML(xml);
addCustomDefs();
} catch (e) {
console.error(e);
clearViewer();
} finally {
isLoading.value = false;
setProcessStatus(processNodeInfo.value);
}
}
}
const elementHover = (element) => {
if (element === null) {
return;
}
if (toRaw(props.allCommentList) == null) { //临时解决,以后可以传入
return;
}
const overlays = bpmnViewer.value.get("overlays");
const commentAllList = toRaw(props.allCommentList)
let { finishedTaskSet } = processNodeInfo.value;
if (element.type !== "bpmn:Process" && finishedTaskSet.indexOf(element.id) > -1) {
let html = ``; // 默认值
if (element.type === "bpmn:StartEvent") {
commentAllList.forEach(comment => {
if (comment.activityId === element.id) {
html += `<p>发起人:${comment.assigneeName}</p>
<p>创建时间:${comment.createTime}</p>`;
}
});
} else if (element.type === "bpmn:UserTask") {
commentAllList.forEach(comment => {
if (comment.activityId === element.id && comment.commentList[0]) {
html += `<p>审批人:${comment.assigneeName}</p>
<p>审批意见:${comment.commentList && comment.commentList[0] ? comment.commentList[0].fullMessage : ""}</p>
<p>审批时间:${comment.endTime}</p>
<p>-----------------------------------------</p>`;
}
});
} else if (element.type === "bpmn:EndEvent") {
commentAllList.forEach(comment => {
if (comment.activityId === element.id) {
html = `<p>结束时间:${comment.endTime}</p>`;
}
});
}
overlays.add(element, {
position: { left: 0, bottom: 0 },
html: `<div class="element-overlays">${html} </div>`
});
}
}
const elementOut = (element) => {
if (element === null) {
return;
}
const overlays = bpmnViewer.value.get("overlays");
overlays.remove({ element });
}
// 设置流程图元素状态
const setProcessStatus = (pNodeInfo) => {
processNodeInfo.value = pNodeInfo;
if (isLoading.value || processNodeInfo.value == null || bpmnViewer.value == null) return;
let { finishedSequenceFlowSet, finishedTaskSet, unfinishedTaskSet } = processNodeInfo.value;
const canvas = bpmnViewer.value.get('canvas');
const elementRegistry = bpmnViewer.value.get('elementRegistry');
if (Array.isArray(finishedSequenceFlowSet)) {
finishedSequenceFlowSet.forEach(item => {
if (item != null && item != 'newSequenceFlowId') { //去掉之前收回创建的id
canvas.addMarker(item, 'success');
let element = elementRegistry.get(item);
const conditionExpression = element.businessObject.conditionExpression;
if (conditionExpression) {
canvas.addMarker(item, 'condition-expression');
}
}
});
}
if (Array.isArray(finishedTaskSet)) {
finishedTaskSet.forEach(item => {
canvas.addMarker(item, 'success');
});
}
if (Array.isArray(unfinishedTaskSet)) {
unfinishedTaskSet.forEach(item => {
canvas.addMarker(item, 'current');
});
}
}
watch(
() => props.xml,
(newXml) => {
importXML(newXml)
},
{ immediate: true }
)
watch(
() => props.finishedInfo,
(newInfo) => {
setProcessStatus(newInfo)
},
{ immediate: true }
)
onBeforeUnmount(() => {
clearViewer()
})
</script>
<style scoped>
.comment-dialog :deep() .el-dialog__body {
padding: 0px;
}
.element-overlays {
position: relative;
box-sizing: border-box;
padding: 8px;
background: rgba(0, 0, 0, 0.6);
border-radius: 4px;
color: #fafafa;
width: 320px;
}
</style>
3、修改后进行测试,果然正常了,不知道是什么原因引起之前的问题,目前还不得而知。