From e8ef7263819e847d55cd35e006aa02635fd7b82e Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 14 五月 2025 17:54:21 +0800 Subject: [PATCH] 2025-05-14 --- src/tabviews/custom/components/chart/antv-X6/index.jsx | 1351 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 1,191 insertions(+), 160 deletions(-) diff --git a/src/tabviews/custom/components/chart/antv-X6/index.jsx b/src/tabviews/custom/components/chart/antv-X6/index.jsx index 3e2990b..ed4283f 100644 --- a/src/tabviews/custom/components/chart/antv-X6/index.jsx +++ b/src/tabviews/custom/components/chart/antv-X6/index.jsx @@ -1,8 +1,8 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' -import { Spin, Tooltip, Empty, message, Modal, notification } from 'antd' -import { VerticalAlignTopOutlined, VerticalAlignBottomOutlined, SaveOutlined, ZoomInOutlined, ZoomOutOutlined, OneToOneOutlined, DoubleLeftOutlined, DownloadOutlined } from '@ant-design/icons' +import { Spin, Tooltip, message, Modal, notification, Switch, Button } from 'antd' +import { UndoOutlined, RedoOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined, ZoomInOutlined, ZoomOutOutlined, OneToOneOutlined, QuestionCircleOutlined, ClearOutlined } from '@ant-design/icons' import { Graph, Shape } from '@antv/x6' import { Stencil } from '@antv/x6-plugin-stencil' import { Transform } from '@antv/x6-plugin-transform' @@ -14,12 +14,14 @@ import { Export } from '@antv/x6-plugin-export' import Api from '@/api' -import UtilsDM from '@/utils/utils-datamanage.js' import MKEmitter from '@/utils/events.js' import asyncComponent from '@/utils/asyncComponent' import NormalHeader from '@/tabviews/custom/components/share/normalheader' +// import lanes from '@/menu/components/chart/antv-X6/lane.json' +// import xflows from '@/menu/components/chart/antv-X6/xflow.json' import './index.scss' +const { confirm } = Modal const NodeUpdate = asyncComponent(() => import('./nodeupdate')) const groups = { @@ -136,8 +138,8 @@ 'mk-rect', { inherit: 'rect', - width: 66, - height: 36, + width: 100, + height: 32, attrs: { body: { strokeWidth: 1, @@ -166,8 +168,8 @@ 'mk-polygon', { inherit: 'polygon', - width: 66, - height: 36, + width: 100, + height: 32, attrs: { body: { strokeWidth: 1, @@ -196,8 +198,8 @@ 'mk-paral', { inherit: 'polygon', - width: 66, - height: 36, + width: 100, + height: 32, attrs: { body: { strokeWidth: 1, @@ -224,8 +226,8 @@ 'mk-circle', { inherit: 'circle', - width: 36, - height: 36, + width: 40, + height: 40, attrs: { body: { strokeWidth: 1, @@ -254,8 +256,8 @@ 'mk-ellipse', { inherit: 'ellipse', - width: 66, - height: 36, + width: 100, + height: 32, attrs: { body: { strokeWidth: 1, @@ -284,8 +286,8 @@ 'mk-star', { inherit: 'polygon', - width: 36, - height: 36, + width: 40, + height: 40, points: '100,10 40,198 190,78 10,78 160,198', attrs: { body: { @@ -315,41 +317,84 @@ Graph.registerNode( 'mk-text', { - inherit: 'rect', - width: 66, - height: 36, + inherit: 'text-block', + width: 100, + height: 50, + text: '鏂囨湰鍩�', attrs: { body: { - strokeWidth: 0, - fill: 'transparent' - }, - text: { - fontSize: 12, - fill: '#262626' + fill: '#ffffff', + stroke: '#000000', + strokeWidth: 1, + rx: 0, + ry: 0 } } }, true ) +const styles = { + blue: '#1890ff', + red: '#f5222d', + orange_red: '#fa541c', + orange: '#fa8c16', + orange_yellow: '#faad14', + yellow: '#fadb14', + yellow_green: '#a0d911', + green: '#52c41a', + cyan: '#13c2c2', + blue_purple: '#3860f4', + purple: '#722ed1', + magenta: '#eb2f96', + grass_green: '#aeb303', + deep_red: '#c32539', + deep_blue: '#1d3661', + blue1: '#e6f7ff', + red1: '#fff1f0', + orange_red1: '#fff2e8', + orange1: '#fff7e6', + orange_yellow1: '#fffbe6', + yellow1: '#feffe6', + yellow_green1: '#fcffe6', + green1: '#f6ffed', + cyan1: '#e6fffb', + blue_purple1: '#f0f5ff', + purple1: '#f9f0ff', + magenta1: '#fff0f6', + grass_green1: '#f2efda', + deep_red1: '#fff0f0', + deep_blue1: '#eff1f4' +} + +let sysColor = '#1890ff' +let lightColor = '#e6f7ff' +if (window.GLOB.style) { + let type = window.GLOB.style.replace(/bg_black_style_|bg_white_style_/, '') + sysColor = styles[type] || '#1890ff' + lightColor = styles[type + '1'] || '#e6f7ff' +} + class antvX6Chart extends Component { static propTpyes = { - config: PropTypes.object, - mainSearch: PropTypes.any + config: PropTypes.object } state = { config: null, - toolunfold: true, - nodeunfold: true, editing: false, node: null, - arr_field: 'id,cells', - loading: false + loading: false, + status: 0, + flowname: '', + flowcode: '', + orgs: [], + empty: true } selectNode = null mkGraph = null + cells = [] UNSAFE_componentWillMount () { const { config } = this.props @@ -358,27 +403,38 @@ let BID = '' let BData = '' - if (config.setting.supModule) { - BData = window.GLOB.CacheData.get(config.setting.supModule) + _config.setting.supModule = '' + + if (_config.plot.supModule && _config.plot.supModule.length > 0) { + _config.setting.supModule = _config.plot.supModule.pop() + } + + if (_config.setting.supModule) { + BData = window.GLOB.CacheData.get(_config.setting.supModule) } else { BData = window.GLOB.CacheData.get(config.$pageId) } if (BData) { BID = BData.$BID || '' } - + this.setState({ config: _config, BID: BID || '', BData: BData || '', plot: _config.plot }, () => { - if (config.setting.onload === 'true') { - setTimeout(() => { - this.loadData() - }, _config.setting.delay || 0) + this.loadData() + + if (_config.plot.function === 'edit') { + this.getorganizations() } }) + } + + componentDidMount () { + MKEmitter.addListener('reloadData', this.reloadData) + MKEmitter.addListener('resetSelectLine', this.resetParentParam) } shouldComponentUpdate (nextProps, nextState) { @@ -392,24 +448,156 @@ this.setState = () => { return } + + MKEmitter.removeListener('reloadData', this.reloadData) + MKEmitter.removeListener('resetSelectLine', this.resetParentParam) + } + + reloadData = (menuId) => { + const { config } = this.state + + if (config.uuid !== menuId) return + + this.loadData() + } + + resetParentParam = (MenuID, id) => { + const { config } = this.state + + if (!config.setting.supModule || config.setting.supModule !== MenuID) return + if (id !== this.state.BID || id !== '') { + this.setState({ BID: id }, () => { + this.loadData() + }) + } + } + + getorganizations = () => { + Api.genericInterface({func: 's_get_organizations_v1'}).then(res => { + if (!res.status) { + notification.error({ + top: 92, + message: res.message, + duration: 10 + }) + return + } + + let orgs = [] + res.organizations && res.organizations.forEach(com => { + let _com = { + key: com.OrgCode, + title: com.OrgName, + shortName: com.ShortName, + checkable: false, + selectable: false, + children: [] + } + let _works = [] + + com.departments.forEach(dep => { + let _dep = { + key: dep.co_pro_code, + title: dep.co_pro_name, + checkable: false, + selectable: false, + children: [] + } + + dep.jobs.forEach(job => { + let _job = { + key: job.jobcode, + title: job.jobname, + checkable: false, + selectable: false, + children: [] + } + + job.work_group.forEach(group => { + if (group.work_group === 'normal') { + group.workers.forEach(work => { + let _work = { + key: work.worker_id, + title: work.workername, + email: work.email || '', + images: work.images || '', + mob: work.mob || '', + sex: work.sex || '', + work_grade: work.work_grade || '', + worker_id: work.worker_id || '', + workercode: work.workercode || '', + workername: work.workername || '', + job_type: job.job_type || '', + parentIds: [com.OrgCode, dep.co_pro_code, job.jobcode], + parentNames: [com.OrgName, dep.co_pro_name, job.jobname] + } + + _job.children.push(_work) + }) + } else { + let _group = { + key: group.work_group, + title: group.work_group, + checkable: false, + selectable: false, + children: [] + } + + group.workers.forEach(work => { + let _work = { + key: work.worker_id, + title: work.workername, + email: work.email || '', + images: work.images || '', + mob: work.mob || '', + sex: work.sex || '', + work_grade: work.work_grade || '', + worker_id: work.worker_id || '', + workercode: work.workercode || '', + workername: work.workername || '', + job_type: job.job_type || '', + parentIds: [com.OrgCode, dep.co_pro_code, job.jobcode, group.work_group], + parentNames: [com.OrgName, dep.co_pro_name, job.jobname, group.work_group] + } + + _group.children.push(_work) + }) + + if (_group.children.length > 0) { + _job.children.push(_group) + } + } + }) + + if (_job.children.length > 0) { + _dep.children.push(_job) + } + }) + + if (_dep.children.length > 0) { + _com.children.push(_dep) + } + }) + + if (_com.children.length > 0) { + _com.works = _works + orgs.push(_com) + } + }) + + this.setState({orgs: orgs}) + }) } async loadData () { - const { mainSearch } = this.props - const { config, arr_field, BID } = this.state + const { BID } = this.state - if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇� + if (!BID) { + this.cells = [] if (!is(fromJS(this.data), fromJS([]))) { - this.data = [] this.handleData() } - return - } - - let searches = config.setting.useMSearch && mainSearch ? mainSearch : [] - - let requireFields = searches.filter(item => item.required && item.value === '') - if (requireFields.length > 0) { + this.setState({empty: true}) return } @@ -417,23 +605,31 @@ loading: true }) - let _orderBy = config.setting.order || '' - let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID) + let param = { + func: 's_get_works_flow_local_param_v6', + ID: BID + } let result = await Api.genericInterface(param) if (result.status) { - if (config.$cache && config.setting.onload !== 'false') { - Api.writeCacheConfig(config.uuid, result.data || '') + let item = result.data && result.data[0] ? result.data[0] : null + let cells = [] + + if (item && item.long_param) { + let long_param = JSON.parse(window.decodeURIComponent(window.atob(item.long_param))) + cells = long_param.cells || [] } + + this.cells = cells + this.handleData() this.setState({ - loading: false + status: item.status || 0, + flowname: item.works_flow_name || '', + flowcode: item.works_flow_code || '', + loading: false, + empty: cells.length === 0 }) - - if (!is(fromJS(this.data), fromJS(result.data || []))) { - this.data = result.data || [] - this.handleData() - } if (result.message) { if (result.ErrCode === 'Y') { @@ -486,10 +682,139 @@ viewrender = () => { const { plot } = this.state - if (plot.subtype === 'xflow') { - this.xflowrender() - } else if (plot.subtype === 'lane') { - this.lanerender() + if (plot.function === 'show') { + if (plot.subtype === 'xflow') { + this.xflowSrender() + } else if (plot.subtype === 'lane') { + this.laneSrender() + } + } else { + if (plot.subtype === 'xflow') { + this.xflowrender() + } else if (plot.subtype === 'lane') { + this.lanerender() + } + } + } + + xflowSrender = () => { + const { config } = this.state + + const graph = new Graph({ + container: document.getElementById(config.uuid + 'container'), + grid: config.plot.grid, + scaling: { + min: 0.5, + max: 2 + }, + autoResize: true, + interacting: false, + panning: true, + background: { + color: config.plot.backgroundColor || 'transparent' + }, + mousewheel: { + enabled: true, + zoomAtMousePosition: true, + modifiers: 'ctrl' + }, + connecting: { + router: 'manhattan', + connector: { + name: 'rounded', + args: { + radius: 8 + } + }, + anchor: 'center', + connectionPoint: 'anchor', + allowBlank: false, + snap: { + radius: 20 + } + } + }) + + if (this.cells.length > 0) { + let cells = [] + this.cells.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) + } + }) + graph.resetCells(cells) + graph.positionContent('center') + } + + if (config.plot.click) { + graph.on('cell:click', ({ node }) => { + this.checkNode(graph, node) + }) + + graph.on('blank:click', () => { + this.checkNode(graph) + }) + } + } + + laneSrender = () => { + const { config } = this.state + + const graph = new Graph({ + container: document.getElementById(config.uuid + 'container'), + scaling: { + min: 0.5, + max: 2 + }, + interacting: false, + autoResize: true, + panning: true, + background: { color: '#ffffff' }, + mousewheel: { + enabled: true, + zoomAtMousePosition: true, + modifiers: 'ctrl' + }, + connecting: { + router: 'manhattan', + connector: { + name: 'rounded', + args: { + radius: 8 + } + }, + anchor: 'center', + connectionPoint: 'anchor', + allowBlank: false, + snap: { + radius: 20 + } + } + }) + + if (this.cells.length > 0) { + let cells = [] + this.cells.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) + } + }) + graph.resetCells(cells) + graph.positionContent('top') + } + + if (config.plot.click) { + graph.on('cell:click', ({ node }) => { + this.checkNode(graph, node) + }) + + graph.on('blank:click', () => { + this.checkNode(graph) + }) } } @@ -560,7 +885,6 @@ } }) - // #region 浣跨敤鎻掍欢 graph .use(new Transform({ resizing: true, @@ -573,21 +897,21 @@ .use(new History()) .use(new Export()) - // #region 鍒濆鍖� stencil const stencil = new Stencil({ title: '娴佺▼鍥�', target: graph, - stencilGraphWidth: 180, + stencilGraphWidth: 230, stencilGraphHeight: 180, groups: [ { title: '閫氱敤鑺傜偣', - name: 'group1' + name: 'group1', + graphHeight: 150 }, { title: '鑷畾涔�', name: 'group2', - graphHeight: 150, + graphHeight: 300, layoutOptions: { rowHeight: 70 } @@ -595,14 +919,13 @@ ], layoutOptions: { columns: 2, - columnWidth: 80, + columnWidth: 110, rowHeight: 55 } }) document.getElementById(config.uuid + 'stencil').appendChild(stencil.container) - // #region 蹇嵎閿笌浜嬩欢 graph.bindKey(['meta+c', 'ctrl+c'], () => { const cells = graph.getSelectedCells() if (cells.length) { @@ -624,7 +947,6 @@ return false }) - // undo redo graph.bindKey(['meta+z', 'ctrl+z'], () => { if (graph.canUndo()) { graph.undo() @@ -638,7 +960,6 @@ return false }) - // 鍒犻櫎鍏冪礌 graph.bindKey(['backspace', 'delete'], () => { const cells = graph.getSelectedCells() if (cells.length) { @@ -665,72 +986,195 @@ showPorts(ports, false) }) - graph.on('node:click', ({ e, x, y, node, view }) => { + graph.on('node:click', ({ node }) => { this.selectNode = node this.setState({node: node.store.data}) }) - graph.on('edge:click', ({ e, x, y, edge, view }) => { + graph.on('edge:click', ({ edge }) => { this.selectNode = edge - + this.setState({node: edge.store.data}) graph.clearTransformWidgets() }) - graph.on('blank:click', ({ e, x, y }) => { + + graph.on('node:dblclick', () => { + setTimeout(() => { + MKEmitter.emit('mk-x6-dbclick') + }, 100) + }) + graph.on('edge:dblclick', () => { + setTimeout(() => { + MKEmitter.emit('mk-x6-dbclick') + }, 100) + }) + + graph.on('blank:click', () => { this.selectNode = null this.setState({node: null}) }) + graph.on('edge:connected', ({ isNew, edge }) => { + if (!isNew) return + + let target = edge.getTargetCell() + let source = edge.getSourceCell() + + if (!target || !source) return + + if (source.prop('mknode') === 'end') { + notification.warning({ + top: 92, + message: '缁撴潫鑺傜偣涓嶅彲娣诲姞鍒嗘敮锛�', + duration: 2 + }) + graph.removeCells([edge]) + return + } + + let mkdata = target.prop('mkdata') + + if (source.prop('mknode') === 'start' && target.prop('mknode') === 'end') { + edge.prop('mknode', 'throughEdge') + } else if (target.prop('mknode') === 'end') { + edge.prop('mknode', 'endEdge') + } else if (target.prop('mknode') === 'start') { + edge.prop('mknode', 'startEdge') + } else if (source.prop('mknode') === 'start') { + edge.prop('mknode', 'firstEdge') + } + if (mkdata) { + edge.prop('mkdata', {status: mkdata.status, statusName: mkdata.statusName}) + } + }) const r1 = graph.createNode({ shape: 'mk-rect', - label: '寮�濮�', + mknode: 'start', + mkdata: {status: 0, statusName: '鏈彁浜�'}, attrs: { body: { - rx: 20, - ry: 26 + rx: 0, + ry: 0, + fill: '#000000', + stroke: '#000000' + }, + text: { + fill: '#ffffff', + text: '寮�濮�' } } }) + + const r4 = graph.createNode({ + shape: 'mk-rect', + attrs: { + body: { + rx: 0, + ry: 0, + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '鑺傜偣' + } + } + }) + + const r5 = graph.createNode({ + shape: 'mk-polygon', + attrs: { + body: { + refPoints: '0,10 10,0 20,10 10,20', + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '鍐崇瓥' + } + } + }) + + const r8 = graph.createNode({ + shape: 'mk-rect', + mknode: 'end', + mkdata: {status: 888, statusName: '宸插畬鎴�'}, + attrs: { + body: { + rx: 0, + ry: 0, + fill: '#000000', + stroke: '#000000' + }, + text: { + fill: '#ffffff', + text: '缁撴潫' + } + } + }) + + stencil.load([r1, r4, r5, r8], 'group1') + const r2 = graph.createNode({ shape: 'mk-rect', - label: '杩囩▼' + attrs: { + body: { + rx: 20, + ry: 26, + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '杩囩▼' + } + } }) const r3 = graph.createNode({ shape: 'mk-rect', attrs: { body: { rx: 6, - ry: 6 + ry: 6, + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '鍙�夎繃绋�' } - }, - label: '鍙�夎繃绋�' + } }) - const r4 = graph.createNode({ - shape: 'mk-polygon', - attrs: { - body: { - refPoints: '0,10 10,0 20,10 10,20' - } - }, - label: '鍐崇瓥' - }) - const r5 = graph.createNode({ + const r6 = graph.createNode({ shape: 'mk-paral', attrs: { body: { - refPoints: '10,0 40,0 30,20 0,20' + refPoints: '10,0 40,0 30,20 0,20', + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '鏁版嵁' } - }, - label: '鏁版嵁' + } }) - const r6 = graph.createNode({ + const r7 = graph.createNode({ shape: 'mk-circle', - label: '杩炴帴' + attrs: { + body: { + fill: '#ffffff', + stroke: '#757575' + }, + text: { + fill: '#000000', + text: '杩炴帴' + } + } }) - - stencil.load([r1, r2, r3, r4, r5, r6], 'group1') const p1 = graph.createNode({ shape: 'mk-ellipse', @@ -742,11 +1186,23 @@ }) const p3 = graph.createNode({ - shape: 'mk-text', - label: '鏂囨湰' + shape: 'mk-text' }) - stencil.load([p1, p2, p3], 'group2') + stencil.load([r2, r3, r6, r7, p1, p2, p3], 'group2') + + if (this.cells.length > 0) { + let cells = [] + this.cells.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) + } + }) + graph.resetCells(cells) + graph.positionContent('center') + } this.mkGraph = graph } @@ -835,18 +1291,24 @@ }) graph + .use(new Transform({ + resizing: true, + rotating: true + })) .use(new Selection()) - .use(new Snapline()) + .use(new Snapline({ + enabled: true, + filter: (Graph) => Graph.prop('shape') !== 'lane' + })) .use(new Keyboard()) .use(new Clipboard()) .use(new History()) .use(new Export()) - // #region 鍒濆鍖� stencil const stencil = new Stencil({ title: '娴佺▼鍥�', target: graph, - stencilGraphWidth: 180, + stencilGraphWidth: 230, stencilGraphHeight: 180, groups: [ { @@ -872,25 +1334,28 @@ ], layoutOptions: { columns: 2, - columnWidth: 80, + columnWidth: 110, rowHeight: 55 } }) document.getElementById(config.uuid + 'stencil').appendChild(stencil.container) - // #region 蹇嵎閿笌浜嬩欢 graph.bindKey(['meta+c', 'ctrl+c'], () => { const cells = graph.getSelectedCells() if (cells.length) { - graph.copy(cells) + if (cells[0].prop('shape') !== 'lane' && cells[0].prop('shape') !== 'edge') { + graph.copy(cells) + } } return false }) graph.bindKey(['meta+x', 'ctrl+x'], () => { const cells = graph.getSelectedCells() if (cells.length) { - graph.cut(cells) + if (cells[0].prop('shape') !== 'lane' && cells[0].prop('shape') !== 'edge') { + graph.cut(cells) + } } return false }) @@ -914,17 +1379,25 @@ return false }) - // 鍒犻櫎鍏冪礌 graph.bindKey(['backspace', 'delete'], () => { const cells = graph.getSelectedCells() if (cells.length) { - graph.removeCells(cells) this.selectNode = null this.setState({node: null}) + + if (cells[0].prop('shape') === 'lane') { + graph.startBatch('delete-lane') + + graph.removeCells(cells) + this.deleteLane(cells[0], graph) + + graph.stopBatch('delete-lane') + } else { + graph.removeCells(cells) + } } }) - // 鎺у埗杩炴帴妗╂樉绀�/闅愯棌 const showPorts = (ports, show) => { for (let i = 0, len = ports.length; i < len; i += 1) { ports[i].style.visibility = show ? 'visible' : 'hidden' @@ -943,8 +1416,10 @@ showPorts(ports, false) }) - graph.on('node:added', ({ cell, index, options }) => { + graph.on('node:added', ({ cell }) => { if (cell.prop('shape') === 'lane') { + if (cell.prop('zIndex') === 0) return + graph.startBatch('add-lane') this.addLane(cell, graph) @@ -956,22 +1431,26 @@ if (num <= 1) { message.warning('璇锋坊鍔犳吵閬擄紒') graph.removeCells([cell]) - } else { + } else if (!cell.prop('parent')) { this.addNode(cell, graph) } } }) - graph.on('node:click', ({ e, x, y, node, view }) => { + graph.on('node:click', ({ node }) => { this.selectNode = node this.setState({node: node.store.data}) + + if (node.prop('shape') === 'lane') { + graph.clearTransformWidgets() + } }) - graph.on('edge:click', ({ e, x, y, edge, view }) => { + graph.on('edge:click', ({ edge }) => { this.selectNode = edge this.setState({node: edge.store.data}) graph.clearTransformWidgets() }) - graph.on('blank:click', ({ e, x, y }) => { + graph.on('blank:click', () => { this.selectNode = null this.setState({node: null}) @@ -1036,8 +1515,7 @@ }) const p3 = graph.createNode({ - shape: 'mk-text', - label: '鏂囨湰' + shape: 'mk-text' }) stencil.load([p1, p2, p3], 'group2') @@ -1049,17 +1527,18 @@ stencil.load([g1], 'group3') - // let data = [{"id":"1","shape":"lane","width":260,"height":500,"position":{"x":0,"y":0},"label":"闃舵1", preId: '', nextId: '2'},{"id":"2","shape":"lane","width":200,"height":500,"position":{"x":260,"y":0},"label":"<Function>", preId: '1', nextId: '3'},{"id":"3","shape":"lane","width":200,"height":500,"position":{"x":460,"y":0},"label":"<Function>", preId: '2', nextId: '4'},{"id":"4","shape":"lane","width":200,"height":500,"position":{"x":660,"y":0},"label":"<Function>", preId: '3', nextId: ''}] - // let cells = [] - // data.forEach((item) => { - // if (item.shape === 'edge') { - // cells.push(graph.createEdge(item)) - // } else { - // cells.push(graph.createNode(item)) - // } - // }) - // graph.resetCells(cells) - // graph.zoomToFit({ padding: 10, maxScale: 1 }) + if (this.cells.length > 0) { + let cells = [] + this.cells.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) + } + }) + graph.resetCells(cells) + graph.positionContent('top') + } this.mkGraph = graph } @@ -1078,11 +1557,25 @@ return } - // let cells = this.mkGraph.getCells() this.selectNode.toBack() } - // zoom() 鍙幏鍙栨垨鑰呰缃缉鏀炬瘮渚� + setback = () => { + if (this.mkGraph.canUndo()) { + this.mkGraph.undo() + } else { + message.warning('鏃犲彲鎾ら攢璁板綍锛�') + } + } + + setprev = () => { + if (this.mkGraph.canRedo()) { + this.mkGraph.redo() + } else { + message.warning('鏃犲彲鍓嶈繘璁板綍锛�') + } + } + setZoomIn = () => { this.mkGraph.zoom(0.1) } @@ -1095,13 +1588,203 @@ this.mkGraph.zoomTo(1) } - save = () => { - // let nodes = this.mkGraph.toJSON() + close = () => { + const { config } = this.state + + let nodes = this.mkGraph.toJSON() + + if (!is(fromJS(nodes.cells), fromJS(this.cells))) { + confirm({ + title: '娴佺▼鍥惧凡淇敼锛岀‘瀹氬叧闂悧?', + okText: '纭畾', + cancelText: '鍙栨秷', + onOk() { + MKEmitter.emit('closeTabView', config.$pageId) + }, + onCancel() {} + }) + } else { + MKEmitter.emit('closeTabView', config.$pageId) + } } - savePicture = () => { - const { config } = this.state - this.mkGraph.exportPNG(config.name, {padding: 20}) + save = () => { + const { BID, plot, status, flowname, flowcode } = this.state + + if (!BID) { + Modal.error({ + title: '鏈幏鍙栧埌娴佺▼ID锛屼笉鍙繚瀛橈紒', + }) + return + } + + let nodes = this.mkGraph.toJSON() + let _status = status + + if (plot.subtype === 'xflow' && status === 10) { + let start_num = 0 + let end_num = 0 + let unvalid = false + let map = new Map() + let appMap = new Map() + + nodes.cells.forEach(item => { + if (item.shape === 'mk-text' || item.shape === 'lane') return + + if (!item.mkdata) { + unvalid = true + } else if (item.mknode === 'start') { + start_num++ + } else if (item.mknode === 'end') { + end_num++ + } else if (item.shape === 'edge') { + if (item.mknode === 'throughEdge') { + if (!item.mkdata.seniorbers || item.mkdata.seniorbers.length === 0) { + unvalid = true + } + } else if (item.mkdata.seniorCondition === 'open') { + + } else if (item.mknode !== 'endEdge' && item.mknode !== 'startEdge' && (!item.mkdata.members || item.mkdata.members.length === 0)) { + unvalid = true + } else if (item.mknode === 'startEdge' || item.mkdata.flowType === 'reject') { + if (map.has(item.source.cell)) { + unvalid = true + } else { + map.set(item.source.cell, true) + } + } else if (item.mkdata.flowType === 'approval' || item.mknode === 'endEdge') { + let val = '' + if (item.mkdata.execCondition === 'open') { + val = item.mkdata.match + item.mkdata.matchVal + } + if (appMap.has(item.source.cell + val)) { + unvalid = true + } else { + appMap.set(item.source.cell + val, true) + } + } + } + }) + + if (start_num !== 1 || end_num === 0 || unvalid) { + _status = 0 + } + } + + this.setState({ + loading: true + }) + + this.mkGraph.toPNG((dataUri) => { + let param = { + func: 's_works_flow_param_upt_v6', + long_param: window.btoa(window.encodeURIComponent(JSON.stringify(nodes))), + flow_image: dataUri, + status: status, + ID: BID, + BID: '' + } + + let ssoParam = { + func: 's_works_flow_param_sso_upt_v6', + status: status, + ID: BID, + works_flow_code: flowcode, + works_flow_name: flowname, + long_param: window.btoa(window.encodeURIComponent(JSON.stringify(nodes))) + } + + Api.genericInterface(param).then(res => { + if (res.status) { + if (plot.subtype === 'xflow') { + Api.getSystemConfig(ssoParam).then(result => { + if (result.status) { + notification.success({ + top: 92, + message: '淇濆瓨鎴愬姛锛�', + duration: 2 + }) + this.setState({ + loading: false, + status: _status + }) + this.cells = nodes.cells + } else { + notification.error({ + top: 92, + message: result.message, + duration: 10 + }) + this.setState({ + loading: false + }) + } + }) + } else { + notification.success({ + top: 92, + message: '淇濆瓨鎴愬姛锛�', + duration: 2 + }) + this.setState({ + loading: false, + status: _status + }) + this.cells = nodes.cells + } + } else { + notification.error({ + top: 92, + message: res.message, + duration: 10 + }) + this.setState({ + loading: false + }) + } + }) + }, {padding: 20}) + } + + clearNode = () => { + let cells = this.mkGraph.getCells() + const that = this + + if (cells.length === 0) { + message.warning('灏氭湭娣诲姞鍏冪礌锛�') + return + } + + confirm({ + title: '纭畾娓呯┖鍏冪礌鍚�?', + content: '娓呯┖鍚庝笉鍙仮澶嶃��', + okText: '纭畾', + cancelText: '鍙栨秷', + onOk() { + that.mkGraph.removeCells(cells) + that.mkGraph.cleanHistory() + }, + onCancel() {} + }) + } + + deleteLane = (cell, graph) => { + let id = cell.id + + let nodes = graph.getNodes() + let cells = [] + + nodes.forEach(item => { + if (item.prop('shape') === 'lane') return + + if (item.prop('parent') === id) { + cells.push(item) + } + }) + + graph.removeCells(cells) + + this.resetlane(cell.id, cell.prop('position/x'), -cell.prop('size/width')) } addLane = (cell, graph) => { @@ -1138,6 +1821,7 @@ } let height = 400 + if (typeof(config.plot.height) === 'number' || /px/.test(config.plot.height)) { height = parseInt(config.plot.height) } @@ -1226,22 +1910,61 @@ } } + delCell = () => { + const { node } = this.state + + let cell = this.mkGraph.getCellById(node.id) + + this.mkGraph.removeCells([cell]) + + this.setState({node: null}) + } + changeProps = (value, key) => { const { node } = this.state if (node.shape === 'edge') { + let labels = this.selectNode.prop('labels') + if (!labels || labels.length === 0) { + labels = [{ + attrs: {label: { text: '' }} + }] + } + if (key === 'title') { - this.selectNode.setLabels(value) + labels = JSON.parse(JSON.stringify(labels)) + labels[0].attrs.label.text = value + this.selectNode.setLabels(labels) } else if (key === 'stroke') { this.selectNode.attr('line/stroke', value) } else if (key === 'strokeWidth') { this.selectNode.attr('line/strokeWidth', value) + } else if (key === 'fontSize') { + labels = JSON.parse(JSON.stringify(labels)) + labels[0].attrs.label.fontSize = value + this.selectNode.setLabels(labels) + } else if (key === 'fontFill') { + labels = JSON.parse(JSON.stringify(labels)) + labels[0].attrs.label.fill = value + this.selectNode.setLabels(labels) } else if (key === 'lineType') { if (value === 'dash') { this.selectNode.attr('line/strokeDasharray', 5) } else { this.selectNode.attr('line/strokeDasharray', 0) } + } else if (key === 'mkdata') { + if (!node.mkdata) { + if (node.target && node.target.cell) { + let cell = this.mkGraph.getCellById(node.target.cell) + + if (cell) { + cell.prop('mkdata', {status: value.status, statusName: value.statusName || ''}) + } + } + } + + this.selectNode.prop('mkdata', value) } } else if (node.shape === 'lane') { if (key === 'title') { @@ -1267,6 +1990,18 @@ this.mkGraph.stopBatch('width-change') } + } else if (node.shape === 'mk-text') { + if (key === 'title') { + this.selectNode.attr('label/text', value) + } else if (key === 'fill') { + this.selectNode.attr('body/fill', value) + } else if (key === 'stroke') { + this.selectNode.attr('body/stroke', value) + } else if (key === 'fontSize') { + this.selectNode.attr('label/style/fontSize', value) + } else if (key === 'fontFill') { + this.selectNode.attr('label/style/color', value) + } } else { if (key === 'title') { this.selectNode.attr('text/text', value) @@ -1278,9 +2013,278 @@ this.selectNode.attr('text/fontSize', value) } else if (key === 'fontFill') { this.selectNode.attr('text/fill', value) - } else if (key === 'mksign') { - this.selectNode.prop('mksign', value) + } else if (key === 'mkdata') { + this.selectNode.prop('mkdata', value) } + } + } + + checkNode = (graph, node) => { + const { plot, config } = this.state + + let nodes = graph.getNodes() + + nodes.forEach(item => { + if (item.prop('shape') === 'lane') return + + if (item.prop('oristyle')) { + let style = item.prop('oristyle') + + item.prop('attrs/body/fill', style.fill) + item.prop('attrs/body/stroke', style.stroke) + item.prop('attrs/text/fill', style.text) + } + }) + + if (!node || ['lane', 'mk-text', 'edge'].includes(node.prop('shape'))) { + MKEmitter.emit('resetSelectLine', config.uuid, '', '') + return + } + + if (!node.prop('oristyle')) { + node.prop('oristyle', { + fill: node.prop('attrs/body/fill'), + stroke: node.prop('attrs/body/stroke'), + text: node.prop('attrs/text/fill') + }) + } + + node.prop('attrs/body/fill', lightColor) + node.prop('attrs/body/stroke', sysColor) + node.prop('attrs/text/fill', sysColor) + + let sign = node.prop('mksign') || '' + + if (plot.click === 'menus') { + let menu = null + + if (plot.menus && plot.menus.length > 0) { + plot.menus.forEach(m => { + if (sign !== m.sign) return + menu = m + }) + } + if (!menu || !menu.MenuID) return + + let newtab = { + MenuID: menu.MenuID, + MenuName: menu.MenuName, + MenuNo: menu.MenuNo || '', + type: menu.tabType, + param: {$BID: sign} + } + + MKEmitter.emit('modifyTabs', newtab, true) + } else if (plot.click === 'menu') { + let menuId = plot.menu.slice(-1)[0] + let menu = null + + if (window.GLOB.mkThdMenus.has(menuId)) { + menu = {...window.GLOB.mkThdMenus.get(menuId)} + } else if (plot.MenuID) { + menu = { + MenuID: plot.MenuID, + MenuName: plot.MenuName, + type: plot.tabType + } + } + + if (!menu) return + + menu.param = {$BID: sign} + + MKEmitter.emit('modifyTabs', menu, true) + } else { + MKEmitter.emit('resetSelectLine', config.uuid, sign, {}) + } + } + + changeStatus = () => { + const { plot, status } = this.state + + let _status = status === 10 ? 0 : 10 + + if (plot.subtype === 'xflow' && _status === 10) { + let nodes = this.mkGraph.toJSON() + + let start_num = 0 + let end_num = 0 + let unvalidId = '' + let emptyNode = null + let emptyEdge = null + let map = new Map() + let appMap = new Map() + let rejectId = '' + let approvalId = '' + + nodes.cells.forEach(item => { + if (item.shape === 'mk-text' || item.shape === 'lane') return + + if (!item.mkdata) { + if (item.shape !== 'edge') { + if (!emptyNode) { + emptyNode = item + } + } else { + if (!emptyEdge) { + emptyEdge = item + } + } + } else if (item.mknode === 'start') { + start_num++ + } else if (item.mknode === 'end') { + end_num++ + } else if (item.shape === 'edge' && !unvalidId && !rejectId && !approvalId) { + if (item.mknode === 'throughEdge') { + if (!item.mkdata.seniorbers || item.mkdata.seniorbers.length === 0) { + unvalidId = item.id + } + } else if (item.mkdata.seniorCondition === 'open') { + + } else if (item.mknode !== 'endEdge' && item.mknode !== 'startEdge' && (!item.mkdata.members || item.mkdata.members.length === 0)) { + unvalidId = item.id + } else if (item.mknode === 'startEdge' || item.mkdata.flowType === 'reject') { + if (map.has(item.source.cell)) { + rejectId = item.source.cell + } else { + map.set(item.source.cell, true) + } + } else if (item.mkdata.flowType === 'approval' || item.mknode === 'endEdge') { + let val = '' + if (item.mkdata.execCondition === 'open') { + val = item.mkdata.match + item.mkdata.matchVal + } + if (appMap.has(item.source.cell + val)) { + approvalId = item.source.cell + } else { + appMap.set(item.source.cell + val, item) + } + } + } + }) + + if (start_num === 0) { + notification.warning({ + top: 92, + message: '璇锋坊鍔犲紑濮嬭妭鐐癸紒', + duration: 2 + }) + } else if (start_num > 1) { + notification.warning({ + top: 92, + message: '寮�濮嬭妭鐐逛笉鍙坊鍔犲涓紒', + duration: 2 + }) + } else if (end_num === 0) { + notification.warning({ + top: 92, + message: '璇锋坊鍔犵粨鏉熻妭鐐癸紒', + duration: 2 + }) + // } else if (end_num > 1) { + // notification.warning({ + // top: 92, + // message: '缁撴潫鑺傜偣涓嶅彲娣诲姞澶氫釜锛�', + // duration: 2 + // }) + } else if (emptyNode) { + let errmsg = '閮ㄥ垎鑺傜偣鏈缃熀鏈俊鎭��' + if (emptyNode.attrs && emptyNode.attrs.text && emptyNode.attrs.text.text) { + errmsg = '鑺傜偣銆�' + emptyNode.attrs.text.text + '銆嬫湭璁剧疆鍩烘湰淇℃伅銆�' + } + notification.warning({ + top: 92, + message: errmsg, + duration: 2 + }) + } else if (emptyEdge) { + let errmsg = '閮ㄥ垎杩炵嚎鏈缃熀鏈俊鎭��' + + let edge = this.mkGraph.getCellById(emptyEdge.id) + let target = edge.getTargetCell() + + let t_label = '' + if (target.attrs && target.attrs.text && target.attrs.text.text) { + t_label = target.attrs.text.text + } + + let source = edge.getSourceCell() + + let s_label = '' + if (source.attrs && source.attrs.text && source.attrs.text.text) { + s_label = source.attrs.text.text + } + + if (t_label && s_label) { + errmsg = '鑺傜偣銆�' + s_label + '銆嬩笌鑺傜偣銆�' + t_label + '銆嬮棿杩炵嚎鏈缃熀鏈俊鎭��' + } + + notification.warning({ + top: 92, + message: errmsg, + duration: 2 + }) + } else if (rejectId) { + let node = this.mkGraph.getCellById(rejectId) + + let title = '' + if (node.attrs && node.attrs.text && node.attrs.text.text) { + title = '鑺傜偣銆�' + node.attrs.text.text + '銆�' + } else if (node.mkdata) { + title = '鐘舵�侊細' + node.mkdata.status + ' - ' + node.mkdata.statusName + } + + notification.warning({ + top: 92, + message: title + ' 涓嶅彲璁剧疆涓ゆ潯椹冲洖杩炵嚎锛�', + duration: 2 + }) + } else if (approvalId) { + let node = this.mkGraph.getCellById(approvalId) + + let title = '' + if (node.attrs && node.attrs.text && node.attrs.text.text) { + title = '鑺傜偣銆�' + node.attrs.text.text + '銆�' + } else if (node.mkdata) { + title = '鐘舵�侊細' + node.mkdata.status + ' - ' + node.mkdata.statusName + } + + notification.warning({ + top: 92, + message: title + ' 鍚庣殑瀹℃壒鍒嗘敮鎵ц鏉′欢閲嶅锛�', + duration: 2 + }) + } else if (unvalidId) { + let edge = this.mkGraph.getCellById(unvalidId) + + let node = edge.getTargetCell() + + let title = '' + if (node.attrs && node.attrs.text && node.attrs.text.text) { + title = node.attrs.text.text + } else if (node.mkdata) { + title = '鐘舵�侊細' + node.mkdata.status + ' - ' + node.mkdata.statusName + } + + let source = edge.getSourceCell() + + let s_label = '' + if (source.attrs && source.attrs.text && source.attrs.text.text) { + s_label = source.attrs.text.text + } else if (source.mkdata) { + s_label = '鐘舵�侊細' + source.mkdata.status + ' - ' + source.mkdata.statusName + } + + notification.warning({ + top: 92, + message: '鑺傜偣銆�' + s_label + '銆嬩笌銆�' + title + '銆嬮棿杩炵嚎鏈缃鎵逛汉锛�', + duration: 2 + }) + } else { + this.setState({status: _status}) + } + } else { + this.setState({status: _status}) } } @@ -1299,7 +2303,32 @@ } render() { - const { loading, config, empty, toolunfold, nodeunfold, node } = this.state + const { loading, config, node, orgs, status, flowname, empty } = this.state + + let style = {...config.style} + + if (config.plot.function === 'show') { + if (config.plot.empty === 'hidden' && empty) { + style.position = 'absolute' + style.width = '100%' + style.zIndex = -1 + } + + return ( + <div className="custom-x6-plot-box" id={'anchor' + config.uuid} style={style}> + {loading ? + <div className="loading-mask"> + <div className="ant-spin-blur"></div> + <Spin /> + </div> : null + } + <NormalHeader config={config} /> + <div className={'canvas only-show' + (config.plot.click ? ' switchable' : '')} style={{width: '100%', minHeight: config.plot.height, height: config.plot.height}} id={config.uuid + 'canvas'}> + <div id={config.uuid + 'container'} className="mk-container"></div> + </div> + </div> + ) + } return ( <div className="custom-x6-plot-box" id={'anchor' + config.uuid} style={config.style}> @@ -1310,7 +2339,6 @@ </div> : null } <NormalHeader config={config} /> - {empty ? <Empty description={false}/> : null} <div className="mk-toolbar"> <div className="left-tool"> {config.plot.subtype === 'xflow' ? <Tooltip title="缃墠"> @@ -1319,14 +2347,6 @@ {config.plot.subtype === 'xflow' ? <Tooltip title="缃悗"> <VerticalAlignBottomOutlined onClick={this.setBottom}/> </Tooltip> : null} - <Tooltip title="淇濆瓨"> - <SaveOutlined onClick={this.save}/> - </Tooltip> - {config.plot.export === 'png' ? <Tooltip title="瀵煎嚭鍥剧墖"> - <DownloadOutlined onClick={this.savePicture}/> - </Tooltip> : null} - </div> - <div className="right-tool"> <Tooltip title="鏀惧ぇ"> <ZoomInOutlined onClick={this.setZoomIn}/> </Tooltip> @@ -1336,21 +2356,32 @@ <Tooltip title="1:1"> <OneToOneOutlined onClick={this.setZoomInt}/> </Tooltip> + <Tooltip title="鍚庨��"> + <UndoOutlined onClick={this.setback}/> + </Tooltip> + <Tooltip title="鍓嶈繘"> + <RedoOutlined onClick={this.setprev}/> + </Tooltip> + <Tooltip title="娓呯┖"> + <ClearOutlined onClick={this.clearNode}/> + </Tooltip> + <Tooltip overlayStyle={{maxWidth: 310}} title="蹇嵎閿細澶嶅埗锛坈trl+c锛夈�佸壀鍒囷紙ctrl+x锛夈�佺矘璐达紙ctrl+v锛夈�佸悗閫�锛坈trl+z锛夈�佸墠杩涳紙ctrl+shift+z锛夈�佸垹闄わ紙backspace 鎴� delete锛夛紱鍙屽嚮鑺傜偣鎴栬繛绾垮彲缂栬緫鑷畾涔変俊鎭��"> + <QuestionCircleOutlined /> + </Tooltip> + </div> + <div className="flow-name">{flowname}</div> + <div className="right-tool"> + <Switch size="large" checked={status === 10} checkedChildren="鍚�" unCheckedChildren="鍋�" onChange={this.changeStatus} /> + <Button className="save" onClick={this.save}>淇濆瓨</Button> + <Button className="close" onClick={this.close}>鍏抽棴</Button> </div> </div> <div className="canvas" style={{width: '100%', minHeight: config.plot.height, height: config.plot.height}} id={config.uuid + 'canvas'}> - <div id={config.uuid + 'stencil'} className={'mk-stencil ' + (toolunfold ? '' : 'merge')}> - <div className="tool-control" onClick={() => this.setState({toolunfold: !toolunfold})}> - <DoubleLeftOutlined /> - </div> - </div> + <div id={config.uuid + 'stencil'} className="mk-stencil"></div> <div id={config.uuid + 'container'} className="mk-container"></div> - <div className={'mk-node-edit ' + (nodeunfold ? '' : 'merge')}> - <div className="tool-control" onClick={() => this.setState({nodeunfold: !nodeunfold})}> - <DoubleLeftOutlined /> - </div> + <div className="mk-node-edit"> <div className="header">璁剧疆</div> - {!node ? <div className="empty">鏈�変腑</div> : <NodeUpdate node={node} onChange={this.changeProps}/>} + {!node ? <div className="empty">鏈�変腑</div> : <NodeUpdate node={node} orgs={orgs} onChange={this.changeProps} onDel={this.delCell}/>} </div> </div> </div> -- Gitblit v1.8.0