项目使用的react ant-design-pro版本 5.2.0
bpmn-js版本 6.3.4
注意: 不同版本的bpmn写法不一样,我这个写法是适用6.3.4的版本,较新的版本可能不适用
如果使用vue或其他框架,写法按照你框架的写法, bpmn-js调用的方法还是一样的
效果图: 查看流程图时,展示已审批过的,与当前正在审批的节点, 以不同颜色区分
实现步骤
- 引入BpmnViewer bpmn-js有提供流程图查看的方法,引入这个就好
import BpmnViewer from 'bpmn-js/lib/Viewer'
- 获取流程定义文件,渲染流程
interface viewProps {
info: any // 获取流程文件的参数
highLightData?: any // 高亮节点
height?: string // 流程图高度
}
const ViewBpmn: React.FC<viewProps> = ({ info, highLightData, height = '60vh' }) => {
const [bpmnModler, setBpmnModler] = useState<any>(null)
const bpmnRef = useRef<any>()
const createDiagram = async () => {
const xmlstr = await processDetail(info)
bpmnModler && bpmnModler.destroy && bpmnModler.destroy()
const newBpmn = new BpmnViewer({
container: bpmnRef.current,
height,
})
const canvas = newBpmn.get('canvas')
newBpmn.importXML(xmlstr, (err: string) => {
if (err) {
message.error(err)
} else {
canvas.zoom('fit-viewport', 'auto')
}
})
setBpmnModler(newBpmn)
}
return (
<Spin spinning={spinLoading} tip="正在加载...">
{info.instanceId ? (
<div className={styles.tip}>
<div className={styles.item}>
<div className={styles.susitem} />
<span>已审核</span>
</div>
<div className={styles.item}>
<div className={styles.proitem} />
<span>当前审核</span>
</div>
<div className={styles.item}>
<div className={styles.unitem} />
<span>待审核</span>
</div>
</div>
) : null}
<div id="canvas" ref={bpmnRef} className={styles.canvas} />
</Spin>
)
}
export default ViewBpmn
- 获取已审批和正在审批的节点与线段id,设置样式 我们这里拿到的数据是这样的,主要是节点与线的id
interface viewProps {
info: any
highLightData?: any // 高亮节点
height?: string // 流程图高度
}
const ViewBpmn: React.FC<viewProps> = ({ info, highLightData, height = '60vh' }) => {
const [bpmnModler, setBpmnModler] = useState<any>(null)
const bpmnRef = useRef<any>()
const createDiagram = async () => {
const xmlstr = await processDetail(info)
bpmnModler && bpmnModler.destroy && bpmnModler.destroy()
const newBpmn = new BpmnViewer({
container: bpmnRef.current,
height,
})
const canvas = newBpmn.get('canvas')
newBpmn.importXML(xmlstr, (err: string) => {
if (err) {
message.error(err)
} else {
canvas.zoom('fit-viewport', 'auto')
if (highLightData) {
const successIds = highLightData.highLine.concat(highLightData.highPoint)
const procesingIds = highLightData.waitingToDo
setNodeColor(successIds, newBpmn, 'nodeSuccess')
setNodeColor(procesingIds, newBpmn, 'nodeProcing')
}
}
})
setBpmnModler(newBpmn)
}
return (
<Spin spinning={spinLoading} tip="正在加载...">
{info.instanceId ? (
<div className={styles.tip}>
<div className={styles.item}>
<div className={styles.susitem} />
<span>已审核</span>
</div>
<div className={styles.item}>
<div className={styles.proitem} />
<span>当前审核</span>
</div>
<div className={styles.item}>
<div className={styles.unitem} />
<span>待审核</span>
</div>
</div>
) : null}
<div id="canvas" ref={bpmnRef} className={styles.canvas} />
</Spin>
)
}
export default ViewBpmn
- 设置不同颜色的样式,通过增加class类名来控制
// 设置节点颜色
const setNodeColor = (ids: any, newBpmn: any, colorClass: string) => {
const elementRegistry = newBpmn.get('elementRegistry')
ids.forEach((item: any) => {
if (elementRegistry._elements[item]) {
const element = elementRegistry._elements[item].gfx
element.classList.add(colorClass)
}
// console.log(elementRegistry, element)
})
}
- less样式文件
.canvas {
width: 100%;
height: 100%;
:global(.nodeSuccess .djs-visual > :nth-child(1)) {
stroke: #52c41a !important;
stroke-width: 3px;
}
:global(.nodeProcing .djs-visual > :nth-child(1)) {
stroke: #1890ff !important;
stroke-width: 3px;
}
}
package.json 版本
"dependencies": {
"@types/codemirror": "^5.60.5",
"antd": "^4.19.0",
"bpmn-js": "^6.3.4",
"bpmn-js-bpmnlint": "^0.15.0",
"bpmn-js-properties-panel": "^0.33.2",
"bpmn-moddle": "^6.0.0",
"bpmnlint": "^6.4.0",
"classnames": "^2.3.0",
"codemirror": "^5.59.2",
"react": "^17.0.0",
"react-codemirror2": "^7.2.1",
},
完整代码
import React, { useState, useEffect, useRef } from 'react'
import { Spin, message } from 'antd'
import { processDetail, processApprovalDetail } from '@/services'
import BpmnViewer from 'bpmn-js/lib/Viewer'
import styles from './index.less'
interface viewProps {
info: any
highLightData?: any
height?: string
}
const ViewBpmn: React.FC<viewProps> = ({ info, highLightData, height = '60vh' }) => {
const [spinLoading, setSpinLoading] = useState<boolean>(true)
const [bpmnModler, setBpmnModler] = useState<any>(null)
const bpmnRef = useRef<any>()
// 设置节点颜色
const setNodeColor = (ids: any, newBpmn: any, colorClass: string) => {
const elementRegistry = newBpmn.get('elementRegistry')
ids.forEach((item: any) => {
if (elementRegistry._elements[item]) {
const element = elementRegistry._elements[item].gfx
element.classList.add(colorClass)
}
// console.log(elementRegistry, element)
})
}
const createDiagram = (xmlstr: string) => {
bpmnModler && bpmnModler.destroy && bpmnModler.destroy()
const newBpmn = new BpmnViewer({
container: bpmnRef.current,
height,
})
const canvas = newBpmn.get('canvas')
newBpmn.importXML(xmlstr, (err: string) => {
if (err) {
message.error(err)
} else {
canvas.zoom('fit-viewport', 'auto')
if (highLightData) {
const successIds = highLightData.highLine.concat(highLightData.highPoint)
const procesingIds = highLightData.waitingToDo
setNodeColor(successIds, newBpmn, 'nodeSuccess')
setNodeColor(procesingIds, newBpmn, 'nodeProcing')
}
}
})
setBpmnModler(newBpmn)
}
const getProcessDetail = async () => {
let diagramXML
if (info.instanceId) {
// 如果是审批详情
diagramXML = await processApprovalDetail(info.instanceId)
} else {
diagramXML = await processDetail(info)
}
createDiagram(diagramXML)
setSpinLoading(false)
}
useEffect(() => {
getProcessDetail()
}, [])
return (
<Spin spinning={spinLoading} tip="正在加载...">
{info.instanceId ? (
<div className={styles.tip}>
<div className={styles.item}>
<div className={styles.susitem} />
<span>已审核</span>
</div>
<div className={styles.item}>
<div className={styles.proitem} />
<span>当前审核</span>
</div>
<div className={styles.item}>
<div className={styles.unitem} />
<span>待审核</span>
</div>
</div>
) : null}
<div id="canvas" ref={bpmnRef} className={styles.canvas} />
</Spin>
)
}
export default ViewBpmn