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>
|