# vue-bpmn-activiti 组件库

### 快速开始

#### 1. 安装组件库

```bash
npm i @jt_coder/vue-bpmn-activiti
```

#### 2. 引用组件库

```javascript
import "@jt_coder/vue-bpmn-activiti/dist/index.css";
import VueBpmn from "@jt_coder/vue-bpmn-activiti";

Vue.use(VueBpmn);
```

### 预览图

![](./docs/images/01.png)

### 流程设计组件（BpmnDesigner）

#### 示例

```javascript
<BpmnDesigner :xmlStr="xml" @change="onChange" />

onChange(xml) {
    console.log("xml:", xml);
},
```

#### 属性说明

| 属性   | 说明                  | 类型   | 默认值 |
| ------ | --------------------- | ------ | ------ |
| xmlStr | activiti xml 格式数据 | string | -      |

#### 事件说明

| 事件名称 | 说明                                     | 回调参数        |
| -------- | ---------------------------------------- | --------------- |
| change   | 元素新增，删除，修改，移动，属性设置触发 | (event) => void |

### 流程预览组件（BpmnView）

#### 示例

```javascript
<BpmnView :xmlStr="bpmnXml" :highlightOptions="highlightOptions" />

data() {
    return {
      bpmnXml,
      highlightOptions: {
        h__highPoint: ["Event_09ccqp5", "Activity_07td992"],
        h__iDo: ["Activity_1bj9xl3"],
        h__waitingToDo: ["Event_1w1dma1"],
      },
    };
  },
```

#### 属性说明

| 属性             | 说明                            | 类型   | 默认值                                                         |
| ---------------- | ------------------------------- | ------ | -------------------------------------------------------------- |
| xmlStr           | activiti xml 格式数据           | string | -                                                              |
| highlightOptions | 高亮节点数据,属性和高亮类型对应 | obj    | null                                                           |
| types            | 高亮类型                        | array  | [ "h__highLine", "h__highPoint", "h__iDo", "h__waitingToDo", ] |

#### 渲染流程

1. 准备流程定义 xml
2. 准备高亮节点数据
3. 渲染图形化流程
4. 根据高亮数据着色

参考：[bpmn colors exapmles, Options3](https://github.com/bpmn-io/bpmn-js-examples/tree/master/colors)

#### java 获取节点高亮数据接口

参考：[Activiti7 精讲&Java 通用型工作流开发实战](https://coding.imooc.com/class/454.html)

```java
/**
    * 获取历史高亮信息
    * @param instanceId 流程实例ID
    */
public Map<String, Object> getHighlight(String instanceId) {
    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(instanceId).singleResult();
    //获取bpmnModel对象
    BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
    //因为我们这里只定义了一个Process 所以获取集合中的第一个即可
    Process process = bpmnModel.getProcesses().get(0);
    //获取所有的FlowElement信息
    Collection<FlowElement> flowElements = process.getFlowElements();

    Map<String, String> map = new HashMap<>();
    for (FlowElement flowElement : flowElements) {
        //判断是否是连线
        if (flowElement instanceof SequenceFlow) {
            SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
            String ref = sequenceFlow.getSourceRef();
            String targetRef = sequenceFlow.getTargetRef();
            map.put(ref + targetRef, sequenceFlow.getId());
        }
    }

    //获取流程实例 历史节点(全部)
    List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(instanceId)
            .list();
    //各个历史节点   两两组合 key
    Set<String> keyList = new HashSet<>();
    for (HistoricActivityInstance i : list) {
        for (HistoricActivityInstance j : list) {
            if (i != j) {
                keyList.add(i.getActivityId() + j.getActivityId());
            }
        }
    }
    //高亮连线ID
    Set<String> highLine = new HashSet<>();
    keyList.forEach(s -> highLine.add(map.get(s)));


    //获取流程实例 历史节点（已完成）
    List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(instanceId)
            .finished()
            .list();
    //高亮节点ID
    Set<String> highPoint = new HashSet<>();
    listFinished.forEach(s -> highPoint.add(s.getActivityId()));

    //获取流程实例 历史节点（待办节点）
    List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
            .processInstanceId(instanceId)
            .unfinished()
            .list();

    //需要移除的高亮连线
    Set<String> set = new HashSet<>();
    //待办高亮节点
    Set<String> waitingToDo = new HashSet<>();

    listUnFinished.forEach(s -> {
        waitingToDo.add(s.getActivityId());

        for (FlowElement flowElement : flowElements) {
            //判断是否是 用户节点
            if (flowElement instanceof UserTask) {
                UserTask userTask = (UserTask) flowElement;

                if (userTask.getId().equals(s.getActivityId())) {
                    List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                    //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                    if (outgoingFlows != null && outgoingFlows.size() > 0) {
                        outgoingFlows.forEach(a -> {
                            if (a.getSourceRef().equals(s.getActivityId())) {
                                set.add(a.getId());
                            }
                        });
                    }
                }
            }
        }
    });

    highLine.removeAll(set);

    Set<String> iDo = new HashSet<>(); //存放 高亮 我的办理节点
    String AssigneeName = getUserInfo().getId();

    List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
            .taskAssignee(AssigneeName)
            .finished()
            .processInstanceId(instanceId).list();

    taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));

    Map<String, Object> reMap = new HashMap<>();
    reMap.put("highPoint", highPoint);
    reMap.put("highLine", highLine);
    reMap.put("waitingToDo", waitingToDo);
    reMap.put("iDo", iDo);
    return reMap;
}
```
