<template>
  <div class="xmind-box" :class="{ 'xmind-box--dashboard': dashboardMode }">
    <div class="action-panel">
      <el-button type="primary" :size="dashboardMode ? 'mini' : 'small'" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
      <!-- <el-button type="primary" icon="el-icon-view" @click="handleRefresh">详情</el-button>
      <el-button type="primary" icon="el-icon-edit" @click="handleRefresh">编辑</el-button>
      <el-button type="primary" icon="el-icon-folder" @click="previewFiles(currentNode)">文件</el-button>
      <el-button type="primary" icon="el-icon-picture" @click="previewImages(currentNode)">图片</el-button> -->
    </div>
    <div class="xmind-container" ref="chart" :style="containerStyle"></div>
    <!-- 新增：三级节点点击弹窗-查看完整信息 -->
    <el-dialog title="节点详情信息" :visible.sync="dialogVisible" width="1200px" center append-to-body>
      <el-form>
        <el-row :gutter="10">
          <el-col :span="6">
            <el-form-item label="进度类别" prop="name">
              <el-input v-model="currentNode.tabNode" placeholder="请输入进度类型"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="一级分类" prop="firstLevelNode">
              <el-input v-model="currentNode.firstLevelNode" placeholder="请输入一级分类"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="步骤名称" prop="secondLevelNode">
              <el-input v-model="currentNode.secondLevelNode" placeholder="请输入步骤名称"></el-input>
            </el-form-item>
          </el-col>

          <el-col :span="12">
            <el-form-item label="负责人" prop="nodeHeader">
              <el-input v-model="currentNode.nodeHeader" placeholder="请输入负责人"></el-input>
            </el-form-item>
          </el-col>

          <el-col :span="12">
            <el-form-item label="规格需求" prop="specification">
              <el-input v-model="currentNode.specification" placeholder="规格需求"></el-input>
            </el-form-item>
          </el-col>

          <el-col :span="24">
            <el-form-item label="成果资料" prop="relatedDocs">
              <file-upload @success="handleFileSuccess" @delete="handleFileDelete" v-model="currentNode.relatedDocs"
                placeholder="成果资料"></file-upload>
            </el-form-item>
          </el-col>

          <el-col :span="24">
            <el-form-item label="相关图片" prop="relatedImages">
              <image-upload v-model="currentNode.relatedImages" placeholder="相关图片"></image-upload>
            </el-form-item>
          </el-col>

          <el-col :span="24">
            <el-form-item label="需求资料" prop="requirementFile">
              <file-upload @success="handleFileSuccess" @delete="handleFileDelete" v-model="currentNode.requirementFile"
                placeholder="需求资料"></file-upload>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <!-- <div class="dialog-content">
        <div class="node-title">{{ currentNode.name }}</div>
        <div class="node-info-item" v-for="(val, key) in currentNode.value" :key="key">
          <span class="label">{{ key }}：</span>
          <span class="value">{{ val || '无' }}</span>
        </div>
      </div> -->
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">提交修改</el-button>
          <el-button type="primary" @click="dialogVisible = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { addFileOperationRecord } from '@/api/oa/fileOperationRecord';
import { updateProjectScheduleStep } from "@/api/oa/projectScheduleStep";
import * as echarts from 'echarts';

