|
|
@ -19,6 +19,7 @@ |
|
|
v-model="query" |
|
|
v-model="query" |
|
|
placeholder="请输入问题..." |
|
|
placeholder="请输入问题..." |
|
|
clearable |
|
|
clearable |
|
|
|
|
|
@keydown.enter="handleSearch" |
|
|
/> |
|
|
/> |
|
|
<el-button type="primary" @click="handleSearch" style=" background: #114FE6;">查询</el-button> |
|
|
<el-button type="primary" @click="handleSearch" style=" background: #114FE6;">查询</el-button> |
|
|
</div> |
|
|
</div> |
|
|
@ -103,13 +104,96 @@ export default { |
|
|
|
|
|
|
|
|
}; |
|
|
}; |
|
|
}, |
|
|
}, |
|
|
|
|
|
// =============== 👇【新增】组件内路由守卫:离开当前路由时触发 =============== |
|
|
|
|
|
beforeRouteLeave(to, from, next) { |
|
|
|
|
|
this.saveDataToLocalStorage(); |
|
|
|
|
|
next(); // 允许导航 |
|
|
|
|
|
}, |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
|
|
|
|
|
|
mounted() { |
|
|
|
|
|
// =============== 👇【新增】页面加载时从 localStorage 恢复数据 =============== |
|
|
|
|
|
this.restoreDataFromLocalStorage(); |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
|
|
|
|
|
|
// 如果有初始数据,可以初始化图谱(可选) |
|
|
|
|
|
if (this.answers.length > 0) { |
|
|
|
|
|
this.initGraph(this.answers[0].result); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
beforeUnmount() { |
|
|
|
|
|
// =============== 👇【新增】组件销毁前也保存一次(兼容非路由跳转场景)============== |
|
|
|
|
|
this.saveDataToLocalStorage(); |
|
|
|
|
|
// 移除页面卸载监听(如果用了 beforeunload) |
|
|
|
|
|
window.removeEventListener('beforeunload', this.handleBeforeUnload); |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
created() { |
|
|
|
|
|
// =============== 👇【新增】监听页面刷新/关闭事件 =============== |
|
|
|
|
|
window.addEventListener('beforeunload', this.handleBeforeUnload); |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
|
|
|
buildNodeLabelMap(nodes) { |
|
|
|
|
|
this._nodeLabelMap = new Map(); |
|
|
|
|
|
nodes.forEach(node => { |
|
|
|
|
|
this._nodeLabelMap.set(node.id, node.data?.type || 'default'); |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
// =============== 👇【新增】统一的数据保存方法 =============== |
|
|
|
|
|
saveDataToLocalStorage() { |
|
|
|
|
|
try { |
|
|
|
|
|
localStorage.setItem('graphQA_queryRecord', this.queryRecord); |
|
|
|
|
|
localStorage.setItem('graphQA_answers', JSON.stringify(this.answers)); |
|
|
|
|
|
console.log('✅ 数据已保存到 localStorage'); |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
console.warn('⚠️ 无法保存到 localStorage:', e); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
|
|
|
|
|
|
// =============== 👇【新增】统一的数据恢复方法 =============== |
|
|
|
|
|
restoreDataFromLocalStorage() { |
|
|
|
|
|
try { |
|
|
|
|
|
const savedQuery = localStorage.getItem('graphQA_queryRecord'); |
|
|
|
|
|
const savedAnswers = localStorage.getItem('graphQA_answers'); |
|
|
|
|
|
|
|
|
|
|
|
if (savedQuery !== null) { |
|
|
|
|
|
this.queryRecord = savedQuery; |
|
|
|
|
|
} |
|
|
|
|
|
if (savedAnswers !== null) { |
|
|
|
|
|
this.answers = JSON.parse(savedAnswers); |
|
|
|
|
|
// 确保 selected 不越界 |
|
|
|
|
|
if (this.answers.length > 0) { |
|
|
|
|
|
this.selected = Math.min(this.selected, this.answers.length - 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
console.log('✅ 数据已从 localStorage 恢复'); |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
console.warn('⚠️ 无法从 localStorage 恢复数据:', e); |
|
|
|
|
|
// 出错时清空(避免脏数据) |
|
|
|
|
|
localStorage.removeItem('graphQA_queryRecord'); |
|
|
|
|
|
localStorage.removeItem('graphQA_answers'); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
// ======================================================================= |
|
|
|
|
|
|
|
|
|
|
|
// =============== 👇【新增】处理页面关闭/刷新的兜底保存 =============== |
|
|
|
|
|
handleBeforeUnload(event) { |
|
|
|
|
|
this.saveDataToLocalStorage(); |
|
|
|
|
|
// 注意:现代浏览器通常不显示自定义消息 |
|
|
|
|
|
event.preventDefault(); |
|
|
|
|
|
event.returnValue = ''; // 必须设置才能触发提示(但实际可能不显示) |
|
|
|
|
|
}, |
|
|
selectGraph(index){ |
|
|
selectGraph(index){ |
|
|
this.selected=index |
|
|
this.selected=index |
|
|
this.formatData(this.answers[index].result) |
|
|
this.formatData(this.answers[index].result) |
|
|
}, |
|
|
}, |
|
|
handleSearch(){ |
|
|
handleSearch(){ |
|
|
this.answers=[] |
|
|
this.answers=[] |
|
|
|
|
|
this.formatData([]) |
|
|
let data={ |
|
|
let data={ |
|
|
text:this.query |
|
|
text:this.query |
|
|
} |
|
|
} |
|
|
@ -127,8 +211,8 @@ export default { |
|
|
}) |
|
|
}) |
|
|
}, |
|
|
}, |
|
|
formatData(data){ |
|
|
formatData(data){ |
|
|
this._graph.stopLayout(); |
|
|
// this._graph.stopLayout(); |
|
|
this.clearGraphState(); |
|
|
// this.clearGraphState(); |
|
|
const updatedEdges = data.edges.map(edge => ({ |
|
|
const updatedEdges = data.edges.map(edge => ({ |
|
|
...edge, |
|
|
...edge, |
|
|
type: this.edgeType, |
|
|
type: this.edgeType, |
|
|
@ -204,6 +288,7 @@ export default { |
|
|
nodes: updatedNodes, |
|
|
nodes: updatedNodes, |
|
|
edges: updatedEdges |
|
|
edges: updatedEdges |
|
|
} |
|
|
} |
|
|
|
|
|
this.buildNodeLabelMap(updatedNodes); |
|
|
const container = this.$refs.graphContainer; |
|
|
const container = this.$refs.graphContainer; |
|
|
console.log(container) |
|
|
console.log(container) |
|
|
if (container!=null){ |
|
|
if (container!=null){ |
|
|
@ -241,19 +326,20 @@ export default { |
|
|
node: { |
|
|
node: { |
|
|
style: { |
|
|
style: { |
|
|
fill: (d) => { |
|
|
fill: (d) => { |
|
|
const label = d?.type; |
|
|
|
|
|
if (label === 'Disease') return '#EF4444'; // 红 |
|
|
const label = d.data?.type; |
|
|
if (label === 'Drug') return '#91cc75'; // 绿 |
|
|
if (label === '疾病') return '#EF4444'; // 红 |
|
|
if (label === 'Symptom') return '#fac858'; // 橙 |
|
|
if (label === '药品'||label === '药物') return '#91cc75'; // 绿 |
|
|
if (label === 'Check') return '#336eee'; // 橙 |
|
|
if (label === '症状') return '#fac858'; // 橙 |
|
|
|
|
|
if (label === '检查') return '#336eee'; // 橙 |
|
|
return '#59d1d4'; // 默认灰蓝 |
|
|
return '#59d1d4'; // 默认灰蓝 |
|
|
}, |
|
|
}, |
|
|
stroke: (d) => { |
|
|
stroke: (d) => { |
|
|
const label = d?.type; |
|
|
const label = d.data?.type; |
|
|
if (label === 'Disease') return '#B91C1C'; |
|
|
if (label === '疾病') return '#B91C1C'; |
|
|
if (label === 'Drug') return '#047857'; |
|
|
if (label === '药品'||label === '药物') return '#047857'; |
|
|
if (label === 'Check') return '#1D4ED8'; // 橙 |
|
|
if (label === '检查') return '#1D4ED8'; // 橙 |
|
|
if (label === 'Symptom') return '#B45309'; |
|
|
if (label === '症状') return '#B45309'; |
|
|
return '#40999b'; |
|
|
return '#40999b'; |
|
|
}, |
|
|
}, |
|
|
labelText: (d) => d.label, |
|
|
labelText: (d) => d.label, |
|
|
@ -282,17 +368,18 @@ export default { |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
edge: { |
|
|
edge: { |
|
|
style: { |
|
|
style: { |
|
|
labelText: (d) => d.label, |
|
|
labelText: (d) => { |
|
|
|
|
|
console.log(d) |
|
|
|
|
|
return d.data.label}, |
|
|
stroke: (d) => { |
|
|
stroke: (d) => { |
|
|
// 获取 target 节点的 label |
|
|
const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID |
|
|
// const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID |
|
|
if (targetLabel === '疾病') return 'rgba(239,68,68,0.5)'; |
|
|
// // 根据 target 节点类型返回对应浅色 |
|
|
if (targetLabel === '药品'||targetLabel === '药物') return 'rgba(145,204,117,0.5)'; |
|
|
// if (targetLabel === 'Disease') return 'rgba(239,68,68,0.5)'; |
|
|
if (targetLabel === '症状') return 'rgba(250,200,88,0.5)'; |
|
|
// if (targetLabel === 'Drug') return 'rgba(145,204,117,0.5)'; |
|
|
if (targetLabel === '检查') return 'rgba(51,110,238,0.5)'; // 橙 |
|
|
// if (targetLabel === 'Symptom') return 'rgba(250,200,88,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) => { |
|
|
@ -342,6 +429,7 @@ export default { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
}; |
|
|
}; |
|
|
|