<template>
  <el-table
    ref="table"
    class="bg-table bg-table-pro"
    :class="{ 'bg-table-tree': !!rowKey }"
    v-bind="attrs"
    :data="data"
    :row-key="rowKey"
    :tree-props="treeProps"
    @selection-change="selectionChange"
    :default-expand-all="defaultExpandAll">
    <el-table-column width="60" v-if="showIndex">
      <template v-slot:header>
        <p style="width: 100%; text-align: center">序号</p>
      </template>
      <template v-slot:default="{ $index }">
        <p style="width: 100%; text-align: center">{{ $index + 1 }}</p>
      </template>
    </el-table-column>
    <el-table-column type="selection" :selectable="selectable" width="60" align="center" v-if="showSelectColumn" />
    <el-table-column
      v-for="(header, index) in headers"
      :key="`col_${index}`"
      :width="header.width"
      :label="header.label"
      :align="header.align"
      :show-overflow-tooltip="!$slots[header.prop]"
      :fixed="header.fixed">
      <template v-slot:header>
        <template v-if="$slots[`header-${header.prop}`]">
          <slot :name="`header-${header.prop}`" />
        </template>
        <template v-else>
          <p class="text-clip">
            <span v-if="header.required" style="color: #d75138">*</span>
            {{ header.label }}
          </p>
        </template>
      </template>

      <template v-slot:default="{ row, $index }">
        <template v-if="$slots[header.prop]">
          <slot :name="header.prop" :row="row" :index="$index" />
        </template>
        <template v-else-if="$slots[`text-${header.prop}`]">
          <p class="text-clip">
            <slot :name="`text-${header.prop}`" :row="row" :index="$index" />
          </p>
        </template>
        <template v-else>
          <p class="text-clip">{{ row[header.prop] }}</p>
        </template>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup>
import { useAttrs, ref, computed, watch, nextTick } from "vue";

const attrs = useAttrs();

const props = defineProps({
  headers: {
    type: Array,
    require: true,
  },
  data: {
    type: Array,
  },
  rowKey: {
    type: String,
  },
  treeProps: {
    type: Object,
  },
  showIndex: {
    type: Boolean,
    default: false,
  },
  selectable: {
    type: Function,
  },
  defaultExpandAll: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(["select"]);

const allSelection = ref([]);

const showSelectColumn = computed(() => {
  return attrs && (attrs["selection-change"] || attrs["select"]);
}); // 是否显示选中列

const addSelectEvent = computed(() => {
  return attrs && attrs["select"];
});

watch(
  () => props.data,
  () => {
    recoverSelection();
  }
);

const table = ref(null);

const recoverSelection = () => {
  let selectionIds = allSelection.value.map((v) => v[props.rowKey]);
  props.data.forEach((v) => {
    if (selectionIds.indexOf(v[props.rowKey]) > -1) {
      nextTick(() => {
        table.value.toggleRowSelection(v, true);
      });
    }
  });
}; // 恢复选中

const selectionChange = (selection) => {
  if (!addSelectEvent.value) return; // 如果用户未监听select事件，则不执行

  if (!props.rowKey) throw Error("监听select事件时，row-key必须传入！");

  upAllSelection(selection);

  emit("select", allSelection.value);
}; // select事件
const upAllSelection = (selection) => {
  let rowIds = props.data.map((v) => v[props.rowKey]);
  let allSelection1 = [...allSelection.value];
  let selectionIds = allSelection1.map((v) => v[props.rowKey]);

  // 首先把当前页的选中全部移除
  selectionIds = selectionIds.filter((v) => rowIds.indexOf(v) === -1);

  // allSelection仅保留selectionIds存在的
  allSelection1 = allSelection1.filter((v) => selectionIds.indexOf(v[props.rowKey]) > -1);

  // 然后再加入当前页的选中
  allSelection1.push(...selection);

  allSelection.value = allSelection1;
}; // 更新当前全部被选中的数据
const clearSelection = () => {
  table.value.clearSelection();
  allSelection.value = [];
}; // 清空选中
const getRowInfo = (row, key) => {
  let currentIndex = -1;
  let parentRows = null;
  let propPath = "";
  let childrenKey = props.treeProps.children;
  let recursionItems = (items, prop) => {
    for (let i = 0; i < items.length; i++) {
      let item = items[i];

      propPath += `${i}.`;

      if (item[prop] === row[prop]) {
        currentIndex = i;
        parentRows = items;
        break;
      } else if (item[childrenKey] && item[childrenKey].length > 0) {
        propPath += `${childrenKey}.`;
        recursionItems(item[childrenKey], prop);
      }
    }
  };

  recursionItems(props.data, key, "");

  return {
    index: currentIndex,
    rows: parentRows,
    $_prop_path: propPath,
  };
};

defineExpose({
  clearSelection,
  getRowInfo,
});
</script>
