bpmn-js 流程图查看设置节点颜色

1,701 阅读2分钟

项目使用的react  ant-design-pro版本 5.2.0

bpmn-js版本  6.3.4

注意: 不同版本的bpmn写法不一样,我这个写法是适用6.3.4的版本,较新的版本可能不适用

如果使用vue或其他框架,写法按照你框架的写法, bpmn-js调用的方法还是一样的

效果图: 查看流程图时,展示已审批过的,与当前正在审批的节点, 以不同颜色区分

bpmn1.jpg

实现步骤

  1. 引入BpmnViewer  bpmn-js有提供流程图查看的方法,引入这个就好
import BpmnViewer from 'bpmn-js/lib/Viewer'
  1. 获取流程定义文件,渲染流程
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
  1. 获取已审批和正在审批的节点与线段id,设置样式  我们这里拿到的数据是这样的,主要是节点与线的id

bpmn2.jpg

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
  1. 设置不同颜色的样式,通过增加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)
    })
  }
  1. 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