activiti7+bpmn.js+react

1、引入包

<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M4</version>
        </dependency>
        <dependency>
            <groupId>org.activiti.dependencies</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>7.1.0.M4</version>
            <type>pom</type>
        </dependency>

2、spring boot 配置文件:spring  下追加:如果不加 好像没有历史表

  activiti:
    historyLevel: audit
    db-history-used: true

3 、修改表结构

alter table ACT_RE_DEPLOYMENT add  PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add  VERSION_ varchar(255) DEFAULT NULL;

配置文件中加一笔:

流程发布:

其中xmlBPMN:

<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="m1605802588480" name="" targetNamespace="http://www.activiti.org/test">  <process id="Process_1" isExecutable="true">    <startEvent id="StartEvent_1y45yut" name="开始">      <outgoing>Flow_0jfbnmb</outgoing>    </startEvent>    <userTask id="Activity_1w1vj9r" name="username1" activiti:formKey="kkk" activiti:assignee="1" activiti:candidateUsers="candidateUsers" activiti:candidateGroups="candidateGroups">      <extensionElements>        <activiti:formData>          <activiti:formProperty id="formProperty_3slq4mu" />        </activiti:formData>        <activiti:properties>          <activiti:property />        </activiti:properties>      </extensionElements>      <incoming>Flow_0jfbnmb</incoming>      <outgoing>Flow_1nolku9</outgoing>    </userTask>    <sequenceFlow id="Flow_0jfbnmb" sourceRef="StartEvent_1y45yut" targetRef="Activity_1w1vj9r" />    <endEvent id="Event_0ahqy2x" name="e">      <incoming>Flow_1nolku9</incoming>    </endEvent>    <sequenceFlow id="Flow_1nolku9" sourceRef="Activity_1w1vj9r" targetRef="Event_0ahqy2x" />  </process>  <bpmndi:BPMNDiagram id="BpmnDiagram_1">    <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">      <bpmndi:BPMNEdge id="Flow_1nolku9_di" bpmnElement="Flow_1nolku9">        <omgdi:waypoint x="400" y="120" />        <omgdi:waypoint x="542" y="120" />      </bpmndi:BPMNEdge>      <bpmndi:BPMNEdge id="Flow_0jfbnmb_di" bpmnElement="Flow_0jfbnmb">        <omgdi:waypoint x="188" y="120" />        <omgdi:waypoint x="300" y="120" />      </bpmndi:BPMNEdge>      <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_1y45yut">        <omgdc:Bounds x="152" y="102" width="36" height="36" />        <bpmndi:BPMNLabel>          <omgdc:Bounds x="160" y="145" width="22" height="14" />        </bpmndi:BPMNLabel>      </bpmndi:BPMNShape>      <bpmndi:BPMNShape id="Activity_1w1vj9r_di" bpmnElement="Activity_1w1vj9r">        <omgdc:Bounds x="300" y="80" width="100" height="80" />      </bpmndi:BPMNShape>      <bpmndi:BPMNShape id="Event_0ahqy2x_di" bpmnElement="Event_0ahqy2x">        <omgdc:Bounds x="542" y="102" width="36" height="36" />        <bpmndi:BPMNLabel>          <omgdc:Bounds x="557" y="145" width="7" height="14" />        </bpmndi:BPMNLabel>      </bpmndi:BPMNShape>    </bpmndi:BPMNPlane>  </bpmndi:BPMNDiagram></definitions>

启动流程:  

完成任务:

工具流程实例查询:

流程定义:

 

前端:采取bpmn.js

 

bpmn.js汉化

 

放一排图标到顶部:

找到保存的方法?

  1. 初始化一个空白设计页面 

       搞个空的流程,结果属性面板没显示?算了 先这样

  1. 向后传递 如何设置名字
  2. 设置用户
  3. 查看设计好的工作流
  4. 我发起的入围
  5. 待我执行的任务
  6. 我完成的流程
  7. 流程归档
  8. 和表单关联

import导入包

 

新的工作流设计器:

bpmnDesign.js

import React, { useEffect, useRef, useState, useImperativeHandle, forwardRef } from 'react';
import BpmnModeler from 'bpmn-js/lib/Modeler';
// 以下为bpmn工作流绘图工具的样式
import 'bpmn-js/dist/assets/diagram-js.css' // 左边工具栏以及编辑节点的样式
import 'bpmn-js-bpmnlint/dist/assets/css/bpmn-js-bpmnlint.css' // bpmnlint

import lintModule from 'bpmn-js-bpmnlint';
import * as bpmnlintConfig from './packed-config';


import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css' // 右边工具栏样式

//為右邊屬性
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
import {Button, Col, Divider, Input, Modal, Row, Space, List, message, Table, Form} from 'antd';
import customTranslateModule from '../BpmnEditor/Modeler/customTranslate';
import getDefaultXml from '../BpmnEditor/sources/xml';
import {Link} from "react-router-dom";



