<template>

  <div class="knowledge-graph-container">
    <Menu
        :initial-active="0"
    />
        <main class="main-body">
          <header class="top-nav">
            <div class="search-container">
              <input v-model="searchKeyword" type="text" placeholder="搜索......" @keydown.enter="search"/>
              <img src="@/assets/搜索.png" style="cursor: pointer" class="search-btn" @click="search"/>
            </div>
            <div class="legend-box">
              <div v-for="(item, index) in legendItems" :key="index" class="legend-item">
                <div
                    :style="{
      backgroundColor: item.color,
      opacity: visibleCategories.has(item.key) ? 1 : 0.3 // ✅ 关键：根据状态调整透明度
    }"
                    class="color-block"
                    @click="toggleCategory(item.key)"
                ></div>
                <span style="    font-size: 12px;color: rgb(0, 0, 0);font-weight: 600;">{{ item.label }}</span>
              </div>
            </div>
          </header>
          <section class="main-content">
            <div class="disease-container">
              <div class="disease-header" :style="headerStyle">
                <div style="display: flex;align-items: center;">
                  <div class="d-title"><img :src="iconSrc" class="d-icon"/>
                    <span v-if="typeRadio=== 'Disease'">疾病信息</span>
                    <span v-if="typeRadio=== 'Drug'">药品信息</span>
                    <span v-if="typeRadio=== 'Check'">检查信息</span>
                  </div>
                  <div v-if="typeRadio=== 'Disease'" class="d-count" :style="headerLabel">{{diseaseCount.toLocaleString()}}种</div>
                  <div v-if="typeRadio=== 'Drug'" class="d-count" :style="headerLabel">{{ drugCount.toLocaleString() }}种</div>
                  <div v-if="typeRadio=== 'Check'" class="d-count" :style="headerLabel">{{checkCount.toLocaleString()}}种</div>
                </div>
                <div>
                  <!-- ✅ 替换开始：自定义下拉选择器（使用 div 实现） -->
                  <div class="select-container" @click="toggleDropdown">
                    <!-- 当前选中项显示 -->
                    <div class="select-display">
                      <span style="color: #000;    background: rgb(255 255 255 / 64%);
    padding: 2px 13px;
    border-radius: 15px;">{{ currentTypeLabel }}</span>
                      <img src="../assets/下拉11.png" class="dropdown-icon" />
                    </div>

                    <!-- 下拉菜单 -->
                    <div v-show="isDropdownOpen" class="select-dropdown">
                      <div
                          v-for="item in typeOptions"
                          :key="item.value"
                          class="select-option"
                          @click.stop="selectType(item.value)"
                      >
                        {{ item.label }}
                      </div>
                    </div>
                  </div>
                  <!-- ✅ 替换结束 -->
                </div>
              </div>
<!--              <div>-->
<!--                <el-radio-group v-model="typeRadio" @change="changeTree">-->
<!--                  <el-radio-->
<!--                      value="Disease"-->
<!--                      :class="{'radio-disease': typeRadio === 'Disease'}"-->
<!--                  >疾病</el-radio>-->
<!--                  <el-radio-->
<!--                      value="Drug"-->
<!--                      :class="{'radio-drug': typeRadio === 'Drug'}"-->
<!--                  >药品</el-radio>-->
<!--                  <el-radio-->
<!--                      value="Check"-->
<!--                      :class="{'radio-check': typeRadio === 'Check'}"-->
<!--                  >检查</el-radio>-->
<!--                </el-radio-group>-->

<!--              </div>-->
              <div v-if="typeRadio === 'Disease'">
                <el-radio-group v-model="DiseaseRadio" @change="changeTree">
                  <el-radio
                      value="ICD10"
                      :class="{'radio-disease': typeRadio === 'Disease'}"
                  >ICD10</el-radio>
                  <el-radio
                      value="Department"
                      :class="{'radio-disease': typeRadio === 'Disease'}"
                  >科室</el-radio>
                  <el-radio
                      value="SZM"
                      :class="{'radio-disease': typeRadio === 'Disease'}"
                  >首字母</el-radio>
                </el-radio-group>

              </div>
              <div v-if="typeRadio === 'Drug'">
                <el-radio-group v-model="DrugRadio" @change="changeTree">
                  <el-radio
                      value="Subject"
                      :class="{'radio-drug': typeRadio === 'Drug'}"
                  >药物分类</el-radio>
                  <el-radio
                      value="SZM"
                      :class="{'radio-drug': typeRadio === 'Drug'}"
                  >首字母</el-radio>
                </el-radio-group>

              </div>
              <div class="disease-body">

                <div class="tree">
                  <el-tree
                      :data="treeData"
                      :props="treeProps"
                      accordion
                      expand-on-click-node
                      :expand-on-click-node="false"
                      @node-click="handleNodeClick"
                  >
                    <template #default="{ node, data }">
                        <span class="custom-tree-node">
                          <span class="code">{{ data.code }}</span>
                          <el-tooltip :content="data.label" placement="top">
                            <span class="label">{{ data.label }}</span>
                          </el-tooltip>
                        </span>
                    </template>
                  </el-tree>
                </div>
              </div>
            </div>
            <div class="graph-viewport">
              <div ref="graphContainer" class="graph-container" id="container"></div>
            </div>
          </section>
        </main>
    <!-- 图谱容器 -->
  </div>