export default {
  name: "Xmind",
  props: {
    list: {
      type: Array,
      default: () => []
    },
    /** 容器高度，综合看板等场景可传 100% 以撑满父级 */
    height: {
      type: String,
      default: '800px'
    },
    /** 综合看板：紧凑、防重叠、三色状态、小圆点 */
    dashboardMode: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    containerStyle () {
      return {
        width: '100%',
        height: this.height,
        minHeight: this.dashboardMode ? '300px' : '240px'
      }
    }
  },
  data () {
    return {
      chartInstance: null, // 保存图表实例，用于后续重绘/销毁
      dialogVisible: false, // 新增：弹窗显示隐藏开关
      currentNode: {}, // 新增：存储当前点击的三级节点完整数据
      clickEvent: null, // 新增：存储点击事件句柄，用于销毁解绑
      users: [],
      supplierList: [],
    };
  },
  watch: {
    // 监听列表数据变化，自动更新图表
    list: {
      deep: true,
      handler () {
        if (this.chartInstance) {
          this.initChart();
        }
      }
    }
  },
  mounted () {
    this.initChart();
    this.$nextTick(() => this.resizeChart());
    window.addEventListener('resize', this.resizeChart);
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resizeChart);
    // 新增：解绑Echarts点击事件，防止内存泄漏
    if (this.chartInstance && this.clickEvent) {
      this.chartInstance.off('click', this.clickEvent);
    }
    // 销毁图表实例，防止内存泄漏
    this.chartInstance?.dispose();
  },
  methods: {
    // 优化：增加防抖处理-窗口自适应，避免频繁触发
    resizeChart () {
      this.chartInstance?.resize()
    },

    handleSubmit () {
      updateProjectScheduleStep(this.currentNode).then(response => {
        this.$modal.msgSuccess("修改成功");
        this.dialogVisible = false;
        this.handleRefresh();
      });
    },

    handleRefresh () {
      this.$emit('refresh')
    },

    handleFileSuccess (resList, res) {
      addFileOperationRecord({
        fileId: res.ossId,
        fileName: res.name,
        type: 1,
        projectId: this.currentNode.projectId,
        trackId: this.currentNode.trackId,
      })
      console.log(this.currentNode, this.currentNode.relatedDocs);
      updateProjectScheduleStep({
        ...this.currentNode,
        relatedDocs: this.currentNode.relatedDocs,
      })
    },

    handleFileDelete (res) {
      addFileOperationRecord({
        fileId: res.ossId,
        fileName: res.name,
        type: 2,
        projectId: this.currentNode.projectId,
        trackId: this.currentNode.trackId,
      })
      console.log(this.currentNode, this.currentNode.relatedDocs);
      updateProjectScheduleStep({
        ...this.currentNode,
        relatedDocs: this.currentNode.relatedDocs,
      })
    },

    /** 看板长标签按字折行（与折线图区域可读性一致） */
    wrapLabelText (text, maxCharsPerLine) {
      if (!text) return ''
      const max = Math.max(4, maxCharsPerLine || 16)
      if (text.length <= max) return text
      const lines = []
      for (let i = 0; i < text.length; i += max) {
        lines.push(text.slice(i, i + max))
      }
      return lines.join('\n')
    },

    // Tab节点 → 一级节点 → 二级节点（叶子带业务数据）
    transformToTreeData (list) {
      if (!list.length) return { name: '暂无项目数据', children: [] };

      const dm = this.dashboardMode
      const projectName = list[0].projectName || '项目进度树图';
      const tabMap = new Map();

      list.forEach(item => {
        const tab = item.tabNode || '默认分组';
        const firstLevel = item.firstLevelNode || '未分类一级节点';
        const secondLevel = item.secondLevelNode || item.stepName || '未命名节点';
        const st = Number(item.status);
        let statusText = '进行中';
        let statusColor = '#E6A23C';
        let lineToNode = { color: '#dcdfe6', width: 1.2 };
        if (st === 2) {
          statusText = '已完成';
          statusColor = '#67C23A';
          lineToNode = { color: '#67C23A', width: 1.8 };
        } else if (st === 0) {
          statusText = '未开始';
          statusColor = '#909399';
        } else if (st === 1) {
          statusText = '待验收/进行中';
          statusColor = '#E6A23C';
        } else if (st === 3) {
          statusText = '暂停';
          statusColor = '#909399';
        }

        const nodeData = {
          name: secondLevel,
          /* 看板：小圆点 + 白边，贴近折线图主色风格 */
          itemStyle: dm
            ? { color: statusColor, borderColor: '#ffffff', borderWidth: 1.25, shadowBlur: 3, shadowColor: 'rgba(0,0,0,0.12)' }
            : { color: statusColor, borderColor: statusColor },
          label: { color: statusColor },
          lineStyle: lineToNode,
          value: {
            ...item,
            statusLabel: statusText
          }
        };

        if (!tabMap.has(tab)) {
          tabMap.set(tab, new Map());
        }
        const firstMap = tabMap.get(tab);
        if (!firstMap.has(firstLevel)) {
          firstMap.set(firstLevel, []);
        }
        firstMap.get(firstLevel).push(nodeData);
      });

      const treeChildren = Array.from(tabMap).map(([tabName, firstMap]) => ({
        name: tabName,
        itemStyle: dm
          ? { color: '#606266', borderColor: '#ffffff', borderWidth: 1, shadowBlur: 2, shadowColor: 'rgba(0,0,0,0.06)' }
          : { color: '#606266', borderColor: '#dcdfe6' },
        lineStyle: { color: '#c0c4cc', width: 1.2 },
        children: Array.from(firstMap).map(([firstName, children]) => ({
          name: firstName,
          itemStyle: dm
            ? { color: '#303133', borderColor: '#ffffff', borderWidth: 1, shadowBlur: 2, shadowColor: 'rgba(0,0,0,0.06)' }
            : { color: '#303133', borderColor: '#dcdfe6' },
          lineStyle: { color: '#c0c4cc', width: 1.2 },
          children
        }))
      }));

      return {
        name: projectName,
        symbolSize: dm ? 7 : undefined,
        itemStyle: dm
          ? { color: '#409eff', borderColor: '#ffffff', borderWidth: 1.5, shadowBlur: 4, shadowColor: 'rgba(64,158,255,0.35)' }
          : { color: '#409eff', borderColor: '#409eff' },
        lineStyle: { color: '#a0cfff', width: 1.5 },
        label: dm ? { distance: 8, fontSize: 11 } : undefined,
        children: treeChildren
      };
    },

    // 初始化图表
    initChart () {
      // 初始化图表实例
      if (!this.chartInstance) {
        this.chartInstance = echarts.init(this.$refs.chart);
      }
      // 重要：先解绑已有点击事件，防止多次绑定导致弹窗多次触发
      if (this.clickEvent) {
        this.chartInstance.off('click', this.clickEvent);
      }
      // 转换数据格式
      const treeData = this.transformToTreeData(this.list);
      const dm = this.dashboardMode;
      const escapeHtml = (s) => String(s == null ? '' : s)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
      const option = {
        backgroundColor: dm ? 'transparent' : undefined,
        tooltip: {
          trigger: 'item',
          enterable: true,
          confine: true,
          extraCssText: 'max-width:420px;white-space:normal;word-break:break-word;border-radius:6px;box-shadow:0 2px 12px rgba(0,0,0,0.08);',
          formatter: (params) => {
            const data = params.data
            const title = (data && data.name) != null ? data.name : (params.name || '')
            let tip = `<div style="font-size:13px;font-weight:600;margin-bottom:6px;line-height:1.45;color:#303133">${escapeHtml(title)}</div>`
            if (data && data.value) {
              const v = data.value
              tip += `<div style="font-size:12px;line-height:1.55;color:#606266">负责人：${v.nodeHeader != null && v.nodeHeader !== '' ? escapeHtml(v.nodeHeader) : '无'}</div>`
              tip += `<div style="font-size:12px;line-height:1.55;color:#606266">规格需求：${v.specification != null && v.specification !== '' ? escapeHtml(v.specification) : '无'}</div>`
              tip += `<div style="font-size:12px;line-height:1.55;color:#606266">状态：${v.statusLabel != null && v.statusLabel !== '' ? escapeHtml(v.statusLabel) : '无'}</div>`
              tip += `<div style="font-size:12px;line-height:1.55;color:#606266">计划完成：${v.planEnd != null && v.planEnd !== '' ? escapeHtml(v.planEnd) : '无'}</div>`
            }
            return tip
          }
        },
        series: [
          {
            type: 'tree',
            data: [treeData],
            /* 与折线图区域一致：留白、白底在容器上 */
            ...(dm ? { left: '1%', right: '5%', top: '2%', bottom: '2%' } : {}),
            symbol: 'circle',
            ...(dm ? {} : { symbolSize: 6 }),
            edgeShape: dm ? 'polyline' : 'curve',
            edgeForkPosition: dm ? '74%' : '50%',
            orient: 'LR',
            initialTreeDepth: 4,
            roam: true,
            scaleLimit: dm ? { min: 0.22, max: 5 } : undefined,
            label: {
              show: true,
              fontSize: dm ? 11 : 12,
              fontWeight: 400,
              position: 'left',
              verticalAlign: 'middle',
              ...(dm ? { align: 'right' } : {}),
              distance: 8,
              overflow: 'none',
              lineHeight: dm ? 15 : 14,
              color: dm ? '#606266' : undefined
            },
            /*
             * levels[i]：根下一层起 Tab / 分类 / 叶；缩小状态圆点，叶节点标签放右侧防挤压
             */
            levels: dm
              ? [
                {
                  symbolSize: 6,
                  itemStyle: { borderWidth: 1, borderColor: '#fff' },
                  label: {
                    position: 'left',
                    distance: 8,
                    fontSize: 11,
                    width: 118,
                    overflow: 'break',
                    lineHeight: 14,
                    padding: [2, 6, 2, 6]
                  }
                },
                {
                  symbolSize: 5,
                  itemStyle: { borderWidth: 1, borderColor: '#fff' },
                  label: {
                    position: 'left',
                    distance: 10,
                    fontSize: 11,
                    width: 160,
                    overflow: 'break',
                    lineHeight: 14,
                    padding: [2, 8, 2, 6]
                  }
                },
                {
                  symbolSize: 4,
                  itemStyle: { borderWidth: 1, borderColor: '#fff', shadowBlur: 2, shadowColor: 'rgba(0,0,0,0.1)' },
                  label: {
                    position: 'right',
                    verticalAlign: 'middle',
                    align: 'left',
                    distance: 12,
                    fontSize: 11,
                    width: 232,
                    overflow: 'break',
                    lineHeight: 15,
                    padding: [2, 8, 2, 8],
                    formatter: (p) => this.wrapLabelText(p.name, 17)
                  }
                }
              ]
              : [
                { symbolSize: 10 },
                { symbolSize: 7 },
                { symbolSize: 5 },
                { symbolSize: 3 }
              ],
            lineStyle: {
              width: dm ? 1 : 1.2,
              curveness: dm ? 0.1 : 0.3,
              color: dm ? '#e4e7ed' : '#ccc'
            },
            emphasis: {
              focus: 'descendant',
              lineStyle: { width: 2, color: '#409eff' },
              itemStyle: dm ? { shadowBlur: 6, shadowColor: 'rgba(64,158,255,0.45)' } : undefined
            },
            expandAndCollapse: true,
            animationDuration: 280
          }
        ]
      };
      // 渲染图表
      this.chartInstance?.setOption(option, true);

      this.clickEvent = (params) => {
        const data = params.data;
        if (data && data.value && data.value.trackId) {
          this.currentNode = { ...data.value };
          this.dialogVisible = true;
        }
      };
      // 绑定点击事件
      this.chartInstance.on('click', this.clickEvent);
    }
  }
};
</script>

<style scoped>
.xmind-box {
  position: relative;
}

.action-panel {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1000;
}

.xmind-container {
  background: #fafafa;
  border-radius: 8px;
}

.xmind-box--dashboard {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

/* 与综合看板折线图区域一致：白底、细边框、轻圆角 */
.xmind-box--dashboard .xmind-container {
  flex: 1;
  min-height: 0;
  background: #fff;
  border: 1px solid #ebeef5;
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.8);
}

/* 新增：弹窗内部样式美化 */
:deep(.dialog-content) {
  padding: 10px 0;
}

:deep(.node-title) {
  font-size: 16px;
  font-weight: bold;
  color: #1890FF;
  text-align: center;
  padding: 8px 0;
  border-bottom: 1px solid #f0f0f0;
  margin-bottom: 15px;
}

:deep(.node-info-item) {
  display: flex;
  padding: 6px 0;
  font-size: 14px;
  line-height: 1.6;
}

:deep(.label) {
  width: 80px;
  color: #666;
  font-weight: 500;
}

:deep(.value) {
  flex: 1;
  color: #333;
}

:deep(.dialog-footer) {
  text-align: center;
}
</style>