import {
    SearchOutlined,
    ZoomInOutlined,
    ZoomOutOutlined,
    SaveOutlined,
    ExportOutlined,
    VideoCameraOutlined,
    UploadOutlined,
    TagOutlined,
    CheckOutlined,
IssuesCloseOutlined
} from '@ant-design/icons';

import {addByString, getDefinitions} from "../api/workflow";
import { getUserList } from "../api/Security";
import {withRouter} from 'react-router-dom';
import WorkflowDesign from "./workflowDesign";
export default function BpmnDesign() {
    // let bpmnModeler=null;
    //const  [mybpmnModeler, setMybpmnModeler] =  useState(null); //所有用户列表 供选择人使用
    const modelerRef = useRef(null);

    const  [users, setUsers] =  useState([]); //所有用户列表 供选择人使用
    //
    //控制可见性
    const  [modalvisiable, setModalvisiable] =  useState(false);  //modal可见性
    // const  [selectedRowKeys,setSelectedRowKeys] =  useState([]);  //选择的人
    const  [selectedUserId,setSelectedUserId] =  useState(-1);  //选择的人
    const  [selectedUserName,setSelectedName] =  useState("");  //选择的人的名字
    const [selectElement,setSelectElement] =  useState(null);  //选择usertask节点
    const [activeNodeEle, setActiveNode] = useState(null);  //代替上一行的内容
    const [lintActive,setLintActive]= useState(false);


    useEffect(()=>{
        initBpmn();
    },[])

    // var customTranslateModule = {
    //     translate: [ 'value', customTranslate ]
    // };

    const columns = [
        {
            title: 'id',
            dataIndex: 'userid',
            key: 'userid',
        },
        {
            title: '用户名',
            dataIndex: 'name',
            key: 'name',
        },
        {
            title: '启用状态',
            dataIndex: 'userFlag',
            key: 'userFlag',
        }
    ];


const  initBpmn=()=>{

    modelerRef.current =
        new BpmnModeler({
            container:"#canvas",
            //添加控制板
            propertiesPanel: {
                parent: '#js-properties-panel'
            },
            additionalModules: [
                // 右边的属性栏
                customTranslateModule,
                propertiesProviderModule,
                propertiesPanelModule,
                lintModule
            ],
            linting: {
                bpmnlint: bpmnlintConfig,
                active:false  //如果要检查 要配置这里
            },
            moddleExtensions: {
                camunda: camundaModdleDescriptor
            },
            height:'100vh'
        })

    const logo = document.querySelector('.bjs-powered-by');
    const bpmnContainer = document.querySelector('.bjs-container');
    if (bpmnContainer && logo) {
        bpmnContainer.removeChild(logo);
    }
    renderDiagram();
    getUsers();  //获取全部用户信息 为选择用户做准备
    addListener();  //模型上追加监听器
}


    const initActiveNode = () => {
        const canvas = modelerRef.current.get('canvas');
        const rootElement = canvas.getRootElement();
        setActiveNode(rootElement);
    };

// const createBpmnDiagram= async ()=>{
//         let xmlStr2="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:camunda=\"http://camunda.org/schema/1.0/bpmn\" xmlns:activiti=\"http://activiti.org/bpmn\" xmlns:tns=\"http://www.activiti.org/test\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" id=\"m1605802588480\" name=\"\" targetNamespace=\"http://www.activiti.org/test\">\\n  <process id=\"Process_1\" isExecutable=\"true\">\\n    <startEvent id=\"StartEvent_1y45yut\" name=\"开始\">\\n      <outgoing>Flow_0jfbnmb</outgoing>\\n    </startEvent>\\n    <userTask id=\"Activity_1w1vj9r\" name=\"username1\" activiti:formKey=\"kkk\" activiti:assignee=\"1\" activiti:candidateUsers=\"candidateUsers\" activiti:candidateGroups=\"candidateGroups\">\\n      <extensionElements>\\n        <activiti:formData>\\n          <activiti:formProperty id=\"formProperty_3slq4mu\" />\\n        </activiti:formData>\\n        <activiti:properties>\\n          <activiti:property />\\n        </activiti:properties>\\n      </extensionElements>\\n      <incoming>Flow_0jfbnmb</incoming>\\n      <outgoing>Flow_1nolku9</outgoing>\\n    </userTask>\\n    <sequenceFlow id=\"Flow_0jfbnmb\" sourceRef=\"StartEvent_1y45yut\" targetRef=\"Activity_1w1vj9r\" />\\n    <endEvent id=\"Event_0ahqy2x\" name=\"e\">\\n      <incoming>Flow_1nolku9</incoming>\\n    </endEvent>\\n    <sequenceFlow id=\"Flow_1nolku9\" sourceRef=\"Activity_1w1vj9r\" targetRef=\"Event_0ahqy2x\" />\\n  </process>\\n  <bpmndi:BPMNDiagram id=\"BpmnDiagram_1\">\\n    <bpmndi:BPMNPlane id=\"BpmnPlane_1\" bpmnElement=\"Process_1\">\\n      <bpmndi:BPMNEdge id=\"Flow_0jfbnmb_di\" bpmnElement=\"Flow_0jfbnmb\">\\n        <omgdi:waypoint x=\"188\" y=\"120\" />\\n        <omgdi:waypoint x=\"300\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNEdge id=\"Flow_1nolku9_di\" bpmnElement=\"Flow_1nolku9\">\\n        <omgdi:waypoint x=\"400\" y=\"120\" />\\n        <omgdi:waypoint x=\"542\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNShape id=\"StartEvent_1y45yut_di\" bpmnElement=\"StartEvent_1y45yut\">\\n        <omgdc:Bounds x=\"152\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"160\" y=\"145\" width=\"22\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Activity_1w1vj9r_di\" bpmnElement=\"Activity_1w1vj9r\">\\n        <omgdc:Bounds x=\"300\" y=\"80\" width=\"100\" height=\"80\" />\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Event_0ahqy2x_di\" bpmnElement=\"Event_0ahqy2x\">\\n        <omgdc:Bounds x=\"542\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"557\" y=\"145\" width=\"7\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n    </bpmndi:BPMNPlane>\\n  </bpmndi:BPMNDiagram>\\n</definitions>\n";
//          mybpmnModeler.importXML(xmlStr2);
//          const diagramXML = getDefaultXml();
//          //this.renderDiagram(diagramXML);
//         try {
//         //const result = await bpmnModeler.importXML(xmlStr2);
//     } catch (e) {
//         console.error(e);
//     }
//     }


    const renderDiagram = () => {
        //let XML="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:camunda=\"http://camunda.org/schema/1.0/bpmn\" xmlns:activiti=\"http://activiti.org/bpmn\" xmlns:tns=\"http://www.activiti.org/test\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" id=\"m1605802588480\" name=\"\" targetNamespace=\"http://www.activiti.org/test\">\\n  <process id=\"Process_1\" isExecutable=\"true\">\\n    <startEvent id=\"StartEvent_1y45yut\" name=\"开始\">\\n      <outgoing>Flow_0jfbnmb</outgoing>\\n    </startEvent>\\n    <userTask id=\"Activity_1w1vj9r\" name=\"username1\" activiti:formKey=\"kkk\" activiti:assignee=\"1\" activiti:candidateUsers=\"candidateUsers\" activiti:candidateGroups=\"candidateGroups\">\\n      <extensionElements>\\n        <activiti:formData>\\n          <activiti:formProperty id=\"formProperty_3slq4mu\" />\\n        </activiti:formData>\\n        <activiti:properties>\\n          <activiti:property />\\n        </activiti:properties>\\n      </extensionElements>\\n      <incoming>Flow_0jfbnmb</incoming>\\n      <outgoing>Flow_1nolku9</outgoing>\\n    </userTask>\\n    <sequenceFlow id=\"Flow_0jfbnmb\" sourceRef=\"StartEvent_1y45yut\" targetRef=\"Activity_1w1vj9r\" />\\n    <endEvent id=\"Event_0ahqy2x\" name=\"e\">\\n      <incoming>Flow_1nolku9</incoming>\\n    </endEvent>\\n    <sequenceFlow id=\"Flow_1nolku9\" sourceRef=\"Activity_1w1vj9r\" targetRef=\"Event_0ahqy2x\" />\\n  </process>\\n  <bpmndi:BPMNDiagram id=\"BpmnDiagram_1\">\\n    <bpmndi:BPMNPlane id=\"BpmnPlane_1\" bpmnElement=\"Process_1\">\\n      <bpmndi:BPMNEdge id=\"Flow_0jfbnmb_di\" bpmnElement=\"Flow_0jfbnmb\">\\n        <omgdi:waypoint x=\"188\" y=\"120\" />\\n        <omgdi:waypoint x=\"300\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNEdge id=\"Flow_1nolku9_di\" bpmnElement=\"Flow_1nolku9\">\\n        <omgdi:waypoint x=\"400\" y=\"120\" />\\n        <omgdi:waypoint x=\"542\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNShape id=\"StartEvent_1y45yut_di\" bpmnElement=\"StartEvent_1y45yut\">\\n        <omgdc:Bounds x=\"152\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"160\" y=\"145\" width=\"22\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Activity_1w1vj9r_di\" bpmnElement=\"Activity_1w1vj9r\">\\n        <omgdc:Bounds x=\"300\" y=\"80\" width=\"100\" height=\"80\" />\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Event_0ahqy2x_di\" bpmnElement=\"Event_0ahqy2x\">\\n        <omgdc:Bounds x=\"542\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"557\" y=\"145\" width=\"7\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n    </bpmndi:BPMNPlane>\\n  </bpmndi:BPMNDiagram>\\n</definitions>\n";
       const XML = getDefaultXml();
        modelerRef.current.importXML(XML, (err) => {
            if (err) {
                Modal.error({ title: 'XML解析失败' });
                return false;
            }
            initActiveNode();
            return true;
        });
    };


  const  getUsers=()=>{
      getUserList().then(
          (res) => {
              setUsers(res.data);
          },
          (error) => {
              console.log("get UserList failed!");
          }
      );
  }

  //追加监听器
  const addListener=()=>{
      addModelerListener();
      addEventBusListener();
  }




    const addEventBusListener=()=>{
        const bpmnjs = modelerRef.current;
        const eventBus = bpmnjs.get('eventBus');
        eventBus.on('element.click', function(e) {
            elementClick(e);
        });
    }


    const addModelerListener = () => {
        const bpmnjs = modelerRef.current;
        //const events = ['element.click', 'element.changed'];
        const events = ['element.click'];
        events.forEach((eventType) => {
            bpmnjs.on(eventType, (e) => {
                const { element } = e;
                const { type } = element;
                if (type !== 'label') {
                    setActiveNode(element);
                }
            });
        });
    };

    // const addModelerListener=()=>{
    //   // bpmnModeler.on('element.click', e => {
    //   //       console.log('modelerListener', e);
    //   //   });
    // }


   const elementClick=(e)=> {
       const bpmnjs = modelerRef.current;
      //  let modeling = bpmnjs.get('modeling');
        if (e.element.businessObject.$type === 'bpmn:StartEvent') {
            console.log(
                '这是一个开始节点',
                e.element.businessObject.id,
                e.element.businessObject.$type,
                e.element.businessObject.name
            );
            // 修改节点ID
            // modeling.updateProperties(e.element, {
            //     id: 'StartEvent_ops_coffee'
            // });
        }
        if (e.element.businessObject.$type === 'bpmn:UserTask') {
            console.log(
                '这是一个用户节点',
                e.element.businessObject.id,
                e.element.businessObject.$type,
                e.element.businessObject.name
            );
            //this.selectElement = e.element;
            setSelectElement(e.element);    //选中的元素
            //this.setColumnDialogVisible = true;
            //console.log(this.selectElement);
            //修改节点名称
            // modeling.updateProperties(e.element, {
            //   name: this.user.id
            // });
        }else{
            setSelectElement(null);
        }
    }

    const container = {
        width: "100%",
        height:"100%"
    };
    const bpmnDesignClass = {
        minHeight: "100vh",
    };

    const properties_panel = {
        // position:"absolute",
        // right:"0",
        // top:"0",
        // width:"300px"
    };



//get xml
    const getBpmnXML = async () => {
        const bpmnModeler = modelerRef.current;
        return new Promise((resolve, reject) => {
            bpmnModeler.saveXML({ format: true }, (err, xml) => {
                if (err) {
                    reject(err);
                }
                resolve(xml);
            });
        });
    };

    const onSave = async () => {
        const xml = await getBpmnXML();
        addByString(xml).then(
            (res) => {
                message.success('保存成功');
            },
            (error) => {
                message.error('failed');
                console.log("get response failed!");
            }
        );
    };
    const saveDiagram = () => {
       //verify  by lint?
        const bpmnModeler = modelerRef.current;
        const linting = bpmnModeler.get('linting');
        const { _button, _active } = linting;
        if (!_active) {
            linting.toggle();
            message.success('开启流程检查!');
            return;
        }
        const { innerText } = _button;
        const errorTexts = Number(innerText.split(' Errors')[0]);
        if (errorTexts > 0) {
            message.success('流程有错误,无法保存,请检查!');
            return;
        }



        onSave().then(
            console.log("saveDiagram!")
        );
    };
//选择雇员
    const SearchEmp= () => {
        if(selectElement==null){
          setModalvisiable(false);
            setSelectedUserId(-1);
      }else {
          setModalvisiable(true);

          setSelectedUserId(-1);

      }
    };

    const  returnDefList=()=>{
        // BrowserRouter.context.routes.push('/main/tool/processDef');
        //history.push('/main/tool/processDef')
    }


    const  cancelModal=()=>{
       setModalvisiable(false);
    }

    const onSelectChange = selectedRowKeys => {
        console.log('selectedRowKeys changed: ', selectedRowKeys);
        setSelectedRowKeys(selectedRowKeys );
    };

    // const rowSelection = {
    //     selectedRowKeys,
    //     onChange: onSelectChange,
    // };

    const  rowSelection = {
        onChange: (selectedRowKeys, selectedRows) => {
             console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
        },
        onSelect: (record, selected, selectedRows) => {
            if(selected){
                // this.setState({
                //     selectedUserId: record.userid,
                // });
                setSelectedUserId( record.userid);
                //setSelectedName( record.name);
            }
        },
    };


//选择确定
    const selConfirm = ()=>{
        const bpmnModeler = modelerRef.current;
        //选择的用户
       //  if(selectedRowKeys.length==0){return}
       //  let uId=selectedRowKeys[0];
       //
       //  let t=users.filter(item=>item.userid=uId);
       //
       // if (t.length==0) return;

        if (selectedUserId==-1){
            message.info("请选择一个用户")
            return;
        }



        let modeling = bpmnModeler.get('modeling');
        modeling.updateProperties(selectElement, {
            name: selectedUserId+"",
            //执行人
            assignee: selectedUserId+"" ,
            //候选人
           // candidateUsers:'candidateUsers',
            //候选组
           // candidateGroups:'candidateGroups'
        });
        setModalvisiable(false);
    };

    const  checkBPMN=()=>{
        const bpmnModeler = modelerRef.current;
        const linting = bpmnModeler.get('linting');
        const { _button, _active } = linting;
        if (!_active) {
            linting.toggle();
            message.success('开启流程检查!');
            return;
        }
    }

    const closeCheckBPMN=()=>{
        const bpmnModeler = modelerRef.current;
        const linting = bpmnModeler.get('linting');
        const { _button, _active } = linting;
        if (_active) {
            linting.toggle();
            message.success('关闭流程检查!');
            return;
        }
    }
return(
    <>
    <div className={bpmnDesignClass}>

        <Row justify={"center"}>
            <Button icon={<SearchOutlined/>} key={"SearchEmp"}
                    onClick={() => SearchEmp()}
            />
            <Button icon={<ZoomInOutlined />} key={"zoomin"}

            />
            <Button icon={<ZoomOutOutlined />} key={"zoomout"}/>
            <Button icon={<CheckOutlined />} key={"CheckOutlined"}
                    onClick={() => checkBPMN()}
            />
            <Button icon={ <IssuesCloseOutlined />} key={"IssuesCloseOutlined"}
                    onClick={() => closeCheckBPMN()}
            />



            <Button icon={<SaveOutlined />} key={"SaveOutlined"}
             onClick={() => saveDiagram()}
            />
            <Link to={"/main/tool/processDef"}>
                <Button icon={<ExportOutlined />} key={"ExportOutlined"}/>
            </Link>
        </Row>

        <Row>
        <Col span={18}>
            <div id="canvas" className={container}>
            </div>
        </Col>


        <Col span={6}>
            <div
                className={properties_panel}
                id="js-properties-panel"
                style={{ height: '100%' }}
            />
        </Col>

        </Row>
    </div>

        <Modal
            width={600}
            title="选择审批人"
            visible={modalvisiable}
            cancelText='返回'
            onCancel={cancelModal}
            footer={null}
        >
            <Table
                //rowKey={record => record.userid}
                     // rowSelection={rowSelection}

                     rowSelection={{
                         type: "radio",
                         ...rowSelection,
                     }}
                     rowKey="userid"
                     columns={columns}
                     dataSource={users} />

            <Row>
                <Col span={16}></Col>
                <Col span={3}><Button type="primary" onClick={selConfirm}>确定</Button></Col>
                <Col span={3}><Button onClick={cancelModal}>取消</Button></Col>
                <Col span={2}></Col>
            </Row>
        </Modal>


    </>
)
}


