2022-01-05 12:20:16 +08:00

172 lines
4.0 KiB
Vue

<template>
<div v-loading="loading" class="pro-table">
<div class="header">
<div class="action-container">
<el-button
v-if="props.createText"
type="primary"
size="mini"
:icon="Plus"
@click="onCreate"
>
{{ props.createText }}
</el-button>
</div>
</div>
<el-table :data="displayTableData" v-bind="$attrs">
<slot></slot>
</el-table>
<el-config-provider :locale="zhCn">
<el-pagination
v-if="paginationInfo.showPagination"
class="pagination"
:current-page="paginationInfo.currentPage"
layout="total, jumper, prev, pager, next, sizes"
:page-size="paginationInfo.pageSize"
:total="paginationInfo.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</el-config-provider>
</div>
</template>
<script setup lang="ts">
import { defineProps, withDefaults, provide, ref } from 'vue'
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
import { Plus } from '@element-plus/icons-vue'
import {
ITableDataItem,
IPaginationInfo,
IOnCreated,
} from '~/interfaces/proTable'
import {
DELETE_ROW,
UPDATE_ROW,
PAGINATION_INFO,
CREATE_ROW,
} from '~/constants/proTable'
import { HandleProTableData } from '~/tools/proTable'
interface Props {
request: () => Promise<{ data: ITableDataItem[] }>
// 分页
showPagination?: boolean
currentPage?: number
pageSize?: number
pageSizes?: number[]
// header
createText?: string
}
const props = withDefaults(defineProps<Props>(), {
currentPage: 1,
pageSize: 10,
pageSizes: () => [10, 20, 30, 40, 50, 100],
showPagination: true,
})
const emit = defineEmits(['onCreated'])
// 分页
const paginationInfo = ref<IPaginationInfo>({
currentPage: props.currentPage,
pageSize: props.pageSize,
pageSizes: props.pageSizes,
showPagination: props.showPagination,
total: 0,
})
const handleSizeChange = (val: number) => {
paginationInfo.value.pageSize = val
updateTheView()
}
const handleCurrentChange = (val: number) => {
paginationInfo.value.currentPage = val
updateTheView()
}
// 数据获取
const tableData = ref<ITableDataItem[]>([])
const displayTableData = ref<ITableDataItem[]>(tableData.value)
const loading = ref(false)
async function getData() {
try {
loading.value = true
const { data } = await props.request()
tableData.value = data
paginationInfo.value.total = tableData.value?.length
updateTheView()
loading.value = false
} catch (e) {
loading.value = false
console.log((e as Error).message)
}
}
onMounted(async () => {
await getData()
})
const updateTheView = () => {
if (!paginationInfo.value?.showPagination) {
displayTableData.value = tableData.value
}
const { currentPage, pageSize } = paginationInfo.value
const pageStart: number = (currentPage - 1) * pageSize
displayTableData.value = tableData.value.slice(
pageStart,
pageStart + pageSize,
)
paginationInfo.value.total = tableData.value.length
}
const handleTable = computed(() => {
return new HandleProTableData(updateTheView, tableData)
})
const onCreate = () => {
emit('onCreated', handleTable.value.createRow)
}
// 暴漏给给父组件用的方法
defineExpose({
paginationInfo,
...handleTable.value,
})
// 发送给后代组件使用
provide(PAGINATION_INFO, paginationInfo)
provide(UPDATE_ROW, handleTable.value.updatedRow)
provide(DELETE_ROW, handleTable.value.deleteRow)
provide(CREATE_ROW, handleTable.value.createRow)
</script>
<style scoped lang="scss">
.pro-table {
width: 100%;
.header {
margin-bottom: 8px;
}
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 15px;
$marginLeft: 15px;
::v-deep(.btn-prev) {
margin-left: $marginLeft !important;
}
::v-deep(.el-input) {
margin-left: $marginLeft !important;
}
::v-deep(.el-pager li) {
margin: 0 2px;
}
}
}
</style>