<template>
  <div class="klp-list-container">
    <!-- 列表加载状态 -->
    <div v-loading="loading" class="list-loading-wrapper">
      <!-- 列表项渲染 -->
      <div 
        v-for="(item, index) in listData" 
        :key="item[listKey] || index" 
        class="klp-list-item"
        :class="{ 'active': isSelected(item) }"
        @click.stop="handleItemClick(item)" 
      >
        <!-- 列表标题区域 - 文字溢出省略+Tooltip -->
        <div class="klp-list-title">
          <span class="title-label">{{ titleLabel }}：</span>
          <el-tooltip 
            :content="item[titleField]" 
            placement="top"
            :disabled="!isContentOverflow(item)"
            effect="light"
          >
            <span class="title-value">{{ item[titleField] }}</span>
          </el-tooltip>
        </div>  

        <!-- 右侧操作按钮组 -->
        <div class="klp-list-actions">
          <slot name="actions" :item="item" :isSelected="isSelected(item)"></slot>
        </div>
      </div>

      <!-- 空状态提示 -->
      <div v-if="listData.length === 0 && !loading" class="klp-list-empty">
        <el-empty description="暂无数据" />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "KLPList",
  components: {},
  props: {
    /** 列表数据源（必传） */
    listData: {
      type: Array,
      required: true,
      default: () => []
    },

    /** 列表项唯一标识字段（必传，如orderId、id） */
    listKey: {
      type: String,
      required: true
    },

    /** 列表标题前置标签（如"订单编号："） */
    titleLabel: {
      type: String,
      required: true,
      default: "标题"
    },

    /** 列表项标题对应的字段名（如orderCode、name） */
    titleField: {
      type: String,
      required: true,
      default: "title"
    },

    /** 列表加载状态 */
    loading: {
      type: Boolean,
      required: false,
      default: false
    },

    /** 标题最大宽度占容器的百分比（0-100），控制文字溢出 */
    titleMaxPercent: {
      type: Number,
      required: false,
      default: 80 // 默认占容器80%宽度
    }
  },
  data() {
    return {
      // 内部管理选中状态：存储当前选中项的唯一键值（单选中）
      selectedKey: null,
      // 文字溢出检测临时元素（避免重复创建）
      overflowCheckElements: {},
      // 容器宽度缓存
      containerWidth: 0
    };
  },
  methods: {
    /**
     * 判断当前列表项是否被选中
     * @param {Object} item - 列表项数据
     * @returns {Boolean} 选中状态
     */
    isSelected(item) {
      const itemKey = item[this.listKey];
      return this.selectedKey === itemKey;
    },

    /**
     * 列表项点击事件：切换选中状态（单选中逻辑）
     * @param {Object} item - 点击的列表项数据
     */
    handleItemClick(item) {
      const itemKey = item[this.listKey]; 
      // 单选中逻辑：点击已选中项取消选中，点击未选中项切换选中（取消其他项）
      // this.selectedKey = this.selectedKey === itemKey ? null : itemKey;
      this.selectedKey = itemKey;
      
      // 向父组件触发事件：传递当前选中项（null表示无选中）
      const selectedItem = this.selectedKey ? item : null;
      this.$emit("item-click", selectedItem, item);
    },

    /**
     * 清空选中状态（支持父组件通过ref调用）
     */
    clearSelection() {
      this.selectedKey = null;
      // 触发清空选中事件
      this.$emit("selection-cleared");
    },

    /**
     * 主动设置选中项（支持父组件通过ref调用）
     * @param {String/Number} targetKey - 要选中项的唯一键值
     */
    setSelection(targetKey) {
      const isExist = this.listData.some(item => item[this.listKey] === targetKey);
      if (isExist) {
        this.selectedKey = targetKey;
        // 触发选中事件
        const selectedItem = this.listData.find(item => item[this.listKey] === targetKey);
        this.$emit("item-click", selectedItem);
      } else {
        this.selectedKey = null;
        console.warn(`列表中不存在key为${targetKey}的项`);
      }
    },

    /**
     * 判断文字是否溢出（控制Tooltip显示/隐藏）
     * @param {Object} item - 列表项数据
     * @returns {Boolean} 是否溢出
     */
    isContentOverflow(item) {
      const itemKey = item[this.listKey];
      const content = item[this.titleField] || "";

      // 内容为空时不显示Tooltip
      if (!content) return false;

       // 获取容器宽度并增加存在性检查
      const container = this.$el.querySelector('.klp-list-container');
      if (!container) return false; // 容器不存在时直接返回
      this.containerWidth = container.clientWidth;
      
      // 计算标题内容最大可用宽度（减去标签和边距）
      const labelWidth = this.$el.querySelector('.title-label')?.offsetWidth || 60;
      const availableWidth = (this.containerWidth * this.titleMaxPercent / 100) - labelWidth - 20;

      // 创建临时元素测量文字实际宽度（复用元素避免性能问题）
      if (!this.overflowCheckElements[itemKey]) {
        const tempEl = document.createElement("span");
        // 复制title-value的样式（确保测量准确）
        tempEl.style.cssText = `
          visibility: hidden;
          position: absolute;
          white-space: nowrap;
          font-size: 14px;
          font-weight: 500;
          color: #303133;
        `;
        tempEl.textContent = content;
        document.body.appendChild(tempEl);
        this.overflowCheckElements[itemKey] = tempEl;
      }

      // 比较文字实际宽度与可用宽度
      const tempEl = this.overflowCheckElements[itemKey];
      return tempEl.offsetWidth > availableWidth;
    },

    /**
     * 监听容器宽度变化
     */
    handleResize() {
      // 宽度变化时重新计算溢出状态
      this.$forceUpdate();
    }
  },
  watch: {
    /** 列表数据变化时，重置选中状态和溢出检测元素 */
    listData: {
      deep: true,
      handler() {
        this.clearSelection();
        // 清理临时测量元素
        Object.values(this.overflowCheckElements).forEach(el => {
          document.body.removeChild(el);
        });
        this.overflowCheckElements = {};
      }
    },

    /** 标题最大百分比变化时，重新计算溢出 */
    titleMaxPercent() {
      this.$forceUpdate();
    }
  },
  mounted() {
    this.$nextTick(() => {
    const container = this.$el.querySelector('.klp-list-container');
      // 增加存在性检查
      this.containerWidth = container ? container.clientWidth : 0;
    });
    
    // 监听窗口大小变化
    window.addEventListener('resize', this.handleResize);
  },
  beforeDestroy() {
    // 清理临时元素
    Object.values(this.overflowCheckElements).forEach(el => {
      document.body.removeChild(el);
    });
    
    // 移除事件监听
    window.removeEventListener('resize', this.handleResize);
  }
};
</script>