lint 使用:ps:基于bpmn-js的流程设计器校验实现

使用目的:校验

注意点:

            linting: {
                bpmnlint: bpmnlintConfig,
                active:false  //如果要检查 要配置这里
            },

lint配置文件.bpmnlintrc:

{
  "extends": "bpmnlint:recommended",
  "rules": {
    "label-required": "off"
  }
}

ps:全网最详bpmn.js教材-基础篇

基于bpmn.js、React、Midway.js的在线流程编辑、数据管理工具(1)

汉化

查看流程:

调整--带参数

查看流程界面读取参数

根据参数查询后台流程定义数据

根据后台数据渲染页面

 

启动工作流:

    /**
     *
     * @param id  act_re_procdef.id
     * @param businessKey  业务 businessKey,自定义
     * @return
     */
    @ApiOperation(value = "启动流程")
    @GetMapping("/startProcessInstanceById")
    public R startProcessInstanceById(String id, String businessKey) {
        int userId=UserUtil.getUserId();
        Authentication.setAuthenticatedUserId(userId+"");
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(id, businessKey);
        return R.strData(processInstance.getId());
    }

查看流程实例:

select * from ACT_HI_PROCINST t

删除流程实例:

    @ApiOperation(value = "删除流程")
    @GetMapping("/deleteProcessInstance")
    public R deleteProcessInstance(String processInstanceId,String deleteReason) {
        ProcessInstance result = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (result != null) {
            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
            return R.strData("删除成功");
        }else {
            throw new ReturnException("未找到该流程");
        }
    }

