刘光辉
12 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import ElementRegistry from 'diagram-js/lib/core/ElementRegistry';
import { typeTask, typeTrigger } from '../config/variableName';
import { changeTypeByTaskShape } from '../config';
export class BpmnLintError {
  public element: any;
  public message: string;
  constructor(element: any | any[], message: string) {
    this.element = element;
    this.message = message;
  }
}
 
// 自定义bpmnLint规则
abstract class BpmnLintBase {
  protected registry: ElementRegistry;
  protected root: any;
  protected constructor(registry: ElementRegistry, root: any) {
    this.registry = registry;
    this.root = root;
  }
  public abstract validate(): boolean;
  protected error: BpmnLintError | undefined;
  public getError(): BpmnLintError | undefined {
    return this.error;
  }
}
/**
 * xml元素校验
 *  1.流程必须要有一个【开始,结束】节点 且只能有一个。
 *  2.至少有一个【审批】节点,
 *  3.分流网关和合流官网必须成对关系。
 *  4.除了开始节点(只有出线)及结束节点(只有进线) 其它节点必须要含有出线和入线。
 *  5.分流节点出线必须有多条出线,只有一条进线; 合流节点必须有多条进线,只能有一条出线。
 *
 */
let jnpfProps: any;
class FormValidator extends BpmnLintBase {
  public constructor(registry: ElementRegistry, root: any, props: any) {
    super(registry, root);
    jnpfProps = props;
  }
  validate(): boolean {
    let errorList: any = [];
    let allElements = this.root.children;
    if (allElements && allElements.length > 0) {
      let newElementData = allElements.reduce((classified: any, element: any) => {
        // 获取元素类型 (网关元素存在分流和合流 所以需要取 wnGatewayType)
        let elementType = (element.type === 'bpmn:InclusiveGateway' ? element.wnGatewayType : element.type)?.replace('bpmn:', '')?.toLowerCase();
        // 如果分类对象中不存在当前类型的数组,则创建一个新数组
        if (!classified[elementType]) classified[elementType] = [];
        // 将元素添加到相应类型的数组中
        classified[elementType].push(element);
        return classified;
      }, {});
      if (newElementData) {
        if (!(newElementData.hasOwnProperty('startevent') && newElementData.hasOwnProperty('endevent') && newElementData.hasOwnProperty('usertask'))) {
          this.error = new BpmnLintError(null, '确保画布上至少包含【开始-审批-结束】节点');
          return false;
        }
        // 开始节点
        if (newElementData['startevent']) {
          if (newElementData['startevent'].length > 1) {
            // 开始 结束节点只有拥有一个
            this.error = new BpmnLintError(null, '画布上只能存在一个开始节点');
            return false;
          }
          // 开始节点只能有一个出线
          if (newElementData['startevent'][0]) {
            let outLine = newElementData['startevent'][0].outgoing;
            let inLine = newElementData['startevent'][0].incoming; // 进线
            if (inLine && inLine.length > 0) {
              errorList.push({
                element: newElementData['startevent'][0],
                error: '开始节点不存在进线,请删除多余线条!',
              });
            }
            if (!outLine) {
              errorList.push({
                element: newElementData['startevent'][0],
                error: '开始元素不能单独使用,请于其它元素进行连线使用!',
              });
            }
          }
        }
        // 结束节点:
        if (newElementData['endevent']) {
          if (newElementData['endevent'].length > 1) {
            this.error = new BpmnLintError(null, '画布上只能存在一个结束节点,请删除多余节点元素!');
            return false;
          }
          // 结束节点只能有一个进线
          if (newElementData['endevent'][0]) {
            let outLine = newElementData['endevent'][0].outgoing;
            let inLine = newElementData['endevent'][0].incoming; // 进线
            if (outLine && outLine.length > 0) {
              errorList.push({
                element: newElementData['endevent'][0],
                error: '结束节点不存在出线,请删除多余线条!',
              });
            }
            if (!inLine) {
              errorList.push({
                element: newElementData['endevent'][0],
                error: '结束元素不能单独使用,请于其它元素进行连线使用!',
              });
            }
          }
        }
        // 网关
        if (newElementData.hasOwnProperty('confluence') || newElementData.hasOwnProperty('divide')) {
          if (!(newElementData['confluence'] && newElementData['confluence'].length && newElementData['divide'] && newElementData['divide'].length)) {
            this.error = new BpmnLintError(null, '请您检查分流与合流是否成对使用!');
            return false;
          }
        }
        // 任务节点
        if (newElementData['usertask']) {
          // 遍历进线元素 必须有一条进线及出线元素
          let userTaskList = newElementData['usertask'];
          userTaskList.map((userTaskShape: any) => {
            let outLine = userTaskShape.outgoing;
            let inLine = userTaskShape.incoming; // 进线
            // 任务节点必须要有一个进线和出线
            if (!(outLine?.length && inLine?.length)) {
              if (!changeTypeByTaskShape[userTaskShape?.wnType] || (jnpfProps.type === 2 && changeTypeByTaskShape[userTaskShape?.wnType])) {
                errorList.push({
                  element: userTaskShape,
                  error: '元素不能单独使用,请确保连接至少一个执行节点',
                });
              } else if (changeTypeByTaskShape[userTaskShape?.wnType] && !inLine?.length) {
                errorList.push({
                  element: userTaskShape,
                  error: '执行元素不能单独使用,请确保连接到触发节点',
                });
              }
            }
            if (userTaskShape?.wnType === typeTask) {
              // 如果任务节点只有触发节点 则报错 需要连接其它节点或者结束节点。
              if (outLine.every(s => s.target.wnType === typeTrigger))
                errorList.push({
                  element: userTaskShape,
                  error: '审批元素不能只包含触发节点, 请确保至少有一条出线与其他元素相连接',
                });
            }
          });
        }
        if (errorList && errorList.length > 0) {
          this.error = new BpmnLintError(errorList, errorList[0].error);
          return false;
        }
      }
    } else {
      this.error = new BpmnLintError(null, '画布上不存在元素,至少包含【开始-审批-结束】节点');
      return false;
    }
    return true;
  }
}
 
export function validate(registry: ElementRegistry, root: any, props: any): BpmnLintError | undefined {
  /***/
  const validators = [new FormValidator(registry, root, props)];
 
  for (let validator of validators) {
    if (!validator.validate()) {
      return validator.getError();
    }
  }
}