</template>

<script>
import {
  getCheckTree,
  getCount,
  getDiseaseDepartTree,
  getDiseaseTree, getDrugSubjectTree,
  getDrugTree,
  getGraph,
  getTestGraphData
} 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 Fuse from 'fuse.js';
export default {
  name: 'Display',
  components: {Menu},
  data() {
    return {
      G6: null, // 添加这个
      // 节点样式
      nodeShowLabel: true,
      nodeFontSize: 12,
      nodeFontColor: '#fff',
      nodeShape: 'circle',
      nodeSize: 50,
      nodeFill: '#9FD5FF',
      nodeStroke: '#5B8FF9',
      nodeLineWidth: 2,
      nodeFontFamily: 'Microsoft YaHei, sans-serif',

      // 边样式
      edgeShowLabel: true,
      edgeFontSize: 10,
      edgeFontColor: '#666666',
      edgeType: 'quadratic',
      edgeLineWidth: 2,
      edgeStroke: '#b6b2b2',
      edgeEndArrow: true,
      edgeFontFamily: 'Microsoft YaHei, sans-serif',

      defaultData: {
        nodes: [
          {id: 'A', label: '人工智能'},
          {id: 'B', label: '机器学习'},
          {id: 'C', label: '深度学习'}
        ],
        edges: [
          {source: 'A', target: 'B', label: '包含'},
          {source: 'B', target: 'C', label: '子领域'}
        ]
      },
      treeData: [],
      treeProps: {
        children: 'children',
        label: 'title' // 虽然用插槽，但 el-tree 内部仍会读取，可留空或任意
      },
      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' }
      ],
      visibleCategories: new Set(), // 先空着
      diseaseCount:0,
      drugCount:0,
      checkCount:0,
      originalNodeStyles: new Map(), // 保存原始节点样式
      originalEdgeStyles: new Map(), // 保存原始边样式
      searchResults: {
        nodes: [],
        edges: []
      },
      searchKeyword:"",
      drugSubjectTree:[],
      DrugRadio:"Subject",
      isDropdownOpen: false,
      typeOptions: [
        { value: 'Disease', label: '疾病' },
        { value: 'Drug', label: '药品' },
        { value: 'Check', label: '检查' }
      ]
    }
  },
  computed: {
    currentTypeLabel() {
      const option = this.typeOptions.find(opt => opt.value === this.typeRadio);
      return option ? option.label : '请选择';
    },
    // 根据当前选择的类型返回不同的背景颜色
    headerStyle() {
      let backgroundColor = '#fff'; // 默认颜色
      switch (this.typeRadio) {
        case 'Disease':
          backgroundColor = '#990A00'; // 疾病选中时的颜色
          break;
        case 'Drug':
          backgroundColor = '#9ECA7F'; // 药品选中时的颜色
          break;
        case 'Check':
          backgroundColor = '#2265f4'; // 检查选中时的颜色
          break;
        default:
          break;
      }
      return {
        backgroundColor, // 动态设置背景色
      };
    },
    iconSrc() {
      switch (this.typeRadio) {
        case 'Disease':
          return require('@/assets/red.png'); // 疾病的图标
        case 'Drug':
          return require('@/assets/green.png'); // 药品的图标
        case 'Check':
          return require('@/assets/blue.png'); // 检查的图标
        default:
          return require('@/assets/blue.png'); // 默认图标
      }
    },
    headerLabel() {
      let backgroundColor = '#fff'; // 默认颜色
      switch (this.typeRadio) {
        case 'Disease':
          backgroundColor = '#790800'; // 疾病选中时的颜色
          break;
        case 'Drug':
          backgroundColor = '#638C0B'; // 药品选中时的颜色
          break;
        case 'Check':
          backgroundColor = '#5384EF'; // 检查选中时的颜色
          break;
        default:
          break;
      }
      return {
        backgroundColor, // 动态设置背景色
      };
    },

// #790800
  },
  async mounted() {

    this.visibleCategories = new Set(this.legendItems.map(i => i.key));
    await this.loadDiseaseICD10TreeData()
    this.loadDiseaseDepartTreeData()
    this.loadDiseaseSZMTreeData()
    this.getCount()
    this.loadDrugTreeData()
    this.loadCheckTreeData()
    this.loadDrugSubjectTreeData()
    this.treeData=this.diseaseICD10Tree
    await this.$nextTick();
    try {
      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);
    }

  },

  beforeUnmount() {
    if (this._graph!=null){
      this._graph.stopLayout();
      this.clearGraphState();
      this._graph.destroy()
      this._graph = null;
    }
    window.removeEventListener('resize', this.handleResize);
  },
  watch: {
    // 节点相关
    nodeShowLabel: 'updateAllNodes',
    nodeFontSize: 'updateAllNodes',
    nodeFontColor: 'updateAllNodes',
    nodeShape: 'updateAllNodes',
    nodeSize: 'updateAllNodes',
    nodeFill: 'updateAllNodes',
    nodeStroke: 'updateAllNodes',
    nodeLineWidth: 'updateAllNodes',
    nodeFontFamily: 'updateAllNodes',

    // 边相关
    edgeShowLabel: 'updateAllEdges',
    edgeFontSize: 'updateAllEdges',
    edgeFontColor: 'updateAllEdges',
    edgeType: 'updateAllEdges',
    edgeLineWidth: 'updateAllEdges',
    edgeStroke: 'updateAllEdges',
    edgeEndArrow: 'updateAllEdges',
    edgeFontFamily: 'updateAllEdges',
  },
  methods: {
    // 切换下拉菜单显隐
    toggleDropdown() {
      this.isDropdownOpen = !this.isDropdownOpen;
    },

// 选择类型并关闭下拉
    selectType(value) {
      if (this.typeRadio !== value) {
        this.typeRadio = value;
        this.changeTree(); // 触发数据更新
      }
      this.isDropdownOpen = false;
    },
    search() {
      const keyword = this.searchKeyword?.trim();
      if (!keyword) {
        this.clearSearchHighlight();
        return;
      }

      const nodeData = this._graph?.getNodeData() || [];
      const edgeData = this._graph?.getEdgeData() || [];

      // === 1. 节点搜索项 ===
      const nodeSearchItems = nodeData.map(node => ({
        id: node.id,
        name: node.data?.name || '',
        label: node.data?.label || ''
      }));

      // === 2. 边搜索项（用于模糊匹配）===
      const edgeSearchItems = edgeData.map(edge => {
        const sourceName = this._nodeLabelMap.get(edge.source) || '';
        const targetName = this._nodeLabelMap.get(edge.target) || '';
        const relLabel = edge.data?.relationship?.properties?.label || '';
        const fullText = [sourceName, relLabel, targetName].filter(Boolean).join(' ');
        return {
          id: edge.id,
          sourceId: edge.source,
          targetId: edge.target,
          fullText
        };
      });

      // === 3. Fuse 搜索（启用中文分词）===
      const fuseOptions = {
        includeScore: true,
        threshold: 0.4,
        ignoreLocation: true,
        tokenize: true, // ✅ 支持中文
        keys: ['name', 'label']
      };

      const edgeFuseOptions = {
        includeScore: true,
        threshold: 0.5,
        ignoreLocation: true,
        tokenize: true,
        keys: ['fullText']
      };

      const nodeFuse = new Fuse(nodeSearchItems, fuseOptions);
      const edgeFuse = new Fuse(edgeSearchItems, edgeFuseOptions);

      // 初步结果
      const directNodeIds = nodeFuse.search(keyword).map(r => r.item.id);
      const matchedEdgesFromSearch = edgeFuse.search(keyword).map(r => r.item);
      const matchedEdgeIdsFromSearch = matchedEdgesFromSearch.map(e => e.id);

      // === 4. 关键：从命中的节点，反查“两端都被命中的边” ===
      const nodeSet = new Set(directNodeIds);
      const additionalEdgeIds = [];

      edgeData.forEach(edge => {
        // 如果边的 source 和 target 都在命中的节点集合中
        if (nodeSet.has(edge.source) && nodeSet.has(edge.target)) {
          additionalEdgeIds.push(edge.id);
        }
      });

      // 合并边 ID（去重）
      const allEdgeIds = Array.from(new Set([
        ...matchedEdgeIdsFromSearch,
        ...additionalEdgeIds
      ]));

      // === 5. 节点：直接命中的 + 从边补的（保持你原有逻辑）===
      const finalNodeIds = new Set(directNodeIds);
      matchedEdgesFromSearch.forEach(edge => {
        finalNodeIds.add(edge.sourceId);
        finalNodeIds.add(edge.targetId);
      });
      // 注意：additionalEdge 对应的节点已在 directNodeIds 中，无需再加

      // === 6. 调用高亮（不改此函数）===
      this.highlightSearchResults(
          Array.from(finalNodeIds),
          allEdgeIds
      );
    },
    highlightSearchResults(nodeIds, edgeIds) {
      if (!this._graph) return;

      const allNodes = this._graph.getNodeData().map(n => n.id);
      const allEdges = this._graph.getEdgeData().map(e => e.id);

      // 1️⃣ 先清除所有 search 相关状态（避免残留）
      allNodes.forEach(id => {
        this._graph.setElementState(id, 'active', false);
        this._graph.setElementState(id, 'inactive', false);
      });
      allEdges.forEach(id => {
        this._graph.setElementState(id, 'active', false);
        this._graph.setElementState(id, 'inactive', false);
      });

      // 2️⃣ 高亮匹配项
      nodeIds.forEach(id => {
        if (this._graph.hasNode(id)) {
          this._graph.setElementState(id, 'active', true);
        }
      });
      edgeIds.forEach(id => {
        if (this._graph.hasEdge(id)) {
          this._graph.setElementState(id, 'active', true);
        }
      });

      // 3️⃣ 淡化未匹配项
      const matchedNodeSet = new Set(nodeIds);
      const matchedEdgeSet = new Set(edgeIds);

      allNodes.forEach(id => {
        if (!matchedNodeSet.has(id)) {
          this._graph.setElementState(id, 'inactive', true);
        }
      });
      allEdges.forEach(id => {
        if (!matchedEdgeSet.has(id)) {
          this._graph.setElementState(id, 'inactive', true);
        }
      });

      // 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 });
      }
    },
    clearSearchHighlight() {
      if (!this._graph) return;

      const allNodes = this._graph.getNodeData().map(n => n.id);
      const allEdges = this._graph.getEdgeData().map(e => e.id);

      // 关闭所有 search 状态
      [...allNodes, ...allEdges].forEach(id => {
        this._graph.setElementState(id, 'normal', true);
      });
    },
    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){
        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 (!index[category]) index[category] = [];
            index[category].push(node.id);
          }else{
            if (!index["Other"]) index["Other"] = [];
            index["Other"].push(node.id);
          }
        });
        this.categoryToNodeIds = index;
      }

    },
