<template>
  <!-- 公共树形组件：基于 Element UI el-tree 封装 -->
  <!-- common_tree_wrapper：用作非 scoped 样式的全局命名空间，防止样式泄漏到其他组件 -->
  <div class="common_tree_wrapper common_tree">
    <!--
      el-tree 核心配置说明：
      - ref: 用于父组件通过 this.$refs 调用 el-tree 原生方法（如 setCheckedKeys、getCheckedNodes 等）
      - data: 树形数据源（由父组件通过 props 传入）
      - props: 配置 el-tree 如何读取数据结构中的字段（label/children）
      - node-key: 每个树节点的唯一标识字段，用于选中/高亮定位
      - show-checkbox: 开启多选复选框
      - highlight-current: 高亮当前点击选中的节点
      - default-expand-all: 默认展开所有节点
    -->
    <el-tree ref="commonTree" class="tree_container" :data="treeData" :props="treeProps" :node-key="nodeKey"
      :show-checkbox="showCheckbox" :highlight-current="highlightCurrent" :default-expand-all="defaultExpandAll"
      :default-expanded-keys="defaultExpandedKeys" :current-node-key="currentNodeKey"
      :expand-on-click-node="expandOnClickNode" @node-click="handleNodeClick" @check="handleNodeCheck">
      <!--
        自定义树节点内容插槽（slot-scope）
        - node: 当前节点的完整数据对象（label、children、data 等）
        - data: 当前节点绑定的用户数据（即 treeData 中的每一项）
      -->
      <span class="custom_tree_node" slot-scope="{ node, data }">
        <!-- 节点名称区域 -->
        <span class="node_label" :title="data[treeProps.label]">
          <!-- 名称文本单独包裹一层，确保省略号只作用于真正承载文字的元素 -->
          <span class="node_label_text">{{ data[treeProps.label] }}</span>
          <!-- 右侧计数（可选，数据存在 count 字段时显示） -->
          <span class="node_count" v-if="data.count !== undefined && data.count !== null">
            ({{ data.count }})
          </span>
        </span>

        <!--
          AI 讲解按钮（Element UI 文字按钮 type="text"）
          - 默认隐藏（opacity: 0）
          - 通过父级 hover 显示
          - @click.stop 阻止冒泡，避免触发树节点点击
        -->
        <el-button class="ai_explain_btn" type="text" size="mini" icon="" @click.stop="handleAiExplain(node, data)">
          <img src="@/assets/knowledgeGraph/aiIcon.png" alt="AI讲解" style="width: 16px; height: 16px;">
          <span>AI讲解</span>
        </el-button>
      </span>
    </el-tree>
  </div>
</template>

<script>
/**
 * CommonTree 公共树形组件
 *
 * 功能说明：
 * 1. 基于 Element UI el-tree 二次封装，支持数据传入渲染
 * 2. 支持多选复选框
 * 3. 节点点击回传、节点勾选回传
 * 4. 鼠标悬停节点行显示 "AI讲解" 按钮，点击打印并回传当前节点
 *
 * 父组件使用示例：
 * <CommonTree
 *   :tree-data="knowledgeTreeData"
 *   :tree-props="{ label: 'knowledgeName', children: 'children' }"
 *   node-key="knowledgeId"
 *   show-checkbox
 *   @node-click="handleTreeClick"
 *   @node-check="handleTreeCheck"
 *   @ai-explain="handleAiExplain"
 * />
 */
