diff --git a/src/views/monitor/topology-build/index.vue b/src/views/monitor/topology-build/index.vue index 64dc2c09..43a514d5 100644 --- a/src/views/monitor/topology-build/index.vue +++ b/src/views/monitor/topology-build/index.vue @@ -59,10 +59,16 @@ const graphG6Data = reactive>({ labelCfg: { position: 'center', }, - style: { - fill: '#00b050', - stroke: '#00b050', - lineWidth: 1, + type: 'image', + img: '/svg/service_db.svg', + clipCfg: { + show: true, + width: 0, + height: 0, + type: 'circle', + y: -3, + x: -6, + r: 23, }, }, // 2 O&M @@ -71,6 +77,15 @@ const graphG6Data = reactive>({ x: 50, y: 450, label: 'O&M', + type: 'triangle', + icon: { + show: true, + // 可更换为其他图片地址 + img: '/svg/service_db.svg', + width: 24, + height: 24, + offset: 39, + }, }, // 100 EMS { @@ -369,7 +384,7 @@ const graphCanvasMenu = new Menu({ style=" display: flex; flex-direction: column; - width: 140px; + width: 140px; " >
@@ -586,7 +601,28 @@ function fnRanderGraph() { size: [80, 40], style: { radius: 8, + // fill: '#ffffff', + stroke: '#ffffff', + lineWidth: 1, + cursor: 'pointer', }, + labelCfg: { + position: 'center', + offset: 0, + style: { + fill: '#000000', + fontSize: 12, + fontWeight: 500, + }, + }, + icon: { + show: false, + img: '/svg/service.svg', + width: 25, + height: 25, + offset: 20, // triangle 特有 + }, + direction: 'up', // triangle 三角形的方向 }, // 全局边 三次贝塞尔曲线 defaultEdge: { @@ -598,6 +634,17 @@ function fnRanderGraph() { lineWidth: 1, cursor: 'pointer', }, + labelCfg: { + refX: 0, + refY: 0, + position: 'middle', + autoRotate: false, + style: { + fill: '#ffffff', + fontSize: 12, + fontWeight: 500, + }, + }, }, // defaultEdge: { // type: 'line', @@ -791,21 +838,36 @@ let modalState: ModalStateType = reactive({ x: 0, y: 0, type: 'circle', - size: 0, + size: [0], anchorPoints: false, - style: {}, + style: { + fill: '#ffffff', + stroke: '#ffffff', + lineWidth: 1, + }, label: '', - labelCfg: {}, + labelCfg: { + position: 'center', + offset: 0, + style: { + fill: '#000000', + fontSize: 12, + fontWeight: 500, + }, + }, }, formEdgeOrigin: {}, formEdge: { id: '', source: '', target: '', - type: '', + type: 'polyline', style: { + offset: 20, + radius: 2, stroke: '#ffffff', lineWidth: 1, + cursor: 'pointer', }, label: '', labelCfg: { @@ -933,9 +995,16 @@ function fnModalOkEdge(edge: any) { }); return; } - graphG6.value.removeItem(edge.id); - edge.id = `${edge.source}~${Date.now()}~${edge.target}`; - graphG6.value.addItem('edge', edge); + // graphG6.value.removeItem(edge.id); + // edge.id = `${edge.source}~${Date.now()}~${edge.target}`; + // graphG6.value.addItem('edge', edge); + const item = graphG6.value.findById(edge.id); + if (item) { + graphG6.value.updateItem(item, edge); + } else { + edge.id = `${edge.source}~${Date.now()}~${edge.target}`; + graphG6.value.addItem('edge', edge); + } modalState.visible = false; modalStateFormEdge.resetFields(); modalState.formEdgeOrigin = {}; @@ -953,41 +1022,202 @@ const modalStateFormNode = Form.useForm( ); /**图节点内置边类型 */ -const nodeType = [ +const nodeTypeOptions = [ { - type: 'circle', - description: '圆形', + value: 'circle', + label: '圆形', }, { - type: 'rect', - description: '矩形', + value: 'rect', + label: '矩形', }, { - type: 'ellipse', - description: '椭圆', + value: 'ellipse', + label: '椭圆', }, { - type: 'diamond', - description: '菱形', + value: 'diamond', + label: '菱形', }, { - type: 'triangle', - description: '三角形', + value: 'triangle', + label: '三角形', }, { - type: 'star', - description: '星形', + value: 'star', + label: '星形', }, { - type: 'image', - description: '图片', + value: 'image', + label: '图片', }, { - type: 'donut', - description: '面包圈', + value: 'donut', + label: '面包圈', }, ]; +/**图节点标签文本位置 */ +const nodePositionOptions = [ + { + value: 'top', + label: '上', + }, + { + value: 'left', + label: '左', + }, + { + value: 'right', + label: '右', + }, + { + value: 'bottom', + label: '下', + }, + { + value: 'center', + label: '居中', + }, +]; + +/**图节点三角形方向 */ +const nodeDirectionOptions = [ + { value: 'up', label: '向上' }, + { value: 'down', label: '向下' }, + { value: 'left', label: '向左' }, + { value: 'right', label: '向右' }, +]; + +/**图节点图片裁剪的形状 */ +const nodeImageClipCfgOptions = [ + { value: 'circle', label: '圆形' }, + { value: 'rect', label: '矩形' }, + { value: 'ellipse', label: '椭圆' }, +]; + +/**图节点类型输入限制 */ +function fnNodeTypeChange(type: any) { + console.log(type); + + // 设置图标属性 + if (['circle', 'ellipse', 'diamond', 'star', 'donut'].includes(type)) { + const nodeOrigin = modalState.formNodeOrigin; + if (nodeOrigin.icon) { + modalState.formNode = Object.assign(modalState.formNode, { + icon: nodeOrigin.icon, + }); + } else { + modalState.formNode = Object.assign(modalState.formNode, { + icon: { + show: false, + img: '', + width: 25, + height: 25, + }, + }); + } + } else if (type === 'triangle') { + // 三角 + const nodeOrigin = modalState.formNodeOrigin; + if (nodeOrigin.icon) { + modalState.formNode = Object.assign(modalState.formNode, { + direction: nodeOrigin.direction || 'up', // triangle 三角形的方向 + icon: Object.assign({ offset: 20 }, nodeOrigin.icon), + }); + } else { + modalState.formNode = Object.assign(modalState.formNode, { + direction: 'up', // triangle 三角形的方向 + icon: { + show: false, + img: '/svg/service.svg', + width: 25, + height: 25, + offset: 20, // triangle 特有 + }, + }); + } + } + // 设置图片属性 + if (type === 'image') { + const nodeOrigin = modalState.formNodeOrigin; + if (nodeOrigin.img) { + modalState.formNode = Object.assign(modalState.formNode, { + img: nodeOrigin.img, + clipCfg: nodeOrigin.clipCfg, + }); + } else { + modalState.formNode = Object.assign(modalState.formNode, { + img: '/svg/service.svg', + clipCfg: { + show: false, + width: 0, + height: 0, + type: 'circle', + }, + }); + } + Reflect.deleteProperty(modalState.formNode, 'style'); + } else { + // 当切换非图片时补充style属性 + if (!Reflect.has(modalState.formNode, 'style')) { + modalState.formNode = Object.assign(modalState.formNode, { + style: { + fill: '#ffffff', + stroke: '#ffffff', + lineWidth: 1, + }, + }); + } + } +} + +/**图节点大小输入限制 */ +function fnNodeSizeChange(value: any) { + // 处理格式 + let intArr: number[] = []; + for (const v of value) { + const intV = parseInt(v); + if (!isNaN(intV)) { + intArr.push(intV); + } + } + // 节点类型限制size + const nodeType = modalState.formNode.type; + switch (nodeType) { + case 'circle': + case 'star': + case 'donut': + intArr = intArr.slice(0, 1); + break; + case 'rect': + case 'ellipse': + case 'diamond': + case 'triangle': + case 'image': + intArr = intArr.slice(0, 2); + break; + } + modalState.formNode.size = intArr; +} + +/**图节点编辑监听更新视图 */ +watch(modalState.formNode, node => { + const info = JSON.parse(JSON.stringify(node)); + const nodeId = info.id; + console.log(info); + if (nodeId) { + if (info.type === 'image') { + Reflect.deleteProperty(info, 'style'); + } + graphG6.value.clearItemStates(nodeId, 'selected'); + graphG6.value.updateItem(nodeId, info); + if (info.type === 'triangle' || info.type === 'image') { + graphG6.value.read(graphG6.value.save()); + } + } +}); + /**图节点新增 */ function fnModalOkNode(node: any) { console.log(JSON.parse(JSON.stringify(graphG6.value.save()))); @@ -998,8 +1228,17 @@ function fnModalOkNode(node: any) { }); return; } - graphG6.value.removeItem(node.id); - graphG6.value.addItem('node', node); + // graphG6.value.removeItem(node.id); + // graphG6.value.addItem('node', node); + const item = graphG6.value.findById(node.id); + if (item) { + graphG6.value.updateItem(item, node); + } else { + graphG6.value.addItem('node', node); + } + if (node.type === 'triangle' || node.type === 'image') { + graphG6.value.read(graphG6.value.save()); + } modalState.visible = false; modalStateFormNode.resetFields(); modalState.formNodeOrigin = {}; @@ -1018,7 +1257,7 @@ function fnModalOk() { } if (type === 'node') { const node = JSON.parse(JSON.stringify(modalState.formNode)); - fnModalOkEdge(node); + fnModalOkNode(node); } } @@ -1032,13 +1271,22 @@ function fnModalCancel() { // 边编辑还原 const edgeOrigin = JSON.parse(JSON.stringify(modalState.formEdgeOrigin)); if (type === 'edge' && edgeOrigin.id) { - graphG6.value.removeItem(edgeOrigin.id); - graphG6.value.addItem('edge', edgeOrigin); + graphG6.value.updateItem(edgeOrigin.id, edgeOrigin); + // graphG6.value.removeItem(edgeOrigin.id); + // graphG6.value.addItem('edge', edgeOrigin); modalStateFormEdge.resetFields(); modalState.formEdgeOrigin = {}; } - - modalStateFormNode.resetFields(); + // 节点编辑还原 + const nodeOrigin = JSON.parse(JSON.stringify(modalState.formNodeOrigin)); + if (type === 'node' && nodeOrigin.id) { + graphG6.value.updateItem(nodeOrigin.id, nodeOrigin); + if (nodeOrigin.type === 'triangle' || nodeOrigin.type === 'image') { + graphG6.value.read(graphG6.value.save()); + } + modalStateFormNode.resetFields(); + modalState.formNodeOrigin = {}; + } } /**保存图数据 */ @@ -1124,6 +1372,400 @@ function fnGraphLoad() { @ok="fnModalOk" @cancel="fnModalCancel" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签文本及其配置 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1167,6 +1810,7 @@ function fnGraphLoad() { @@ -1235,7 +1879,7 @@ function fnGraphLoad() {