vueFlow.vue 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. <template lang="">
  2. <div class="vueFlow">
  3. <div id="container"></div>
  4. <div id="stencil"></div>
  5. <div id="graph-container"></div>
  6. <div id="minimap"></div>
  7. </div>
  8. <el-button @click="submitAll" type="primary" style="margin-top:15px">保存</el-button>
  9. <el-dialog
  10. title="节点信息配置"
  11. v-model="dialogVisible"
  12. width="800"
  13. v-loading="loading"
  14. >
  15. <byForm
  16. :formConfig="formType === 'handle-btn' ? formConfig : branchBtnConfig"
  17. :formOption="formOption"
  18. v-model="formData.data"
  19. :rules="rules"
  20. ref="byform"
  21. >
  22. </byForm>
  23. <template #footer>
  24. <el-button @click="dialogVisible = false" size="default"
  25. >取 消</el-button
  26. >
  27. <el-button
  28. type="danger"
  29. @click="deleteFlowDefinitionNodeObj()"
  30. size="default"
  31. :loading="submitLoading"
  32. >
  33. 删 除
  34. </el-button>
  35. <el-button
  36. type="primary"
  37. @click="submitForm('byform')"
  38. size="default"
  39. :loading="submitLoading"
  40. >
  41. 确 定
  42. </el-button>
  43. </template>
  44. </el-dialog>
  45. <el-dialog
  46. title="节点信息配置"
  47. v-model="startModalType"
  48. width="500"
  49. v-loading="loading"
  50. >
  51. <div>
  52. 节点后执行方法
  53. <el-input style="margin-top:10px" v-model="handlingMethod"></el-input>
  54. </div>
  55. <template #footer>
  56. <el-button @click="startModalType = false" size="default">取 消</el-button>
  57. <el-button type="primary" @click="startModalType = false" size="default" :loading="submitLoading">
  58. 确 定
  59. </el-button>
  60. </template>
  61. </el-dialog>
  62. </template>
  63. <script lang="ts" setup>
  64. import {
  65. defineComponent,
  66. ref,
  67. onMounted,
  68. onUnmounted,
  69. watch,
  70. reactive,
  71. toRefs,
  72. computed,
  73. nextTick,
  74. getCurrentInstance,
  75. onDeactivated,
  76. onActivated,
  77. } from "vue";
  78. import byForm from "@/components/byForm/index";
  79. import { Graph, Shape } from "@antv/x6";
  80. import { Stencil } from "@antv/x6-plugin-stencil";
  81. import { Transform } from "@antv/x6-plugin-transform";
  82. import { Selection } from "@antv/x6-plugin-selection";
  83. import { Snapline } from "@antv/x6-plugin-snapline";
  84. import { Keyboard } from "@antv/x6-plugin-keyboard";
  85. import { Clipboard } from "@antv/x6-plugin-clipboard";
  86. import { register } from "@antv/x6-vue-shape";
  87. import { History } from "@antv/x6-plugin-history";
  88. import Cookies from "js-cookie";
  89. import { ElMessage, ElMessageBox } from "element-plus";
  90. import startBtn from "./startBtn.vue";
  91. import endBtn from "./endBtn.vue";
  92. import handleBtn from "./handleBtn.vue";
  93. import branchBtn from "./branchBtn.vue";
  94. import { MiniMap } from "@antv/x6-plugin-minimap";
  95. import useTagsViewStore from "@/store/modules/tagsView";
  96. import { rectToBox } from "@vue-flow/core/dist/utils/graph";
  97. defineProps({
  98. title: {
  99. type: Object,
  100. default: "",
  101. },
  102. });
  103. const { proxy } = getCurrentInstance();
  104. const internalInstance = getCurrentInstance();
  105. const dialogVisible = ref(false);
  106. const modalType = ref("add");
  107. const loading = ref(false);
  108. const submitLoading = ref(false);
  109. let formType = ref(1); //1办理 2分支
  110. const formData = reactive({
  111. data: {
  112. userName: "",
  113. password: "",
  114. },
  115. });
  116. const startModalType = ref(false);
  117. const handlingMethod = ref("");
  118. const byform = ref(null);
  119. const flowDefinitionNodeObj = ref({});
  120. const rules = reactive({
  121. nodeName: [
  122. {
  123. required: true,
  124. message: "请输入节点名称",
  125. trigger: "blur",
  126. },
  127. ],
  128. handleObjectType: [
  129. {
  130. required: true,
  131. message: "办理人类型不能为空",
  132. trigger: "blur",
  133. },
  134. ],
  135. handleObjectId: [
  136. {
  137. required: true,
  138. message: "办理人不能为空",
  139. trigger: "blur",
  140. },
  141. ],
  142. });
  143. const branchBtnConfig = computed(() => {
  144. return [
  145. {
  146. type: "input",
  147. prop: "nodeName",
  148. label: "节点名称",
  149. required: true,
  150. itemType: "text",
  151. },
  152. ];
  153. });
  154. const formConfig = computed(() => {
  155. return [
  156. {
  157. type: "input",
  158. prop: "nodeName",
  159. label: "节点名称",
  160. required: true,
  161. itemType: "text",
  162. },
  163. {
  164. type: "select",
  165. prop: "handleObjectType",
  166. label: "办理人",
  167. placeholder: "请选择办理人类型",
  168. required: true,
  169. itemWidth: 50,
  170. fn: (e) => {
  171. gethandleObjectList(e, true);
  172. },
  173. //1用户 2部门负责人 3部门总监 4岗位 5角色
  174. data: [
  175. {
  176. label: "用户",
  177. value: 1,
  178. },
  179. {
  180. label: "部门负责人",
  181. value: 2,
  182. },
  183. {
  184. label: "部门总监",
  185. value: 3,
  186. },
  187. {
  188. label: "岗位",
  189. value: 4,
  190. },
  191. {
  192. label: "角色",
  193. value: 5,
  194. },
  195. ],
  196. },
  197. // {
  198. // type: "treeSelect",
  199. // prop: "handleObjectId",
  200. // label: "请选择办理人",
  201. // itemWidth: 30,
  202. // data: [],
  203. // },
  204. {
  205. type: "select",
  206. label: "",
  207. itemWidth: 50,
  208. prop: "handleObjectId",
  209. placeholder: "请选择办理人",
  210. data: [],
  211. },
  212. {
  213. type: "input",
  214. prop: "handlingMethod",
  215. label: "节点后置执行方法",
  216. required: true,
  217. itemType: "text",
  218. },
  219. {
  220. type: "input",
  221. prop: "jumpCondition",
  222. label: "条件表达式",
  223. required: true,
  224. itemType: "text",
  225. },
  226. {
  227. type: "checkbox",
  228. prop: "nodeButtonSet",
  229. label: "节点按钮",
  230. //1通过 2驳回 3返回上一步 4退回到发起人
  231. data: [
  232. {
  233. label: "通过",
  234. value: 1,
  235. disabled: true,
  236. },
  237. {
  238. label: "驳回",
  239. value: 2,
  240. },
  241. {
  242. label: "返回上一步",
  243. value: 3,
  244. },
  245. {
  246. label: "退回到发起人",
  247. value: 4,
  248. },
  249. ],
  250. },
  251. {
  252. type: "radio",
  253. prop: "jobNumber11",
  254. label: "审批意见必填",
  255. data: [
  256. {
  257. label: "是",
  258. value: 1,
  259. },
  260. {
  261. label: "否",
  262. value: 0,
  263. },
  264. ],
  265. },
  266. ];
  267. });
  268. const formOption = reactive({
  269. inline: true,
  270. labelWidth: 130,
  271. itemWidth: 100,
  272. });
  273. let graph;
  274. const submitForm = () => {
  275. byform.value.handleSubmit((valid) => {
  276. flowDefinitionNodeObj.value[formData.data.id] = formData.data;
  277. dialogVisible.value = false;
  278. formData.data.cell.setData({
  279. title: formData.data.nodeName,
  280. });
  281. });
  282. };
  283. const submitFormData = {
  284. flowInfoId: null,
  285. titleTemplate: null,
  286. tenantId: Cookies.get("tenantId"),
  287. nodeObject: "",
  288. lineObject: "",
  289. flowDefinitionNodeList: [],
  290. };
  291. const submitAll = () => {
  292. if (proxy.title == "") {
  293. ElMessage({
  294. message: "请输入流程标题",
  295. type: "warning",
  296. });
  297. return;
  298. }
  299. submitFormData.titleTemplate = proxy.title;
  300. const nodeList = graph.toJSON().cells;
  301. submitFormData.nodeObject = JSON.stringify(nodeList);
  302. submitFormData.lineObject = JSON.stringify(flowDefinitionNodeObj.value);
  303. console.log(nodeList);
  304. const isStart = false;
  305. for (let i = 0; i < nodeList.length; i++) {
  306. const element = nodeList[i];
  307. //是办理节点
  308. if (
  309. element.shape != "start-btn" &&
  310. element.shape != "edge" &&
  311. element.shape != "end-btn"
  312. ) {
  313. if (!flowDefinitionNodeObj.value[element.id]) {
  314. ElMessage({
  315. message: "有节点未配置,请检查节点",
  316. type: "warning",
  317. });
  318. return;
  319. }
  320. submitFormData.flowDefinitionNodeList.push({
  321. ...flowDefinitionNodeObj.value[element.id],
  322. nodeType: element.shape == "branch-btn" ? 3 : 2,
  323. });
  324. }
  325. if (element.shape == "end-btn") {
  326. submitFormData.flowDefinitionNodeList.push({
  327. ...flowDefinitionNodeObj.value[element.id],
  328. });
  329. }
  330. if (element.shape == "start-btn") {
  331. submitFormData.flowDefinitionNodeList.push({
  332. nodeName: "开始",
  333. nodeType: 1,
  334. id: 1,
  335. parentId: 0,
  336. nodeButtonSet: [1],
  337. handlingMethod: handlingMethod.value,
  338. });
  339. }
  340. //说明是线
  341. if (element.shape == "edge") {
  342. if (!flowDefinitionNodeObj.value[element.target.cell]) {
  343. ElMessage({
  344. message: "有节点未配置,请检查节点",
  345. type: "warning",
  346. });
  347. return;
  348. }
  349. flowDefinitionNodeObj.value[element.target.cell].id = element.target.cell;
  350. flowDefinitionNodeObj.value[element.target.cell].parentId =
  351. element.source.cell;
  352. submitFormData.flowDefinitionNodeList = [];
  353. }
  354. }
  355. addVersion();
  356. };
  357. //选取一个随机不重复的正整数id
  358. const randomId = () => {
  359. const id = Math.floor(Math.random() * 100000000000000000);
  360. if (flowDefinitionNodeObj.value[id]) {
  361. randomId();
  362. } else {
  363. return id;
  364. }
  365. };
  366. const addVersion = () => {
  367. const idObg = {};
  368. for (let i = 0; i < submitFormData.flowDefinitionNodeList.length; i++) {
  369. const element = submitFormData.flowDefinitionNodeList[i];
  370. if (element.parentId == null && element.nodeName == "结束") {
  371. ElMessage({
  372. message: "有结束节点未连线,请配置",
  373. type: "warning",
  374. });
  375. return;
  376. }
  377. if (isNaN(element.id)) {
  378. if (idObg[element.id]) {
  379. element.id = idObg[element.id];
  380. } else {
  381. const id = randomId();
  382. idObg[element.id] = id;
  383. element.id = id;
  384. }
  385. }
  386. if (isNaN(element.parentId) && element.nodeName != "开始") {
  387. if (idObg[element.parentId]) {
  388. element.parentId = idObg[element.parentId];
  389. } else {
  390. const id = randomId();
  391. idObg[element.parentId] = id;
  392. element.parentId = id;
  393. }
  394. }
  395. //nodeButtonSet转成字符串类型,用逗号隔开
  396. if (element.nodeButtonSet) {
  397. element.nodeButtonSet = element.nodeButtonSet.join(",");
  398. }
  399. }
  400. proxy.post("/flowDefinition/addVersion", submitFormData).then((res) => {
  401. ElMessage({
  402. message: "保存成功",
  403. type: "success",
  404. });
  405. useTagsViewStore().delView(router.currentRoute.value);
  406. history.go(-1);
  407. });
  408. };
  409. //将组数里的id和parentId转换成整正整数类型
  410. const changeId = (arr) => {
  411. for (let i = 0; i < arr.length; i++) {
  412. const element = arr[i];
  413. element.id = parseInt(element.id);
  414. element.parentId = parseInt(element.parentId);
  415. }
  416. };
  417. const deleteFlowDefinitionNodeObj = (id) => {
  418. graph.removeNode(formData.data.id);
  419. delete flowDefinitionNodeObj.value[id];
  420. dialogVisible.value = false;
  421. };
  422. const gethandleObjectList = (e, flag) => {
  423. if (flag) {
  424. formData.data.handleObjectId = "";
  425. }
  426. if (e === 1) {
  427. proxy
  428. .get(
  429. "/tenantUser/list?pageNum=1&pageSize=1000&tenantId=" +
  430. submitFormData.tenantId,
  431. {}
  432. )
  433. .then((res) => {
  434. formConfig.value[2].data = res.rows.map((item) => {
  435. return {
  436. label: item.nickName,
  437. value: item.userId,
  438. };
  439. });
  440. });
  441. }
  442. if (e === 3 || e === 2) {
  443. proxy
  444. .get(
  445. "/tenantDept/list?pageNum=1&pageSize=1000&tenantId=" +
  446. submitFormData.tenantId,
  447. {}
  448. )
  449. .then((res) => {
  450. formConfig.value[2].data = res.data.map((item) => {
  451. return {
  452. label: item.deptName,
  453. value: item.deptId,
  454. };
  455. });
  456. });
  457. }
  458. if (e === 4) {
  459. }
  460. if (e === 5) {
  461. proxy
  462. .get(
  463. "/tenantRole/list?pageNum=1&pageSize=1000&tenantId=" +
  464. submitFormData.tenantId,
  465. {}
  466. )
  467. .then((res) => {
  468. formConfig.value[2].data = res.rows.map((item) => {
  469. return {
  470. label: item.roleName,
  471. value: item.roleId,
  472. };
  473. });
  474. });
  475. }
  476. };
  477. const getTenantDept = () => {};
  478. getTenantDept();
  479. const recursive = (data) => {
  480. data.map((item) => {
  481. item.label = item.deptName;
  482. item.id = item.deptId;
  483. if (item.children) {
  484. recursive(item.children);
  485. } else {
  486. item.children = [];
  487. }
  488. });
  489. };
  490. const pushRoom = (port: any) => {
  491. if (port.node.shape == "end-btn") {
  492. flowDefinitionNodeObj.value[port.node.id] = {
  493. nodeName: "结束",
  494. nodeType: 99,
  495. id: port.id,
  496. nodeButtonSet: "",
  497. parentId: null,
  498. };
  499. }
  500. };
  501. //用于存储流程定义节点数据
  502. const antvInit = (data) => {
  503. graph = new Graph({
  504. height: 600,
  505. container: document.getElementById("graph-container")!,
  506. grid: true,
  507. onPortRendered: pushRoom,
  508. mousewheel: {
  509. enabled: true,
  510. zoomAtMousePosition: true,
  511. modifiers: "ctrl",
  512. minScale: 0.5,
  513. maxScale: 3,
  514. },
  515. connecting: {
  516. allowLoop: false,
  517. // router: 'manhattan',
  518. connector: {
  519. name: "rounded",
  520. args: {
  521. radius: 8,
  522. },
  523. },
  524. anchor: "center",
  525. connectionPoint: "anchor",
  526. allowBlank: false,
  527. snap: {
  528. radius: 20,
  529. },
  530. createEdge() {
  531. return new Shape.Edge({
  532. attrs: {
  533. line: {
  534. stroke: "#A2B1C3",
  535. strokeWidth: 2,
  536. targetMarker: {
  537. name: "block",
  538. width: 12,
  539. height: 8,
  540. },
  541. },
  542. },
  543. zIndex: 0,
  544. });
  545. },
  546. validateConnection({ targetMagnet }) {
  547. return !!targetMagnet;
  548. },
  549. },
  550. highlighting: {
  551. magnetAdsorbed: {
  552. name: "stroke",
  553. args: {
  554. attrs: {
  555. fill: "#5F95FF",
  556. stroke: "#5F95FF",
  557. },
  558. },
  559. },
  560. },
  561. });
  562. graph.use(
  563. new MiniMap({
  564. container: document.getElementById("minimap"),
  565. })
  566. );
  567. const stencil = new Stencil({
  568. title: "流程图",
  569. target: graph,
  570. stencilGraphWidth: 360,
  571. stencilGraphHeight: 280,
  572. collapsable: true,
  573. groups: [
  574. {
  575. title: "基础流程图",
  576. name: "group1",
  577. },
  578. ],
  579. layoutOptions: {
  580. columns: 1,
  581. columnWidth: 170,
  582. rowHeight: 100,
  583. },
  584. });
  585. document.getElementById("stencil")!.appendChild(stencil.container);
  586. // #region 使用插件
  587. graph
  588. .use(
  589. new Transform({
  590. resizing: true,
  591. rotating: true,
  592. })
  593. )
  594. .use(
  595. new Selection({
  596. enabled: true,
  597. rubberband: true,
  598. showNodeSelectionBox: true,
  599. })
  600. )
  601. .use(
  602. new Snapline({
  603. enabled: true,
  604. })
  605. )
  606. .use(
  607. new Keyboard({
  608. enabled: true,
  609. })
  610. )
  611. .use(
  612. new Clipboard({
  613. enabled: true,
  614. })
  615. )
  616. .use(
  617. new History({
  618. enabled: true,
  619. })
  620. );
  621. // 控制连接桩显示/隐藏
  622. const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
  623. for (let i = 0, len = ports.length; i < len; i += 1) {
  624. ports[i].style.visibility = show ? "visible" : "hidden";
  625. }
  626. };
  627. graph.on("node:mouseenter", () => {
  628. const container = document.getElementById("graph-container")!;
  629. const ports = container.querySelectorAll(
  630. ".x6-port-body"
  631. ) as NodeListOf<SVGElement>;
  632. showPorts(ports, true);
  633. });
  634. graph.on("node:mouseleave", () => {
  635. const container = document.getElementById("graph-container")!;
  636. const ports = container.querySelectorAll(
  637. ".x6-port-body"
  638. ) as NodeListOf<SVGElement>;
  639. showPorts(ports, false);
  640. });
  641. // #endregion
  642. graph.on("cell:click", ({ e, x, y, cell, view }) => {
  643. console.log(flowDefinitionNodeObj.value);
  644. console.log(cell);
  645. if (cell.shape === "start-btn") {
  646. startModalType.value = true;
  647. return;
  648. }
  649. if (cell.shape === "end-btn" || cell.shape === "edge") {
  650. ElMessageBox.confirm("是否删除", "提示", {
  651. confirmButtonText: "确定",
  652. cancelButtonText: "取消",
  653. type: "warning",
  654. }).then(() => {
  655. graph.removeNode(cell.id);
  656. // delete flowDefinitionNodeObj.value[id]
  657. });
  658. return;
  659. }
  660. formType.value = cell.shape;
  661. if (flowDefinitionNodeObj.value[cell.id]) {
  662. // 默认去调对应的处理人接口
  663. gethandleObjectList(
  664. flowDefinitionNodeObj.value[cell.id].handleObjectType
  665. );
  666. setTimeout(() => {
  667. formData.data = flowDefinitionNodeObj.value[cell.id];
  668. formData.data.cell = cell;
  669. }, 300);
  670. } else {
  671. formData.data = {
  672. id: cell.id,
  673. cell: cell,
  674. nodeButtonSet: [1],
  675. };
  676. }
  677. dialogVisible.value = true;
  678. });
  679. // #region 初始化图形
  680. const ports = {
  681. groups: {
  682. top: {
  683. position: "top",
  684. attrs: {
  685. circle: {
  686. r: 4,
  687. magnet: true,
  688. stroke: "#5F95FF",
  689. strokeWidth: 1,
  690. fill: "#fff",
  691. style: {
  692. visibility: "hidden",
  693. },
  694. },
  695. },
  696. },
  697. right: {
  698. position: "right",
  699. attrs: {
  700. circle: {
  701. r: 4,
  702. magnet: true,
  703. stroke: "#5F95FF",
  704. strokeWidth: 1,
  705. fill: "#fff",
  706. style: {
  707. visibility: "hidden",
  708. },
  709. },
  710. },
  711. },
  712. bottom: {
  713. position: "bottom",
  714. attrs: {
  715. circle: {
  716. r: 4,
  717. magnet: true,
  718. stroke: "#5F95FF",
  719. strokeWidth: 1,
  720. fill: "#fff",
  721. style: {
  722. visibility: "hidden",
  723. },
  724. },
  725. },
  726. },
  727. left: {
  728. position: "left",
  729. attrs: {
  730. circle: {
  731. r: 4,
  732. magnet: true,
  733. stroke: "#5F95FF",
  734. strokeWidth: 1,
  735. fill: "#fff",
  736. style: {
  737. visibility: "hidden",
  738. },
  739. },
  740. },
  741. },
  742. },
  743. items: [
  744. {
  745. group: "top",
  746. },
  747. {
  748. group: "right",
  749. },
  750. {
  751. group: "bottom",
  752. },
  753. {
  754. group: "left",
  755. },
  756. ],
  757. };
  758. Graph.registerNode(
  759. "custom-rect",
  760. {
  761. inherit: "rect",
  762. width: 66,
  763. height: 36,
  764. attrs: {
  765. body: {
  766. strokeWidth: 1,
  767. stroke: "#5F95FF",
  768. fill: "#EFF4FF",
  769. },
  770. text: {
  771. fontSize: 12,
  772. fill: "#262626",
  773. },
  774. },
  775. ports: { ...ports },
  776. },
  777. true
  778. );
  779. register({
  780. shape: "start-btn",
  781. width: 150,
  782. height: 90,
  783. component: startBtn,
  784. effect: ["title"],
  785. ports: { ...ports },
  786. data: {
  787. title: 80,
  788. },
  789. });
  790. register({
  791. shape: "handle-btn",
  792. width: 150,
  793. height: 90,
  794. effect: ["title"],
  795. component: handleBtn,
  796. ports: { ...ports },
  797. });
  798. register({
  799. shape: "branch-btn",
  800. width: 150,
  801. height: 90,
  802. effect: ["title"],
  803. component: branchBtn,
  804. ports: { ...ports },
  805. });
  806. register({
  807. shape: "end-btn",
  808. width: 150,
  809. height: 90,
  810. effect: ["title"],
  811. component: endBtn,
  812. ports: { ...ports },
  813. });
  814. // const r1 = graph.createNode({
  815. // shape: 'start-btn',
  816. // label: '开始',
  817. // zIndex: 100,
  818. // attrs: {
  819. // body: {
  820. // rx: 20,
  821. // ry: 26,
  822. // },
  823. // },
  824. // data: {
  825. // title: 80,
  826. // },
  827. // })
  828. const r2 = graph.createNode({
  829. shape: "handle-btn",
  830. label: "办理",
  831. zIndex: 100,
  832. attrs: {
  833. body: {
  834. rx: 40,
  835. ry: 46,
  836. },
  837. },
  838. });
  839. const r3 = graph.createNode({
  840. shape: "branch-btn",
  841. label: "分支",
  842. zIndex: 100,
  843. attrs: {
  844. body: {
  845. rx: 40,
  846. ry: 46,
  847. },
  848. },
  849. });
  850. const r4 = graph.createNode({
  851. shape: "end-btn",
  852. label: "结束",
  853. zIndex: 100,
  854. attrs: {
  855. body: {
  856. rx: 20,
  857. ry: 26,
  858. },
  859. },
  860. });
  861. stencil.load([r2, r3, r4], "group1");
  862. // const startNode = graph.addNode({
  863. // shape: 'custom-rect',
  864. // label: '开始',
  865. // id: 1,
  866. // x: 500,
  867. // y: 100,
  868. // })
  869. if (data) {
  870. graph.fromJSON(data);
  871. } else {
  872. graph.addNode({
  873. shape: "start-btn",
  874. x: 500,
  875. y: 20,
  876. label: "开始",
  877. id: 1,
  878. attrs: {},
  879. });
  880. }
  881. };
  882. const getFlowInfo = () => {
  883. proxy
  884. .post("/flowDefinition/getDetails", { id: submitFormData.id })
  885. .then((res) => {
  886. if (res.lineObject) {
  887. flowDefinitionNodeObj.value = JSON.parse(res.lineObject);
  888. for (const key in flowDefinitionNodeObj.value) {
  889. if (flowDefinitionNodeObj.value[key].nodeButtonSet) {
  890. flowDefinitionNodeObj.value[key].nodeButtonSet =
  891. flowDefinitionNodeObj.value[key].nodeButtonSet.map((item) => {
  892. return item * 1;
  893. });
  894. }
  895. }
  896. }
  897. if (res.nodeObject) {
  898. antvInit(JSON.parse(res.nodeObject));
  899. } else {
  900. antvInit();
  901. }
  902. for (const key in flowDefinitionNodeObj.value) {
  903. //延迟等待dom渲染完成
  904. setTimeout(() => {
  905. if (
  906. flowDefinitionNodeObj.value[key].nodeName != "结束" &&
  907. flowDefinitionNodeObj.value[key].cell != "开始"
  908. ) {
  909. let htmlNode = document.querySelector(
  910. "g[data-cell-id='" + key + "']"
  911. );
  912. //获取htmlNode节点下的title,修改title的内容
  913. htmlNode.getElementsByClassName("title")[0].innerHTML =
  914. flowDefinitionNodeObj.value[key].nodeName;
  915. }
  916. }, 2000);
  917. }
  918. dialogVisible.value = false;
  919. });
  920. };
  921. const router = useRouter();
  922. onActivated(() => {});
  923. onDeactivated(() => {
  924. console.log(window.document.getElementById("minimap").children);
  925. if (window.document.getElementById("minimap").children.length > 1) {
  926. window.document.getElementById("minimap").children[0].remove();
  927. }
  928. });
  929. onMounted(() => {
  930. //获取url router参数
  931. submitFormData.flowInfoId = router.currentRoute.value.query.flowInfoId;
  932. submitFormData.id = router.currentRoute.value.query.id;
  933. submitFormData.tenantId = router.currentRoute.value.query.tenantId;
  934. if (submitFormData.flowInfoId) {
  935. getFlowInfo();
  936. // antvInit()
  937. // setTimeout(() => {
  938. // for (let i = 0; i < dataJson.flowDefinitionNodeList.length; i++) {
  939. // const element = dataJson.flowDefinitionNodeList[i];
  940. // console.log(element)
  941. // if(!element.cell) {
  942. // continue
  943. // }
  944. // if( element.cell.nodeName != '开始' && element.cell.nodeName != '结束'){
  945. // flowDefinitionNodeObj.value[element.cell.id] = element
  946. // flowDefinitionNodeObj.value[element.cell.id].nodeButtonSet = element.nodeButtonSet.split(',')
  947. // graph.addNode({
  948. // shape: 'handle-btn',
  949. // x: element.cell.position.x,
  950. // y: element.cell.position.y,
  951. // label: '办理',
  952. // id:element.cell.id,
  953. // attrs: {
  954. // },
  955. // })
  956. // }
  957. // }
  958. // console.log(flowDefinitionNodeObj.value)
  959. // }, 1000);
  960. }
  961. setTimeout(() => {
  962. if (window.document.getElementById("minimap").children.length > 1) {
  963. window.document.getElementById("minimap").children[0].remove();
  964. }
  965. }, 500);
  966. });
  967. </script>
  968. <style lang="scss" scope>
  969. #minimap .x6-widget-minimap {
  970. border: 1px solid #dcdcdc;
  971. }
  972. .x6-widget-stencil-group-title {
  973. display: none !important;
  974. }
  975. .x6-widget-stencil-title {
  976. display: none;
  977. }
  978. .x6-widget-stencil-content {
  979. top: 0 !important;
  980. &::-webkit-scrollbar {
  981. width: 2px !important;
  982. height: 2px !important;
  983. }
  984. }
  985. .vueFlow {
  986. position: relative;
  987. display: flex;
  988. justify-content: space-between;
  989. overflow: hidden;
  990. height: 600px;
  991. .x6-graph {
  992. width: 100% !important;
  993. }
  994. #stencil {
  995. position: fixed;
  996. top: 250px;
  997. left: 30px;
  998. z-index: 100;
  999. width: 190px;
  1000. height: 550px;
  1001. background: #fff;
  1002. overflow: hidden;
  1003. background: #eee;
  1004. border-radius: 20px;
  1005. }
  1006. #container {
  1007. }
  1008. #graph-container {
  1009. width: 100%;
  1010. position: absolute;
  1011. right: 0;
  1012. top: 0;
  1013. }
  1014. }
  1015. #stencil .x6-widget-stencil-content .x6-widget-stencil-group-content .x6-graph {
  1016. height: 900px !important;
  1017. }
  1018. </style>