export default {
  name: 'CommonTree',

  // ==================== Props 配置（由父组件传入） ====================
  props: {
    /**
     * 树形数据源
     * 数据结构示例：
     * [
     *   { id: 1, label: '节点1', count: 10, children: [
     *     { id: 11, label: '子节点1', count: 5 }
     *   ]}
     * ]
     */
    treeData: {
      type: Array,
      default: () => []
    },

    /**
     * el-tree 的 props 配置，用于映射数据结构的字段
     * 默认：{ label: 'label', children: 'children' }
     * 如使用其他字段名，可传：{ label: 'knowledgeName', children: 'childList' }
     */
    treeProps: {
      type: Object,
      default: () => ({
        label: 'label',
        children: 'children'
      })
    },

    /**
     * 节点唯一标识字段名
     * 用于选中、高亮、展开等操作的定位
     */
    nodeKey: {
      type: String,
      default: 'id'
    },

    /** 是否显示多选复选框 */
    showCheckbox: {
      type: Boolean,
      default: false
    },

    /** 是否高亮当前点击的节点 */
    highlightCurrent: {
      type: Boolean,
      default: true
    },

    /** 是否默认展开所有节点 */
    defaultExpandAll: {
      type: Boolean,
      default: true
    },

    /**
     * 默认展开的节点 key 数组
     * 与 defaultExpandAll 互斥使用
     */
    defaultExpandedKeys: {
      type: Array,
      default: () => []
    },

    /** 当前高亮选中的节点 key */
    currentNodeKey: {
      type: [String, Number],
      default: ''
    },

    /**
     * 点击节点时是否展开/收起
     * false：只有点击小箭头才展开；点击节点文字只触发选中
     * true：点击节点文字也会触发展开/收起
     */
    expandOnClickNode: {
      type: Boolean,
      default: false
    }
  },

  // ==================== 数据状态 ====================
  data() {
    return {
      // 当前选中的节点数据（单选时使用）
      currentSelectedNode: null
    };
  },

  // ==================== 方法 ====================
  methods: {
    /**
     * 树节点点击事件（单选）
     * @param {Object} data  - 当前节点绑定的用户数据
     * @param {Object} node  - el-tree 节点对象（包含 level、parent 等信息）
     * 触发事件：this.$emit('node-click', data, node)
     */
    handleNodeClick(data, node) {
      this.currentSelectedNode = data;
      this.$emit('node-click', data, node);
    },

    /**
     * 树节点勾选事件（多选，showCheckbox=true 时生效）
     * @param {Object} data             - 当前勾选/取消的节点数据
     * @param {Object} checkedInfo      - 勾选状态详情
     * @param {Array}  checkedInfo.checkedNodes       - 所有被勾选的节点对象数组
     * @param {Array}  checkedInfo.checkedKeys        - 所有被勾选的节点 key 数组（含半选）
     * @param {Array}  checkedInfo.halfCheckedKeys    - 半选状态的节点 key 数组
     */
    handleNodeCheck(data, checkedInfo) {
      this.$emit('node-check', data, checkedInfo);
    },

    /**
     * AI 讲解按钮点击事件
     * 1. 打印当前节点数据（方便调试）
     * 2. 通过 $emit 回传给父组件处理
     *
     * @param {Object} node  - el-tree 节点对象
     * @param {Object} data  - 当前节点绑定的用户数据
     */
    handleAiExplain(node, data) {
      // ===== 打印调试信息 =====
      console.log('========== [CommonTree] AI讲解点击 ==========');
      console.log('当前节点数据 data:', data);
      console.log('当前节点对象 node:', node);
      console.log('节点标签 label:', data[this.treeProps.label]);
      console.log('节点唯一键 key:', data[this.nodeKey]);
      console.log('节点层级 level:', node.level);
      console.log('是否叶子节点 isLeaf:', node.isLeaf);
      console.log('===============================================');

      // ===== 回传给父组件 =====
      this.$emit('ai-explain', {
        nodeData: data,           // 当前节点的用户数据
        nodeInstance: node,       // el-tree 节点实例
        nodeKey: data[this.nodeKey], // 当前节点 key
        nodeLabel: data[this.treeProps.label] // 当前节点显示名称
      });
    },

    /**
     * 对外暴露方法：获取所有勾选的节点（仅多选模式 showCheckbox=true 有效）
     * @param {Boolean} leafOnly - 是否只返回叶子节点
     * @returns {Array} 选中的节点对象数组
     */
    getCheckedNodes(leafOnly = false) {
      return this.$refs.commonTree.getCheckedNodes(leafOnly);
    },

    /**
     * 对外暴露方法：获取所有勾选节点的 key 数组
     * @param {Boolean} leafOnly
     * @returns {Array} 选中的节点 key 数组
     */
    getCheckedKeys(leafOnly = false) {
      return this.$refs.commonTree.getCheckedKeys(leafOnly);
    },

    /**
     * 对外暴露方法：通过 keys 设置哪些节点被选中
     * @param {Array} keys       - 要选中的节点 key 数组
     * @param {Boolean} leafOnly - 是否只设置叶子节点
     */
    setCheckedKeys(keys, leafOnly = false) {
      this.$refs.commonTree.setCheckedKeys(keys, leafOnly);
    },

    /**
     * 对外暴露方法：清空所有选中节点
     */
    clearChecked() {
      this.$refs.commonTree.setCheckedKeys([]);
    },

    /**
     * 对外暴露方法：设置当前高亮的节点
     * @param {String|Number} key - 节点 key
     */
    setCurrentKey(key) {
      this.$refs.commonTree.setCurrentKey(key);
    }
  }
};
</script>

