nodeUtil.ts 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. import {
  2. bpmnSequenceFlow,
  3. bpmnIncoming,
  4. bpmnOutgoing,
  5. bpmnInclusive,
  6. typeStart,
  7. typeTask,
  8. typeSubFlow,
  9. typeEnd,
  10. typeTrigger,
  11. typeEventTrigger,
  12. typeTimeTrigger,
  13. typeNoticeTrigger,
  14. typeWebhookTrigger,
  15. typeGetData,
  16. typeAddData,
  17. typeUpdateData,
  18. typeDelData,
  19. typeInterface,
  20. typeMessage,
  21. typeLaunchFlow,
  22. typeSchedule,
  23. typeProcessing,
  24. typeGateway,
  25. typeInclusion,
  26. typeOutside,
  27. } from '../config/variableName';
  28. import { buildBitUUID } from '../utils/uuidUtil';
  29. import { hasGatewayType, typeConfig } from '../config';
  30. import { is } from 'bpmn-js/lib/util/ModelUtil';
  31. import { getExternalLabelMid } from 'bpmn-js/lib/util/LabelUtil';
  32. export class NodeUtils {
  33. /**
  34. * 判断节点类型
  35. * @param {Node} node - 节点数据
  36. * @returns Boolean
  37. */
  38. static isStartNode(node) {
  39. return node && node?.type === typeStart;
  40. }
  41. static isApproverNode(node) {
  42. return node && node?.type === typeTask;
  43. }
  44. static isProcessingNode(node) {
  45. return node && node?.type === typeProcessing;
  46. }
  47. static isSubFlowNode(node) {
  48. return node && node?.type === typeSubFlow;
  49. }
  50. static isInterflowNode(node) {
  51. return node && node?.type === typeTask && node?.isInterflow;
  52. }
  53. static isConnectNode(node) {
  54. return node && node?.type === bpmnSequenceFlow;
  55. }
  56. static isEndNode(node) {
  57. return node && node?.type === typeEnd;
  58. }
  59. static isTriggerNode(node) {
  60. return node && node?.type === typeTrigger;
  61. }
  62. static isEventTriggerNode(node) {
  63. return node && node?.type === typeEventTrigger;
  64. }
  65. static isTimeTriggerNode(node) {
  66. return node && node?.type === typeTimeTrigger;
  67. }
  68. static isNoticeTriggerNode(node) {
  69. return node && node?.type === typeNoticeTrigger;
  70. }
  71. static isWebhookTriggerNode(node) {
  72. return node && node?.type === typeWebhookTrigger;
  73. }
  74. static isGetDataNode(node) {
  75. return node && node?.type === typeGetData;
  76. }
  77. static isAddDataNode(node) {
  78. return node && node?.type === typeAddData;
  79. }
  80. static isUpdateDataNode(node) {
  81. return node && node?.type === typeUpdateData;
  82. }
  83. static isDeleteDataNode(node) {
  84. return node && node?.type === typeDelData;
  85. }
  86. static isDataInterfaceNode(node) {
  87. return node && node?.type === typeInterface;
  88. }
  89. static isMessageNode(node) {
  90. return node && node?.type === typeMessage;
  91. }
  92. static isLaunchFlowNode(node) {
  93. return node && node?.type === typeLaunchFlow;
  94. }
  95. static isScheduleNode(node) {
  96. return node && node?.type === typeSchedule;
  97. }
  98. static isOutsideNode(node) {
  99. return node && node?.type === typeOutside;
  100. }
  101. /**
  102. * 获取上节点元素
  103. * @param element 当前元素
  104. */
  105. static getPreNodeList(element) {
  106. let preList: any[] = [];
  107. if (!element || !element.incoming || !element.incoming.length) return preList;
  108. for (let i = 0; i < element.incoming.length; i++) {
  109. const item = element.incoming[i];
  110. preList.push(item.source);
  111. }
  112. return preList;
  113. }
  114. /**
  115. * 生成条件组名称
  116. * @param conditions 条件组
  117. * @param matchLogic and / or
  118. */
  119. static getConditionsContent(conditions, matchLogic) {
  120. let content = '';
  121. for (let i = 0; i < conditions.length; i++) {
  122. const e = conditions[i];
  123. content += conditions.length == 1 ? '' : (i == 0 ? '' : ` ${matchLogic} `) + '( ';
  124. for (let j = 0; j < e.groups.length; j++) {
  125. const groups = e.groups[j];
  126. const logic = j == 0 ? '' : ` ${e.logic} `;
  127. const text = ` ${groups.fieldName} ${groups.symbolName}${groups.fieldLabel ? groups.fieldLabel : groups.fieldValue || groups.fieldValue === 0 ? groups.fieldValue : ''
  128. } `;
  129. content += logic + text;
  130. }
  131. content += conditions.length == 1 ? '' : ' )';
  132. }
  133. return content;
  134. }
  135. /**
  136. * 自动生成网关
  137. * @param xml xml
  138. * @param elementRegistry 节点元素
  139. */
  140. static autoCreateGateWay(xml, elementRegistry, jnpfData) {
  141. let parser = new DOMParser();
  142. let xmlDoc = parser.parseFromString(xml, 'text/xml');
  143. let process: any = xmlDoc.querySelector('#Process_1');
  144. let plane: any = xmlDoc.querySelector('#BPMNPlane_1');
  145. let divideList: any[] = [];
  146. let confluenceList: any = [];
  147. const allList: any[] = elementRegistry.getAll() || [];
  148. allList.map((item: any) => {
  149. // 过滤任务节点的网关
  150. let groupId = item?.businessObject?.$attrs?.customGroupId;
  151. if (item.incoming?.length > 1 && !groupId) confluenceList.push({ key: item.id, gatewayType: 'inclusion' });
  152. if (item.outgoing && item.outgoing.length > 1 && !groupId) {
  153. divideList.push({
  154. key: item.id,
  155. gatewayType: jnpfData.data[item.id]?.divideRule || 'inclusion',
  156. });
  157. }
  158. });
  159. // 新增分流xml标签
  160. if (divideList?.length) {
  161. divideList.map((item: any) => {
  162. let targetElement = xmlDoc.querySelector(`#${item.key}`);
  163. if (targetElement) {
  164. let targeChildren: any = targetElement.children;
  165. let outgoingList: any = [];
  166. let incomingList: any = [];
  167. for (var i = 0; i < targeChildren.length; i++) {
  168. if (targeChildren[i].nodeName === bpmnOutgoing) {
  169. // 将该值赋值给新生成的分流元素上 删除原来元素上的outgoing 并且生成一条新的outgoing连接到该线条上。
  170. outgoingList.push(targeChildren[i]);
  171. } else {
  172. incomingList.push(targeChildren[i]);
  173. }
  174. }
  175. // 新增一个分流节点 并且连接线到目前的元素上
  176. let gatewayElement = NodeUtils.createGateway(xmlDoc, item.gatewayType);
  177. let gatewayId = 'Gateway_' + buildBitUUID();
  178. let flowId = 'flow_' + buildBitUUID();
  179. gatewayElement.setAttribute('id', gatewayId);
  180. let flowElement = xmlDoc.createElement('bpmn2:sequenceFlow');
  181. flowElement.setAttribute('id', flowId);
  182. flowElement.setAttribute('sourceRef', item.key);
  183. flowElement.setAttribute('targetRef', gatewayId);
  184. let conditionExpression = xmlDoc.createElement('bpmn2:conditionExpression');
  185. conditionExpression.setAttribute('xsi:type', 'bpmn2:tFormalExpression');
  186. let testText = xmlDoc.createTextNode('${' + `${flowId}` + '}');
  187. conditionExpression.appendChild(testText);
  188. let childElement = xmlDoc.createElement(bpmnIncoming); // 替换为您想要创建的子标签的名称
  189. let textNode = xmlDoc.createTextNode(flowId);
  190. childElement.appendChild(textNode);
  191. gatewayElement.appendChild(childElement);
  192. if (outgoingList?.length) {
  193. let set: any = new Set();
  194. outgoingList.map((item: any) => {
  195. let outgoingId = item.textContent;
  196. let outgoingItemElementId = `#${outgoingId}`; // 替换成您要操作的元素的 ID
  197. let outgoingItemElement: any = xmlDoc.querySelector(outgoingItemElementId);
  198. outgoingItemElement.setAttribute('sourceRef', gatewayId);
  199. allList.map((itemElement: any) => {
  200. if (itemElement.id === outgoingId) set.add(itemElement.source?.id);
  201. });
  202. gatewayElement.appendChild(item);
  203. });
  204. set.forEach((item: any) => {
  205. let element: any = xmlDoc.getElementById(item);
  206. let childElement = xmlDoc.createElement(bpmnOutgoing);
  207. element.appendChild(childElement);
  208. let textNode = xmlDoc.createTextNode(flowId);
  209. childElement.appendChild(textNode);
  210. });
  211. }
  212. flowElement.appendChild(conditionExpression);
  213. process.appendChild(gatewayElement);
  214. process.appendChild(flowElement);
  215. this.handleCreateGatewayBounds(xmlDoc, gatewayId, plane);
  216. }
  217. });
  218. }
  219. if (confluenceList?.length) {
  220. confluenceList.map((item: any) => {
  221. let targetElement = xmlDoc.querySelector(`#${item.key}`);
  222. if (targetElement) {
  223. let targeChildren: any = targetElement.children;
  224. let outgoingList: any = [];
  225. let incomingList: any = [];
  226. for (var i = 0; i < targeChildren.length; i++) {
  227. if (targeChildren[i].nodeName === bpmnOutgoing) {
  228. // 将该值赋值给新生成的分流元素上 删除原来元素上的outgoing 并且生成一条新的outgoing连接到该线条上。
  229. outgoingList.push(targeChildren[i]);
  230. } else {
  231. incomingList.push(targeChildren[i]);
  232. }
  233. }
  234. // 新增一个分流节点 并且连接线到目前的元素上
  235. let gatewayElement = NodeUtils.createGateway(xmlDoc, item.gatewayType);
  236. let gatewayId = 'Gateway_' + buildBitUUID();
  237. let flowId = 'Flow_' + buildBitUUID();
  238. gatewayElement.setAttribute('id', gatewayId);
  239. let flowElement = xmlDoc.createElement('bpmn2:sequenceFlow');
  240. let conditionExpression = xmlDoc.createElement('bpmn2:conditionExpression');
  241. conditionExpression.setAttribute('xsi:type', 'bpmn2:tFormalExpression');
  242. let testText = xmlDoc.createTextNode('${' + `${flowId}` + '}');
  243. conditionExpression.appendChild(testText);
  244. flowElement.setAttribute('id', flowId);
  245. flowElement.setAttribute('sourceRef', gatewayId);
  246. flowElement.setAttribute('targetRef', item.key);
  247. let childElement = xmlDoc.createElement(bpmnOutgoing); // 替换为您想要创建的子标签的名称
  248. let textNode = xmlDoc.createTextNode(flowId);
  249. childElement.appendChild(textNode);
  250. gatewayElement.appendChild(childElement);
  251. if (incomingList && incomingList.length) {
  252. let set: any = new Set();
  253. incomingList.map((item: any) => {
  254. let incomingId = item.textContent;
  255. let incomingItemElementId = `#${incomingId}`; // 替换成您要操作的元素的 ID
  256. let incomingItemElement: any = xmlDoc.querySelector(incomingItemElementId);
  257. incomingItemElement.setAttribute('targetRef', gatewayId);
  258. allList.map((itemElement: any) => {
  259. if (itemElement.id === incomingId) set.add(itemElement.target?.id);
  260. });
  261. gatewayElement.appendChild(item);
  262. });
  263. set.forEach((item: any) => {
  264. let element: any = xmlDoc.getElementById(item);
  265. let childElement = xmlDoc.createElement(bpmnIncoming);
  266. // 新增新的出线线条在元素上
  267. element.appendChild(childElement);
  268. let textNode = xmlDoc.createTextNode(flowId);
  269. childElement.appendChild(textNode);
  270. });
  271. }
  272. flowElement.appendChild(conditionExpression);
  273. process.appendChild(gatewayElement);
  274. process.appendChild(flowElement);
  275. this.handleCreateGatewayBounds(xmlDoc, gatewayId, plane);
  276. }
  277. });
  278. }
  279. const newXml = new XMLSerializer().serializeToString(xmlDoc);
  280. return encodeURIComponent(newXml);
  281. }
  282. /**
  283. * 自动删除网关
  284. * @param flowXml
  285. * @returns
  286. */
  287. static autoDelGateWay(flowXml: string, type: number, nodeMap: any, isPreview: boolean) {
  288. let parser = new DOMParser();
  289. let xmlDoc = parser.parseFromString(decodeURIComponent(flowXml), 'text/xml');
  290. let oldXmlDoc = parser.parseFromString(decodeURIComponent(flowXml), 'text/xml');
  291. if (type != 1) {
  292. let process: any = xmlDoc.querySelector('#Process_1');
  293. let plane: any = xmlDoc.querySelector('#BPMNPlane_1');
  294. let gatewayList = NodeUtils.getAllGateway(xmlDoc);
  295. gatewayList.map((item: any) => {
  296. let incoming = item.getElementsByTagName(bpmnIncoming) || []; // 对于网关的进线线条
  297. let outgoing = item.getElementsByTagName(bpmnOutgoing) || []; // 对于网关的出线线条
  298. let sourceElement: any = []; // 当前网关的进线元素
  299. let targetElement: any = []; // 当前网关的出线元素
  300. for (let i = 0; i < incoming.length; i++) {
  301. // 获取进线元素的id
  302. let flowId = `#${incoming[i].innerText || incoming[i].textContent}`;
  303. // 然后在全局内找到该线条
  304. let connectElement: any = xmlDoc.querySelector(flowId);
  305. // 获取到该线条的进线元素
  306. let sourceElementId = connectElement.getAttribute('sourceRef');
  307. sourceElement.push(xmlDoc.querySelector(`#${sourceElementId}`));
  308. }
  309. for (let i = 0; i < outgoing.length; i++) {
  310. let flowId = `#${outgoing[i].innerText || outgoing[i].textContent}`;
  311. let connectElement: any = xmlDoc.querySelector(flowId);
  312. let targetElementId = connectElement.getAttribute('targetRef');
  313. targetElement.push(xmlDoc.querySelector(`#${targetElementId}`));
  314. }
  315. // 合流网关(网关有多条进线 一条出线)
  316. if (sourceElement.length > 1 && targetElement.length === 1) {
  317. // 获取当前的出线元素
  318. let targetElementId = targetElement[0]?.id;
  319. // 删除targetElement旧的进线元素
  320. const incomingList = NodeUtils.getIncomingConnectByElement(targetElement[0]) || [];
  321. incomingList.map((targetComingChildren: any) => {
  322. targetElement[0].removeChild(targetComingChildren);
  323. });
  324. // 遍历网关进线线条
  325. let list: any = [];
  326. // 迭代器
  327. for (let i = 0; i < incoming.length; i++) {
  328. let flowId = incoming[i].innerText || incoming[i].textContent;
  329. let connectElement: any = xmlDoc.querySelector(`#${flowId}`);
  330. let connectElementDi: any = xmlDoc.querySelector(`#${flowId}_di`);
  331. let connectWaypoint = connectElementDi.getElementsByTagName('di:waypoint');
  332. connectElement.setAttribute('targetRef', targetElementId);
  333. list.push(incoming[i]);
  334. let id = item.getAttribute('id');
  335. if (id.includes('_isSimple')) {
  336. let outGoingId = outgoing[0].innerText || outgoing[0].textContent;
  337. let outGoingDi: any = xmlDoc.querySelector(`#${outGoingId}_di`);
  338. let test: any = new Set();
  339. let newWayList = this.getGatewayWaypoints(test, outGoingDi, outgoing, oldXmlDoc, connectWaypoint);
  340. for (let i = 0; i < newWayList?.length; i++) {
  341. if (!connectWaypoint[i]) {
  342. let newWaypoint = xmlDoc.createElementNS('http://www.omg.org/spec/DD/20100524/DI', 'di:waypoint');
  343. newWaypoint.setAttribute('x', newWayList[i].x);
  344. newWaypoint.setAttribute('y', newWayList[i].y);
  345. connectElementDi.appendChild(newWaypoint);
  346. }
  347. }
  348. }
  349. }
  350. // 给targetElement设置新的进线元素
  351. list.map((item: any) => {
  352. targetElement[0]?.appendChild(item);
  353. });
  354. // 删除该网关及网关对应的出线元素
  355. process.removeChild(item);
  356. let flowId = outgoing[0].innerText || outgoing[0].textContent;
  357. let connectElement: any = xmlDoc.querySelector(`#${flowId}`);
  358. let connectElementDi: any = xmlDoc.querySelector(`#${flowId}_di`);
  359. let itemDi: any = xmlDoc.querySelector(`#${item.getAttribute('id')}_di`);
  360. process.removeChild(connectElement);
  361. connectElementDi && plane.removeChild(connectElementDi);
  362. itemDi && plane.removeChild(itemDi);
  363. }
  364. // 分流网关(网关有一条进线 多条出线)
  365. if (sourceElement.length === 1 && targetElement.length > 1) {
  366. // 获取当前的进元素
  367. let sourceElementId = sourceElement[0].id;
  368. // 删除sourceElement旧的出线元素
  369. const outgoingList = NodeUtils.getOutgoingConnectByElement(sourceElement[0]) || [];
  370. outgoingList.map((sourceElementChildren: any) => {
  371. sourceElement[0].removeChild(sourceElementChildren);
  372. });
  373. // 遍历网关出线线条
  374. let list: any = [];
  375. for (let i = 0; i < outgoing.length; i++) {
  376. // 获取进线元素的id
  377. let flowId = outgoing[i].innerText || outgoing[i].textContent;
  378. let incomingId = incoming[0].innerText || incoming[0].textContent;
  379. // 然后在全局内找到该线条 并且设置该线条的出线元素为targetElementId
  380. let connectElement: any = xmlDoc.querySelector(`#${flowId}`);
  381. connectElement.setAttribute('sourceRef', sourceElementId);
  382. // 给sourceElement设置新的出线信息
  383. list.push(outgoing[i]);
  384. let id = item.getAttribute('id');
  385. if (id.includes('_isSimple')) {
  386. let itemDi: any = xmlDoc.querySelector(`#${flowId}_di`);
  387. let itemDiWaypoint = itemDi.getElementsByTagName('di:waypoint');
  388. let incomingDi: any = xmlDoc.querySelector(`#${incomingId}_di`);
  389. let waypoint: any = incomingDi.getElementsByTagName('di:waypoint');
  390. let newWayList: any = [];
  391. for (let i = 0; i < waypoint.length; i++) {
  392. newWayList.push({
  393. x: waypoint[i].getAttribute('x'),
  394. y:
  395. i === waypoint.length - 1
  396. ? String(Number(waypoint[i].getAttribute('y')) + typeConfig[bpmnInclusive].renderer.attr.height / 2)
  397. : waypoint[i].getAttribute('y'),
  398. });
  399. }
  400. for (let i = 0; i < itemDiWaypoint.length; i++) {
  401. i != 0 && newWayList.push({ x: itemDiWaypoint[i].getAttribute('x'), y: itemDiWaypoint[i].getAttribute('y') });
  402. }
  403. for (let i = 0; i < newWayList.length; i++) {
  404. if (itemDiWaypoint[i]) {
  405. itemDiWaypoint[i].setAttribute('x', newWayList[i].x);
  406. itemDiWaypoint[i].setAttribute('y', newWayList[i].y);
  407. } else {
  408. let newWaypoint = xmlDoc.createElementNS('http://www.omg.org/spec/DD/20100524/DI', 'di:waypoint');
  409. newWaypoint.setAttribute('x', newWayList[i].x);
  410. newWaypoint.setAttribute('y', newWayList[i].y);
  411. itemDi.appendChild(newWaypoint);
  412. }
  413. }
  414. }
  415. }
  416. list.map((item: any) => {
  417. sourceElement[0].appendChild(item);
  418. });
  419. // 删除该网关及网关对应的出线元素
  420. process.removeChild(item);
  421. let flowId = incoming[0].innerText || incoming[0].textContent;
  422. let connectElement: any = xmlDoc.querySelector(`#${flowId}`);
  423. let connectElementDi: any = xmlDoc.querySelector(`#${flowId}_di`);
  424. let itemDi: any = xmlDoc.querySelector(`#${item.getAttribute('id')}_di`);
  425. process.removeChild(connectElement);
  426. connectElementDi && plane.removeChild(connectElementDi);
  427. itemDi && plane.removeChild(itemDi);
  428. }
  429. });
  430. // 有颜色的线条颜色标签重新生成
  431. if (isPreview) {
  432. let list = process.getElementsByTagName('bpmn2:sequenceFlow');
  433. let newList: any = [];
  434. for (let i = 0; i < list.length; i++) {
  435. let sourceRef = list[i].getAttribute('sourceRef');
  436. let targetRef = list[i].getAttribute('targetRef');
  437. if (
  438. nodeMap &&
  439. nodeMap.has(sourceRef) &&
  440. nodeMap.has(targetRef) &&
  441. nodeMap.get(sourceRef)?.type === '0' &&
  442. (nodeMap.get(targetRef)?.type === '0' || nodeMap.get(targetRef)?.type === '1')
  443. ) {
  444. newList.push(list[i]);
  445. }
  446. }
  447. newList.forEach((node: any) => {
  448. process.removeChild(node);
  449. process.appendChild(node);
  450. });
  451. }
  452. }
  453. return xmlDoc;
  454. }
  455. static createGateway(xmlDoc: any, type: 'parallel' | 'inclusion' | 'exclusive' | 'choose') {
  456. if (type === 'inclusion' || type === 'choose') return xmlDoc.createElement('bpmn2:inclusiveGateway');
  457. if (type === 'parallel') return xmlDoc.createElement('bpmn2:parallelGateway');
  458. if (type === 'exclusive') return xmlDoc.createElement('bpmn2:exclusiveGateway');
  459. }
  460. static getAllGateway(xmlDoc: any) {
  461. let gateWayList: any = [];
  462. let parallelGateways = xmlDoc.getElementsByTagName('bpmn2:parallelGateway');
  463. let inclusiveGateways = xmlDoc.getElementsByTagName('bpmn2:inclusiveGateway');
  464. let exclusiveGateways = xmlDoc.getElementsByTagName('bpmn2:exclusiveGateway');
  465. for (let i = 0; i < parallelGateways.length; i++) {
  466. gateWayList.push(parallelGateways[i]);
  467. }
  468. for (let i = 0; i < inclusiveGateways.length; i++) {
  469. gateWayList.push(inclusiveGateways[i]);
  470. }
  471. for (let i = 0; i < exclusiveGateways.length; i++) {
  472. gateWayList.push(exclusiveGateways[i]);
  473. }
  474. return gateWayList;
  475. }
  476. /**
  477. * 获取element下的进线元素
  478. * @param element 元素
  479. * @returns {Array} 进线元素数组
  480. */
  481. static getIncomingConnectByElement(element: any) {
  482. let list: any = [];
  483. let incomingElements = element?.getElementsByTagName(bpmnIncoming);
  484. for (let i = 0; i < incomingElements?.length; i++) {
  485. list.push(incomingElements[i]);
  486. }
  487. return list;
  488. }
  489. /**
  490. * 获取element下的出线元素
  491. * @param element 元素
  492. * @returns {Array} 出线元素数组
  493. */
  494. static getOutgoingConnectByElement(element: any) {
  495. let list: any = [];
  496. let outgoingElements = element?.getElementsByTagName(bpmnOutgoing);
  497. for (let i = 0; i < outgoingElements?.length; i++) {
  498. list.push(outgoingElements[i]);
  499. }
  500. return list;
  501. }
  502. static getLastElementList(element: any, allElements: any[]) {
  503. let lastList: any = [];
  504. if (element && element.incoming && element.incoming.length) {
  505. element.incoming.forEach((item: any) => {
  506. return allElements.forEach((last: any) => {
  507. // last中的出线若和 item的id相同 则获取到上一个节点的信息
  508. if (last.outgoing && last.outgoing.length) {
  509. let nextElement = last.outgoing.find((outgoing: any) => {
  510. return outgoing.id === item.id;
  511. });
  512. if (nextElement) {
  513. lastList.push(last);
  514. return element;
  515. }
  516. }
  517. });
  518. });
  519. }
  520. return lastList;
  521. }
  522. static getNextElementList = (element: any, allElements: any[]) => {
  523. let lastList: any = [];
  524. if (element && element.outgoing && element.outgoing.length) {
  525. element.outgoing.forEach((item: any) => {
  526. let list = allElements.forEach((last: any) => {
  527. // last中的出线若和 item的id相同 则获取到上一个节点的信息
  528. if (last.incoming && last.incoming.length) {
  529. let nextElement = last.incoming.find((incoming: any) => {
  530. return incoming.id === item.id;
  531. });
  532. if (nextElement) {
  533. lastList.push(last);
  534. return element;
  535. }
  536. }
  537. });
  538. return list;
  539. });
  540. }
  541. return lastList;
  542. };
  543. static getEndlessLoop = (bpmn: any) => {
  544. // 获取 BPMN 图中的所有元素
  545. let elementRegistry = bpmn.get('elementRegistry');
  546. let elements = elementRegistry.getAll();
  547. // 构建图数据结构
  548. let graph = {};
  549. let edgeMap = {}; // 用于存储边信息,key 是源节点,value 是目标节点和连线 id
  550. elements.forEach(element => {
  551. if (element.type === 'bpmn:SequenceFlow') {
  552. const sourceId = element.source.id;
  553. const targetId = element.target.id;
  554. const edgeId = element.id;
  555. if (!graph[sourceId]) graph[sourceId] = [];
  556. graph[sourceId].push(targetId);
  557. if (!edgeMap[sourceId]) edgeMap[sourceId] = [];
  558. edgeMap[sourceId].push({ targetId, edgeId });
  559. }
  560. });
  561. // 使用修改后的 DFS 检测所有环路并找出每个环路的最后一个进入环路的连线
  562. function findAllCycles(graph, edgeMap) {
  563. let visited = new Set();
  564. let stack: any = [];
  565. let stackSet: any = new Set();
  566. let cycles: any = [];
  567. function visit(node, startNode) {
  568. if (stackSet.has(node)) {
  569. // 找到环,记录从开始节点到环路的路径上的连线,并选择路径上的最后一条连线作为最后一个进入环路的连线
  570. let pathEdges: any = [];
  571. let isCycle = false;
  572. for (let i = stack.indexOf(startNode); i < stack.length - 1; i++) {
  573. let source = stack[i];
  574. let target = stack[i + 1];
  575. let edge = edgeMap[source].find(edge => edge.targetId === target);
  576. if (edge) {
  577. pathEdges.push(edge.edgeId);
  578. if (source === node) {
  579. isCycle = true;
  580. break;
  581. }
  582. }
  583. }
  584. if (isCycle) cycles.push(pathEdges[pathEdges.length - 1]);
  585. return;
  586. }
  587. if (visited.has(node)) return; // 已访问过,且无环
  588. visited.add(node);
  589. stack.push(node);
  590. stackSet.add(node);
  591. let neighbors = graph[node] || [];
  592. for (const neighbor of neighbors) {
  593. visit(neighbor, startNode);
  594. }
  595. stack.pop();
  596. stackSet.delete(node);
  597. }
  598. for (const node in graph) {
  599. visit(node, node);
  600. }
  601. return cycles;
  602. }
  603. return findAllCycles(graph, edgeMap);
  604. };
  605. // 网关坐标
  606. static getGatewayWaypoints = (test: any, outGoingDi: any, outgoing: any, xmlDoc: any, connectWaypoint?: any) => {
  607. let newList: any = [];
  608. let id = outGoingDi.getAttribute('bpmnElement');
  609. let gateway = xmlDoc.querySelector(`#${id}`);
  610. let itemDi: any = xmlDoc.querySelector(`#${id}_di`);
  611. let itemDiWaypoint = itemDi.getElementsByTagName('di:waypoint');
  612. for (let i = 0; i < itemDiWaypoint.length; i++) {
  613. newList.push({
  614. x: itemDiWaypoint[i].getAttribute('x'),
  615. y: itemDiWaypoint[i].getAttribute('y'),
  616. });
  617. }
  618. // 获取网关子坐标 如果子元素还是网关则继续查找后代元素
  619. let childrenElementId = gateway.getAttribute('targetRef');
  620. let childrenElement = xmlDoc.querySelector(`#${childrenElementId}`);
  621. if (childrenElementId.includes('Gateway_')) {
  622. let childrenOutGoingList = childrenElement.getElementsByTagName(bpmnOutgoing);
  623. let childrenOutGoingId = outgoing[0].innerText || outgoing[0].textContent;
  624. let childrenOutGoingDi: any = xmlDoc.querySelector(`#${childrenOutGoingId}_di`);
  625. let childrenList: any = this.getGatewayWaypoints(test, childrenOutGoingDi, childrenOutGoingList, xmlDoc);
  626. if (!test.has(id)) test.add(id);
  627. else newList.pop();
  628. newList = newList.concat(childrenList);
  629. } else if (connectWaypoint?.length > 0) {
  630. // 如果是其它节点
  631. for (let i = 0; i < connectWaypoint.length - 1; i++) {
  632. newList.unshift({
  633. x: connectWaypoint[i].getAttribute('x'),
  634. y: connectWaypoint[i].getAttribute('y'),
  635. });
  636. }
  637. }
  638. return newList;
  639. };
  640. // 校验连线是否存在条件标签 不存则需要手动添加。
  641. static verificationConnect = bpmn => {
  642. let elementRegistry: any = bpmn.get('elementRegistry');
  643. let modeling = bpmn.get('modeling');
  644. let moddle = bpmn.get('moddle');
  645. let connect = elementRegistry.getAll().filter((element: any) => {
  646. if (is(element, 'bpmn:SequenceFlow') && !element?.businessObject?.conditionExpression && element.type != 'label') return element;
  647. });
  648. if (connect?.length > 0) {
  649. connect.forEach(sequenceFlow => {
  650. let conditionExpression = moddle.create('bpmn:FormalExpression', {
  651. body: '${' + `${sequenceFlow.id}` + '}',
  652. });
  653. modeling.updateProperties(sequenceFlow, {
  654. conditionExpression: conditionExpression,
  655. });
  656. if (sequenceFlow.label?.x) {
  657. let label = elementRegistry.get(sequenceFlow.label.id);
  658. label.x = sequenceFlow.label.x;
  659. label.y = sequenceFlow.label.y;
  660. modeling.updateProperties(label, {});
  661. }
  662. });
  663. }
  664. };
  665. static gatewayTypeSettings = (bpmn: any, node: any) => {
  666. let elementRegistry: any = bpmn.get('elementRegistry');
  667. let allElement = elementRegistry.getAll();
  668. let jnpfData = bpmn.get('jnpfData');
  669. allElement.map((element: any) => {
  670. if (hasGatewayType.has(element.wnType)) {
  671. let sourceElement = element.incoming[0]?.source;
  672. jnpfData.setValue(sourceElement.id, { divideRule: element.wnType });
  673. if(sourceElement.wmType != typeOutside && node[sourceElement.id]) node[sourceElement.id].divideRule = element.wnType;
  674. } else if (element.wnType != typeTrigger) {
  675. let sourceElement = element.incoming[0]?.source;
  676. if (sourceElement?.id && !hasGatewayType.has(sourceElement.wnType) && node[sourceElement.id]) {
  677. jnpfData.setValue(sourceElement.id, { divideRule: typeInclusion });
  678. node[sourceElement.id].divideRule = typeInclusion;
  679. }
  680. }
  681. });
  682. return node;
  683. };
  684. // 自动生成网关位置
  685. static handleCreateGatewayBounds = (xmlDoc, gatewayId, plane) => {
  686. let gatewayBpmnEdge = xmlDoc.createElement('bpmndi:BPMNShape');
  687. let waypoint = xmlDoc.createElement('dc:Bounds');
  688. gatewayBpmnEdge.setAttribute('id', gatewayId + '_di');
  689. gatewayBpmnEdge.setAttribute('bpmnElement', gatewayId);
  690. waypoint.setAttribute('x', '1');
  691. waypoint.setAttribute('y', '1');
  692. waypoint.setAttribute('width', '1');
  693. waypoint.setAttribute('height', '1');
  694. gatewayBpmnEdge.appendChild(waypoint);
  695. plane.appendChild(gatewayBpmnEdge);
  696. };
  697. // label生成位置
  698. static updateLabelWaypoints: any = (connection, elementRegistry, jnpfData, type = 0) => {
  699. let targetElement = elementRegistry.get(connection.target?.id);
  700. let sourceElement = elementRegistry.get(connection.source?.id);
  701. let labelCenter = getExternalLabelMid(connection);
  702. if (connection?.label && targetElement && sourceElement)
  703. labelCenter = this.updateLabelCenter(targetElement, sourceElement, labelCenter, connection, jnpfData.data?.layout?.value, type);
  704. return labelCenter;
  705. };
  706. static getNewLabelWaypoints: any = (connection, elementRegistry, jnpfData, type = 0) => {
  707. let targetElement = elementRegistry.get(connection.target.id);
  708. let sourceElement = elementRegistry.get(connection.source.id);
  709. let labelCenter = getExternalLabelMid(connection);
  710. labelCenter = this.updateLabelCenter(targetElement, sourceElement, labelCenter, connection, jnpfData.data?.layout?.value, type);
  711. return labelCenter;
  712. };
  713. static updateLabelCenter = (targetElement, sourceElement, labelCenter, connection, layoutType, type) => {
  714. let connectWaypointsStart = connection.waypoints[0];
  715. let connectWaypointsEnd = connection.waypoints[connection.waypoints.length - 1];
  716. let defaultLabelCenter = labelCenter;
  717. if (layoutType === 'horizontal' && type != 1) {
  718. if (targetElement?.incoming?.length > 1) {
  719. labelCenter = {
  720. x: sourceElement.x + sourceElement.width + 16,
  721. y: sourceElement.y + sourceElement.height / 2 - 35,
  722. };
  723. // 如果线条箭头y坐标在targetElement 顶部或者底部 取线条的顶部或者底部位置
  724. if (connectWaypointsEnd?.y === targetElement.y || connectWaypointsEnd?.y === targetElement.y + targetElement.height) {
  725. labelCenter.y = connection.waypoints[1]?.y - 35;
  726. }
  727. if (connectWaypointsStart?.y === sourceElement.y) {
  728. labelCenter = {
  729. x: connectWaypointsStart.x - 70,
  730. y: connectWaypointsStart.y - 35,
  731. };
  732. }
  733. if (connectWaypointsStart.y === sourceElement.y + sourceElement.height) {
  734. labelCenter = {
  735. x: connectWaypointsStart.x - 70,
  736. y: connectWaypointsStart.y + 10,
  737. };
  738. }
  739. if (connectWaypointsStart.x === sourceElement.x) {
  740. labelCenter = {
  741. x: connectWaypointsStart.x - 140,
  742. y: connectWaypointsStart.y - 35,
  743. };
  744. }
  745. if (sourceElement.outgoing.length > 1) {
  746. labelCenter = defaultLabelCenter
  747. }
  748. } else {
  749. // 根据箭头坐标位置不同显示不同的坐标
  750. labelCenter = {
  751. x: targetElement.x - 140,
  752. y: targetElement.y + targetElement.height / 2 - 35,
  753. };
  754. // 上方
  755. if (connectWaypointsEnd?.y === targetElement.y)
  756. labelCenter = {
  757. x: connectWaypointsEnd?.x - 70,
  758. y: connectWaypointsEnd?.y - 35,
  759. };
  760. // 下方
  761. if (connectWaypointsEnd?.y === targetElement.y + targetElement.height)
  762. labelCenter = {
  763. x: connectWaypointsEnd?.x - 70,
  764. y: connectWaypointsEnd?.y + 10,
  765. };
  766. // 右方
  767. if (connectWaypointsEnd?.x === targetElement.x + targetElement.width) {
  768. labelCenter = {
  769. x: connectWaypointsEnd?.x + 10,
  770. y: connectWaypointsEnd?.y - 35,
  771. };
  772. }
  773. // 左方
  774. if (connectWaypointsEnd?.x === targetElement.x) {
  775. labelCenter = {
  776. x: connectWaypointsEnd?.x - 140,
  777. y: connectWaypointsEnd?.y - 35,
  778. };
  779. }
  780. }
  781. }
  782. if ((layoutType === 'vertical' && type != 1) || type === 1) {
  783. if (targetElement?.incoming?.length > 1) {
  784. labelCenter = {
  785. x: connectWaypointsStart.x - 70,
  786. y: sourceElement.y + sourceElement.height + 10,
  787. };
  788. // 左右
  789. if (connectWaypointsStart?.x === sourceElement.x || connectWaypointsStart?.x === sourceElement.x + sourceElement.width) {
  790. labelCenter = {
  791. x: connection.waypoints[1].x - 70,
  792. y: connection.waypoints[2]?.y > connection.waypoints[1]?.y ? connection.waypoints[1].y + 35 : connection.waypoints[1].y - 35,
  793. };
  794. }
  795. //上方
  796. if (connectWaypointsStart?.y === sourceElement.y) {
  797. labelCenter = {
  798. x: connectWaypointsStart.x - 70,
  799. y: sourceElement.y - 35,
  800. };
  801. }
  802. if (sourceElement.outgoing.length > 1) {
  803. labelCenter = defaultLabelCenter
  804. }
  805. } else {
  806. labelCenter = {
  807. x: targetElement.x + targetElement.width / 2 - 20,
  808. y: targetElement.y - 60,
  809. };
  810. // 上方
  811. if (connectWaypointsEnd?.y === targetElement.y)
  812. labelCenter = {
  813. x: connectWaypointsEnd?.x - 70,
  814. y: connectWaypointsEnd?.y - 35,
  815. };
  816. // 下方
  817. if (connectWaypointsEnd?.y === targetElement.y + targetElement.height)
  818. labelCenter = {
  819. x: connectWaypointsEnd?.x - 70,
  820. y: connectWaypointsEnd?.y + 10,
  821. };
  822. // 左方
  823. if (connectWaypointsEnd?.x === targetElement.x)
  824. labelCenter = {
  825. x: targetElement.x - 140,
  826. y: connectWaypointsEnd?.y - 35,
  827. };
  828. // 右方
  829. if (connectWaypointsEnd.x === targetElement?.x + targetElement.width) {
  830. labelCenter = {
  831. x: connectWaypointsEnd?.x + 10,
  832. y: connectWaypointsEnd?.y - 35,
  833. };
  834. }
  835. }
  836. }
  837. return labelCenter;
  838. };
  839. }