// 切换某个类别的显示状态
    toggleCategory (key){
      if (this.visibleCategories.has(key)) {
        this.visibleCategories.delete(key)
      } else {
        this.visibleCategories.add(key)
      }
      this.updateGraphFilter()
    },

// 更新 G6 图的过滤规则
    updateGraphFilter() {
      console.log('visibleCategories:', this.visibleCategories);

      // Step 1: 收集所有当前应该显示的节点 ID（扁平化）
      const visibleNodeIds = new Set();
      for (const [category, nodeIds] of Object.entries(this.categoryToNodeIds)) {
        if (this.visibleCategories.has(category)) {
          nodeIds.forEach(id => visibleNodeIds.add(id));
        }
      }

      // Step 2: 更新节点的显示状态
      for (const [category, nodeIds] of Object.entries(this.categoryToNodeIds)) {
        if (this.visibleCategories.has(category)) {
          this._graph.showElement(nodeIds, true);
        } else {
          this._graph.hideElement(nodeIds, true);
        }
      }

      // Step 3: 处理边的显示/隐藏
      const edges = this._graph.getEdgeData(); // 获取所有边数据
      const edgesToShow = [];
      const edgesToHide = [];

      edges.forEach(edge => {
        const sourceVisible = visibleNodeIds.has(edge.source);
        const targetVisible = visibleNodeIds.has(edge.target);

        // 只有当 source 和 target 都可见时，才显示这条边
        if (sourceVisible && targetVisible) {
          edgesToShow.push(edge.id);
        } else {
          edgesToHide.push(edge.id);
        }
      });

      if (edgesToShow.length > 0) {
        this._graph.showElement(edgesToShow, true);
      }
      if (edgesToHide.length > 0) {
        this._graph.hideElement(edgesToHide, true);
      }
    },

    changeTree(){
      if(this.typeRadio=="Disease"){
        if(this.DiseaseRadio=="ICD10") {
          this.treeData=this.diseaseICD10Tree
        }
        if(this.DiseaseRadio=="Department") {
          this.treeData=this.diseaseDepartTree
        }
        if(this.DiseaseRadio=="SZM") {
          this.treeData=this.diseaseSZMTree
        }
      }
      if(this.typeRadio=="Drug") {
        if(this.DrugRadio=="Subject") {
          this.treeData=this.drugSubjectTree
        }
        if(this.DrugRadio=="SZM") {
          this.treeData=this.drugTree
        }
      }
      if(this.typeRadio=="Check") {
        this.treeData=this.checkTree
      }
    },
    async loadDiseaseICD10TreeData() {
      try {
        const res = await fetch('/icd10.json')
        if (!res.ok) throw new Error('Failed to load JSON')
        this.diseaseICD10Tree = await res.json()
      } catch (error) {
        console.error('加载 ICD-10 数据失败:', error)
        this.$message.error('加载编码数据失败，请检查文件路径')
      }
    },
    async loadDiseaseDepartTreeData() {
      try {
        const res = await getDiseaseDepartTree()
        this.diseaseDepartTree = res
      } catch (error) {
      }
    },
    async loadDiseaseSZMTreeData() {
      try {
        const res = await getDiseaseTree()
        this.diseaseSZMTree = res
      } catch (error) {
      }
    },
    async loadDrugSubjectTreeData() {
      try {
        const res = await getDrugSubjectTree()
        this.drugSubjectTree = res
      } catch (error) {
      }
    },
    async loadDrugTreeData() {
      try {
        const res = await getDrugTree()
        this.drugTree = res
        console.log(this.drugTree)
      } catch (error) {
      }
    },
    async loadCheckTreeData() {
      try {
        const res = await getCheckTree()
        this.checkTree = res
        console.log(this.checkTree)
      } catch (error) {
      }
    },
    async handleNodeClick(data) {
      console.log('点击节点:', data)
      // 可用于显示详情、复制 code 等
      if (
          (data.type === "Drug" || data.type === "Check") &&
          !data.children // 确保没有 children 属性（或 children 为 undefined / null / 空数组）
      ) {
        const response = await getGraph(data); // 等待 Promise 解析
        this.formatData(response)
      }
      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"
        const response = await getGraph(data); // 等待 Promise 解析
        this.formatData(response)
      }
    },
    buildNodeLabelMap(nodes) {
      this._nodeLabelMap = new Map();
      nodes.forEach(node => {
        this._nodeLabelMap.set(node.id, node.data?.label || 'default');
      });
    },
    clearGraphState() {
      if (!this._graph) return;

      // 1. 清除所有节点和边的状态
      this._graph.getNodeData().forEach(node => {
        this._graph.setElementState(node.id,[]);

      });
      this._graph.getEdgeData().forEach(edge => {
        this._graph.setElementState(edge.id,[]);
      });

      // 2. （可选）取消所有 pending 的交互
      // 比如如果你有高亮定时器，这里 clearTimeout
    },
    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 = {
        nodes: updatedNodes,
        edges: updatedEdges
      }
      this.buildNodeLabelMap(updatedNodes);
      this.updateGraph(updatedData)
      this.buildCategoryIndex();
    },
    getLevelLabel(level) {
      const map = {
        chapter: '章',
        section: '节',
        category: '类目',
        subcategory: '亚目',
        diagnosis: '条目'
      }
      return map[level] || level
    },

    getTagType(level) {
      const map = {
        chapter: 'primary',
        section: 'success',
        category: 'warning',
        subcategory: 'info',
        diagnosis: 'info'
      }
      return map[level] || ''
    },
    initGraph() {

      if (this._graph!=null){
        this._graph.destroy()
        this._graph = null;
      }
      if (!this._nodeLabelMap) {
        this.buildNodeLabelMap(this.defaultData.nodes);
      }
      console.log(this.defaultData)
      console.log(this._nodeLabelMap)
      const container = this.$refs.graphContainer;
      if (!container) return;
      if (container!=null){
        const width = container.clientWidth || 800;
        const height = container.clientHeight || 600;
        console.log(width)
        console.log(height)
        const graph = new Graph({
          container,
          width,
          height,
          layout: {
            type: 'force', // 力导向布局
            gravity: 0.3,   // 重力系数，控制节点聚集程度
            repulsion: 500, // 排斥力
            attraction: 20,  // 吸引力
            preventOverlap: true, // 防止节点重叠
            // center: [width / 2, height / 2]
            // type: 'radial',
            // preventOverlap: true,
            // unitRadius: 200,
            // maxPreventOverlapIteration:100
            // type: 'force-atlas2',
            // preventOverlap: true,
            // kr: 1000,
            // center: [250, 250],
            // barnesHut:true,

          },
          autoFit: {
            type: 'center', // 自适应类型：'view' 或 'center'
            options: {
              // 仅适用于 'view' 类型
              when: 'always', // 何时适配：'overflow'(仅当内容溢出时) 或 'always'(总是适配)
              direction: 'both', // 适配方向：'x'、'y' 或 'both'
            },
            animation: {
              // 自适应动画效果
              duration: 1000, // 动画持续时间(毫秒)
              easing: 'ease-in-out', // 动画缓动函数
            },
          },
          behaviors: [ 'zoom-canvas', 'drag-element',
            'click-select','focus-element', {
              type: 'hover-activate',
              degree: 1,
            },
            {
              type: 'drag-canvas',
              enable: (event) => event.shiftKey === false,
            },
            {
              type: 'brush-select',
            },
          ],

          node: {
            style: {
              fill: (d) => {
                const label = d.data?.label;
                if (label === 'Disease') return '#EF4444';   // 红
                if (label === 'Drug') return '#91cc75';      // 绿
                if (label === 'Symptom') return '#fac858';   // 橙
                if (label === 'Check') return '#336eee';   // 橙
                return '#59d1d4';                            // 默认灰蓝
              },
              stroke: (d) => {
                const label = d.data?.label;
                if (label === 'Disease') return '#B91C1C';
                if (label === 'Drug') return '#047857';
                if (label === 'Check') return '#1D4ED8';   // 橙
                if (label === 'Symptom') return '#B45309';
                return '#40999b';
              },
              labelText: (d) => d.data.name,
              labelPlacement: 'center',
              labelWordWrap: true,
              labelMaxWidth: '150%',
              labelMaxLines: 3,
              labelTextOverflow: 'ellipsis',
              labelTextAlign: 'center',
              opacity: 1
            },
            state: {
              active: {
                lineWidth: 2,
                shadowColor: '#ffffff',
                shadowBlur: 10,
                opacity: 1
              },
              highlight:{
                stroke: '#FF5722',
                lineWidth: 4,
                opacity: 1
              },
              inactive: {
                opacity: 0.8
              },
              normal:{
                opacity: 1
              }


            },
          },
          edge: {
            style: {
              labelText: (d) => d.data.relationship.properties.label,
              stroke: (d) => {
                // 获取 target 节点的 label
                const targetLabel = this._nodeLabelMap.get(d.source); // d.target 是目标节点 ID
                // 根据 target 节点类型返回对应浅色
                if (targetLabel === 'Disease') return 'rgba(239,68,68,0.5)';
                if (targetLabel === 'Drug') return 'rgba(145,204,117,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
              },
              // labelFill: (d) => {
              //   // 获取 target 节点的 label
              //   const targetLabel = this._nodeLabelMap.get(d.target); // d.target 是目标节点 ID
              //   // 根据 target 节点类型返回对应浅色
              //
              //   if (targetLabel === 'Disease') return '#ff4444';
              //   if (targetLabel === 'Drug') return '#2f9b70';
              //   if (targetLabel === 'Symptom') return '#f89775';
              //   return '#6b91ff'; // default
              // }

            },
            state: {
              selected: {
                stroke: '#1890FF',
                lineWidth: 2,
              },
              highlight: {
                halo: true,
                haloStroke: '#1890FF',
                haloLineWidth: 6,
                haloStrokeOpacity: 0.3,
                lineWidth: 3,
                opacity: 1
              },
              inactive: {
                opacity: 0.8
              },
              normal:{
                opacity: 1
              }

            },

          },
          data:this.defaultData,

        });
        this.$nextTick(() => {
          graph.render();
          // graph.fitView()
          // graph.fitView({ padding: 30, duration: 1000, easing: 'ease-in' });
        });

        console.log("Container scroll position after:", container.scrollTop, container.scrollLeft);
        // graph.fitView();
        // graph.on('node:pointerover', (evt) => {
        //   const nodeItem = evt.target; // 获取当前鼠标进入的节点元素
        //   const relatedEdges = graph.getRelatedEdgesData(nodeItem.id);
        //   const relatedEdgeIds = relatedEdges.map(edge => edge.id);
        //
        //   // 3. 高亮这些边（比如用 'highlight' 状态）
        //   relatedEdgeIds.forEach(edgeId => {
        //     graph.setElementState(edgeId, 'highlight', true);
        //   });
        //   graph.setElementState(nodeItem.id, 'active',true);
        //
        //   // 2. 获取邻居节点 ID（去重）
        //   const neighborNodeIds = new Set();
        //   relatedEdges.forEach(edge => {
        //     if (edge.source !== nodeItem.id) neighborNodeIds.add(edge.source);
        //     if (edge.target !== nodeItem.id) neighborNodeIds.add(edge.target);
        //   });
        //
        //   neighborNodeIds.forEach(id => {
        //     graph.setElementState(id, 'active', true);
        //   });
        //
        //   graph.getEdgeData().forEach(edge => {
        //     if (!relatedEdgeIds.includes(edge.id)) {
        //       graph.setElementState(edge.id, 'inactive', true);
        //     }
        //   });
        //   graph.getNodeData().forEach(node => {
        //     if (node.id !== nodeItem.id && !neighborNodeIds.has(node.id)) {
        //       graph.setElementState(node.id, 'inactive',true);
        //     }
        //   });
        // });
        // graph.on('node:pointerleave', (evt) => {
        //   graph.getEdgeData().forEach(edge => {
        //     graph.setElementState(edge.id, 'highlight', false);
        //     graph.setElementState(edge.id, 'inactive', false);
        //     graph.setElementState(edge.id, 'normal', true);
        //   });
        //   graph.getNodeData().forEach(node => {
        //     graph.setElementState(node.id, 'active', false);
        //     graph.setElementState(node.id, 'inactive', false);
        //     graph.setElementState(node.id, 'normal', true);
        //   });
        // });
        graph.on('node:click', (evt) => {
          const nodeItem = evt.target.id; // 获取当前鼠标进入的节点元素
          let node=graph.getNodeData(nodeItem).data
          let data={
            label:node.name,
            type:node.label
          }
          getGraph(data).then(response=>{
            console.log(response)
            this.formatData(response)
          }); // 等待 Promise 解析
        });
        graph.once('afterlayout', () => {
          if (!graph.destroyed) {
            graph.fitCenter({ padding: 40, duration: 1000 });
          }
        });
        this._graph = graph
        this._graph.setPlugins([  {
          type: 'tooltip',
          // 只对节点启用，边不显示tooltip
          enable: (e) => e.targetType === 'edge',
          getContent: (e, items) => {
            console.log(items)
            console.log(e)
            const edge = items[0]; // 当前悬停的边
            if (!edge) return '';
            const data=items[0].data
            const sourceId = edge.source;
            const targetId = edge.target;

            // 获取节点数据（通过图实例）
            const sourceNode = this._graph.getNodeData(sourceId);
            console.log(sourceNode)
            const targetNode = this._graph.getNodeData(targetId);

            const sourceName = sourceNode?.data.name || sourceId;
            const targetName = targetNode?.data.name || targetId;
            const rel = data.relationship.properties.label  || '关联';

            return `<div style="padding: 4px 8px; color: #b6b2b2; border-radius: 4px; font-size: 12px;">
        ${sourceName} — ${rel} —> ${targetName}
      </div>`;
          },
        },])
      }


    },

    updateGraph(data) {
      if (!this._graph) return
      this._graph.setData(data)
      this._graph.render();
    },

    updateAllNodes() {
      if (!this._graph) return
      const updatedNodes = this.defaultData.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,
          labelFontColor: this.nodeFontColor,
        }
      }))
      const updatedData = {
        nodes: updatedNodes,
        edges: this.defaultData.edges
      }
      this.defaultData = updatedData
      this.updateGraph(updatedData)
    },

    updateAllEdges() {
      if (!this._graph) return
      const updatedEdges = this.defaultData.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 updatedData = {
        nodes: this.defaultData.nodes,
        edges: updatedEdges
      }
      this.defaultData = updatedData
      this.updateGraph(updatedData)
    },

    clearAllStates() {
      if (!this._graph) return

      // 清除所有节点的状态
      this._graph.getNodes().forEach(node => {
        this._graph.clearItemStates(node)
      })

      // 清除所有边的状态
      this._graph.getEdges().forEach(edge => {
        this._graph.clearItemStates(edge)
      })
    },

    handleResize() {
      const container = this.$refs.graphContainer
      if (this._graph && container) {
        this._graph.resize(container.offsetWidth, container.offsetHeight)
      }
    },

    resetView() {
      this._graph?.fitView()
    },

    resetStyle() {
      Object.assign(this, {
        nodeShowLabel: true,
        nodeFontSize: 12,
        nodeFontColor: '#000000',
        nodeShape: 'circle',
        nodeSize: 60,
        nodeFill: '#9FD5FF',
        nodeStroke: '#5B8FF9',
        nodeLineWidth: 2,
        nodeFontFamily: 'Microsoft YaHei, sans-serif',

        edgeShowLabel: true,
        edgeFontSize: 10,
        edgeFontColor: '#666666',
        edgeType: 'line',
        edgeLineWidth: 2,
        edgeStroke: '#F00',
        edgeEndArrow: true,
        edgeFontFamily: 'Microsoft YaHei, sans-serif'
      })
    }
  }
}
</script>

