<template>
    <el-table
        class="pro-table"
        ref="tableRef"
        v-loading="loading"
        :data="tableData"
        :row-key="rowKey"
        :row-class-name="({ row }) => row[rowKey]"
        :max-height="maxHeight"
        @selection-change="selectionChange"
    >
        <slot />
        <template v-for="item in tableColumns" :key="item">
            <el-table-column v-if="item.type && columnTypes.includes(item.type)" v-bind="item"></el-table-column>
            <TableColumn v-if="!item.type && item.prop" :column="item">
                <template v-for="slot in Object.keys($slots)" #[slot]="scope">
                    <slot :name="slot" v-bind="scope" />
                </template>
            </TableColumn>
        </template>
    </el-table>
</template>

<script setup name="ProTable">
import { provide, reactive, ref, unref } from 'vue'
import TableColumn from './components/TableColumn.vue'
import useSelection from '@/hooks/useSelection'

const props = defineProps({
    columns: {
        type: Array,
        default: () => []
    },
    tableData: {
        type: Array,
        default: () => []
    },
    loading: {
        type: Boolean,
        default: false
    },
    maxHeight: {
        type: [Number, String],
        default: ''
    },
    rowKey: {
        type: String,
        default: 'id'
    }
})

const { isSelected, selectedList, selectedListIds, selectionChange } = useSelection(props.rowKey)

const columnTypes = ['selection', 'radio', 'index', 'expand', 'sort']
const tableRef = ref()
const enumMap = ref(new Map())
const tableColumns = reactive(props.columns)

// 扁平化 columns
const flatColumnsFunc = columns => {
    columns.forEach(async column => {
        // 设置enumMap
        await setEnumMap(column)
    })
}
// 定义 enumMap 存储 enum 值
const setEnumMap = async ({ prop, enum: enumValue }) => {
    if (!enumValue) return

    // 如果当前 enumMap 存在相同的值 return
    if (enumMap.value.has(prop) && (typeof enumValue === 'function' || enumMap.value.get(prop) === enumValue)) return

    // 当前 enum 为静态数据，则直接存储到 enumMap
    if (typeof enumValue !== 'function') return enumMap.value.set(prop, unref(enumValue))

    // 为了防止接口执行慢，而存储慢，导致重复请求，所以预先存储为[]，接口返回后再二次存储
    enumMap.value.set(prop, [])

    // 当前 enum 为后台数据需要请求数据，则调用该请求接口，并存储到 enumMap
    const { rows } = await enumValue()
    enumMap.value.set(prop, rows)
}

flatColumnsFunc(tableColumns)

provide('enumMap', enumMap)

defineExpose({
    tableRef,
    isSelected,
    selectedList,
    selectedListIds
})
</script>

<style lang="scss" scoped>
.pro-table {
    :deep(.el-table__header) {
        width: 100% !important;
    }
    :deep(.el-table__body) {
        width: 100% !important;
    }
}
</style>
