|
|
|
@ -139,7 +139,6 @@ |
|
|
|
v-if="_graph" |
|
|
|
:graph="_graph" |
|
|
|
class="toolbar-position" |
|
|
|
style="position: absolute; top: 40px; left: 750px; z-index: 1000; width: auto;" |
|
|
|
/> |
|
|
|
<div ref="graphContainer" class="graph-container" id="container"></div> |
|
|
|
</div> |
|
|
|
@ -161,16 +160,15 @@ import { |
|
|
|
} from "@/api/graph" |
|
|
|
import {Graph, Tooltip} from '@antv/g6'; |
|
|
|
import Menu from "@/components/Menu.vue"; |
|
|
|
import {a} from "vue-router/dist/devtools-EWN81iOl.mjs"; |
|
|
|
import GraphToolbar from "@/components/GraphToolbar.vue"; |
|
|
|
import { markRaw } from 'vue'; |
|
|
|
import {a} from "vue-router/dist/devtools-EWN81iOl.mjs"; |
|
|
|
|
|
|
|
import Fuse from 'fuse.js'; |
|
|
|
import {ElMessage} from "element-plus"; |
|
|
|
import {getGraphStyleActive} from "@/api/style"; |
|
|
|
|
|
|
|
export default { |
|
|
|
name: 'Display', |
|
|
|
components: {Menu, GraphToolbar}, |
|
|
|
components: {Menu,GraphToolbar}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
_graph: null, |
|
|
|
@ -212,41 +210,41 @@ export default { |
|
|
|
children: 'children', |
|
|
|
label: 'title' // 虽然用插槽,但 el-tree 内部仍会读取,可留空或任意 |
|
|
|
}, |
|
|
|
typeRadio: "Disease", |
|
|
|
DiseaseRadio: "ICD10", |
|
|
|
drugTree: [], |
|
|
|
diseaseDepartTree: [], |
|
|
|
diseaseICD10Tree: [], |
|
|
|
diseaseSZMTree: [], |
|
|
|
checkTree: [], |
|
|
|
typeRadio:"Disease", |
|
|
|
DiseaseRadio:"ICD10", |
|
|
|
drugTree:[], |
|
|
|
diseaseDepartTree:[], |
|
|
|
diseaseICD10Tree:[], |
|
|
|
diseaseSZMTree:[], |
|
|
|
checkTree:[], |
|
|
|
legendItems: [ |
|
|
|
{key: 'Disease', label: '疾病', color: '#EF4444'}, |
|
|
|
{key: 'Drug', label: '药品', color: '#91cc75'}, |
|
|
|
{key: 'Check', label: '检查', color: '#336eee'}, |
|
|
|
{key: 'Symptom', label: '症状', color: '#fac858'}, |
|
|
|
{key: 'Other', label: '其他', color: '#59d1d4'} |
|
|
|
{ key: 'Disease', label: '疾病', color: '#EF4444' }, |
|
|
|
{ key: 'Drug', label: '药品', color: '#91cc75' }, |
|
|
|
{ key: 'Check', label: '检查', color: '#336eee' }, |
|
|
|
{ key: 'Symptom', label: '症状', color: '#fac858' }, |
|
|
|
{ key: 'Other', label: '其他', color: '#59d1d4' } |
|
|
|
], |
|
|
|
visibleCategories: new Set(), // 先空着 |
|
|
|
diseaseCount: 0, |
|
|
|
drugCount: 0, |
|
|
|
checkCount: 0, |
|
|
|
diseaseCount:0, |
|
|
|
drugCount:0, |
|
|
|
checkCount:0, |
|
|
|
originalNodeStyles: new Map(), // 保存原始节点样式 |
|
|
|
originalEdgeStyles: new Map(), // 保存原始边样式 |
|
|
|
searchResults: { |
|
|
|
nodes: [], |
|
|
|
edges: [] |
|
|
|
}, |
|
|
|
searchKeyword: "", |
|
|
|
drugSubjectTree: [], |
|
|
|
DrugRadio: "Subject", |
|
|
|
searchKeyword:"", |
|
|
|
drugSubjectTree:[], |
|
|
|
DrugRadio:"Subject", |
|
|
|
isDropdownOpen: false, |
|
|
|
typeOptions: [ |
|
|
|
{value: 'Disease', label: '疾病'}, |
|
|
|
{value: 'Drug', label: '药品'}, |
|
|
|
{value: 'Check', label: '检查'} |
|
|
|
{ value: 'Disease', label: '疾病' }, |
|
|
|
{ value: 'Drug', label: '药品' }, |
|
|
|
{ value: 'Check', label: '检查' } |
|
|
|
], |
|
|
|
configs: [], |
|
|
|
parsedStyles: {}, |
|
|
|
configs:[], |
|
|
|
parsedStyles:{}, |
|
|
|
enToZhLabelMap: { |
|
|
|
Disease: '疾病', |
|
|
|
Drug: '药品', |
|
|
|
@ -325,7 +323,7 @@ export default { |
|
|
|
this.loadDrugTreeData() |
|
|
|
this.loadCheckTreeData() |
|
|
|
this.loadDrugSubjectTreeData() |
|
|
|
this.treeData = this.diseaseICD10Tree |
|
|
|
this.treeData=this.diseaseICD10Tree |
|
|
|
await this.$nextTick(); |
|
|
|
try { |
|
|
|
await this.getDefault() |
|
|
|
@ -367,7 +365,7 @@ export default { |
|
|
|
return { |
|
|
|
...edge, |
|
|
|
id: edge.data?.relationship?.id || edge.id, |
|
|
|
type: styleConf.edgeType || this.edgeType, |
|
|
|
type: styleConf.edgeType ||this.edgeType, |
|
|
|
style: { |
|
|
|
endArrow: styleConf.edgeEndArrow !== undefined ? styleConf.edgeEndArrow : true, |
|
|
|
stroke: styleConf.edgeStroke || this.edgeStroke, |
|
|
|
@ -443,7 +441,7 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
beforeUnmount() { |
|
|
|
if (this._graph != null) { |
|
|
|
if (this._graph!=null){ |
|
|
|
this._graph.stopLayout(); |
|
|
|
this.clearGraphState(); |
|
|
|
this._graph.destroy() |
|
|
|
@ -482,7 +480,7 @@ export default { |
|
|
|
return {}; |
|
|
|
} |
|
|
|
}, |
|
|
|
async getDefault() { |
|
|
|
async getDefault(){ |
|
|
|
const response = await getGraphStyleActive(); |
|
|
|
const data = response.data; |
|
|
|
if (!Array.isArray(data) || data.length === 0) { |
|
|
|
@ -650,7 +648,7 @@ export default { |
|
|
|
// 4️⃣ 聚焦第一个匹配项 |
|
|
|
const firstMatch = nodeIds[0] || edgeIds[0]; |
|
|
|
if (firstMatch && (this._graph.hasNode(firstMatch) || this._graph.hasEdge(firstMatch))) { |
|
|
|
this._graph.focusElement(firstMatch, {animation: true, duration: 600}); |
|
|
|
this._graph.focusElement(firstMatch, { animation: true, duration: 600 }); |
|
|
|
} |
|
|
|
}, |
|
|
|
clearSearchHighlight() { |
|
|
|
@ -664,26 +662,26 @@ export default { |
|
|
|
this._graph.setElementState(id, 'normal', true); |
|
|
|
}); |
|
|
|
}, |
|
|
|
getCount() { |
|
|
|
getCount().then(res => { |
|
|
|
this.diseaseCount = res.Disease |
|
|
|
this.drugCount = res.Drug |
|
|
|
this.checkCount = res.Check |
|
|
|
getCount(){ |
|
|
|
getCount().then(res=>{ |
|
|
|
this.diseaseCount=res.Disease |
|
|
|
this.drugCount=res.Drug |
|
|
|
this.checkCount=res.Check |
|
|
|
console.log(res) |
|
|
|
}) |
|
|
|
}, |
|
|
|
buildCategoryIndex() { |
|
|
|
const index = {}; |
|
|
|
if (this._graph != null) { |
|
|
|
if (this._graph!=null){ |
|
|
|
const nodes = this._graph.getNodeData() // 获取所有节点 |
|
|
|
nodes.forEach(node => { |
|
|
|
console.log(node.data.label) |
|
|
|
const category = node.data.label; // 假设 label 是类别 |
|
|
|
if (category == 'Drug' || category == 'Symptom' || |
|
|
|
category == 'Disease' || category == 'Check') { |
|
|
|
if(category=='Drug'||category=='Symptom'|| |
|
|
|
category=='Disease'||category=='Check'){ |
|
|
|
if (!index[category]) index[category] = []; |
|
|
|
index[category].push(node.id); |
|
|
|
} else { |
|
|
|
}else{ |
|
|
|
if (!index["Other"]) index["Other"] = []; |
|
|
|
index["Other"].push(node.id); |
|
|
|
} |
|
|
|
@ -693,7 +691,7 @@ export default { |
|
|
|
|
|
|
|
}, |
|
|
|
// 切换某个类别的显示状态 |
|
|
|
toggleCategory(key) { |
|
|
|
toggleCategory (key){ |
|
|
|
if (this.visibleCategories.has(key)) { |
|
|
|
this.visibleCategories.delete(key) |
|
|
|
} else { |
|
|
|
@ -748,28 +746,28 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
changeTree() { |
|
|
|
if (this.typeRadio == "Disease") { |
|
|
|
if (this.DiseaseRadio == "ICD10") { |
|
|
|
this.treeData = this.diseaseICD10Tree |
|
|
|
changeTree(){ |
|
|
|
if(this.typeRadio=="Disease"){ |
|
|
|
if(this.DiseaseRadio=="ICD10") { |
|
|
|
this.treeData=this.diseaseICD10Tree |
|
|
|
} |
|
|
|
if (this.DiseaseRadio == "Department") { |
|
|
|
this.treeData = this.diseaseDepartTree |
|
|
|
if(this.DiseaseRadio=="Department") { |
|
|
|
this.treeData=this.diseaseDepartTree |
|
|
|
} |
|
|
|
if (this.DiseaseRadio == "SZM") { |
|
|
|
this.treeData = this.diseaseSZMTree |
|
|
|
if(this.DiseaseRadio=="SZM") { |
|
|
|
this.treeData=this.diseaseSZMTree |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.typeRadio == "Drug") { |
|
|
|
if (this.DrugRadio == "Subject") { |
|
|
|
this.treeData = this.drugSubjectTree |
|
|
|
if(this.typeRadio=="Drug") { |
|
|
|
if(this.DrugRadio=="Subject") { |
|
|
|
this.treeData=this.drugSubjectTree |
|
|
|
} |
|
|
|
if (this.DrugRadio == "SZM") { |
|
|
|
this.treeData = this.drugTree |
|
|
|
if(this.DrugRadio=="SZM") { |
|
|
|
this.treeData=this.drugTree |
|
|
|
} |
|
|
|
} |
|
|
|
if (this.typeRadio == "Check") { |
|
|
|
this.treeData = this.checkTree |
|
|
|
if(this.typeRadio=="Check") { |
|
|
|
this.treeData=this.checkTree |
|
|
|
} |
|
|
|
}, |
|
|
|
async loadDiseaseICD10TreeData() { |
|
|
|
@ -829,15 +827,15 @@ export default { |
|
|
|
const response = await getGraph(data); // 等待 Promise 解析 |
|
|
|
this.formatData(response) |
|
|
|
} |
|
|
|
if (data.level == "category" || |
|
|
|
data.level == "subcategory" || |
|
|
|
data.level == "diagnosis") { |
|
|
|
data.type = "Disease" |
|
|
|
if(data.level=="category"|| |
|
|
|
data.level=="subcategory"|| |
|
|
|
data.level=="diagnosis"){ |
|
|
|
data.type="Disease" |
|
|
|
const response = await getGraph(data); // 等待 Promise 解析 |
|
|
|
this.formatData(response) |
|
|
|
} |
|
|
|
if (data.type === "Disease") { |
|
|
|
data.type = "Disease" |
|
|
|
if(data.type === "Disease"){ |
|
|
|
data.type="Disease" |
|
|
|
const response = await getGraph(data); // 等待 Promise 解析 |
|
|
|
this.formatData(response) |
|
|
|
} |
|
|
|
@ -853,21 +851,21 @@ export default { |
|
|
|
|
|
|
|
// 1. 清除所有节点和边的状态 |
|
|
|
this._graph.getNodeData().forEach(node => { |
|
|
|
this._graph.setElementState(node.id, []); |
|
|
|
this._graph.setElementState(node.id,[]); |
|
|
|
|
|
|
|
}); |
|
|
|
this._graph.getEdgeData().forEach(edge => { |
|
|
|
this._graph.setElementState(edge.id, []); |
|
|
|
this._graph.setElementState(edge.id,[]); |
|
|
|
}); |
|
|
|
|
|
|
|
// 2. (可选)取消所有 pending 的交互 |
|
|
|
// 比如如果你有高亮定时器,这里 clearTimeout |
|
|
|
}, |
|
|
|
formatData(data) { |
|
|
|
if (!this._graph) return; |
|
|
|
formatData(data){ |
|
|
|
this._graph.stopLayout(); |
|
|
|
this.clearGraphState(); |
|
|
|
|
|
|
|
|
|
|
|
// === 1. 构建 nodeId → label 映射 === |
|
|
|
const nodeIdToEnLabel = {}; |
|
|
|
data.nodes.forEach(node => { |
|
|
|
@ -904,7 +902,7 @@ export default { |
|
|
|
return { |
|
|
|
...edge, |
|
|
|
id: edge.data?.relationship?.id || edge.id, |
|
|
|
type: styleConf.edgeType || this.edgeType, |
|
|
|
type: styleConf.edgeType ||this.edgeType, |
|
|
|
style: { |
|
|
|
endArrow: styleConf.edgeEndArrow !== undefined ? styleConf.edgeEndArrow : true, |
|
|
|
stroke: styleConf.edgeStroke || this.edgeStroke, |
|
|
|
@ -922,6 +920,7 @@ export default { |
|
|
|
nodes: updatedNodes, |
|
|
|
edges: updatedEdges |
|
|
|
}; |
|
|
|
|
|
|
|
this.buildNodeLabelMap(updatedNodes); |
|
|
|
this.updateGraph(updatedData) |
|
|
|
this.buildCategoryIndex(); |
|
|
|
@ -949,7 +948,7 @@ export default { |
|
|
|
}, |
|
|
|
initGraph() { |
|
|
|
|
|
|
|
if (this._graph != null) { |
|
|
|
if (this._graph!=null){ |
|
|
|
this._graph.destroy() |
|
|
|
this._graph = null; |
|
|
|
} |
|
|
|
@ -960,7 +959,7 @@ export default { |
|
|
|
console.log(this._nodeLabelMap) |
|
|
|
const container = this.$refs.graphContainer; |
|
|
|
if (!container) return; |
|
|
|
if (container != null) { |
|
|
|
if (container!=null){ |
|
|
|
const width = container.clientWidth || 800; |
|
|
|
const height = container.clientHeight || 600; |
|
|
|
console.log(width) |
|
|
|
@ -1000,8 +999,8 @@ export default { |
|
|
|
easing: 'ease-in-out', // 动画缓动函数 |
|
|
|
}, |
|
|
|
}, |
|
|
|
behaviors: ['zoom-canvas', 'drag-element', |
|
|
|
'click-select', 'focus-element', { |
|
|
|
behaviors: [ 'zoom-canvas', 'drag-element', |
|
|
|
'click-select','focus-element', { |
|
|
|
type: 'hover-activate', |
|
|
|
degree: 1, |
|
|
|
}, |
|
|
|
@ -1048,7 +1047,7 @@ export default { |
|
|
|
shadowBlur: 10, |
|
|
|
opacity: 1 |
|
|
|
}, |
|
|
|
highlight: { |
|
|
|
highlight:{ |
|
|
|
stroke: '#FF5722', |
|
|
|
lineWidth: 4, |
|
|
|
opacity: 1 |
|
|
|
@ -1056,7 +1055,7 @@ export default { |
|
|
|
inactive: { |
|
|
|
opacity: 0.8 |
|
|
|
}, |
|
|
|
normal: { |
|
|
|
normal:{ |
|
|
|
opacity: 1 |
|
|
|
} |
|
|
|
|
|
|
|
@ -1104,14 +1103,14 @@ export default { |
|
|
|
inactive: { |
|
|
|
opacity: 0.8 |
|
|
|
}, |
|
|
|
normal: { |
|
|
|
normal:{ |
|
|
|
opacity: 1 |
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
data: this.defaultData, |
|
|
|
data:this.defaultData, |
|
|
|
|
|
|
|
}); |
|
|
|
this.$nextTick(() => { |
|
|
|
@ -1169,10 +1168,10 @@ export default { |
|
|
|
// }); |
|
|
|
graph.on('node:click', (evt) => { |
|
|
|
const nodeItem = evt.target.id; // 获取当前鼠标进入的节点元素 |
|
|
|
let node = graph.getNodeData(nodeItem).data |
|
|
|
let data = { |
|
|
|
label: node.name, |
|
|
|
type: node.label |
|
|
|
let node=graph.getNodeData(nodeItem).data |
|
|
|
let data={ |
|
|
|
label:node.name, |
|
|
|
type:node.label |
|
|
|
} |
|
|
|
getGraph(data).then(response=>{ |
|
|
|
console.log(response) |
|
|
|
@ -1184,7 +1183,7 @@ export default { |
|
|
|
graph.fitCenter({ padding: 40, duration: 1000 }); |
|
|
|
} |
|
|
|
}); |
|
|
|
this._graph = graph |
|
|
|
this._graph = markRaw(graph) |
|
|
|
this._graph.setPlugins([ { |
|
|
|
type: 'tooltip', |
|
|
|
// 只对节点启用,边不显示tooltip |
|
|
|
@ -1194,7 +1193,7 @@ export default { |
|
|
|
console.log(e) |
|
|
|
const edge = items[0]; // 当前悬停的边 |
|
|
|
if (!edge) return ''; |
|
|
|
const data = items[0].data |
|
|
|
const data=items[0].data |
|
|
|
const sourceId = edge.source; |
|
|
|
const targetId = edge.target; |
|
|
|
|
|
|
|
@ -1205,7 +1204,7 @@ export default { |
|
|
|
|
|
|
|
const sourceName = sourceNode?.data.name || sourceId; |
|
|
|
const targetName = targetNode?.data.name || targetId; |
|
|
|
const rel = data.relationship.properties.label || '关联'; |
|
|
|
const rel = data.relationship.properties.label || '关联'; |
|
|
|
|
|
|
|
return `<div style="padding: 4px 8px; color: #b6b2b2; border-radius: 4px; font-size: 12px;"> |
|
|
|
${sourceName} — ${rel} —> ${targetName} |
|
|
|
@ -1215,11 +1214,7 @@ export default { |
|
|
|
{ |
|
|
|
type: 'toolbar', |
|
|
|
onClick: (id) => { |
|
|
|
if (id === 'reset') { |
|
|
|
// 1. 如果是重置,直接在本地执行方法 |
|
|
|
this.localResetGraph(); |
|
|
|
} else if (this.$refs.toolbarRef) { |
|
|
|
// 2. 其他功能(放大、导出等)继续交给组件处理 |
|
|
|
if (this.$refs.toolbarRef) { |
|
|
|
this.$refs.toolbarRef.handleToolbarAction(id); |
|
|
|
} |
|
|
|
}, |
|
|
|
@ -1228,52 +1223,13 @@ export default { |
|
|
|
{id: 'zoom-in', value: 'zoom-in', title: '放大'}, |
|
|
|
{id: 'zoom-out', value: 'zoom-out', title: '缩小'}, |
|
|
|
{id: 'auto-fit', value: 'auto-fit', title: '聚焦'}, |
|
|
|
{id: 'reset', value: 'reset', title: '重置'}, |
|
|
|
{id: 'export', value: 'export', title: '导出图谱'}, |
|
|
|
]; |
|
|
|
}, |
|
|
|
}, |
|
|
|
]) |
|
|
|
]) |
|
|
|
} |
|
|
|
}, |
|
|
|
localResetGraph() { |
|
|
|
// 1. 检查图表实例和数据是否存在 |
|
|
|
if (!this._graph) return; |
|
|
|
|
|
|
|
if (!this.defaultData || !this.defaultData.nodes) { |
|
|
|
this.$message.warning("未找到可重置的数据源"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
// 2. 彻底清理鼠标指针状态 |
|
|
|
const canvas = this._graph.getCanvas(); |
|
|
|
if (canvas && typeof canvas.setCursor === 'function') { |
|
|
|
canvas.setCursor('default'); |
|
|
|
} |
|
|
|
|
|
|
|
// 3. 彻底销毁当前图谱实例 |
|
|
|
// 销毁会移除所有 DOM 节点和事件监听,彻底解决 EventBoundary 问题 |
|
|
|
this._graph.destroy(); |
|
|
|
this._graph = null; |
|
|
|
|
|
|
|
// 4. 重新初始化 |
|
|
|
this.$nextTick(() => { |
|
|
|
// initGraph 内部会自动读取 this.defaultData |
|
|
|
this.initGraph(); |
|
|
|
|
|
|
|
// 5. 重新构建分类索引(因为 destroy 也会清空之前的交互索引) |
|
|
|
this.buildCategoryIndex(); |
|
|
|
|
|
|
|
this.$message.success("图谱已重置"); |
|
|
|
}); |
|
|
|
} catch (err) { |
|
|
|
console.error('重置图谱失败:', err); |
|
|
|
// 降级处理:如果销毁失败,尝试刷新页面(可选) |
|
|
|
// location.reload(); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
updateGraph(data) { |
|
|
|
if (!this._graph) return |
|
|
|
this._graph.setData(data) |
|
|
|
@ -1285,7 +1241,7 @@ export default { |
|
|
|
const updatedNodes = this.defaultData.nodes.map(node => ({ |
|
|
|
...node, |
|
|
|
type: this.nodeShape, |
|
|
|
style: { |
|
|
|
style:{ |
|
|
|
size: this.nodeSize, |
|
|
|
fill: this.nodeFill, |
|
|
|
stroke: this.nodeStroke, |
|
|
|
@ -1303,7 +1259,6 @@ export default { |
|
|
|
this.defaultData = updatedData |
|
|
|
this.updateGraph(updatedData) |
|
|
|
}, |
|
|
|
|
|
|
|
updateAllEdges() { |
|
|
|
if (!this._graph) return |
|
|
|
const updatedEdges = this.defaultData.edges.map(edge => ({ |
|
|
|
@ -1474,7 +1429,6 @@ button:hover { |
|
|
|
} |
|
|
|
|
|
|
|
.graph-container { |
|
|
|
flex: 1; |
|
|
|
background: #fff; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
@ -1613,10 +1567,14 @@ button:hover { |
|
|
|
flex: 1; |
|
|
|
border: 1px dashed #e2e8f0; |
|
|
|
border-radius: 12px; |
|
|
|
position: relative !important; /* 必须:作为工具栏参照物 */ |
|
|
|
overflow: hidden; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
color: #ccc; |
|
|
|
background: #fff; |
|
|
|
padding: 0 !important; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1712,7 +1670,6 @@ button:hover { |
|
|
|
/deep/ .radio-check .el-radio__input.is-checked+.el-radio__label { |
|
|
|
color: #1890ff; |
|
|
|
} |
|
|
|
|
|
|
|
/* 自定义下拉样式 */ |
|
|
|
.select-container { |
|
|
|
position: relative; |
|
|
|
@ -1742,7 +1699,7 @@ button:hover { |
|
|
|
background: rgba(255, 255, 255, 0.64); |
|
|
|
border: 1px solid #e0e0e0; |
|
|
|
border-radius: 8px; |
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); |
|
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15); |
|
|
|
z-index: 10; |
|
|
|
min-width: 80px; |
|
|
|
color: #000; |
|
|
|
@ -1759,4 +1716,16 @@ button:hover { |
|
|
|
background-color: #f5f7fa; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.custom-graph-toolbar) { |
|
|
|
position: absolute !important; /* 脱离文档流,解决占位问题 */ |
|
|
|
top: 0 !important; |
|
|
|
right: 0 !important; |
|
|
|
z-index: 1000 !important; |
|
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.9) !important; |
|
|
|
padding: 4px 8px !important; |
|
|
|
border-radius: 8px !important; |
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1) !important; |
|
|
|
border: 1px solid #ebeef5 !important |
|
|
|
} |
|
|
|
</style> |