134 lines
3.7 KiB
Vue
134 lines
3.7 KiB
Vue
<template>
|
||
<div class="base-table">
|
||
<el-table
|
||
v-bind="$attrs"
|
||
:data="data"
|
||
border
|
||
stripe
|
||
v-loading="loading"
|
||
header-cell-class-name="table-header-gray"
|
||
>
|
||
<template v-for="col in visibleColumns" :key="col.prop">
|
||
|
||
<el-table-column
|
||
v-if="!col.slot"
|
||
v-bind="col"
|
||
:prop="col.prop"
|
||
:label="col.label"
|
||
:min-width="col.minWidth || '120'"
|
||
:width="col.width"
|
||
:fixed="col.fixed"
|
||
show-overflow-tooltip
|
||
/>
|
||
|
||
<el-table-column
|
||
v-else
|
||
v-bind="col"
|
||
:prop="col.prop"
|
||
:label="col.label"
|
||
:min-width="col.minWidth || '120'"
|
||
:width="col.width"
|
||
:fixed="col.fixed"
|
||
>
|
||
<template #default="scope">
|
||
<slot :name="col.prop" :row="scope.row" :index="scope.$index"></slot>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
</template>
|
||
|
||
<template #empty>
|
||
<el-empty description="暂无数据" />
|
||
</template>
|
||
</el-table>
|
||
|
||
<div v-if="showPagination" class="pagination-container">
|
||
<el-pagination
|
||
v-bind="paginationConfig"
|
||
v-model:current-page="localPage"
|
||
v-model:page-size="localLimit"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref, watch } from 'vue'
|
||
import { usePermissionStore } from '@/stores/permission'
|
||
|
||
// --- Props 定义 ---
|
||
const props = defineProps({
|
||
// 数据源
|
||
data: { type: Array, default: () => [] },
|
||
// 列配置 (核心)
|
||
columns: { type: Array as () => any[], required: true },
|
||
// 页面编码 (用于权限隔离,如果列名全局唯一可不传,但建议传)
|
||
pageCode: { type: String, default: '' },
|
||
|
||
loading: { type: Boolean, default: false },
|
||
total: { type: Number, default: 0 },
|
||
showPagination: { type: Boolean, default: true },
|
||
page: { type: Number, default: 1 },
|
||
limit: { type: Number, default: 10 }
|
||
})
|
||
|
||
const emit = defineEmits(['update:page', 'update:limit', 'pagination'])
|
||
|
||
const permStore = usePermissionStore()
|
||
|
||
// --- 核心逻辑:计算当前可见的列 ---
|
||
const visibleColumns = computed(() => {
|
||
return props.columns.filter(col => {
|
||
// 1. 获取该列在数据库中对应的 code
|
||
// 如果列配置里显式写了 code,就用写的;如果没有,默认认为 prop 就是 code
|
||
const permissionKey = col.code || col.prop
|
||
|
||
// 2. 如果这个列不需要权限控制 (比如序号 index),可以在配置里加个 ignoreAuth: true
|
||
if (col.ignoreAuth) return true
|
||
|
||
// 3. 问 Store:我有这个权限吗?
|
||
// 注意:我们在 PermissionStore 里存的是全局唯一的 code
|
||
return permStore.hasColumnPermission(props.pageCode, permissionKey)
|
||
})
|
||
})
|
||
|
||
// --- 分页逻辑处理 ---
|
||
const localPage = ref(props.page)
|
||
const localLimit = ref(props.limit)
|
||
|
||
watch(() => props.page, (val) => localPage.value = val)
|
||
watch(() => props.limit, (val) => localLimit.value = val)
|
||
|
||
const handleSizeChange = (val: number) => {
|
||
emit('update:limit', val)
|
||
emit('pagination', { page: localPage.value, limit: val })
|
||
}
|
||
|
||
const handleCurrentChange = (val: number) => {
|
||
emit('update:page', val)
|
||
emit('pagination', { page: val, limit: localLimit.value })
|
||
}
|
||
|
||
const paginationConfig = {
|
||
pageSizes: [10, 20, 50, 100],
|
||
background: true
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.pagination-container {
|
||
margin-top: 15px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
:deep(.table-header-gray th) {
|
||
background-color: #f8f9fb !important;
|
||
color: #606266;
|
||
font-weight: 600;
|
||
height: 45px;
|
||
}
|
||
</style> |