<script lang="ts" setup>
|
import { reactive, ref, computed, watch, nextTick, onBeforeMount, useAttrs } from 'vue'
|
import { ElTable, ElPagination } from 'element-plus-secondary'
|
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
|
import TableBody from './TableBody.vue'
|
import { propTypes } from '@/utils/propTypes'
|
import { useI18n } from '@/hooks/web/useI18n'
|
const { t } = useI18n()
|
const props = defineProps({
|
columns: propTypes.arrayOf(propTypes.string),
|
isSearch: propTypes.bool.def(false),
|
showPagination: propTypes.bool.def(true),
|
multipleSelection: propTypes.array.def(() => []),
|
pagination: propTypes.object,
|
isRememberSelected: propTypes.bool.def(false),
|
selectedFlags: propTypes.string.def('id'),
|
tableData: propTypes.array,
|
emptyDesc: propTypes.string,
|
emptyImg: propTypes.string,
|
border: propTypes.bool.def(false),
|
showEmptyImg: propTypes.bool.def(true),
|
dataLoading: propTypes.bool.def(false)
|
})
|
|
const attrs = useAttrs()
|
|
const handleListeners = () => {
|
Object.keys(attrs).forEach(key => {
|
if (key.startsWith('on')) {
|
if (['onSizeChange', 'onCurrentChange'].includes(key)) {
|
state.paginationEvent[key.slice(2)] = attrs[key]
|
} else {
|
state.tableEvent[key.slice(2)] = attrs[key]
|
}
|
} else {
|
state.tableAttrs[key] = attrs[key]
|
}
|
})
|
}
|
const toggleRowSelection = row => {
|
table.value.toggleRowSelection(row, true)
|
}
|
const toggleAllSelection = () => {
|
table.value.toggleAllSelection()
|
}
|
const clearSelection = () => {
|
table.value.clearSelection()
|
}
|
const handlerSelected = multipleSelection => {
|
state.multipleSelectionCache = [...state.multipleSelectionCache, ...multipleSelection]
|
const flags = state.multipleSelectionCache.map(ele => ele[props.selectedFlags])
|
// 当前页的选中项索引
|
const notCurrentArr = []
|
props.tableData.forEach(ele => {
|
const resultIndex = flags.indexOf(ele[props.selectedFlags])
|
if (resultIndex !== -1) {
|
table.value.toggleRowSelection(ele, true)
|
notCurrentArr.push(resultIndex)
|
}
|
})
|
notCurrentArr.sort().reduceRight((_, next) => {
|
state.multipleSelectionCache.splice(next, 1)
|
}, 0)
|
}
|
|
onBeforeMount(() => {
|
handleListeners()
|
})
|
|
const state = reactive({
|
paginationEvent: {},
|
paginationDefault: {
|
currentPage: 1,
|
pageSizes: [10, 20, 50, 100],
|
pageSize: 10,
|
layout: 'total, prev, pager, next, sizes, jumper',
|
total: 0
|
},
|
multipleSelectionCache: [],
|
tableEvent: {},
|
tableAttrs: {}
|
})
|
|
const imgType = computed(() => {
|
return props.emptyImg ? props.emptyImg : props.isSearch ? 'tree' : 'noneWhite'
|
})
|
const table = ref(null)
|
|
const multipleSelectionAll = computed(() => [
|
...state.multipleSelectionCache,
|
...props.multipleSelection
|
])
|
watch(
|
props.pagination,
|
() => {
|
state.paginationDefault = {
|
...state.paginationDefault,
|
...props.pagination
|
}
|
},
|
{ deep: true, immediate: true }
|
)
|
|
watch(
|
props.tableData,
|
() => {
|
nextTick(() => {
|
table.value.doLayout()
|
})
|
if (!props.isRememberSelected) return
|
// 先拷贝 重新加载数据会触发SelectionChange 导致this.multipleSelection为空
|
const multipleSelection = [...props.multipleSelection]
|
nextTick(() => {
|
handlerSelected(multipleSelection)
|
})
|
},
|
{ deep: true }
|
)
|
defineExpose({
|
toggleRowSelection,
|
clearSelection,
|
toggleAllSelection,
|
multipleSelectionAll
|
})
|
</script>
|
|
<template>
|
<div class="flex-table" :class="!tableData.length && 'no-data'">
|
<el-table
|
ref="table"
|
:border="border"
|
v-bind="state.tableAttrs"
|
:data="tableData"
|
:style="{ width: '100%', height: '100%' }"
|
v-on="state.tableEvent"
|
v-loading="props.dataLoading"
|
>
|
<table-body :columns="columns">
|
<slot />
|
</table-body>
|
<template #empty>
|
<empty-background
|
v-if="props.showEmptyImg"
|
:description="props.emptyDesc ? props.emptyDesc : t('data_set.no_data')"
|
:img-type="imgType || 'noneWhite'"
|
/>
|
<div v-else :style="{ width: '100%' }" />
|
</template>
|
</el-table>
|
<div v-if="showPagination && !!tableData.length" class="pagination-cont">
|
<el-pagination
|
v-model:current-page="state.paginationDefault.currentPage"
|
v-model:page-size="state.paginationDefault.pageSize"
|
background
|
v-bind="state.paginationDefault"
|
v-on="state.paginationEvent"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<style lang="less" scoped>
|
.flex-table {
|
display: flex;
|
height: 100%;
|
flex-direction: column;
|
justify-content: space-between;
|
.pagination-cont {
|
display: flex;
|
justify-content: flex-end;
|
margin-top: 10px;
|
}
|
|
&.no-data {
|
:deep(.ed-table__inner-wrapper::before) {
|
display: none;
|
}
|
}
|
}
|
</style>
|