<template>
  <div class="common-table">
    <div class="table-header" v-if="showHeader">
      <div class="header-left">
        <slot name="header-left">
          <h3 v-if="title">{{ title }}</h3>
        </slot>
      </div>
      <div class="header-right">
        <slot name="header-actions"></slot>
      </div>
    </div>

    <div class="table-container">
      <el-table
        style="width: 100%"
        :data="tableData"
        :height="computedTableHeight"
        :max-height="maxHeight"
        :stripe="stripe"
        border
        :size="size"
        :fit="fit"
        :show-header="showTableHeader"
        :highlight-current-row="highlightCurrentRow"
        :row-key="rowKey"
        :empty-text="emptyText"
        :default-expand-all="defaultExpandAll"
        :expand-row-keys="expandRowKeys"
        :default-sort="defaultSort"
        :tooltip-effect="tooltipEffect"
        :show-summary="showSummary"
        :sum-text="sumText"
        :summary-method="summaryMethod"
        :span-method="spanMethod"
        :select-on-indeterminate="selectOnIndeterminate"
        :indent="indent"
        :lazy="lazy"
        :load="load"
        :tree-props="treeProps"
        @select="handleSelect"
        @select-all="handleSelectAll"
        @selection-change="handleSelectionChange"
        @cell-mouse-enter="handleCellMouseEnter"
        @cell-mouse-leave="handleCellMouseLeave"
        @cell-click="handleCellClick"
        @cell-dblclick="handleCellDblClick"
        @row-click="handleRowClick"
        @row-contextmenu="handleRowContextmenu"
        @row-dblclick="handleRowDblClick"
        @header-click="handleHeaderClick"
        @header-contextmenu="handleHeaderContextmenu"
        @sort-change="handleSortChange"
        @filter-change="handleFilterChange"
        @current-change="handleCurrentChange"
        @header-dragend="handleHeaderDragend"
        @expand-change="handleExpandChange"
      >
        <el-table-column
          v-if="selection"
          type="selection"
          width="55"
          :selectable="selectable"
          :reserve-selection="reserveSelection"
        />
        <el-table-column v-if="expand" type="expand" width="50">
          <template #default="props">
            <slot name="expand" :row="props.row" :index="props.$index"></slot>
          </template>
        </el-table-column>
        <el-table-column
          v-if="index"
          type="index"
          width="60"
          :label="indexLabel"
          :index="indexMethod"
        />

        <template v-for="column in columns" :key="column.prop">
          <el-table-column
            :prop="column.prop"
            :label="column.label"
            :width="column.autoWidth ? undefined : column.width"
            :min-width="column.minWidth || (column.autoWidth ? undefined : 120)"
            :fixed="column.fixed"
            :render-header="column.renderHeader"
            :sortable="column.sortable"
            :sort-method="column.sortMethod"
            :sort-by="column.sortBy"
            :sort-orders="column.sortOrders"
            :resizable="column.resizable !== false"
            :formatter="column.formatter"
            :show-overflow-tooltip="column.showOverflowTooltip !== false"
            :align="column.align || 'left'"
            :header-align="column.headerAlign"
            :class-name="column.className"
            :label-class-name="column.labelClassName"
            :filters="column.filters"
            :filter-placement="column.filterPlacement"
            :filter-multiple="column.filterMultiple"
            :filter-method="column.filterMethod"
            :filtered-value="column.filteredValue"
          >
            <template #default="scope" v-if="column.slot">
              <slot
                :name="column.slot"
                :row="scope.row"
                :column="column"
                :index="scope.$index"
              ></slot>
            </template>
          </el-table-column>
        </template>
      </el-table>
    </div>

    <div class="table-footer" v-if="pagination">
      <el-config-provider :locale="zhCn">
        <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="pageSizes"
          :total="total"
          :layout="paginationLayout"
          :background="paginationBackground"
          :small="paginationSmall"
          :disabled="paginationDisabled"
          :hide-on-single-page="hideOnSinglePage"
          @size-change="handleSizeChange"
          @current-change="handleCurrentPageChange"
          @prev-click="handlePrevClick"
          @next-click="handleNextClick"
        />
      </el-config-provider>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch } from "vue";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";

