UNPKG

vue-flow-editor

Version:

vue-flow-editor 是基于 Vue2.0 以及 G6@3.1.10 实现的流程编辑器。在线操作地址:

395 lines (365 loc) 18.2 kB
<html> <head> <meta charset="utf-8"> <title>vue-flow-editor demo</title> <link type="text/css" rel="stylesheet" href="http://martsforever-pot.gitee.io/vue-flow-editor/dist/vue-flow-editor.min.css?v=0.2.3"> <link rel="stylesheet" href="http://martsforever-pot.gitee.io/vue-flow-editor/lib/element-ui.css"> <style> html, body { padding: 0; margin: 0; } </style> </head> <body> <div id="app"> </div> <script src="http://martsforever-pot.gitee.io/vue-flow-editor/lib/g6.umd.min.js"></script> <script src="http://martsforever-pot.gitee.io/vue-flow-editor/lib/vue.min.js"></script> <script src="http://martsforever-pot.gitee.io/vue-flow-editor/lib/vue-composition-api/vue-composition-api.umd.js"></script> <script src="http://martsforever-pot.gitee.io/vue-flow-editor/lib/element-ui.js"></script> <script src="http://martsforever-pot.gitee.io/vue-flow-editor/dist/vue-flow-editor.min.js?v=0.2.3"></script> <script> "use strict"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } console.log(window); Vue.use(window.vueCompositionApi.default); Vue.use(window.VueFlowEditor.default); var Ele = window.ELEMENT; var G6 = window.G6.default; var reactive = window.vueCompositionApi.reactive; function delay(time) { return new Promise(function (resolve) { return setTimeout(resolve, time); }); } var AppData = { "nodes": [{ "data": {}, "id": "start-node", "label": "开始", "shape": "ellipse", "size": [120, 40], "x": 380, "y": 100 }, { "data": {}, "id": "1588848310120", "label": "主管审批", "shape": "rect", "size": [120, 40], "x": 380, "y": 180 }, { "data": {}, "id": "1588848322179", "label": "经理审批", "shape": "rect", "size": [120, 40], "x": 380, "y": 260 }, { "data": {}, "id": "1588848338211", "label": "金额>2万", "shape": "diamond", "size": [120, 40], "x": 380, "y": 340 }, { "data": {}, "id": "1588848351476", "label": "财务打款", "shape": "rect", "size": [120, 40], "x": 380, "y": 460 }, { "data": {}, "id": "end-node", "label": "结束", "shape": "ellipse", "size": [120, 40], "x": 380, "y": 540 }, { "data": {}, "id": "1588848397511", "label": "VIP审批", "shape": "rect", "size": [120, 40], "x": 620, "y": 340 }, { "data": {}, "id": "1588848436694", "label": "金额>10万", "shape": "diamond", "size": [120, 40], "x": 780, "y": 340 }, { "data": {}, "id": "1588848449431", "label": "CEO审批", "shape": "rect", "size": [120, 40], "x": 980, "y": 460 }], "edges": [{ "shape": "flow-polyline-round", "source": "start-node", "sourceAnchor": 2, "target": "1588848310120", "targetAnchor": 0 }, { "shape": "flow-polyline-round", "source": "1588848310120", "sourceAnchor": 2, "target": "1588848322179", "targetAnchor": 0 }, { "shape": "flow-polyline-round", "source": "1588848322179", "sourceAnchor": 2, "target": "1588848338211", "targetAnchor": 0 }, { "shape": "flow-polyline-round", "source": "1588848338211", "sourceAnchor": 2, "target": "1588848351476", "targetAnchor": 0, "label": "否" }, { "shape": "flow-polyline-round", "source": "1588848351476", "sourceAnchor": 2, "target": "end-node", "targetAnchor": 0 }, { "shape": "flow-polyline-round", "source": "1588848338211", "sourceAnchor": 3, "target": "1588848397511", "targetAnchor": 1, "label": "是" }, { "shape": "flow-polyline-round", "source": "1588848436694", "sourceAnchor": 3, "target": "1588848449431", "targetAnchor": 0, "label": "是" }, { "shape": "flow-polyline-round", "source": "1588848449431", "sourceAnchor": 1, "target": "1588848351476", "targetAnchor": 3 }, { "shape": "flow-polyline-round", "source": "1588848436694", "sourceAnchor": 2, "target": "1588848351476", "targetAnchor": 3, "label": "否" }, { "shape": "flow-polyline-round", "source": "1588848397511", "sourceAnchor": 3, "target": "1588848436694", "targetAnchor": 1 }] }; new Vue({ el: '#app', template: "\n <div class=\"app\" style=\"height: 100vh\">\n <vue-flow-editor\n ref=\"editor\"\n :data=\"state.data\"\n :grid=\"showGrid\"\n :miniMap=\"showMiniMap\"\n :onRef=\"onRef\"\n :multipleSelect=\"true\"\n :loading=\"state.editorLoading\"\n\n :disabledUndo=\"false\"\n :disabledDragEdge=\"true\"\n\n :beforeDelete=\"handleBeforeDelete\"\n :afterDelete=\"handleAfterDelete\"\n :beforeAdd=\"handleBeforeAdd\"\n :afterAdd=\"handleAfterAdd\"\n\n @dblclick-node=\"onDblclickNode\"\n @dblclick-edge=\"onDblClickEdge\"\n >\n <div slot=\"menu\">\n <vue-flow-edit-menu-group v-for=\"(group,groupIndex) in state.menuData\" :label=\"group.label\" :key=\"groupIndex\">\n <vue-flow-edit-menu v-for=\"(menu,menuIndex) in group.menus\" :key=\"menuIndex\" :model=\"menu\"/>\n </vue-flow-edit-menu-group>\n </div>\n <div slot=\"model\" style=\"padding: 16px\">\n <el-form v-if=\"!!state.detailModel\" ref=\"form\" :model=\"state.detailModel\" label-width=\"100px\">\n\n <el-form-item label=\"\u8282\u70B9\u540D\u79F0\" prop=\"label\">\n <el-input v-model=\"state.detailModel.label\"/>\n </el-form-item>\n\n <template v-if=\"state.detailModel.type !== 'edge'\">\n <el-form-item label=\"\u8282\u70B9\u80CC\u666F\u8272\" prop=\"style.fill\">\n <el-color-picker v-model=\"state.detailModel.style.fill\"/>\n </el-form-item>\n <el-form-item label=\"\u8282\u70B9\u8FB9\u6846\u8272\" prop=\"style.stroke\">\n <el-color-picker v-model=\"state.detailModel.style.stroke\"/>\n </el-form-item>\n <el-form-item label=\"\u8282\u70B9\u6587\u5B57\u8272\" prop=\"labelCfg.style.stroke\">\n <el-color-picker v-model=\"state.detailModel.labelCfg.style.fill\"/>\n </el-form-item>\n </template>\n\n </el-form>\n </div>\n\n <template slot=\"toolbar\">\n <el-tooltip content=\"\u6D4B\u8BD5\u5DE5\u5177\u680F\u63D2\u69FD\">\n <div class=\"vue-flow-editor-toolbar-item\">\n <i class=\"el-icon-search\"/>\n </div>\n </el-tooltip>\n </template>\n\n <template slot=\"foot\">\n <el-button type=\"primary\" @click=\"save\">\u4FDD\u5B58</el-button>\n <el-button @click=\"cancel\">\u53D6\u6D88</el-button>\n </template>\n </vue-flow-editor>\n </div>\n ", setup: function setup() { var state = reactive({ data: AppData, detailModel: null, editorLoading: false, selectOptions: [{ label: '待确认', value: '0' }, { label: '填写表单', value: '1' }, { label: '部门负责人审批', value: '2' }, { label: '总经理审批', value: '3' }], menuData: [{ label: '流程节点', menus: [{ label: '开始', shape: 'ellipse', id: 'start-node' }, { label: '结束', shape: 'ellipse', id: 'end-node' }, { label: '审批节点', busType: '123' }, { label: '判断节点' }] }, { label: '其他形状节点', menus: [{ label: '矩形节点', shape: 'rect' }, { label: '圆形节点', shape: 'circle' }, { label: '椭圆节点', shape: 'ellipse' }, { label: '菱形节点', shape: 'diamond' }, { label: '三角形节点', shape: 'triangle' }, { label: '星形节点', shape: 'star' }] }] }); var editor; function onDblclickNode(e) { var model = G6.Util.clone(e.item.get('model')); model.style = model.style || {}; model.labelCfg = model.labelCfg || { style: {} }; state.detailModel = model; editor.openModel(); } function onDblClickEdge(e) { var _e$item$get = e.item.get('model'), source = _e$item$get.source, target = _e$item$get.target, style = _e$item$get.style, labelCfg = _e$item$get.labelCfg, label = _e$item$get.label; var model = { label: label, source: source, target: target, style: style || {}, labelCfg: labelCfg || { style: {} }, type: null, id: null }; model.type = e.item.get('type'); model.id = e.item.get('id'); state.detailModel = model; editor.openModel(); } function cancel() { editor.closeModel(); } function save() { editor.updateModel(state.detailModel); editor.closeModel(); } function handleBeforeDelete(_x, _x2) { return _handleBeforeDelete.apply(this, arguments); } function _handleBeforeDelete() { _handleBeforeDelete = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(model, type) { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!(type === 'node')) { _context.next = 8; break; } if (!(model.label === '开始')) { _context.next = 8; break; } state.editorLoading = true; _context.next = 5; return delay(1000); case 5: state.editorLoading = false; Ele.Notification.error('不可以删除【开始】节点'); return _context.abrupt("return", Promise.reject('reject')); case 8: case "end": return _context.stop(); } } }, _callee); })); return _handleBeforeDelete.apply(this, arguments); } function handleAfterDelete(model, type) { if (type === 'edge') { console.log('delete edge'); } else { console.log('after delete', model.label, _objectSpread({}, model)); } } function handleBeforeAdd(model, type) { if (type === 'edge') { if (model.source === 'end-node') { Ele.Notification.error('结束节点不能输出连线其他节点'); return Promise.reject('reject'); } } if (type === 'node') { if (model.id === 'start-node' || model.id === 'end-node') { var data = editor.editorState.graph.save(); for (var i = 0; i < data.nodes.length; i++) { var node = data.nodes[i]; if (node.id === model.id) { Ele.Notification.error("\u53EA\u80FD\u6709\u4E00\u4E2A" + (model.id === 'start-node' ? '开始' : '结束') + "\u8282\u70B9"); return Promise.reject('reject'); } } } } } function handleAfterAdd(model, type) { if (type === 'edge') { console.log("\u65B0\u589E\u8FDE\u63A5\u7EBF"); } } return { state: state, showGrid: true, showMiniMap: false, onDblclickNode: onDblclickNode, onDblClickEdge: onDblClickEdge, cancel: cancel, save: save, handleBeforeDelete: handleBeforeDelete, handleAfterDelete: handleAfterDelete, handleBeforeAdd: handleBeforeAdd, handleAfterAdd: handleAfterAdd, onRef: function onRef(e) { return editor = e; } }; } }).$mount(); </script> </body> </html>