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

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

注意: 不同版本的bpmn写法不一样,我这个写法是适用6.3.4的版本,较新的版本可能不适用
如果使用vue或其他框架,写法按照你框架的写法, bpmn-js调用的方法还是一样的

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

 

实现步骤
1. 引入BpmnViewer  bpmn-js有提供流程图查看的方法,引入这个就好
import BpmnViewer from 'bpmn-js/lib/Viewer'
2. 获取流程定义文件,渲染流程
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
3. 获取已审批和正在审批的节点与线段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
4. 设置不同颜色的样式,通过增加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)
    })
  }
5. 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",
    "@umijs/route-utils": "^2.0.0",
    "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",
    "braft-editor": "^2.3.9",
    "classnames": "^2.3.0",
    "codemirror": "^5.59.2",
    "echarts": "^5.3.2",
    "file-saver": "^2.0.5",
    "js-cookie": "^3.0.1",
    "lodash": "^4.17.0",
    "moment": "^2.29.0",
    "omit.js": "^2.0.2",
    "rc-menu": "^9.1.0",
    "rc-util": "^5.16.0",
    "react": "^17.0.0",
    "react-codemirror2": "^7.2.1",
    "react-dev-inspector": "^1.7.0",
    "react-dom": "^17.0.0",
    "react-helmet-async": "^1.2.0",
    "umi": "^3.5.0",
    "umi-plugin-keep-alive": "^0.0.1-beta.30"
  },
  "devDependencies": {
    "@ant-design/pro-cli": "^2.1.0",
    "@playwright/test": "^1.17.0",
    "@types/express": "^4.17.0",
    "@types/history": "^4.7.0",
    "@types/jest": "^26.0.0",
    "@types/lodash": "^4.14.0",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@types/react-helmet": "^6.1.0",
    "@umijs/fabric": "^2.8.0",
    "@umijs/openapi": "^1.3.0",
    "@umijs/plugin-blocks": "^2.2.0",
    "@umijs/plugin-esbuild": "^1.4.0",
    "@umijs/plugin-openapi": "^1.3.0",
    "@umijs/preset-ant-design-pro": "^1.3.0",
    "@umijs/preset-dumi": "^1.1.0",
    "@umijs/preset-react": "^2.1.0",
    "cross-env": "^7.0.0",
    "cross-port-killer": "^1.3.0",
    "detect-installer": "^1.0.0",
    "eslint": "^7.32.0",
    "gh-pages": "^3.2.0",
    "husky": "^7.0.4",
    "jsdom-global": "^3.0.0",
    "lint-staged": "^10.0.0",
    "mockjs": "^1.1.0",
    "prettier": "^2.5.0",
    "stylelint": "^13.0.0",
    "swagger-ui-react": "^3.52.0",
    "typescript": "^4.5.0",
    "umi-serve": "^1.9.10"
  },
完整代码
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

 

posted @ 2022-07-22 18:00  潇湘羽西  阅读(5158)  评论(0编辑  收藏  举报