<!--
  ==========================================================================
  样式分两块：
  1. 下面这个不带 scoped 的 style 块：专门覆盖 Element UI 原生类名（连接线、padding、间距、选中态）
     - scoped + :deep 在 el-tree 深层级嵌套下经常不生效，改用非 scoped 搭配组件唯一根类
       .common_tree_wrapper 做命名空间隔离，不会污染全局其他 el-tree
  2. 后面带 scoped 的 style 块：放自定义节点内容（custom_tree_node / node_label / ai_explain_btn 等）
  ==========================================================================
-->
<style lang="scss">
/* ============== 可配置常量 ============== */
$line_color: #DCDFE6; // 连接线颜色（虚线）
$line_style: dashed; // 连接线样式
$line_width: 1px; // 连接线宽度
$indent_size: 35px; // 每层缩进
$node_height: 36px; // 单行节点高度
$node_padding_l: 15px; // 节点左侧 padding （用户要求：15px）
$node_gap: 10px; // 节点上下间距   （用户要求：10px）
$label_color: #333333; // 节点文字       （用户要求）
$label_active: #2E64FA; // 选中节点文字    （用户要求）
$label_fs: 14px; // 文字字号       （用户要求）
$label_fw: 400; // 文字字重       （用户要求）
$btn_color: #4F3EFF; // AI讲解按钮颜色  （用户要求）

/* =========================================================
   命名空间：.common_tree_wrapper（只影响本组件）
   ========================================================= */