<style scoped>
.knowledge-graph-container {
  display: flex;
  height: 100vh;
}

.control-panel {
  width: 280px;
  background: #f5f7fa;
  padding: 16px;
  border-right: 1px solid #ddd;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
  font-family: 'Microsoft YaHei';
}

.section {
  margin-bottom: 10px;
  padding: 10px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.section h5 {
  margin-top: 0;
  color: #333;
  font-size: 14px;
}

.slider-group {
  margin: 10px 0;
  display: flex;
  align-items: center;
}

.slider-group span {
  margin-right: 10px;
  font-size: 12px;
}

.form-group {
  margin: 10px 0;
  display: flex;
  align-items: center;
}

.form-group label {
  margin-right: 8px;
  font-size: 12px;
}

.form-group select,
.form-group input[type="number"] {
  padding: 4px;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 12px;
}

.color-picker {
  margin: 10px 0;
  display: flex;
  align-items: center;
}

.color-picker label {
  margin-right: 8px;
  font-size: 12px;
}

.color-picker input[type="color"] {
  width: 40px;
  height: 20px;
  border: none;
  cursor: pointer;
}

button {
  width: 45%;
  padding: 10px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  margin-right: 2%;
}

button:hover {
  background: #0056b3;
}

.graph-container {
  flex: 1;
  background: #fff;
  width: 100%;
  height: 100%;
  border: 1px dashed #e2e8f0;
  border-radius: 12px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  user-select: none;
}

.color-block {
  width: 30px;
  height: 15px;
  border-radius: 18px;
  transition: all 0.2s ease;
}

.legend-item:hover {
  opacity: 0.8;
}


/* --- 主体区域 --- */
.main-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
  overflow: auto;
}

