|
|
@ -157,6 +157,7 @@ import Menu from "@/components/Menu.vue"; |
|
|
import {a} from "vue-router/dist/devtools-EWN81iOl.mjs"; |
|
|
import {a} from "vue-router/dist/devtools-EWN81iOl.mjs"; |
|
|
|
|
|
|
|
|
import Fuse from 'fuse.js'; |
|
|
import Fuse from 'fuse.js'; |
|
|
|
|
|
import {getGraphStyleActive} from "@/api/style"; |
|
|
export default { |
|
|
export default { |
|
|
name: 'Display', |
|
|
name: 'Display', |
|
|
components: {Menu}, |
|
|
components: {Menu}, |
|
|
@ -232,7 +233,16 @@ export default { |
|
|
{ value: 'Disease', label: '疾病' }, |
|
|
{ value: 'Disease', label: '疾病' }, |
|
|
{ value: 'Drug', label: '药品' }, |
|
|
{ value: 'Drug', label: '药品' }, |
|
|
{ value: 'Check', label: '检查' } |
|
|
{ value: 'Check', label: '检查' } |
|
|
] |
|
|
], |
|
|
|
|
|
configs:[], |
|
|
|
|
|
parsedStyles:{}, |
|
|
|
|
|
enToZhLabelMap: { |
|
|
|
|
|
Disease: '疾病', |
|
|
|
|
|
Drug: '药品', |
|
|
|
|
|
Check: '检查', |
|
|
|
|
|
Symptom: '症状', |
|
|
|
|
|
Other: '其他' |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
computed: { |
|
|
computed: { |
|
|
@ -307,41 +317,66 @@ export default { |
|
|
this.treeData=this.diseaseICD10Tree |
|
|
this.treeData=this.diseaseICD10Tree |
|
|
await this.$nextTick(); |
|
|
await this.$nextTick(); |
|
|
try { |
|
|
try { |
|
|
|
|
|
await this.getDefault() |
|
|
const response = await getTestGraphData(); // 等待 Promise 解析 |
|
|
const response = await getTestGraphData(); // 等待 Promise 解析 |
|
|
const updatedNodes = response.nodes.map(node => ({ |
|
|
// === 1. 构建 nodeId → label 映射 === |
|
|
...node, |
|
|
const nodeIdToEnLabel = {}; |
|
|
type: this.nodeShape, |
|
|
response.nodes.forEach(node => { |
|
|
style:{ |
|
|
nodeIdToEnLabel[node.id] = node.data.label; // e.g. "Disease" |
|
|
size: this.nodeSize, |
|
|
}); |
|
|
fill: this.nodeFill, |
|
|
|
|
|
stroke: this.nodeStroke, |
|
|
// === 2. 处理节点:根据自身 label 设置样式 === |
|
|
lineWidth: this.nodeLineWidth, |
|
|
const updatedNodes = response.nodes.map(node => { |
|
|
label: this.nodeShowLabel, |
|
|
const enLabel = node.data.label; |
|
|
labelFontSize: this.nodeFontSize, |
|
|
const zhLabel = this.enToZhLabelMap[enLabel] || '其他'; // 默认回退到“其他” |
|
|
labelFontFamily: this.nodeFontFamily, |
|
|
const styleConf = this.parsedStyles[zhLabel] || {}; |
|
|
labelFill: this.nodeFontColor, |
|
|
return { |
|
|
} |
|
|
...node, |
|
|
})) |
|
|
type: styleConf.nodeShape || this.nodeShape, |
|
|
const updatedEdges = response.edges.map(edge => ({ |
|
|
style: { |
|
|
...edge, |
|
|
size: styleConf.nodeSize || this.nodeSize, |
|
|
id: edge.data.relationship.id, |
|
|
fill: styleConf.nodeFill || this.nodeFill, |
|
|
type: this.edgeType, |
|
|
stroke: styleConf.nodeStroke || this.nodeStroke, |
|
|
style: { |
|
|
lineWidth: styleConf.nodeLineWidth || this.nodeLineWidth, |
|
|
endArrow: this.edgeEndArrow, |
|
|
label: styleConf.nodeShowLabel !== undefined ? styleConf.nodeShowLabel : true, |
|
|
stroke: this.edgeStroke, |
|
|
labelFontSize: styleConf.nodeFontSize || this.nodeFontSize, |
|
|
lineWidth: this.edgeLineWidth, |
|
|
labelFontFamily: styleConf.nodeFontFamily || this.nodeFontFamily, |
|
|
label: this.edgeShowLabel, |
|
|
labelFill: styleConf.nodeFontColor || this.nodeFontColor |
|
|
labelFontSize: this.edgeFontSize, |
|
|
} |
|
|
labelFontFamily: this.edgeFontFamily, |
|
|
}; |
|
|
labelFill: this.edgeFontColor, |
|
|
}); |
|
|
}, |
|
|
|
|
|
})) |
|
|
// === 3. 处理边:根据 source 节点的 label 设置样式 === |
|
|
const updatedData = { |
|
|
const updatedEdges = response.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, |
|
|
nodes: updatedNodes, |
|
|
edges: updatedEdges |
|
|
edges: updatedEdges |
|
|
} |
|
|
}; |
|
|
|
|
|
console.log(updatedData) |
|
|
this.defaultData = updatedData |
|
|
this.defaultData = updatedData |
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
this.initGraph(); |
|
|
this.initGraph(); |
|
|
this.buildCategoryIndex(); |
|
|
this.buildCategoryIndex(); |
|
|
window.addEventListener('resize', this.handleResize); |
|
|
window.addEventListener('resize', this.handleResize); |
|
|
@ -349,6 +384,50 @@ export default { |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('加载图谱数据失败:', error); |
|
|
console.error('加载图谱数据失败:', error); |
|
|
} |
|
|
} |
|
|
|
|
|
// try { |
|
|
|
|
|
// await this.getDefault() |
|
|
|
|
|
// const response = await getTestGraphData(); // 等待 Promise 解析 |
|
|
|
|
|
// const updatedNodes = response.nodes.map(node => ({ |
|
|
|
|
|
// ...node, |
|
|
|
|
|
// type: this.nodeShape, |
|
|
|
|
|
// style:{ |
|
|
|
|
|
// size: this.nodeSize, |
|
|
|
|
|
// fill: this.nodeFill, |
|
|
|
|
|
// stroke: this.nodeStroke, |
|
|
|
|
|
// lineWidth: this.nodeLineWidth, |
|
|
|
|
|
// label: this.nodeShowLabel, |
|
|
|
|
|
// labelFontSize: this.nodeFontSize, |
|
|
|
|
|
// labelFontFamily: this.nodeFontFamily, |
|
|
|
|
|
// labelFill: this.nodeFontColor, |
|
|
|
|
|
// } |
|
|
|
|
|
// })) |
|
|
|
|
|
// const updatedEdges = response.edges.map(edge => ({ |
|
|
|
|
|
// ...edge, |
|
|
|
|
|
// id: edge.data.relationship.id, |
|
|
|
|
|
// 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 updatedData = { |
|
|
|
|
|
// nodes: updatedNodes, |
|
|
|
|
|
// edges: updatedEdges |
|
|
|
|
|
// } |
|
|
|
|
|
// this.defaultData = updatedData |
|
|
|
|
|
// setTimeout(() => { |
|
|
|
|
|
// this.initGraph(); |
|
|
|
|
|
// this.buildCategoryIndex(); |
|
|
|
|
|
// window.addEventListener('resize', this.handleResize); |
|
|
|
|
|
// }, 1000); |
|
|
|
|
|
// } catch (error) { |
|
|
|
|
|
// console.error('加载图谱数据失败:', error); |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
@ -384,6 +463,36 @@ export default { |
|
|
edgeFontFamily: 'updateAllEdges', |
|
|
edgeFontFamily: 'updateAllEdges', |
|
|
}, |
|
|
}, |
|
|
methods: { |
|
|
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) |
|
|
|
|
|
}, |
|
|
// 切换下拉菜单显隐 |
|
|
// 切换下拉菜单显隐 |
|
|
toggleDropdown() { |
|
|
toggleDropdown() { |
|
|
this.isDropdownOpen = !this.isDropdownOpen; |
|
|
this.isDropdownOpen = !this.isDropdownOpen; |
|
|
@ -871,22 +980,22 @@ export default { |
|
|
|
|
|
|
|
|
node: { |
|
|
node: { |
|
|
style: { |
|
|
style: { |
|
|
fill: (d) => { |
|
|
// fill: (d) => { |
|
|
const label = d.data?.label; |
|
|
// const label = d.data?.label; |
|
|
if (label === 'Disease') return '#EF4444'; // 红 |
|
|
// if (label === 'Disease') return '#EF4444'; // 红 |
|
|
if (label === 'Drug') return '#91cc75'; // 绿 |
|
|
// if (label === 'Drug') return '#91cc75'; // 绿 |
|
|
if (label === 'Symptom') return '#fac858'; // 橙 |
|
|
// if (label === 'Symptom') return '#fac858'; // 橙 |
|
|
if (label === 'Check') return '#336eee'; // 橙 |
|
|
// if (label === 'Check') return '#336eee'; // 橙 |
|
|
return '#59d1d4'; // 默认灰蓝 |
|
|
// return '#59d1d4'; // 默认灰蓝 |
|
|
}, |
|
|
// }, |
|
|
stroke: (d) => { |
|
|
// stroke: (d) => { |
|
|
const label = d.data?.label; |
|
|
// const label = d.data?.label; |
|
|
if (label === 'Disease') return '#B91C1C'; |
|
|
// if (label === 'Disease') return '#B91C1C'; |
|
|
if (label === 'Drug') return '#047857'; |
|
|
// if (label === 'Drug') return '#047857'; |
|
|
if (label === 'Check') return '#1D4ED8'; // 橙 |
|
|
// if (label === 'Check') return '#1D4ED8'; // 橙 |
|
|
if (label === 'Symptom') return '#B45309'; |
|
|
// if (label === 'Symptom') return '#B45309'; |
|
|
return '#40999b'; |
|
|
// return '#40999b'; |
|
|
}, |
|
|
// }, |
|
|
labelText: (d) => d.data.name, |
|
|
labelText: (d) => d.data.name, |
|
|
labelPlacement: 'center', |
|
|
labelPlacement: 'center', |
|
|
labelWordWrap: true, |
|
|
labelWordWrap: true, |
|
|
@ -921,16 +1030,16 @@ export default { |
|
|
edge: { |
|
|
edge: { |
|
|
style: { |
|
|
style: { |
|
|
labelText: (d) => d.data.relationship.properties.label, |
|
|
labelText: (d) => d.data.relationship.properties.label, |
|
|
stroke: (d) => { |
|
|
// stroke: (d) => { |
|
|
// 获取 target 节点的 label |
|
|
// // 获取 target 节点的 label |
|
|
const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID |
|
|
// const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID |
|
|
// 根据 target 节点类型返回对应浅色 |
|
|
// // 根据 target 节点类型返回对应浅色 |
|
|
if (targetLabel === 'Disease') return 'rgba(239,68,68,0.5)'; |
|
|
// if (targetLabel === 'Disease') return 'rgba(239,68,68,0.5)'; |
|
|
if (targetLabel === 'Drug') return 'rgba(145,204,117,0.5)'; |
|
|
// if (targetLabel === 'Drug') return 'rgba(145,204,117,0.5)'; |
|
|
if (targetLabel === 'Symptom') return 'rgba(250,200,88,0.5)'; |
|
|
// if (targetLabel === 'Symptom') return 'rgba(250,200,88,0.5)'; |
|
|
if (targetLabel === 'Check') return 'rgba(51,110,238,0.5)'; // 橙 |
|
|
// if (targetLabel === 'Check') return 'rgba(51,110,238,0.5)'; // 橙 |
|
|
return 'rgba(89,209,212,0.5)'; // default |
|
|
// return 'rgba(89,209,212,0.5)'; // default |
|
|
}, |
|
|
// }, |
|
|
// labelFill: (d) => { |
|
|
// labelFill: (d) => { |
|
|
// // 获取 target 节点的 label |
|
|
// // 获取 target 节点的 label |
|
|
// const targetLabel = this._nodeLabelMap.get(d.target); // d.target 是目标节点 ID |
|
|
// const targetLabel = this._nodeLabelMap.get(d.target); // d.target 是目标节点 ID |
|
|
|