.common_tree_wrapper {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  padding: 8px 0;

  /* ===================== 基础 ===================== */
  .tree_container,
  .el-tree {
    width: 100%;
    background: transparent;
  }

  /* ===================== 节点行样式 =====================
     padding-left: 15px，上下间距 10px，字体 400/14/#333
  */
  .el-tree-node__content {
    padding-left: 0 !important;
    padding-right: 12px;
    height: $node_height;
    line-height: $node_height;
    background: transparent;
    border-radius: 4px;
    margin-top: $node_gap;
    margin-bottom: $node_gap;
    font-weight: $label_fw;
    font-size: $label_fs;
    color: $label_color;

    &:hover {
      background-color: #f0f7ff;
    }
  }

  /* 第一级也统一 15px */
  .el-tree>.el-tree-node>.el-tree-node__content {
    padding-left: $node_padding_l !important;
  }

  /* ===================== 自定义展开收起图标样式 ===================== */
  .el-tree-node__expand-icon {
    width: 16px;
    height: 16px;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    cursor: pointer;
    margin-right: 8px;
    padding: 0 !important;
    border: none !important;
    /* 去掉Element UI默认的transform旋转过渡动画，直接切换图标 */
    transform: none !important;
    transition: none !important;
  }
  /* 去掉展开状态的transform旋转 */
  .el-tree-node__expand-icon.expanded {
    transform: none !important;
    -webkit-transform: none !important;
  }

  /* 隐藏Element UI默认的箭头伪元素 */
  .el-tree-node__expand-icon::before {
    display: none !important;
  }

  /* 收起状态：显示加号 icon_jia */
  .el-tree-node__expand-icon:not(.expanded):not(.is-leaf)::after {
    content: '\e64e';
    font-family: 'iconfont' !important;
    font-size: 16px;
    color: #E0E3E9;
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 16px;
    text-align: center;
  }

  /* 展开状态：显示减号 icon_jian */
  .el-tree-node__expand-icon.expanded:not(.is-leaf)::after {
    content: '\e64f';
    font-family: 'iconfont' !important;
    font-size: 16px;
    color: #2E64FA;
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 16px;
    text-align: center;

  }

  /* 叶子节点的占位符，保持对齐一致 */
  .el-tree-node__expand-icon.is-leaf {
    width: 16px !important;
    height: 16px !important;
    display: inline-block !important;
    cursor: default;
    visibility: hidden;
    margin-right: 8px;
    padding: 0 !important;
  }

  /* ===================== 虚线连接线（核心） ===================== */

  /* 1. 竖虚线：画在 children 容器的左侧，贯穿所有子节点 */
  .el-tree-node .el-tree-node__children {
    overflow: visible;
    position: relative;
    margin-left: 0;
    padding-left: $indent_size; // 层级缩进

    &::before {
      content: '';
      position: absolute;
      top: 0;
      bottom: $node_gap + $node_height / 2; // 末端停在最后一个节点"半高"处，和横线接上
      left: 18px; // 竖线 x 坐标
      width: $line_width;
      border-left: $line_width $line_style $line_color;
    }
  }

  /* 2. 横虚线：画在每个节点行的左侧，从竖线方向延伸到文字左边 */
  .el-tree-node {
    position: relative;

    >.el-tree-node__content::before {
      content: '';
      position: absolute;
      top: 50%;
      left: -($indent_size - 18px); // 起点对齐竖线
      width: $indent_size - 20px; // 横线长度
      height: 0;
      border-top: $line_width $line_style $line_color;
      pointer-events: none;
    }
  }

  /* 3. 第一级节点不画横线 */
  .el-tree>.el-tree-node>.el-tree-node__content::before {
    display: none;
  }

  /* 4. 最后一个子节点：竖线在横线之下的部分用白色盖掉，形成"L"拐角 */
  .el-tree-node>.el-tree-node__children>.el-tree-node:last-child {
    >.el-tree-node__content::after {
      content: '';
      position: absolute;
      top: 50%;
      bottom: -$node_gap;
      left: 18px - $indent_size; // 与竖线同 x
      width: $line_width + 2px;
      background: #fff; // 白色遮挡（面板必须是白色背景）
      z-index: 1;
    }
  }

  /* ===================== 选中 & 复选框 ===================== */
  .el-tree-node.is-current>.el-tree-node__content {
    background-color: #e6f0ff;
    color: $label_active; // 让文字内容（含原生 el-tree label 模式）也变色

    /* 额外命中自定义 slot 中的 .node_label，防止 scoped 里写的 #333 覆盖掉选中色 */
    .node_label {
      color: $label_active !important;
      font-weight: $label_fw;
    }
  }

  .el-checkbox {
    margin-right: 6px;
  }

  /* ===================== AI 讲解按钮（Element UI 文字按钮） =====================
     字体 400 / 14 / #4F3EFF；opacity 0 默认隐藏，hover 节点行显示
  */

  .ai_explain_btn.el-button--text {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 4px 6px !important;
    height: auto !important;
    min-height: 24px;
    margin-left: 8px;
    opacity: 0;
    transition: opacity 0.2s ease;
    white-space: nowrap;
    flex-shrink: 0;
    position: relative;
    z-index: 3;
    font-weight: 400; // 用户要求
    font-size: 14px; // 用户要求
    color: $btn_color !important; // 用户要求：#4F3EFF

    // 确保内部img和span都居中对齐
    img {
      display: inline-block;
      vertical-align: middle;
      flex-shrink: 0;
      margin-right: 4px;
    }
    span {
      display: inline-block;
      vertical-align: middle;
      line-height: 1;
    }
  }

  .ai_explain_btn.el-button--text:hover {
    color: darken($btn_color, 10%) !important;
  }

  .ai_explain_btn .ai_icon {
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 16px;
    text-align: center;
    font-size: 10px;
    font-weight: 600;
    color: #fff;
    background: $btn_color;
    border-radius: 3px;
    font-style: normal;
    flex-shrink: 0;
  }

  .ai_explain_btn.el-button--text:hover .ai_icon {
    background: darken($btn_color, 10%);
  }

  /* hover 节点行时，让 AI 讲解按钮淡入 */
  .el-tree-node__content:hover .ai_explain_btn.el-button--text {
    opacity: 1 !important;
  }
}
</style>

<!-- ===============================================================
     以下 scoped 样式块：只处理"自定义节点内容"（我们自己模板里写的）
     类名是自定义的，能被 scoped 正常命中，无需 :deep
   =============================================================== -->
<style lang="scss" scoped>
.custom_tree_node {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: 1;
  padding-right: 8px;
  height: 36px;
  line-height: 36px;
  overflow: hidden;
  position: relative;
  z-index: 2;
  min-width: 0; /* flex子项关键：允许收缩到内容宽度以下 */

  /* ===== 节点文字（用户要求：400 / 14px / #333333） ===== */
  .node_label {
    flex: 1;
    display: inline-flex;
    align-items: center;
    font-weight: 400;
    font-size: 14px;
    color: #333333;
    min-width: 0; /* flex子项关键：允许收缩 */

    /* 名称文本：唯一承载文字的元素，在这里设置省略号 */
    .node_label_text {
      display: inline-block;
      flex: 1;
      min-width: 0; /* 关键：防止flex子项被最小宽度撑开 */
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      line-height: 1;
    }

    /* 计数（60）：灰色小字，不收缩 */
    .node_count {
      color: #909399;
      margin-left: 4px;
      font-size: 13px;
      flex-shrink: 0;
    }
  }
}
</style>