.top-nav {
  height: 7vw;
  padding: 0 30px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #f0f0f0;
}

.search-container {
  width: 330px;
  height: 30px;
  background: #fff;
  border-radius: 18px;
  display: flex;
  align-items: center;
  padding: 0 15px;
  box-shadow: 4px 2px 9px 1px rgb(97 99 100 / 19%);
}

.search-container input {
  border: none;
  outline: none;
  background: transparent;
  width: 100%;
  font-size: 13px;
}

.search-btn {
  width: 16px;

}
/*.search-btn:hover {
 background-color: rgba(34, 101, 244, 0.64);
  border-radius: 50%;
  padding: 2px 0;
}*/
.legend-box {
  display: flex;
  gap: 20px;
}

.leg-item {
  display: flex;
  align-items: center;
  font-size: 13px;
}

.leg-item i {
  width: 24px;
  height: 8px;
  border-radius: 4px;
  margin-right: 8px;
}

.main-content {
  flex: 1;
  padding: 20px 30px;
  display: flex;
  gap: 20px;
  height: 50vw;
}

.disease-container {
  width: 360px;
  border: 1px solid #f0f0f0;
  border-radius: 12px;
  overflow: hidden;
  max-height: 85vh;
}

.disease-header {
  height: 50px;
  background: #2265f4;
  color: #fff;
  display: flex;
  align-items: center;
  padding: 0 2px 0px 15px;
  justify-content: space-between;
}
.d-title{
  display: flex;
  align-items: center;
  font-size: 13px;
}
.d-count{
  font-size: 9px;
  background-color: #5989F0;
  border-radius: 7px;
  padding: 0px 4px;
  margin-left: 7px;
}