查询我的发起的流程:


    /**
     * 获取流程实例
     */
    @ApiOperation(value = "查询流程信息by user")
    @GetMapping("/getProcessInstancesByUserId")
    public R getProcessInstancesByUserId() {
        //act_hi_procinst
        int userId=UserUtil.getUserId();
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().startedBy(userId+"")
                .list();
        List<Map<String, Object>> collect = list.stream().map(processInstance -> {
            //获取资源
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(processInstance.getDeploymentId()).singleResult();
            return new CreateMap.Build()
                    .setAttribute("id", processInstance.getId())
                    .setAttribute("deploymentId", processInstance.getDeploymentId())
                    .setAttribute("description", processInstance.getDescription())
                    .setAttribute("name", processInstance.getName())
                    .setAttribute("businessKey", processInstance.getBusinessKey())
                    .setAttribute("processDefinitionKey", processInstance.getProcessDefinitionKey())
                    .setAttribute("processDefinitionId", processInstance.getProcessDefinitionId())
                    .setAttribute("processDefinitionName", processInstance.getProcessDefinitionName())
                    //是否完成
                    .setAttribute("isEnded", processInstance.isEnded())
                    //是否挂起
                    .setAttribute("isSuspended", processInstance.isSuspended())
                    .setAttribute("resourceName", processDefinition.getResourceName())
                    .build();
        }).collect(Collectors.toList());


        return R.ok(collect);
    }

