bpmnLintUtil.ts 7.1 KB

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