// Props 定义
const props = defineProps({
  // 表格数据
  data: {
    type: Array,
    default: () => [],
  },
  // 表格列配置
  columns: {
    type: Array,
    default: () => [],
  },
  // 表格标题
  title: {
    type: String,
    default: "",
  },
  // 是否显示表格头部
  showHeader: {
    type: Boolean,
    default: true,
  },
  // 是否显示表头
  showTableHeader: {
    type: Boolean,
    default: true,
  },
  // 表格高度
  tableHeight: {
    type: [String, Number],
    default: "auto",
  },
  // 是否自动计算表格高度
  autoHeight: {
    type: Boolean,
    default: false,
  },
  // 自动计算时的最大显示行数
  maxRows: {
    type: Number,
    default: 10,
  },
  // 行高（像素）
  rowHeight: {
    type: Number,
    default: 45,
  },
  // 表格最大高度
  maxHeight: [String, Number],
  // 是否为斑马纹表格
  stripe: {
    type: Boolean,
    default: false,
  },
  // 是否带有纵向边框
  border: {
    type: Boolean,
    default: false,
  },
  // Table 的尺寸
  size: {
    type: String,
    default: "default", // large, default, small
  },
  // 列的宽度是否自撑开
  fit: {
    type: Boolean,
    default: true,
  },
  // 是否要高亮当前行
  highlightCurrentRow: {
    type: Boolean,
    default: false,
  },
  // 行数据的 Key
  rowKey: [String, Function],
  // 空数据时显示的文本内容
  emptyText: {
    type: String,
    default: "暂无数据",
  },
  // 是否默认展开所有行
  defaultExpandAll: {
    type: Boolean,
    default: false,
  },
  // 可以通过该属性设置目前展开的行
  expandRowKeys: Array,
  // 默认的排序列的 prop 和顺序
  defaultSort: Object,
  // tooltip effect 属性
  tooltipEffect: {
    type: String,
    default: "dark", // dark, light
  },
  // 是否在表尾显示合计行
  showSummary: {
    type: Boolean,
    default: false,
  },
  // 合计行第一列的文本
  sumText: {
    type: String,
    default: "合计",
  },
  // 自定义的合计计算方法
  summaryMethod: Function,
  // 合并行或列的计算方法
  spanMethod: Function,
  // 在多选表格中，当仅有部分行被选中时的点击行为
  selectOnIndeterminate: {
    type: Boolean,
    default: true,
  },
  // 展示树形数据时，树节点的缩进
  indent: {
    type: Number,
    default: 16,
  },
  // 是否懒加载子节点数据
  lazy: {
    type: Boolean,
    default: false,
  },
  // 加载子节点数据的函数
  load: Function,
  // 渲染嵌套数据的配置选项
  treeProps: {
    type: Object,
    default: () => ({
      hasChildren: "hasChildren",
      children: "children",
    }),
  },
  // 是否显示多选框
  selection: {
    type: Boolean,
    default: false,
  },
  // 仅对 type=selection 的列有效，类型为 Function
  selectable: Function,
  // 仅对 type=selection 的列有效，类型为 Boolean，为 true 则会在数据更新之后保留之前选中的数据
  reserveSelection: {
    type: Boolean,
    default: false,
  },
  // 是否显示展开按钮
  expand: {
    type: Boolean,
    default: false,
  },
  // 是否显示索引列
  index: {
    type: Boolean,
    default: false,
  },
  // 索引列的标题
  indexLabel: {
    type: String,
    default: "#",
  },
  // 自定义索引的计算方法
  indexMethod: Function,
  // 是否显示分页
  pagination: {
    type: Boolean,
    default: true,
  },
  // 当前页码
  currentPage: {
    type: Number,
    default: 1,
  },
  // 每页显示条数
  pageSize: {
    type: Number,
    default: 10,
  },
  // 每页显示个数选择器的选项设置
  pageSizes: {
    type: Array,
    default: () => [10, 20, 50, 100],
  },
  // 总条数
  total: {
    type: Number,
    default: 0,
  },
  // 组件布局，子组件名用逗号分隔
  paginationLayout: {
    type: String,
    default: "total, sizes, prev, pager, next, jumper",
  },
  // 是否为分页按钮添加背景色
  paginationBackground: {
    type: Boolean,
    default: true,
  },
  // 是否使用小型分页
  paginationSmall: {
    type: Boolean,
    default: false,
  },
  // 是否禁用分页
  paginationDisabled: {
    type: Boolean,
    default: false,
  },
  // 只有一页时是否隐藏
  hideOnSinglePage: {
    type: Boolean,
    default: false,
  },
});

// Emits 定义
const emit = defineEmits([
  "select",
  "select-all",
  "selection-change",
  "cell-mouse-enter",
  "cell-mouse-leave",
  "cell-click",
  "cell-dblclick",
  "row-click",
  "row-contextmenu",
  "row-dblclick",
  "header-click",
  "header-contextmenu",
  "sort-change",
  "filter-change",
  "current-change",
  "header-dragend",
  "expand-change",
  "size-change",
  "current-page-change",
  "prev-click",
  "next-click",
]);

// 响应式数据
const currentPage = ref(props.currentPage);
const pageSize = ref(props.pageSize);