根据名字查询我的任务:

    /**
     * 查询我的待办任务
     */
    @GetMapping("/getTaskByAssignee")
    public R getTaskByAssignee(String assignee) {
        List<Task> zhangsanTask = taskService.createTaskQuery()
                .taskAssignee(assignee)
                //.taskName("zhangsan")
                .list();
        List<Map<String, Object>> collect = zhangsanTask.stream().map(tk -> {

            return new CreateMap.Build()
                    .setAttribute("id", tk.getId())
                    .setAttribute("processInstanceId", tk.getProcessInstanceId())
                    .setAttribute("name", tk.getName())
                    .setAttribute("assignee", tk.getAssignee())
                    //是否挂起
                    .setAttribute("isSuspended", tk.isSuspended())
                    .build();
        }).collect(Collectors.toList());
        return R.ok(collect);
    }

 

{
  "code": "200",
  "data": [
    {
      "processInstanceId": "0325fddf-c4dd-11eb-90ed-505bc2b03111",
      "isSuspended": false,
      "name": "admin",
      "id": "032cb4a4-c4dd-11eb-90ed-505bc2b03111",
      "assignee": "21001"
    }
  ]
}

完成任务:

 

 

根据processInstanceId 查询流程定义信息

 

查看流程实例:

import React, { useEffect, useRef, useState, useImperativeHandle, forwardRef } from 'react';