<style scoped>
/* 列表容器基础样式 */
.klp-list-container {
  max-height: calc(100vh - 220px);
  overflow-y: auto;
  padding-right: 8px;
  margin-top: 10px;
  width: 100%; /* 确保容器宽度正确计算 */
  box-sizing: border-box;
}

/* 加载状态容器（避免加载时容器塌陷） */
.list-loading-wrapper {
  min-height: 100px;
}

/* 列表项样式 */
.klp-list-item {
  padding: 6px 8px;
  margin-bottom: 6px;
  border-bottom: 1px solid #e6e6e6;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
  width: 100%; /* 确保列表项占满容器宽度 */
}

/* 列表项选中状态（左侧高亮边框+背景色） */
.klp-list-item.active {
  border-left: 3px solid #409eff;
  background-color: #f5f7fa;
}

/* 列表标题区域（占满中间空间，让操作按钮靠右） */
.klp-list-title {
  display: flex;
  align-items: center;
  flex: 1;
  min-width: 0; /* 关键：允许flex项缩小到内容尺寸以下 */
  overflow: hidden; /* 确保内容不会超出容器 */
}

/* 标题前置标签样式 */
.klp-list-title .title-label {
  color: #606266;
  margin-right: 6px;
  font-size: 13px;
  white-space: nowrap; /* 标签不换行 */
  flex-shrink: 0; /* 标签不缩小 */
}

/* 标题内容样式（溢出省略） */
.klp-list-title .title-value {
  color: #303133;
  font-weight: 500;
  font-size: 14px;
  white-space: nowrap; /* 禁止换行 */
  overflow: hidden; /* 超出部分隐藏 */
  text-overflow: ellipsis; /* 超出部分显示省略号 */
  flex: 1; /* 占据剩余空间 */
  min-width: 0; /* 关键：允许内容区域缩小 */
}

/* 操作按钮组（按钮间距控制） */
.klp-list-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0; /* 操作区不缩小 */
  margin-left: 8px;
}

/* 空状态样式（居中显示） */
.klp-list-empty {
  padding: 40px 0;
  text-align: center;
}
</style>
    