<template>
  <div class="knowledge_graph" ref="knowledgeGraph" :style="{ maxHeight: containerHeight + 'px' }">

    <div class="graph_top">
      <!-- 顶部信息模块 -->
      <div class="knowledge_header">
        <div class="header_top">
          <span class="header_title">我的知识图谱</span>
          <!-- 年级选择标签，只有一个年级时不显示 -->
          <el-checkbox-group v-if="gradeList && gradeList.length > 1" v-model="currentGradeList" @change="handleGradeChange">
            <el-checkbox v-for="grade in gradeList" :key="grade.value" :label="grade.value">
              {{ grade.label }}
            </el-checkbox>
          </el-checkbox-group>
        </div>
        <div class="header_stats">
          <span class="stats_text">
            你的知识图谱共包含 <span class="stats_num">{{ totalCount }}</span> 个知识点。当前
            红色薄弱知识点<span class="stats_weak"> {{ weakCount }}</span> 个，
            黄色待提升知识点<span class="stats_good"> {{ goodCount }}</span> 个，
            <span class="stats_excellent">坚持练习，把全部知识点都进阶为绿色已掌握状态吧！</span>
          </span>
        </div>
      </div>

      <!-- 环形扩散图组件 -->
      <circular-diffusion :subjectName="actualSubjectName" :subjectScoreRate="subjectScoreRate"
        :tableData="displayTableData"
        :classLevel="classLevel" :classGroupName="classGroupName"
        :currentKnowledgeId="currentLinkedKnowledgeId || currentKnowledgeId || defaultKnowledgeId"
        :addedKnowledgeIds="addedKnowledgeIds"
        @legend-change="handleLegendChange"
        @legend-visibility-change="handleLegendVisibilityChange"
        @activeTabChange="handleActiveTabChange"
        @add-practice="handleAddPractice"
        @knowledge-item-click="handleKnowledgeItemClick" />

      <!-- 区域展示组件 -->
      <region
        :partitionData="partitionData"
        :addedKnowledgeIds="addedKnowledgeIds"
        :selectedKnowledgeId="currentLinkedKnowledgeId || currentKnowledgeId || defaultKnowledgeId"
        :legendVisibility="legendVisibility"
        @add-practice="handleAddPractice"
        @item-click="handleRegionItemClick" />
    </div>
  </div>
</template>

<script>
import CircularDiffusion from './knowledgeGraph/circularDiffusion.vue';
import Region from './knowledgeGraph/region.vue';
import { mapState } from 'vuex';