// 以下为bpmn工作流绘图工具的样式
import 'bpmn-js/dist/assets/diagram-js.css' // 左边工具栏以及编辑节点的样式
import 'bpmn-js-bpmnlint/dist/assets/css/bpmn-js-bpmnlint.css' // bpmnlint

import BpmnViewer from 'bpmn-js/lib/Viewer';
import {getDef, getHighlight} from "../api/workflow";

import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css' // 右边工具栏样式

//為右邊屬性
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'

import {Button, Col, Divider, Input, Modal, Row, Space, List, message, Table, Form} from 'antd';
import customTranslateModule from '../BpmnEditor/Modeler/customTranslate';
import './ViewProcInst.css';

export default function ViewProcInst(prop) {
    const modelerRef = useRef(null);
    useEffect(()=>{   //读取外部
        let procId=prop.procId;
        let procInstId=prop.procInstId;
        initBpmn(procId,procInstId);
    },[])

const  initBpmn=(procId,procInstId)=>{
    modelerRef.current =
        new BpmnViewer({
            container:"#canvas",
            additionalModules: [
                customTranslateModule,
            ],
            height:'100vh'
        })

    const logo = document.querySelector('.bjs-powered-by');
    const bpmnContainer = document.querySelector('.bjs-container');
    if (bpmnContainer && logo) {
        bpmnContainer.removeChild(logo);
    }
    renderDiagram(procId,procInstId);
    //setColor2(procInstId)  //不能这样写 因为异步的原因!!!
}

    const renderDiagram = (procId,procInstId) => {
      let xml="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\" xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:camunda=\"http://camunda.org/schema/1.0/bpmn\" xmlns:activiti=\"http://activiti.org/bpmn\" xmlns:tns=\"http://www.activiti.org/test\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" id=\"m1605802588480\" name=\"\" targetNamespace=\"http://www.activiti.org/test\">\\n  <process id=\"Process_1\" isExecutable=\"true\">\\n    <startEvent id=\"StartEvent_1y45yut\" name=\"开始\">\\n      <outgoing>Flow_0jfbnmb</outgoing>\\n    </startEvent>\\n    <userTask id=\"Activity_1w1vj9r\" name=\"username1\" activiti:formKey=\"kkk\" activiti:assignee=\"1\" activiti:candidateUsers=\"candidateUsers\" activiti:candidateGroups=\"candidateGroups\">\\n      <extensionElements>\\n        <activiti:formData>\\n          <activiti:formProperty id=\"formProperty_3slq4mu\" />\\n        </activiti:formData>\\n        <activiti:properties>\\n          <activiti:property />\\n        </activiti:properties>\\n      </extensionElements>\\n      <incoming>Flow_0jfbnmb</incoming>\\n      <outgoing>Flow_1nolku9</outgoing>\\n    </userTask>\\n    <sequenceFlow id=\"Flow_0jfbnmb\" sourceRef=\"StartEvent_1y45yut\" targetRef=\"Activity_1w1vj9r\" />\\n    <endEvent id=\"Event_0ahqy2x\" name=\"e\">\\n      <incoming>Flow_1nolku9</incoming>\\n    </endEvent>\\n    <sequenceFlow id=\"Flow_1nolku9\" sourceRef=\"Activity_1w1vj9r\" targetRef=\"Event_0ahqy2x\" />\\n  </process>\\n  <bpmndi:BPMNDiagram id=\"BpmnDiagram_1\">\\n    <bpmndi:BPMNPlane id=\"BpmnPlane_1\" bpmnElement=\"Process_1\">\\n      <bpmndi:BPMNEdge id=\"Flow_0jfbnmb_di\" bpmnElement=\"Flow_0jfbnmb\">\\n        <omgdi:waypoint x=\"188\" y=\"120\" />\\n        <omgdi:waypoint x=\"300\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNEdge id=\"Flow_1nolku9_di\" bpmnElement=\"Flow_1nolku9\">\\n        <omgdi:waypoint x=\"400\" y=\"120\" />\\n        <omgdi:waypoint x=\"542\" y=\"120\" />\\n      </bpmndi:BPMNEdge>\\n      <bpmndi:BPMNShape id=\"StartEvent_1y45yut_di\" bpmnElement=\"StartEvent_1y45yut\">\\n        <omgdc:Bounds x=\"152\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"160\" y=\"145\" width=\"22\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Activity_1w1vj9r_di\" bpmnElement=\"Activity_1w1vj9r\">\\n        <omgdc:Bounds x=\"300\" y=\"80\" width=\"100\" height=\"80\" />\\n      </bpmndi:BPMNShape>\\n      <bpmndi:BPMNShape id=\"Event_0ahqy2x_di\" bpmnElement=\"Event_0ahqy2x\">\\n        <omgdc:Bounds x=\"542\" y=\"102\" width=\"36\" height=\"36\" />\\n        <bpmndi:BPMNLabel>\\n          <omgdc:Bounds x=\"557\" y=\"145\" width=\"7\" height=\"14\" />\\n        </bpmndi:BPMNLabel>\\n      </bpmndi:BPMNShape>\\n    </bpmndi:BPMNPlane>\\n  </bpmndi:BPMNDiagram>\\n</definitions>\n";
       // let xml = getDefaultXml();
        getDef(procId).then(
            (res) => {
                 xml=res.data;
                    console.log("======xmlxmlxml======:"+xml);
                    modelerRef.current.importXML(xml, (err) => {
                    if (err) {
                        Modal.error({ title: 'XML解析失败' });
                        return false;
                    }
                        setColor2(procInstId)
                    return true;
                });
            },
            (error) => {
                console.log("get response failed!");
            }
        );
    };


    const setColor2=(procInstId)=> {
        debugger;
        // access viewer components
        const canvas = modelerRef.current.get('canvas');
        // 获取到全部节点
        const allShapes = modelerRef.current.get('elementRegistry').getAll();
        //获取高亮的shapeId
        getHighlight(procInstId).then((res) => {
            debugger;
            const { highPoint } = res.data;

            //循环节点添加颜色
            allShapes.forEach(element => {
                const shapeId = element.businessObject.id;
                if (element.businessObject.$type == 'bpmn:UserTask') {
                    highPoint.forEach(utid => {
                        if (shapeId == utid) {
                            console.log("===========utid======:"+utid+"=====shapeId:======="+shapeId)
                            canvas.addMarker(shapeId, 'highlight');
                        }
                    });
                }
            });
        });
    }


    const container = {
        width: "100%",
        height:"100%"
    };
    const bpmnDesignClass = {
        minHeight: "100vh",
    };

return(
    <>
            <div id="canvas" className={container}>
            </div>
    </>
)
}


