vueFlow.vue 20 KB

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