export default {
  name: 'KnowledgeGraph',
  components: {
    CircularDiffusion,
    Region
  },
  props: {
    subjectScoreRate: {
      type: Number,
      default: 85
    },
    tableData: {
      type: Array,
      default: () => []
    },
    fatalVulnerability: {
      type: Array,
      default: () => []
    },
    highVulnerability: {
      type: Array,
      default: () => []
    },
    allKnowledgeList: {
      type: Array,
      default: () => []
    },
    classLevel: {
      type: [String, Number],
      default: ''
    },
    classGroupName: {
      type: String,
      default: ''
    },
    currentKnowledgeId: {
      type: [String, Number],
      default: ''
    },
    showRegion: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      // 容器最大高度
      containerHeight: 600,
      // 当前选中的年级列表（多选）
      currentGradeList: [],
      // 年级列表（从localStorage的student_gradesList读取）
      gradeList: [],
      // 中心圆点学科名称（通过 subjectCode 从 student_subjectList 匹配）
      subjectNameState: '',
      // 默认选中知识点ID：接口返回的 knowList 中"第一棵节点树的最后一个子节点（叶子）"
      defaultKnowledgeId: '',
      // 接口返回的真实统计数据
      graphStats: {
        allKnowNum: 0,   // 知识点总数
        weakKnowNum: 0,  // 薄弱数量
        goodKnowNum: 0   // 待提升数量
      },
      // 接口返回的树形知识数据（第一层直接传给环形扩散图）
      knowList: [],
      // knowList 扁平化后的一维数组（用于统计、列表展示）
      flatKnowList: [],
      // 知识点分区：由 knowledge_partition 接口返回
      // conquerZone: 薄弱补强区 / improveZone: 能力提升区 / consolidateZone: 扎实巩固区
      partitionData: {
        conquerZone: [],
        improveZone: [],
        consolidateZone: []
      },
      // 当前会话中"已加入练习"的知识点 ID 容器（响应式：父级 $set 后自动驱动子组件按钮置灰）
      // 形如 { '1001': true }
      addedKnowledgeIds: {},
      // 环形扩散图 ↔ 区域卡片 的联动选中知识点 ID
      // - 点环形扩散图圆点 → 写这里 → region 读 prop :selectedKnowledgeId 高亮并滚动居中
      // - 点 region 某行条目 → 写这里 → circularDiffusion 读 prop :currentKnowledgeId 放大圆点 + 更新右侧折线表格
      currentLinkedKnowledgeId: '',
      // 假数据：表格树形结构数据（用于无接口数据时兜底）
      mockTableData: [],
      // 图例可见状态联动：薄弱(1)/良好(2)/优秀(3) → 控制 region.vue 对应区域显示/隐藏
      legendVisibility: { 1: true, 2: true, 3: true }
    };
  },
  computed: {
    ...mapState('target', ['subjectCode', 'subjectName']),
    // 中心圆点学科名称：优先从 localStorage 的 student_subjectList 匹配 subjectCode
    actualSubjectName() {
      return this.subjectNameState || '知识点';
    },
    // 统计知识点总数：优先使用接口返回的 allKnowNum
    totalCount() {
      if (this.graphStats.allKnowNum !== null && this.graphStats.allKnowNum !== undefined) {
        return this.graphStats.allKnowNum;
      }
      return this.displayAllKnowledgeList.length;
    },
    // 薄弱知识点数量（knowledgeType === 1）：优先使用接口返回的 weakKnowNum
    weakCount() {
      if (this.graphStats.weakKnowNum !== null && this.graphStats.weakKnowNum !== undefined) {
        return this.graphStats.weakKnowNum;
      }
      return this.displayAllKnowledgeList.filter(item => item.knowledgeType === 1).length;
    },
    // 良好/待提升知识点数量（knowledgeType === 2）：优先使用接口返回的 goodKnowNum
    goodCount() {
      if (this.graphStats.goodKnowNum !== null && this.graphStats.goodKnowNum !== undefined) {
        return this.graphStats.goodKnowNum;
      }
      return this.displayAllKnowledgeList.filter(item => item.knowledgeType === 2).length;
    },
    // 优秀知识点数量（knowledgeType === 3）
    excellentCount() {
      return this.displayAllKnowledgeList.filter(item => item.knowledgeType === 3).length;
    },
    // 实际显示的表格数据：接口knowList > props.tableData > 假数据
    displayTableData() {
      if (this.knowList && this.knowList.length > 0) {
        return this.knowList;
      }
      if (this.tableData && this.tableData.length > 0) {
        return this.tableData;
      }
      return this.mockTableData;
    },


    // 实际显示的全部知识点数据：flatKnowList > props.allKnowledgeList > 假数据
    displayAllKnowledgeList() {
      if (this.flatKnowList && this.flatKnowList.length > 0) {
        return this.flatKnowList;
      }
      if (this.allKnowledgeList && this.allKnowledgeList.length > 0) {
        return this.allKnowledgeList;
      }
      // 假数据：全部知识点（扁平化结构，用于列表显示和区域展示）
      return [
        { knowledgeId: '1', knowledgeName: '函数与方程', knowledgeType: 1, gradeScoreRate: 45, classScoreRate: 45, examNum: 8, questionNum: 120, scoreRateDiff: -5 },
        { knowledgeId: '1-1', knowledgeName: '一元二次方程', knowledgeType: 1, gradeScoreRate: 35, classScoreRate: 35, examNum: 5, questionNum: 60, scoreRateDiff: -10 },
        { knowledgeId: '1-2', knowledgeName: '函数图像', knowledgeType: 1, gradeScoreRate: 55, classScoreRate: 55, examNum: 3, questionNum: 40, scoreRateDiff: -2 },
        { knowledgeId: '2', knowledgeName: '几何图形', knowledgeType: 2, gradeScoreRate: 72, classScoreRate: 72, examNum: 4, questionNum: 80, scoreRateDiff: 3 },
        { knowledgeId: '2-1', knowledgeName: '三角形', knowledgeType: 2, gradeScoreRate: 68, classScoreRate: 68, examNum: 2, questionNum: 30, scoreRateDiff: 2 },
        { knowledgeId: '2-2', knowledgeName: '圆的性质', knowledgeType: 2, gradeScoreRate: 78, classScoreRate: 78, examNum: 2, questionNum: 50, scoreRateDiff: 5 },
        { knowledgeId: '3', knowledgeName: '概率统计', knowledgeType: 3, gradeScoreRate: 90, classScoreRate: 90, examNum: 1, questionNum: 25, scoreRateDiff: 8 },
        { knowledgeId: '3-1', knowledgeName: '数据分析', knowledgeType: 3, gradeScoreRate: 92, classScoreRate: 92, examNum: 1, questionNum: 15, scoreRateDiff: 10 },
        { knowledgeId: '3-2', knowledgeName: '概率计算', knowledgeType: 3, gradeScoreRate: 88, classScoreRate: 88, examNum: 1, questionNum: 10, scoreRateDiff: 6 },
        { knowledgeId: '4', knowledgeName: '数列', knowledgeType: 2, gradeScoreRate: 65, classScoreRate: 65, examNum: 6, questionNum: 90, scoreRateDiff: 1 },
        { knowledgeId: '5', knowledgeName: '立体几何', knowledgeType: 1, gradeScoreRate: 50, classScoreRate: 50, examNum: 7, questionNum: 100, scoreRateDiff: -3 },
        { knowledgeId: '6', knowledgeName: '向量', knowledgeType: 2, gradeScoreRate: 82, classScoreRate: 82, examNum: 3, questionNum: 45, scoreRateDiff: 4 },
        { knowledgeId: '7', knowledgeName: '导数应用', knowledgeType: 3, gradeScoreRate: 95, classScoreRate: 95, examNum: 2, questionNum: 20, scoreRateDiff: 12 },
        { knowledgeId: '8', knowledgeName: '不等式', knowledgeType: 1, gradeScoreRate: 58, classScoreRate: 58, examNum: 5, questionNum: 75, scoreRateDiff: -1 }
      ];
    }
  },
  watch: {
    // 监听学科变化，重新调用知识图谱接口
    subjectCode(newVal, oldVal) {
      if (newVal && newVal !== oldVal) {
        this.fetchKnowledgeGraph();
        this.fetchKnowledgePartition();
      }
    }
  },
  mounted() {
    // 从localStorage读取年级列表
    this.loadGradeListFromStorage();
    // 初始化容器高度
    this.calculateContainerHeight();
    // 监听窗口大小变化
    window.addEventListener('resize', this.calculateContainerHeight);
    // 首次加载知识图谱数据 + 分区数据
    this.fetchKnowledgeGraph();
    this.fetchKnowledgePartition();
  },
  beforeDestroy() {
    // 移除窗口大小变化监听
    window.removeEventListener('resize', this.calculateContainerHeight);
  },
  methods: {
    /**
     * 从 localStorage 读取年级列表 student_gradesList
     * 并规范化为 [{ label, value }] 结构
     */
    loadGradeListFromStorage() {
      try {
        const raw = localStorage.getItem('student_gradesList');
        if (!raw) return;
        const list = JSON.parse(raw);
        if (!Array.isArray(list)) return;

        // 规范化字段：支持 label/value、label/code、name/value 等常见组合
        this.gradeList = list.map(item => ({
          label: item.label || item.name || String(item.value ?? item.code ?? item),
          value: item.value ?? item.code ?? item.label ?? item.name ?? String(item)
        }));

        // 默认只选中最后一个年级
        //   例：[{高一,10},{高二,11}] → currentGradeList = ['11']（仅选中高二）
        //   同“加入练习接口 gradeCode = gradeList 末尾 value”规则保持一致
        this.currentGradeList = this.gradeList.length > 0
          ? [this.gradeList[this.gradeList.length - 1].value]
          : [];
      } catch (e) {
        console.warn('[KnowledgeGraph] 解析 localStorage.student_gradesList 失败:', e);
      }
    },

    /**
     * 【接口调用】获取知识图谱数据
     * 参数：
     *  - levelCode:    学段CODE（localStorage.student_level_code）
     *  - gradeCodes:   年级codes数组（checkbox选中的value，即使只有1个也要传）
     *  - subjectCode:  学科code（vuex -> target.subjectCode）
     * 调用成功后打印返回数据
     */
    fetchKnowledgeGraph() {
      // 读取学段CODE
      const levelCode = localStorage.getItem('student_level_code') || '';
      // 年级codes：当前选中的value数组；如未初始化则取gradeList全部value
      let gradeCodes = this.currentGradeList && this.currentGradeList.length
        ? this.currentGradeList
        : (this.gradeList || []).map(g => g.value);
      // 学科code
      const subjectCode = this.subjectCode || '';

      const params = {
        levelCode,
        gradeCodes,
        subjectCode
      };
      this.$api.target.knowledgeGraph(params).then(res => {
        if (res.code == 200 && res.data) {
          const d = res.data;
          // 1. 统计数据
          this.graphStats = {
            allKnowNum:  d.allKnowNum  !== undefined ? Number(d.allKnowNum)  : 0,
            weakKnowNum: d.weakKnowNum !== undefined ? Number(d.weakKnowNum) : 0,
            goodKnowNum: d.goodKnowNum !== undefined ? Number(d.goodKnowNum) : 0
          };
          // 2. 中心圆点学科名称：通过 subjectCode 从 localStorage.student_subjectList 匹配
          this.resolveSubjectNameByCode();
          // 3. knowList 树形数据 + 拍平（并把 personalScoreRate 映射为 classScoreRate / gradeScoreRate 以便图表组件识别）
          const list = Array.isArray(d.knowList) ? d.knowList : [];
          this.knowList = this.mapKnowListItem(list);
          this.flatKnowList = this.flattenKnowList(this.knowList);

          // 4. 默认选中：第一棵节点树的最后一个子节点（叶子节点）
          const defaultNode = this.findFirstTreeLastLeafNode(this.knowList);
          this.defaultKnowledgeId = defaultNode ? (defaultNode.knowledgeId ?? '') : '';
        } else {
          // 接口失败 / code !== 200 / 无data：清空数据，扩散图和统计数字归零
          this.resetKnowledgeGraphEmpty();
        }
      }).catch(err => {
        console.error('[KnowledgeGraph] knowledgeGraph 接口异常:', err);
        this.resetKnowledgeGraphEmpty();
      });
    },

    /**
     * 参数和 knowledgeGraph 相同：levelCode / gradeCodes / subjectCode
     * 返回：conquerZone(薄弱) / improveZone(提升) / consolidateZone(巩固)
     */
    fetchKnowledgePartition() {
      const levelCode = localStorage.getItem('student_level_code') || '';
      let gradeCodes = this.currentGradeList && this.currentGradeList.length
        ? this.currentGradeList
        : (this.gradeList || []).map(g => g.value);
      const subjectCode = this.subjectCode || '';
      const params = { levelCode, gradeCodes, subjectCode };

      this.$api.target.knowledgePartition(params).then(res => {
        if (res.code == 200 && res.data) {
          const d = res.data || {};
          this.partitionData = {
            conquerZone:    this.mapPartitionItem(Array.isArray(d.conquerZone)    ? d.conquerZone    : []),
            improveZone:    this.mapPartitionItem(Array.isArray(d.improveZone)    ? d.improveZone    : []),
            consolidateZone:this.mapPartitionItem(Array.isArray(d.consolidateZone)? d.consolidateZone : [])
          };
        } else {
          this.resetPartitionEmpty();
        }
      }).catch(err => {
        console.error('[KnowledgeGraph] knowledgePartition 接口异常:', err);
        this.resetPartitionEmpty();
      });
    },

    /**
     * 分区接口返回的每个子数组字段规范化
     *  - knowledgeId / knowledgeName / personalScoreRate / examNum / knowledgeType
     * 顺便兜底转换成 Number，避免字符串导致渲染异常
     */
    mapPartitionItem(list) {
      if (!Array.isArray(list)) return [];
      return list.map(item => {
        const node = { ...(item || {}) };
        node.knowledgeId    = node.knowledgeId ?? node.id;
        node.knowledgeName  = node.knowledgeName ?? node.name ?? node.label ?? '';
        node.knowledgeType  = Number(node.knowledgeType ?? node.type ?? 3);

        const pRate = node.personalScoreRate ?? node.scoreRate ?? node.personalRate;
        if (pRate !== null && pRate !== undefined && pRate !== '') {
          const n = Number(pRate);
          node.personalScoreRate = isNaN(n) ? 0 : n;
          if (node.classScoreRate === null || node.classScoreRate === undefined) {
            node.classScoreRate = node.personalScoreRate;
          }
          if (node.gradeScoreRate === null || node.gradeScoreRate === undefined) {
            node.gradeScoreRate = node.personalScoreRate;
          }
        }
        // 考频：examNum
        if (node.examNum !== null && node.examNum !== undefined && node.examNum !== '') {
          const n = Number(node.examNum);
          node.examNum = isNaN(n) ? 0 : n;
        }
        return node;
      });
    },

    /**
     * 清空分区数据（接口失败或无数据时调用）
     */
    resetPartitionEmpty() {
      this.partitionData = {
        conquerZone: [],
        improveZone: [],
        consolidateZone: []
      };
    },

    /**
     * 清空知识图谱所有数据（接口失败或无数据时调用）
     * - knowList / flatKnowList 清空
     * - graphStats 三项归零
     * - defaultKnowledgeId 清空
     * - subjectNameState 不重置（保持本地匹配兜底名，避免名称闪烁）
     */
    resetKnowledgeGraphEmpty() {
      this.knowList = [];
      this.flatKnowList = [];
      this.graphStats = {
        allKnowNum: 0,
        weakKnowNum: 0,
        goodKnowNum: 0
      };
      this.defaultKnowledgeId = '';
    },

    /**
     * 从树形 knowList 中取"第一棵节点树的最后一个子节点（叶子）"
     * 规则：取 list[0] 作为根节点，然后一路沿 children[children.length-1] 下钻
     *       直到某节点没有 children 或 children 为空，返回该节点；
     *       list 为空返回 null
     */
    findFirstTreeLastLeafNode(list) {
      if (!Array.isArray(list) || list.length === 0) return null;
      let node = list[0];
      while (node && Array.isArray(node.children) && node.children.length > 0) {
        node = node.children[node.children.length - 1];
      }
      return node || null;
    },

    /**
     * 通过 subjectCode 从 localStorage.student_subjectList 匹配学科名称
     * 并写入 this.subjectNameState
     */
    resolveSubjectNameByCode() {
      try {
        const subjectCode = String(this.subjectCode ?? '');
        if (!subjectCode) return;
        const raw = localStorage.getItem('student_subjectList');
        if (!raw) return;
        const list = JSON.parse(raw);
        if (!Array.isArray(list) || list.length === 0) return;

        const match = list.find(item => {
          const val = String(item.value ?? item.code ?? item.subjectCode ?? item.id ?? '');
          return val === subjectCode;
        });
        if (match) {
          const name = match.label ?? match.name ?? match.subjectName ?? String(match);
          if (name) {
            this.subjectNameState = name;
            return;
          }
        }
        // 兜底：取第一个
        const first = list[0];
        if (first) {
          const fallbackName = first.label ?? first.name ?? first.subjectName ?? String(first);
          if (fallbackName) this.subjectNameState = fallbackName;
        }
      } catch (e) {
        console.warn('[KnowledgeGraph] 解析 localStorage.student_subjectList 失败:', e);
      }
    },

    /**
     * 递归遍历 knowList，确保每个节点具备环形图需要的字段：
     * - knowledgeId / knowledgeName / knowledgeType
     * - personalScoreRate → 同时映射为 classScoreRate、gradeScoreRate（组件读取的是这两个）
     * - isJoin 原样保留（子组件需要据此显示"已加入练习"）
     * - children 递归处理
     */
    mapKnowListItem(list) {
      if (!Array.isArray(list)) return [];
      return list.map(item => {
        const node = { ...(item || {}) };
        // 兼容字段
        node.knowledgeId   = node.knowledgeId   ?? node.id;
        node.knowledgeName = node.knowledgeName ?? node.name ?? node.label;
        node.knowledgeType = Number(node.knowledgeType ?? node.type ?? 3);

        const pRate = node.personalScoreRate ?? node.scoreRate ?? node.personalRate;
        if (pRate !== null && pRate !== undefined) {
          // 环形扩散图 generateTreeData 中会按 classLevel / mode 读取 classScoreRate 或 gradeScoreRate
          // 为了兼容两种路径，把 personalScoreRate 同时复制到两者
          if (node.classScoreRate === null || node.classScoreRate === undefined) {
            node.classScoreRate = Number(pRate);
          }
          if (node.gradeScoreRate === null || node.gradeScoreRate === undefined) {
            node.gradeScoreRate = Number(pRate);
          }
          node.personalScoreRate = Number(pRate);
        }
        if (node.children && node.children.length > 0) {
          node.children = this.mapKnowListItem(node.children);
        }
        return node;
      });
    },

    /**
     * 将 knowList（树形）拍平为一维数组（保留 isJoin 等全部字段）
     */
    flattenKnowList(list, out = []) {
      if (!Array.isArray(list)) return out;
      list.forEach(item => {
        out.push(item);
        if (item.children && item.children.length > 0) {
          this.flattenKnowList(item.children, out);
        }
      });
      return out;
    },

    // 年级切换（多选）
    handleGradeChange(gradeList) {
      this.currentGradeList = gradeList;
      this.$emit('grade-change', gradeList);
      // 年级变化后重新请求知识图谱 + 分区数据
      this.fetchKnowledgeGraph();
      this.fetchKnowledgePartition();
    },
    // 计算容器高度
    calculateContainerHeight() {
      if (this.$refs.knowledgeGraph) {
        // 获取容器距离视口顶部的距离
        const rect = this.$refs.knowledgeGraph.getBoundingClientRect();
        // 计算容器最大高度：窗口高度 - 容器距离顶部的距离 - 底部留白
        const maxHeight = window.innerHeight - rect.top - 20;
        // 设置最小高度为400px
        this.containerHeight = Math.max(maxHeight, 400);
      }
    },

    // 处理图例变化
    handleLegendChange(data) {
      this.$emit('legend-change', data);
    },

    // 处理图例可见状态变化：薄弱(1)/良好(2)/优秀(3) 的可见性
    // 同步更新到 legendVisibility，驱动 region.vue 对应区域显示/隐藏
    handleLegendVisibilityChange(visibility) {
      if (!visibility) return;
      // 保证响应式：直接替换整个对象引用
      this.legendVisibility = {
        1: !!visibility[1],
        2: !!visibility[2],
        3: !!visibility[3]
      };
    },

    // 处理tab切换
    handleActiveTabChange(tab) {
      this.$emit('activeTabChange', tab);
    },

    // 处理知识点点击（来自环形扩散图组件：圆点被用户点击或默认选中）
    handleKnowledgeItemClick(data) {
      // 兼容两种 payload 结构：
      //   1) 圆点点击 / setDefaultSelection 新结构：{ knowledgeId, knowledgeName, ... } (顶层)
      //   2) 旧的 item 包装结构：{ item: {knowledgeId,...}, index: N }
      let knowledgeId = data?.knowledgeId;
      if ((knowledgeId === undefined || knowledgeId === null || knowledgeId === '')
        && data?.item) {
        knowledgeId = data.item.knowledgeId;
      }
      if (knowledgeId !== undefined && knowledgeId !== null && knowledgeId !== '') {
        this.currentLinkedKnowledgeId = String(knowledgeId);
      }
      this.$emit('knowledge-item-click', data);
    },
    // 处理区域卡片中某行条目被点击（来自 region 组件）→ 反向联动到环形扩散图对应圆点高亮 + 右侧数据
    handleRegionItemClick(item) {
      const id = item?.knowledgeId;
      if (id === undefined || id === null || id === '') return;
      this.currentLinkedKnowledgeId = String(id);
    },

    // 处理加入练习
    // 参数来源：
    //   - 环形扩散图按钮：emit 传出 { knowledgeId, knowledgeName, personalScoreRate?, knowledgeType? }
    //   - region 卡片按钮：emit 传出整条 item（含 knowledgeId/Name/personalScoreRate/knowledgeType/examNum...）
    handleAddPractice(item) {
      if (!item) {
        this.$message.warning('未获取到知识点信息');
        return;
      }

      const knowledgeId = item.knowledgeId ?? item.id;
      const knowledgeName = item.knowledgeName ?? item.name ?? item.label ?? '';
      if (!knowledgeId || !knowledgeName) {
        this.$message.warning('知识点信息不完整，请稍后重试');
        return;
      }

      // 已经加过的直接返回，避免重复请求
      if (this.addedKnowledgeIds[String(knowledgeId)]) {
        this.$message.info('该知识点已加入练习');
        return;
      }

      // 得分率：优先 personalScoreRate → gradeScoreRate → classScoreRate
      let personalScoreRate = item.personalScoreRate;
      if (personalScoreRate === null || personalScoreRate === undefined || personalScoreRate === '') {
        personalScoreRate = item.gradeScoreRate ?? item.classScoreRate;
      }
      if (personalScoreRate === null || personalScoreRate === undefined || personalScoreRate === '') {
        personalScoreRate = 0;
      } else {
        personalScoreRate = Number(personalScoreRate);
        if (isNaN(personalScoreRate)) personalScoreRate = 0;
      }

      // 知识点类型：1薄弱 2一般 3优秀
      let knowledgeType = Number(item.knowledgeType ?? item.type ?? 0);
      if (isNaN(knowledgeType)) knowledgeType = 0;

      const subjectCode = this.subjectCode || '';
      const levelCode = localStorage.getItem('student_level_code') || '';

      // 年级CODE：取 gradeList 数组中最后一个年级的 value
      //   - 多个年级（如[{高一,10},{高二,11}]）→ 取最后一个（高二.value = 11）
      //   - 只有一个年级 → 直接取该年级 value
      //   - 空/无效 → 传空串兜底
      let gradeCode = '';
      let gradeName = '';
      let schoolYearId = '';
      if (Array.isArray(this.gradeList) && this.gradeList.length > 0) {
        const lastGrade = this.gradeList[this.gradeList.length - 1];
        if (lastGrade && lastGrade.value !== undefined && lastGrade.value !== null && lastGrade.value !== '') {
          gradeCode = String(lastGrade.value);
        }
        // 年级NAME：与 gradeCode 一一对应，取同一元素的 label
        if (lastGrade && lastGrade.label !== undefined && lastGrade.label !== null) {
          gradeName = String(lastGrade.label);
        }
        const raw = JSON.parse(localStorage.getItem('student_gradesList'));
        schoolYearId = raw?.[0]?.gradeId || '';
      }
      const subjectName = this.subjectName || '';
      const params = {
        knowledgeId,
        knowledgeName,
        personalScoreRate,
        knowledgeType,
        subjectCode,
        subjectName,
        levelCode,
        gradeCode,
        gradeName,
        schoolYearId
      };

      this.$api.target.addExercise(params).then(res => {
        if (res && (res.code == 200 || res.code == 0)) {
          // 成功：提示 + 记录 ID（用 $set 保证响应式，region/circularDiffusion 会自动重新渲染并置灰按钮）
          this.$message.success('已加入练习成功');
          this.$set(this.addedKnowledgeIds, String(knowledgeId), true);
        } else {
          this.$message.error(res.msg);
        }
      }).catch(err => {
        console.error('[KnowledgeGraph] addExercise 接口异常:', err);
        this.$message.error('加入练习失败，请稍后重试');
      });
    }
  }
};
</script>

<style lang="scss" scoped>
.knowledge_graph {
  overflow-y: auto;
  overflow-x: hidden;
  width: 100%;
  box-sizing: border-box;

  .graph_top {
    background: #FFFFFF;
    border-radius: 10px;
    padding: 20px;
    width: 100%;
    box-sizing: border-box;
    overflow: hidden;
  }

  /* 顶部信息模块 */
  .knowledge_header {
    margin-bottom: 10px;

    .header_top {
      display: flex;
      align-items: center;
      gap: 20px;
      margin-bottom: 10px;

      .header_title {
        font-size: 16px;
        font-weight: 500;
        color: #333;
      }
      .el-checkbox-group{
        .el-checkbox{
          margin-right:20px;
        }
      }
    }

    .header_stats {
       font-size: 14px;
      .stats_text {
        color: #999999;
      }

      .stats_num {
        color: #2E64FA;
      }

      .stats_weak {
        color: #F56C6C;
      }

      .stats_good {
        color: #FAC858;
      }
    }
  }

  /* 自定义滚动条样式 */
  &::-webkit-scrollbar {
    width: 6px;
  }

  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }

  &::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;

    &:hover {
      background: #a8a8a8;
    }
  }
}
</style>