ps:React中使用CSS样式的五种方法,主流推荐CSS Modules和Styled Components

后端java:

    /**
     * 高亮显示路程历史
     *
     * @param instanceId   流程实例id
     //* @param username 用户信息
     * @return
     */
    @GetMapping("/getHighlight")
    public R getHighlight(
            @RequestParam("instanceId") String instanceId
            //,@RequestParam("username") String username
    ) {
        int userId=UserUtil.getUserId();
        try {
            // 获取一条流程实例历史
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(instanceId)
                    .singleResult();
            // 根据流程定义 key 获取 BMPN
            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            // 获取流程
            Process process = bpmnModel.getProcesses().get(0);
            // 获取所有流程 FlowElement 的信息,就是所有bpmn的节点
            Collection<FlowElement> flowElements = process.getFlowElements();

            /**
             * 这个 map 中的 key 就是 开始节点和结束节点的编号拼起来的字符串,
             * value 就是开始节点和结束节点的连线,到时候我们根据开始节点和结束节点
             * 就可以获取到需要高亮的连线
             */
            Map<String, String> map = new HashMap<String, String>();
            for (FlowElement flowElement : flowElements) {
                // 判断是否是线条
                if (flowElement instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                    String ref = sequenceFlow.getSourceRef();
                    String targetRef = sequenceFlow.getTargetRef();
                    /**
                     * 保存开始节点和结束节点,与它们之间连线的对应关系
                     * key: 开始节点 编号 + 结束节点 编号
                     * value: 连线编号
                     */
                    map.put(ref + targetRef, sequenceFlow.getId());
                }
            }

            /**
             * 获取已经完成的全部流程历史节点
             */
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .list();
            /**
             * 将各个历史节的开始节点和结束几点的编号两两对应起来,
             * 就可以从上面的 map 中获取到需要高亮的连线
             */
            Set<String> keyList = new HashSet<String>();
            for (HistoricActivityInstance i : list) {
                for (HistoricActivityInstance j : list) {
                    if (i != j) {
                        keyList.add(i.getActivityId() + j.getActivityId());
                    }
                }
            }

            // 获取高亮连线 id
            Set<String> highLine = new HashSet<String>();
            // 根据已经完成的(开始节点编号+结束节点编号)组成的 key 获取需要高亮的连线编号
            keyList.forEach(s -> highLine.add(map.get(s)));


            // 获取已经完成的节点
            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .finished()
                    .list();

            // 已经完成的节点高亮
            Set<String> highPoint = new HashSet<>();
            // 保存已经完成的流程节点编号
            listFinished.forEach(s -> highPoint.add(s.getActivityId()));

            // 获取代办节点
            List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId)
                    .unfinished()
                    .list();

            // 代办的节点高亮
            Set<String> waitingToDo = new HashSet<>();
            // 保存需要代办的节点编号
            listUnFinished.forEach(s -> waitingToDo.add(s.getActivityId()));


            // 获取当前用户完成的任务
            List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
                   // .taskAssignee(username)
                    .taskAssignee(userId+"")
                    .processInstanceId(instanceId)
                    .finished()
                    .list();

            // 当前用户完成的高亮
            Set<String> iDo = new HashSet<String>();
            // 保存用户完成的节点编号
            taskInstanceList.forEach(s -> iDo.add(s.getTaskDefinitionKey()));

            Map<String, Object> reMap = new HashMap<String, Object>();
            // 高亮已经完成的节点
            reMap.put("highPoint", highPoint);
            // 高亮连线节点编号
            reMap.put("highLine", highLine);
            // 高亮代办节点编号
            reMap.put("waitingToDo", waitingToDo);
            // 高亮当前用户完成的节点编号
            reMap.put("iDo", iDo);

            return R.ok(reMap);
        } catch (Exception e) {
            return R.error("");
        }
    }

我完成的流程接口相应信息:(/report/act/history/myFinishTask)

{
  "code": "200",
  "data": [
    {
      "processInstanceId": "d71f0601-c8f1-11eb-995e-505bc2b03111",
      "taskDefinitionKey": "Activity_1igvbr0",
      "name": "21001",
      "id": "d72ce8b6-c8f1-11eb-995e-505bc2b03111",
      "assignee": "21001",
      "procDefName": "testProc001"
    },
    {
      "processInstanceId": "db0aa52e-c995-11eb-aed6-505bc2b03111",
      "taskDefinitionKey": "task001_xj",
      "name": "21001",
      "id": "db149043-c995-11eb-aed6-505bc2b03111",
      "assignee": "21001",
      "procDefName": "Process_100xjname"
    }
  ]
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ps:activiti7数据库表结构参考

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值