.d-icon {
  width: 21px;
  margin-right: 8px;
}

.graph-viewport {
  flex: 1;
  border: 1px dashed #e2e8f0;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ccc;
}


.custom-tree-node {
  display: flex;
  align-items: center;
  width: 100%;
  overflow: hidden;
  font-weight: 500;
}

.code {
  flex-shrink: 0; /* 不允许 code 被压缩 */
  margin-right: 8px;
  font-size: 12px;
  color: #666;
}

.label {
  flex: 1; /* 占据剩余空间 */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-align: left;
  font-size: 12px;
}
.disease-body{
  width: 360px;
  overflow: scroll;
  height: 74vh;
}
/* 隐藏滚动条，但允许滚动 */
.disease-body {
  /* Firefox */
  scrollbar-width: none; /* 'auto' | 'thin' | 'none' */

  /* Webkit (Chrome, Safari, Edge) */
  -ms-overflow-style: none;  /* IE and Edge */
  scrollbar-width: none;     /* Firefox */
  padding-bottom: 9px;
}

.disease-body::-webkit-scrollbar {
  display: none; /* Webkit browsers */
}


/* 动态给每个 el-radio 设置不同的背景颜色 */
/deep/ .radio-disease .el-radio__input.is-checked .el-radio__inner {
  background: rgb(153, 10, 0); /* 疾病的颜色 */
  border-color: rgb(153, 10, 0);
}


