From d1ac67834e4bd2621809a9c778714bf575f80117 Mon Sep 17 00:00:00 2001 From: wente <329538422@qq.com> Date: 星期三, 29 十一月 2023 16:16:15 +0800 Subject: [PATCH] 流程图 --- web/src/views/modules/flowChart/flowChartEdit.vue | 827 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 827 insertions(+), 0 deletions(-) diff --git a/web/src/views/modules/flowChart/flowChartEdit.vue b/web/src/views/modules/flowChart/flowChartEdit.vue new file mode 100644 index 0000000..82c17c2 --- /dev/null +++ b/web/src/views/modules/flowChart/flowChartEdit.vue @@ -0,0 +1,827 @@ +<template> + <div> + <el-row :gutter="[8,8]"> + <el-col :span="3"> + <div class="fa-card-a"> + <div id="stencil2" :style="'height:'+ left_p + 'px'"></div> + </div> + </el-col> + <el-col :span="21"> + <div class="fa-card-a"> + <el-form :inline="true"> + <el-form-item prop="flowId" style="margin-left:10px;width: 180px;"> + <zt-select v-model="flowId" :datas="flowList" @change="flowChange" placeholder="宸ョ▼椤圭洰" + clearable></zt-select> + </el-form-item> + <el-form-item> + <el-button type="primary" v-show="dataForm.id" @click="saveDiagram()">淇濆瓨</el-button> + </el-form-item> + </el-form> + <div id="flowChart"> + </div> + <flowChartNode v-show="type === 'node'" :flowId="flowId" :id="id" :globalGridAttr="globalGridAttr" + :graph="graph"/> + <flowChart-edge v-show="type === 'edge'" :flowId="flowId" :id="id" :globalGridAttr="globalGridAttr" + :graph="graph"/> + </div> + </el-col> + </el-row> + </div> +</template> + +<script> +import {Graph, Shape, Addon, Cell} from '@antv/x6'; +import ConfigNode from './ConfigNode/index.vue' +import flowChartNode from './flowChartNode/index.vue' +import flowChartEdge from './flowChartEdge/index.vue' + +export default { + name: "flowChart-edit", + components: { + flowChartNode, + ConfigNode, + flowChartEdge + }, + data() { + return { + shape: '', + diagramList:[], + diagramName:'', + diagramId:'', + flowList: '', + flowId: '', + diagramJson: '', + dataForm: { // 娴佺▼鍥惧唴瀹� + id: null, + diagram: null + }, + type: '', + id: '', + graph: null, + emptyJson: { + // 鑺傜偣 + nodes: [ + { + id: 'node1', // String锛屽彲閫夛紝鑺傜偣鐨勫敮涓�鏍囪瘑 + width: 500, // Number锛屽彲閫夛紝鑺傜偣澶у皬鐨� width 鍊� + height: 300, // Number锛屽彲閫夛紝鑺傜偣澶у皬鐨� height 鍊� + label: '璇ユ祦绋嬪浘杩樻病鏈夐厤缃�', + attrs: { + body: { + strokeWidth: 0 + }, + } + // text: { + // text: '璇ラ」鐩繕鏈紪鍒剁綉缁滃浘', + // // fontSize: 56, + // fill: 'rgba(0,0,0,0.7)' + // }, + // }, + } + ], + }, + globalGridAttr: { + type: 'mesh', + size: 10, + color: '#e5e5e5', + thickness: 1, + colorSecond: '#d0d0d0', + thicknessSecond: 1, + factor: 4, + bgColor: '#e5e5e5', + showImage: true, + repeat: 'watermark', + angle: 30, + position: 'center', + bgSize: JSON.stringify({width: 150, height: 150}), + opacity: 0.1, + + stroke: '#5F95FF', + strokeWidth: 1, + connector: 'normal', + label: '', + + nodeStroke: '#5F95FF', + nodeStrokeWidth: 1, + nodeFill: '#ffffff', + nodeFontSize: 12, + nodeColor: '#080808', + nodeText: '', + nodeDate: '', + nodeUsers: '', + nodeDataDate: '', + nodeDataText: '' + }, + isReady: false, + curCel: Cell, + left_p: document.documentElement.clientHeight -220, + ports: { + groups: { + top: { + position: 'top', + attrs: { + circle: { + r: 8, + magnet: true, + stroke: '#5F95FF', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden', + }, + }, + }, + }, + right: { + position: 'right', + attrs: { + circle: { + r: 8, + magnet: true, + stroke: '#5F95FF', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden', + }, + }, + }, + }, + bottom: { + position: 'bottom', + attrs: { + circle: { + r: 8, + magnet: true, + stroke: '#5F95FF', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden', + }, + }, + }, + }, + left: { + position: 'left', + attrs: { + circle: { + r: 8, + magnet: true, + stroke: '#5F95FF', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden', + }, + }, + }, + }, + }, + items: [ + { + group: 'top', + }, + { + group: 'right', + }, + { + group: 'bottom', + }, + { + group: 'left', + }, + ], + } + } + }, + watch: { + }, + methods: { + async getFlowList() { + let res = await this.$http.get(`/WfDef/getFlowList`) + this.flowList = res.data + console.log(this.flowList,'this.flowList') + for (let i = 0; i < this.flowList.length; i++) { + if (this.flowList[i] && this.flowList[i].id) { + this.flowId = this.flowList[i].id + console.log(this.flowId, 'this.flowId 6789') + break + } + } + this.flowChange(this.flowId) + }, + flowChange() { + this.dataForm.id = this.flowId + // this.flowId = this.dataForm.id + console.log(this.flowId,'this.flowId') + this.getDiagram() + }, + async getDiagram() { + let res = await this.$http.get(`/WfDef/${this.flowId}`) + if (res.data !== null) { + this.dataForm = res.data + if (res.data.diagram != null && res.data.diagram != '') + this.diagramJson = JSON.parse(this.dataForm.diagram) + else + this.diagramJson = this.emptyJson + console.log(this.diagramJson, 'this.Diagram json') + this.graph.fromJSON(this.diagramJson) + this.graph.centerContent() + this.graph.zoomToFit() + // this.graph.freeze('flowChart') + } else { + this.dataForm.id = null +/* this.graph.fromJSON(this.emptyJson) + this.graph.centerContent() + this.graph.zoomToFit() + this.graph.freeze()*/ + } + }, + init1() { + // console.log(document.documentElement.clientWidth, 'document.documentElement.clientWidth') + // console.log(document.documentElement.clientHeight, 'document.documentElement.clientHeight') + this.graph = new Graph({ + container: document.getElementById('flowChart'), + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight - 240, + // async: true, + grid: { + visible: true, + }, + onToolItemCreated({ tool }) { + const handle = tool + const options = handle.options + if (options && options.index % 2 === 1) { + tool.setAttrs({ fill: 'red' }) + } + }, + autoResize: true, + history: true, + panning: { + enabled: false, + }, + scroller: { + enabled: true, + pageVisible: true, + pageBreak: true, + pannable: true, + }, + mousewheel: { + enabled: true, + zoomAtMousePosition: true, + modifiers: 'ctrl', + minScale: 0.5, + maxScale: 2, + }, + connecting: { + router: { name: 'manhattan' }, + connector: { name: 'rounded' }, + // anchor: 'center', + connectionPoint: 'anchor', + allowBlank: false, + createEdge() { + return new Shape.Edge({ + attrs: { + line: { + stroke: '#A2B1C3', + strokeWidth: 2, + targetMarker: 'classic' + } + }, + tools: { + name: 'segments', + args: { + snapRadius: 20, + attrs: { + fill: '#444', + }, + }, + }, + zIndex: 0, + }) + }, + validateConnection({targetMagnet}) { + return !!targetMagnet + }, + }, + highlighting: { + magnetAdsorbed: { + name: 'stroke', + args: { + attrs: { + fill: '#5F95FF', + stroke: '#5F95FF', + }, + }, + }, + }, + resizing: { + enabled:true, + restricted:true + }, + rotating: true, + selecting: { + enabled: true, + rubberband: true, + rubberEdge: true, + showNodeSelectionBox: true, + }, + snapline: true, + keyboard: true, + clipboard: true, + }) + // graph.fromJSON( + // {nodes:nodes, + // edges:edges} + // ) + this.graph.centerContent() + const stencil = new Addon.Stencil({ + title: '', + target: this.graph, + stencilGraphWidth: 200, + stencilGraphHeight: 480, + // collapsable: true, + groups: [ + { + title: '鍥惧厓', + name: 'group1', + } + ], + layoutOptions: { + columns: 1, + columnWidth: 120, + // rowHeight: 75, + }, + }) + document.getElementById('stencil2').appendChild(stencil.container) + + Graph.registerNode( + 'custom-polygon', + { + inherit: 'polygon', + width: 86, + height: 56, + attrs: { + body: { + strokeWidth: 1, + stroke: '#5F95FF', + fill: '#EFF4FF', + }, + // title:{ + // text:'', + // refX: 40, + // refY: 38, + // fontSize: 14, + // fill: '#262626', + // 'text-anchor': 'start', + // }, + text: { + // refX: 40, + // refY: 14, + fontSize: 14, + fill: '#262626', + // 'text-anchor': 'start', + }, + }, + // markup: [ + // { + // tagName: 'polygon', + // selector: 'body', + // }, + // { + // tagName: 'text', + // selector: 'title', + // }, + // { + // tagName: 'text', + // selector: 'text', + // }, + // ], + ports: { + ...this.ports + // items: [ + // { + // group: 'top', + // }, + // { + // group: 'bottom', + // }, + // ], + }, + }, + true, + ) + + Graph.registerNode( + 'custom-circle', + { + inherit: 'ellipse', + width: 86, + height: 56, + data: { + dataId: '', + finishDate: '' + }, + attrs: { + body: { + strokeWidth: 1, + stroke: '#5F95FF', + fill: '#EFF4FF', + }, + title: { + text: '', + fontSize: 14, + fill: '#262626', + refX: 0.5, + refY: '100%', + refY2: 4, + textAnchor: 'middle', + textVerticalAnchor: 'top', + }, + text: { + fontSize: 14, + fill: '#262626', + refX: 0.5, + refY: 0.5, + textAnchor: 'middle', + textVerticalAnchor: 'middle', + }, + }, + markup: [ + { + tagName: 'ellipse', + selector: 'body', + }, + { + tagName: 'text', + selector: 'title', + }, + { + tagName: 'text', + selector: 'text', + }, + ], + ports: {...this.ports}, + }, + true, + ) + const r6 = this.graph.createNode({ + shape: 'text-block', + label: '鍙�夎繃绋�', + width: 86, + height: 56, + data: { + stepMarker:'' + }, + attrs: { + body: { + strokeWidth: 1, + stroke: '#5F95FF', + fill: '#EFF4FF', + rx: 6, + ry: 6 + }, + text: { + text: '鍙�夎繃绋�', + fontSize: 14, + fill: '#262626', + refX: '0', + refY: -0.5, + refY2: '0', + textAnchor: 'middle', + textVerticalAnchor: 'middle', + }, + }, + markup: [ + { + tagName: 'rect', + selector: 'body', + }, + { + tagName: 'text', + selector: 'text', + }, + ], + ports: {...this.ports}, + }) + const r4 = this.graph.createNode({ + shape: 'custom-polygon', + data: { + stepMarker:'' + }, + attrs: { + body: { + refPoints: '0,10 10,0 20,10 10,20', + }, + }, + label: '鍐崇瓥', + }) + const r5 = this.graph.createNode({ + shape: 'custom-circle', + data: { + stepMarker:'' + }, + label: '闃舵', + }) + stencil.load([r4, r5,r6], 'group1') + + this.graph.bindKey(['meta+c', 'ctrl+c'], () => { + const cells = this.graph.getSelectedCells() + if (cells.length) { + this.graph.copy(cells) + } + return false + }) + + this.graph.bindKey(['meta+x', 'ctrl+x'], () => { + const cells = this.graph.getSelectedCells() + if (cells.length) { + this.graph.cut(cells) + } + return false + }) + + this.graph.bindKey(['meta+v', 'ctrl+v'], () => { + if (!this.graph.isClipboardEmpty()) { + const cells = this.graph.paste({offset: 32}) + this.graph.cleanSelection() + this.graph.select(cells) + } + return false + }) +//undo redo + this.graph.bindKey(['meta+z', 'ctrl+z'], () => { + if (this.graph.history.canUndo()) { + this.graph.history.undo() + } + return false + }) + + this.graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => { + if (this.graph.history.canRedo()) { + this.graph.history.redo() + } + return false + }) + +// select all + this.graph.bindKey(['meta+a', 'ctrl+a'], () => { + const nodes = this.graph.getNodes() + if (nodes) { + this.graph.select(nodes) + } + }) +//delete + this.graph.bindKey('delete', () => { + const cells = this.graph.getSelectedCells() + if (cells.length) { + this.graph.removeCells(cells) + } + }) +// zoom + this.graph.bindKey(['ctrl+1', 'meta+1'], () => { + const zoom = this.graph.zoom() + if (zoom < 1.5) { + this.graph.zoom(0.1) + } + }) + + this.graph.bindKey(['ctrl+2', 'meta+2'], () => { + const zoom = this.graph.zoom() + if (zoom > 0.5) { + this.graph.zoom(-0.1) + } + }) + + this.graph.on('blank:click', ({cell}) => { + this.reset() + this.type = 'grid' + // this.id = cell.id + }) + + this.graph.on('cell:click', ({cell}) => { + // this.type.value = cell.isNode() ? "node" : "edge" + this.type = cell.isNode() ? "node" : "edge" + this.shape = cell.shape + this.id = cell.id + // this.nodeOpt(this.id, this.globalGridAttr) + }) + //鍗曞嚮杈硅妭鐐� + this.graph.on('edge:click', ({edge}) => { + this.reset() + edge.attr('line/stroke', 'orange') + edge.prop('labels/0', { + attrs: { + body: { + stroke: 'orange', + }, + }, + }) + }) + // 鍗曞嚮node鑺傜偣 + this.graph.on('node:click', ({node}) => { + this.reset() + node.attr('line/stroke', 'orange') + node.prop('labels/0', { + attrs: { + body: { + stroke: 'orange', + }, + }, + }) + }) + // 鎺у埗杩炴帴妗╂樉绀�/闅愯棌 + this.graph.on('node:delete', ({view, e}) => { + e.stopPropagation() + view.cell.remove() + }) + + this.graph.on('node:customevent', ({name, view, e}) => { + if (name === 'node:delete') { + e.stopPropagation() + view.cell.remove() + } + }) + // 鍙屽嚮缂栬緫 + this.graph.on('cell:dblclick', ({cell, e}) => { + const isNode = cell.isNode() + const name = cell.isNode() ? 'node-editor' : 'edge-editor' + cell.removeTool(name) + cell.addTools({ + name, + args: { + event: e, + attrs: { + backgroundColor: isNode ? '#EFF4FF' : '#FFF', + text: { + fontSize: 16, + fill: '#262626', + }, + }, + }, + }) + }) + + this.graph.on('node:mouseenter', ({node}) => { + const flowChart = document.getElementById('flowChart') + const ports = flowChart.querySelectorAll( + '.x6-port-body', + ) + this.showPorts(ports, true) + }) + + this.graph.on('node:mouseleave', ({node}) => { + // if (node.hasTool('button-remove')) { + // node.removeTool('button-remove') + // } + const flowChart = document.getElementById('flowChart') + const ports = flowChart.querySelectorAll( + '.x6-port-body', + ) + this.showPorts(ports, false) + }) + + this.graph.on('edge:mouseenter', ({cell}) => { + cell.addTools([ + { + name: 'source-arrowhead', + }, + { + name: 'target-arrowhead', + args: { + attrs: { + fill: 'red', + }, + }, + }, + ]) + cell.addTools( + [ + { + name: 'segments', + args: {snapRadius: 20, attrs: {fill: '#444'}} + } + ] + ) + }) + + this.graph.on('edge:mouseleave', ({cell}) => { + cell.removeTools() + }) + }, + reset() { + this.graph.drawBackground({color: '#fff'}) + const nodes = this.graph.getNodes() + const edges = this.graph.getEdges() + nodes.forEach((node) => { + node.attr('body/stroke', '#5F95FF') + }) + edges.forEach((edge) => { + edge.attr('line/stroke', '#5F95FF') + edge.prop('labels/0', { + attrs: { + body: { + stroke: '#5F95FF', + }, + }, + }) + }) + }, + showPorts(ports, show) { + for (let i = 0, len = ports.length; i < len; i = i + 1) { + ports[i].style.visibility = show ? "visible" : "hidden" + } + }, + nodeOpt(id, globalGridAttr) { + this.curCel = null + if (id) { + let cell = this.graph.getCellById(id) + // console.log(cell, 'let cell 123456') + if (!cell || !cell.isNode()) { + return + } + this.curCel = cell + globalGridAttr.nodeStroke = cell.attr('body/stroke') + globalGridAttr.nodeStrokeWidth = cell.attr('body/strokeWidth') + globalGridAttr.nodeFill = cell.attr('body/fill') + globalGridAttr.nodeFontSize = cell.attr('text/fontSize') + globalGridAttr.nodeFontSize = cell.attr('title/fontSize') + globalGridAttr.nodeColor = cell.attr('text/fill') + globalGridAttr.nodeColor = cell.attr('title/fill') + // globalGridAttr.nodeColor = cell.attr('label/text/fill') + // globalGridAttr.nodeColor = cell.attr('label/title/fill') + globalGridAttr.nodeUsers = cell.attr('approve/users') + globalGridAttr.nodeText = cell.attr('text/text') + globalGridAttr.nodeDate = cell.attr('title/text') + // let data={ + // dataId:this.flowId, + // finishDate: globalGridAttr.nodeDate, + // } + // cell.setData(data) + // console.log( cell.getData(),' cell.getData() 909') + } + return this.curCel; + }, + async saveDiagram() { + console.log(JSON.stringify(this.graph.toJSON()), 'graph.toJSON()') + this.dataForm.diagram = JSON.stringify(this.graph.toJSON()) + console.log(this.dataForm, 'dataFrom') + await this.$http[this.dataForm.id === null ? 'post' : 'put'](`/WfDef`, this.dataForm).then(async res => { + if (res.msg === 'success') { + this.$alert('淇濆瓨鎴愬姛', '鎻愮ず', { + confirmButtonText: '纭畾' + }) + } + }) + } + }, + mounted() { + this.getFlowList() + this.init1() + // this.nodeOpt(this.id, this.globalGridAttr) + // let data={ + // dataId: this.flowId, + // finishDate: this.date + // } + // this.curCel.setData(data) + // if(this.dataForm) { + // this.graph.fromJSON(this.diagramJson) + // } + this.type = 'grid' + } +} +</script> + +<style> +#flowChart { + display: flex; + border: 1px solid #dfe3e8; + width: 100% !important; +} + +.x6-graph-scroller.x6-graph-scroller-pannable { + width: 100% !important; +} + +#stencil2 { + width: 100%; + height: 100%; + position: relative; + border-right: 1px solid #dfe3e8; +} + +.x6-widget-stencil { + position: relative; + height: 100%; +} + +.x6-widget-stencil-content { + position: relative; + height: 100%; +} +.x6-graph-scroller.x6-graph-scroller-paged.x6-graph-scroller-pannable{ + box-shadow:1px 1px 3px #606266; + border-radius: 10px; +} +</style> -- Gitblit v1.9.1