// 计算属性
const tableData = computed(() => {
  if (!props.pagination) {
    return props.data;
  }
  return props.data;
});

// 自动计算表格高度
const computedTableHeight = computed(() => {
  if (!props.autoHeight) {
    return props.tableHeight;
  }
  
  const headerHeight = 50;
  // const paginationHeight = props.pagination ? 50 : 0;
  const noDataHeight = tableData.value.length ? 0 : 50;
  const baseHeight = headerHeight + noDataHeight;
  
  // 如果数据超过最大行数，固定显示最大行数的高度；如果数据不超过最大行数，按实际行数计算高度
  const actualRows = Math.min(tableData.value.length, props.maxRows);
  const contentHeight = actualRows * props.rowHeight;
  
  return `${baseHeight + contentHeight}px`;
});

// 监听器
watch(
  () => props.currentPage,
  (newVal) => {
    currentPage.value = newVal;
  }
);

watch(
  () => props.pageSize,
  (newVal) => {
    pageSize.value = newVal;
  }
);

// 事件处理函数
const handleSelect = (selection, row) => {
  emit("select", selection, row);
};

const handleSelectAll = (selection) => {
  emit("select-all", selection);
};

const handleSelectionChange = (selection) => {
  emit("selection-change", selection);
};

const handleCellMouseEnter = (row, column, cell, event) => {
  emit("cell-mouse-enter", row, column, cell, event);
};

const handleCellMouseLeave = (row, column, cell, event) => {
  emit("cell-mouse-leave", row, column, cell, event);
};

const handleCellClick = (row, column, cell, event) => {
  emit("cell-click", row, column, cell, event);
};

const handleCellDblClick = (row, column, cell, event) => {
  emit("cell-dblclick", row, column, cell, event);
};

const handleRowClick = (row, column, event) => {
  emit("row-click", row, column, event);
};

const handleRowContextmenu = (row, column, event) => {
  emit("row-contextmenu", row, column, event);
};

const handleRowDblClick = (row, column, event) => {
  emit("row-dblclick", row, column, event);
};

const handleHeaderClick = (column, event) => {
  emit("header-click", column, event);
};

const handleHeaderContextmenu = (column, event) => {
  emit("header-contextmenu", column, event);
};

const handleSortChange = (sort) => {
  emit("sort-change", sort);
};

const handleFilterChange = (filters) => {
  emit("filter-change", filters);
};

const handleCurrentChange = (currentRow, oldCurrentRow) => {
  emit("current-change", currentRow, oldCurrentRow);
};

const handleHeaderDragend = (newWidth, oldWidth, column, event) => {
  emit("header-dragend", newWidth, oldWidth, column, event);
};

const handleExpandChange = (row, expandedRows) => {
  emit("expand-change", row, expandedRows);
};

const handleSizeChange = (val) => {
  pageSize.value = val;
  emit("size-change", val);
};

const handleCurrentPageChange = (val) => {
  currentPage.value = val;
  emit("current-page-change", val);
};

const handlePrevClick = (val) => {
  emit("prev-click", val);
};

const handleNextClick = (val) => {
  emit("next-click", val);
};
</script>

<style scoped lang="less">
.common-table {
  background: #fff;
  border-radius: 8px;
  padding: 10px 20px;

  .table-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;

    .header-left {
      flex: 1;               /* 占满剩余空间 */
      display: flex;
      align-items: center;
      gap: 12px;
      h3 {
        margin: 0;
        font-size: 18px;
        font-weight: 600;
        color: #333;
      }
    }

    .header-right {
      display: flex;
      gap: 12px;
    }
  }

  .table-container {
    margin-bottom: 16px;
  }

  .table-footer {
    display: flex;
    justify-content: flex-end;
    align-items: center;

    .el-pagination {
      margin-top: 16px;
    }
  }
}

:deep(.el-table) {
  thead {
    color: #000;
  }
  .el-table__cell {
    padding: 0;
    height: 46px;
    line-height: 46px;
  }
  .el-table__body tr.hover-row > td.el-table__cell {
    background-color: var(--el-table-row-hover-bg-color);
  }
  .el-pagination.is-background {
    .el-pager li {
      border: 1px solid #e7e9ee;
      font-weight: 400;
    }
    .el-pager li:not(.disabled).is-active {
      border: none;
      font-weight: 400;
    }
    .btn-prev,
    .btn-next {
      background-color: var(--el-disabled-bg-color);
    }
  }
}
:deep(.el-table) {
  th.el-table__cell {
    background: #f5f7fa;
    height: 50px;
    text-align: center;
  }
  .el-table__body {
    td.el-table__cell {
      height: 45px;
      line-height: 45px;
    }
  }
  // .el-table__cell {
  //   .cell {
  //     text-align: center;
  //   }
  // }
}
</style>