/deep/ .radio-drug .el-radio__input.is-checked .el-radio__inner {
  background: #52c41a; /* 检查的颜色 */
  border-color:#52c41a;
}

/deep/ .radio-check .el-radio__input.is-checked .el-radio__inner {
  background: #1890ff; /* 药品的颜色 */
  border-color:#1890ff;
}


/* 动态给每个 el-radio 设置不同的背景颜色 */
/deep/ .radio-disease .el-radio__input.is-checked .el-radio__inner:hover {
  background: rgb(153, 10, 0); /* 疾病的颜色 */
  border-color: rgb(153, 10, 0);
}


/deep/ .radio-drug .el-radio__input.is-checked .el-radio__inner:hover {
  background: #52c41a; /* 检查的颜色 */
  border-color:#52c41a;
}

/deep/ .radio-check .el-radio__input.is-checked .el-radio__inner:hover {
  background: #1890ff; /* 药品的颜色 */
  border-color:#1890ff;
}



/* 自定义选中后的样式 */
/deep/ .radio-disease .el-radio__input.is-checked+.el-radio__label {
  color: rgb(153, 10, 0);
}

/deep/ .radio-drug .el-radio__input.is-checked+.el-radio__label {
  color: #52c41a;
}
/deep/ .radio-check .el-radio__input.is-checked+.el-radio__label {
  color: #1890ff;
}
/* 自定义下拉样式 */
.select-container {
  position: relative;
  cursor: pointer;
  user-select: none;
}

.select-display {
  display: flex;
  align-items: center;
  padding: 0 12px;
  height: 25px;
  border-radius: 20px;
  font-size: 12px;
}

.dropdown-icon {
  width: 23px;
  margin-left: 6px;
}

.select-dropdown {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 4px;
  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);
  z-index: 10;
  min-width: 80px;
  color: #000;
  padding: 3px 0px;
}

.select-option {
  padding: 7px 12px;
  font-size: 13px;
  text-align: center;
}

.select-option:hover {
  background-color: #f5f7fa;
}

</style>