From 911c8946bb58bba9c6a533636a7eee3386fbdc65 Mon Sep 17 00:00:00 2001 From: hanyuqing <1106611654@qq.com> Date: Wed, 7 Jan 2026 14:08:15 +0800 Subject: [PATCH] all --- vue/src/system/GraphDemo.vue | 82 +++++++++----- vue/src/system/GraphQA.vue | 257 ++++++++++++++++++++++++++++-------------- vue/src/system/GraphStyle.vue | 2 +- 3 files changed, 228 insertions(+), 113 deletions(-) diff --git a/vue/src/system/GraphDemo.vue b/vue/src/system/GraphDemo.vue index d68488f..93e1a9a 100644 --- a/vue/src/system/GraphDemo.vue +++ b/vue/src/system/GraphDemo.vue @@ -855,37 +855,63 @@ export default { formatData(data){ this._graph.stopLayout(); this.clearGraphState(); - const updatedEdges = data.edges.map(edge => ({ - ...edge, - type: this.edgeType, - style: { - endArrow: this.edgeEndArrow, - stroke: this.edgeStroke, - lineWidth: this.edgeLineWidth, - label: this.edgeShowLabel, - labelFontSize: this.edgeFontSize, - labelFontFamily: this.edgeFontFamily, - labelFill: this.edgeFontColor, - }, - })) - const updatedNodes = data.nodes.map(node => ({ - ...node, - type: this.nodeShape, - style:{ - size: this.nodeSize, - lineWidth: this.nodeLineWidth, - label: this.nodeShowLabel, - labelFontSize: this.nodeFontSize, - labelFontFamily: this.nodeFontFamily, - labelFill: this.nodeFontColor, - opacity: 1, - } - })) - const updatedData = { + + // === 1. 构建 nodeId → label 映射 === + const nodeIdToEnLabel = {}; + data.nodes.forEach(node => { + nodeIdToEnLabel[node.id] = node.data.label; // e.g. "Disease" + }); + // === 2. 处理节点:根据自身 label 设置样式 === + const updatedNodes = data.nodes.map(node => { + const enLabel = node.data.label; + const zhLabel = this.enToZhLabelMap[enLabel] || '其他'; // 默认回退到“其他” + const styleConf = this.parsedStyles[zhLabel] || {}; + return { + ...node, + type: styleConf.nodeShape || this.nodeShape, + style: { + size: styleConf.nodeSize || this.nodeSize, + fill: styleConf.nodeFill || this.nodeFill, + stroke: styleConf.nodeStroke || this.nodeStroke, + lineWidth: styleConf.nodeLineWidth || this.nodeLineWidth, + label: styleConf.nodeShowLabel !== undefined ? styleConf.nodeShowLabel : true, + labelFontSize: styleConf.nodeFontSize || this.nodeFontSize, + labelFontFamily: styleConf.nodeFontFamily || this.nodeFontFamily, + labelFill: styleConf.nodeFontColor || this.nodeFontColor + } + }; + }); + + // === 3. 处理边:根据 source 节点的 label 设置样式 === + const updatedEdges = data.edges.map(edge => { + console.log(edge) + const sourceEnLabel = nodeIdToEnLabel[edge.source]; // e.g. "Disease" + const sourceZhLabel = this.enToZhLabelMap[sourceEnLabel] || '其他'; + const styleConf = this.parsedStyles[sourceZhLabel] || {}; + + return { + ...edge, + id: edge.data?.relationship?.id || edge.id, + type: styleConf.edgeType ||this.edgeType, + style: { + endArrow: styleConf.edgeEndArrow !== undefined ? styleConf.edgeEndArrow : true, + stroke: styleConf.edgeStroke || this.edgeStroke, + lineWidth: styleConf.edgeLineWidth || this.edgeLineWidth, + label: styleConf.edgeShowLabel !== undefined ? styleConf.edgeShowLabel : false, + labelFontSize: styleConf.edgeFontSize || this.edgeFontSize, + labelFontFamily: styleConf.edgeFontFamily || this.edgeFontFamily, + labelFill: styleConf.edgeFontColor || this.edgeFontColor + } + }; + }); + + // === 4. 更新图数据 === + let updatedData = { nodes: updatedNodes, edges: updatedEdges - } + }; + this.buildNodeLabelMap(updatedNodes); this.updateGraph(updatedData) this.buildCategoryIndex(); diff --git a/vue/src/system/GraphQA.vue b/vue/src/system/GraphQA.vue index 0bcce49..2306b22 100644 --- a/vue/src/system/GraphQA.vue +++ b/vue/src/system/GraphQA.vue @@ -76,6 +76,7 @@ import Menu from "@/components/Menu.vue"; import {qaAnalyze} from "@/api/qa"; import {Graph} from "@antv/g6"; import {getGraph} from "@/api/graph"; +import {getGraphStyleActive} from "@/api/style"; export default { @@ -109,7 +110,16 @@ export default { queryRecord:"", - isSending:false + isSending:false, + configs:[], + parsedStyles:{}, + enToZhLabelMap: { + Disease: '疾病', + Drug: '药品', + Check: '检查', + Symptom: '症状', + Other: '其他' + } }; }, @@ -121,6 +131,11 @@ export default { // ======================================================================= mounted() { + this.$nextTick(() => { + setTimeout(() => { + this.getDefault() + }, 300); + }); // =============== 👇【新增】页面加载时从 localStorage 恢复数据 =============== this.restoreDataFromLocalStorage(); // ======================================================================= @@ -145,6 +160,36 @@ export default { // ======================================================================= }, methods: { + safeParseStyles(stylesStr) { + try { + return JSON.parse(stylesStr || '{}'); + } catch (e) { + console.warn('Failed to parse styles:', stylesStr); + return {}; + } + }, + async getDefault(){ + const response = await getGraphStyleActive(); + const data = response.data; + if (!Array.isArray(data) || data.length === 0) { + this.configs = []; + this.parsedStyles = {}; + return; + } + + // 只取第一个(即 is_active=1 的组) + const activeGroup = data[0]; + this.configs = Array.isArray(activeGroup.configs) ? activeGroup.configs : []; + + // 构建 label -> style 映射 + const styleMap = {}; + this.configs.forEach(config => { + const label = config.current_label; + styleMap[label] = this.safeParseStyles(config.styles); + }); + this.parsedStyles = styleMap; + console.log(this.parsedStyles) + }, buildNodeLabelMap(nodes) { this._nodeLabelMap = new Map(); nodes.forEach(node => { @@ -229,37 +274,60 @@ export default { formatData(data){ // this._graph.stopLayout(); // this.clearGraphState(); - const updatedEdges = data.edges.map(edge => ({ - ...edge, - type: this.edgeType, - style: { - endArrow: this.edgeEndArrow, - stroke: this.edgeStroke, - lineWidth: this.edgeLineWidth, - label: this.edgeShowLabel, - labelFontSize: this.edgeFontSize, - labelFontFamily: this.edgeFontFamily, - labelFill: this.edgeFontColor, - - }, - })) - const updatedNodes = data.nodes.map(node => ({ - ...node, - type: this.nodeShape, - style:{ - size: this.nodeSize, - lineWidth: this.nodeLineWidth, - label: this.nodeShowLabel, - labelFontSize: this.nodeFontSize, - labelFontFamily: this.nodeFontFamily, - labelFill: this.nodeFontColor, - opacity: 1, - } - })) - const updatedData = { + // === 1. 构建 nodeId → label 映射 === + const nodeIdToEnLabel = {}; + data.nodes.forEach(node => { + nodeIdToEnLabel[node.id] = node.data.label; // e.g. "Disease" + }); + // === 2. 处理节点:根据自身 label 设置样式 === + const updatedNodes = data.nodes.map(node => { + const enLabel = node.data.label; + const zhLabel = this.enToZhLabelMap[enLabel] || '其他'; // 默认回退到“其他” + const styleConf = this.parsedStyles[zhLabel] || {}; + return { + ...node, + type: styleConf.nodeShape || this.nodeShape, + style: { + size: styleConf.nodeSize || this.nodeSize, + fill: styleConf.nodeFill || this.nodeFill, + stroke: styleConf.nodeStroke || this.nodeStroke, + lineWidth: styleConf.nodeLineWidth || this.nodeLineWidth, + label: styleConf.nodeShowLabel !== undefined ? styleConf.nodeShowLabel : true, + labelFontSize: styleConf.nodeFontSize || this.nodeFontSize, + labelFontFamily: styleConf.nodeFontFamily || this.nodeFontFamily, + labelFill: styleConf.nodeFontColor || this.nodeFontColor + } + }; + }); + + // === 3. 处理边:根据 source 节点的 label 设置样式 === + const updatedEdges = data.edges.map(edge => { + console.log(edge) + const sourceEnLabel = nodeIdToEnLabel[edge.source]; // e.g. "Disease" + const sourceZhLabel = this.enToZhLabelMap[sourceEnLabel] || '其他'; + const styleConf = this.parsedStyles[sourceZhLabel] || {}; + + return { + ...edge, + id: edge.data?.relationship?.id || edge.id, + type: styleConf.edgeType ||this.edgeType, + style: { + endArrow: styleConf.edgeEndArrow !== undefined ? styleConf.edgeEndArrow : true, + stroke: styleConf.edgeStroke || this.edgeStroke, + lineWidth: styleConf.edgeLineWidth || this.edgeLineWidth, + label: styleConf.edgeShowLabel !== undefined ? styleConf.edgeShowLabel : false, + labelFontSize: styleConf.edgeFontSize || this.edgeFontSize, + labelFontFamily: styleConf.edgeFontFamily || this.edgeFontFamily, + labelFill: styleConf.edgeFontColor || this.edgeFontColor + } + }; + }); + + // === 4. 更新图数据 === + let updatedData = { nodes: updatedNodes, edges: updatedEdges - } + }; this.updateGraph(updatedData) }, @@ -274,37 +342,58 @@ export default { this._graph.destroy() this._graph = null; } - const updatedEdges = data.edges.map(edge => ({ - ...edge, - type: this.edgeType, - style: { - endArrow: this.edgeEndArrow, - stroke: this.edgeStroke, - lineWidth: this.edgeLineWidth, - label: this.edgeShowLabel, - labelFontSize: this.edgeFontSize, - labelFontFamily: this.edgeFontFamily, - labelFill: this.edgeFontColor, - - }, - })) - const updatedNodes = data.nodes.map(node => ({ - ...node, - type: this.nodeShape, - style:{ - size: this.nodeSize, - lineWidth: this.nodeLineWidth, - label: this.nodeShowLabel, - labelFontSize: this.nodeFontSize, - labelFontFamily: this.nodeFontFamily, - labelFill: this.nodeFontColor, - opacity: 1, - } - })) - const updatedData = { + // === 1. 构建 nodeId → label 映射 === + const nodeIdToEnLabel = {}; + data.nodes.forEach(node => { + nodeIdToEnLabel[node.id] = node.type; // e.g. "Disease" + }); + // === 2. 处理节点:根据自身 label 设置样式 === + const updatedNodes = data.nodes.map(node => { + const enLabel = node.data.label; + const styleConf = this.parsedStyles[enLabel] || {}; + return { + ...node, + type: styleConf.nodeShape || this.nodeShape, + style: { + size: styleConf.nodeSize || this.nodeSize, + fill: styleConf.nodeFill || this.nodeFill, + stroke: styleConf.nodeStroke || this.nodeStroke, + lineWidth: styleConf.nodeLineWidth || this.nodeLineWidth, + label: styleConf.nodeShowLabel !== undefined ? styleConf.nodeShowLabel : true, + labelFontSize: styleConf.nodeFontSize || this.nodeFontSize, + labelFontFamily: styleConf.nodeFontFamily || this.nodeFontFamily, + labelFill: styleConf.nodeFontColor || this.nodeFontColor + } + }; + }); + + // === 3. 处理边:根据 source 节点的 label 设置样式 === + const updatedEdges = data.edges.map(edge => { + console.log(edge) + const sourceEnLabel = nodeIdToEnLabel[edge.source]; // e.g. "Disease" + const styleConf = this.parsedStyles[sourceEnLabel] || {}; + + return { + ...edge, + id: edge.data?.relationship?.id || edge.id, + type: styleConf.edgeType ||this.edgeType, + style: { + endArrow: styleConf.edgeEndArrow !== undefined ? styleConf.edgeEndArrow : true, + stroke: styleConf.edgeStroke || this.edgeStroke, + lineWidth: styleConf.edgeLineWidth || this.edgeLineWidth, + label: styleConf.edgeShowLabel !== undefined ? styleConf.edgeShowLabel : false, + labelFontSize: styleConf.edgeFontSize || this.edgeFontSize, + labelFontFamily: styleConf.edgeFontFamily || this.edgeFontFamily, + labelFill: styleConf.edgeFontColor || this.edgeFontColor + } + }; + }); + + // === 4. 更新图数据 === + let updatedData = { nodes: updatedNodes, edges: updatedEdges - } + }; this.buildNodeLabelMap(updatedNodes); const container = this.$refs.graphContainer; console.log(container) @@ -342,23 +431,23 @@ export default { node: { style: { - fill: (d) => { - - const label = d.data?.type; - if (label === '疾病') return '#EF4444'; // 红 - if (label === '药品'||label === '药物') return '#91cc75'; // 绿 - if (label === '症状') return '#fac858'; // 橙 - if (label === '检查') return '#336eee'; // 橙 - return '#59d1d4'; // 默认灰蓝 - }, - stroke: (d) => { - const label = d.data?.type; - if (label === '疾病') return '#B91C1C'; - if (label === '药品'||label === '药物') return '#047857'; - if (label === '检查') return '#1D4ED8'; // 橙 - if (label === '症状') return '#B45309'; - return '#40999b'; - }, + // fill: (d) => { + // + // const label = d.data?.type; + // if (label === '疾病') return '#EF4444'; // 红 + // if (label === '药品'||label === '药物') return '#91cc75'; // 绿 + // if (label === '症状') return '#fac858'; // 橙 + // if (label === '检查') return '#336eee'; // 橙 + // return '#59d1d4'; // 默认灰蓝 + // }, + // stroke: (d) => { + // const label = d.data?.type; + // if (label === '疾病') return '#B91C1C'; + // if (label === '药品'||label === '药物') return '#047857'; + // if (label === '检查') return '#1D4ED8'; // 橙 + // if (label === '症状') return '#B45309'; + // return '#40999b'; + // }, labelText: (d) => d.label, labelPlacement: 'center', labelWordWrap: true, @@ -391,14 +480,14 @@ export default { labelText: (d) => { console.log(d) return d.data.label}, - stroke: (d) => { - const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID - if (targetLabel === '疾病') return 'rgba(239,68,68,0.5)'; - if (targetLabel === '药品'||targetLabel === '药物') return 'rgba(145,204,117,0.5)'; - if (targetLabel === '症状') return 'rgba(250,200,88,0.5)'; - if (targetLabel === '检查') return 'rgba(51,110,238,0.5)'; // 橙 - return 'rgba(89,209,212,0.5)'; // default - }, + // stroke: (d) => { + // const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID + // if (targetLabel === '疾病') return 'rgba(239,68,68,0.5)'; + // if (targetLabel === '药品'||targetLabel === '药物') return 'rgba(145,204,117,0.5)'; + // if (targetLabel === '症状') return 'rgba(250,200,88,0.5)'; + // if (targetLabel === '检查') return 'rgba(51,110,238,0.5)'; // 橙 + // return 'rgba(89,209,212,0.5)'; // default + // }, // labelFill: (d) => { // // 获取 target 节点的 label // const targetLabel = this._nodeLabelMap.get(d.target); // d.target 是目标节点 ID diff --git a/vue/src/system/GraphStyle.vue b/vue/src/system/GraphStyle.vue index d3f8165..a120386 100644 --- a/vue/src/system/GraphStyle.vue +++ b/vue/src/system/GraphStyle.vue @@ -380,7 +380,7 @@ export default { edgeFontFamily: 'Microsoft YaHei, sans-serif', edgeFontSize: 10, edgeFontColor: '#666666', - edgeType: 'line', + edgeType: 'quadratic', edgeLineWidth: 2, edgeStroke: '#EF4444', defaultData: {