Files
xiaozhi-esp32-server/main/manager-web/src/components/CustomTable.vue
T

279 lines
6.3 KiB
Vue
Raw Normal View History

2026-06-15 15:44:09 +08:00
<template>
<div class="custom-table-wrapper">
<el-table
ref="tableRef"
:data="data"
:class="['custom-table', tableClass]"
height="100%"
v-loading="loading"
:element-loading-text="loadingText"
:element-loading-spinner="loadingSpinner"
:element-loading-background="loadingBackground"
:header-cell-class-name="headerCellClassName"
:row-class-name="rowClassName"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
>
<!-- 选择列 -->
<el-table-column
v-if="showSelection"
width="55"
align="center"
label="选择"
>
<template slot-scope="scope">
<slot
v-if="$scopedSlots.selection"
name="selection"
:row="scope.row"
:$index="scope.$index"
/>
<el-checkbox
v-else
:value="scope.row.selected"
@change="handleCheckboxChange(scope.row)"
/>
</template>
</el-table-column>
<!-- 动态列 -->
<el-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
:min-width="column.minWidth"
:align="column.align || 'center'"
:show-overflow-tooltip="column.showOverflowTooltip !== false"
>
<template slot-scope="scope">
<!-- 自定义插槽优先使用 column.slot 指定的插槽名否则用 column.prop 作为插槽名 -->
<slot
v-if="$scopedSlots[column.slot] || $scopedSlots[column.prop]"
:name="column.slot || column.prop"
:row="scope.row"
:$index="scope.$index"
:column="column"
/>
<!-- 默认显示 -->
<template v-else>
{{ scope.row[column.prop] }}
</template>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column
v-if="showOperations"
:label="operationsLabel"
align="center"
:width="operationsWidth"
>
<template slot-scope="scope">
<slot name="operations" :row="scope.row" :$index="scope.$index" />
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="table-footer">
<slot name="footer-btns"></slot>
<CustomPagination
v-if="showPagination"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
:page-size-options="pageSizeOptions"
@size-change="handleSizeChange"
@page-change="handlePageChange"
/>
</div>
</div>
</template>
<script>
import CustomPagination from './CustomPagination.vue';
export default {
name: 'CustomTable',
components: {
CustomPagination
},
props: {
// 表格数据
data: {
type: Array,
default: () => []
},
// 列配置
columns: {
type: Array,
default: () => []
},
// 是否显示选择框
showSelection: {
type: Boolean,
default: false
},
// 是否显示操作列
showOperations: {
type: Boolean,
default: false
},
operationsLabel: {
type: String,
default: '操作'
},
operationsWidth: {
type: [String, Number],
default: 180
},
// 分页相关
showPagination: {
type: Boolean,
default: true
},
total: {
type: Number,
default: 0
},
currentPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
},
pageSizeOptions: {
type: Array,
default: () => [10, 20, 50, 100]
},
// 加载状态
loading: {
type: Boolean,
default: false
},
loadingText: {
type: String,
default: 'Loading'
},
loadingSpinner: {
type: String,
default: 'el-icon-loading'
},
loadingBackground: {
type: String,
default: 'rgba(255, 255, 255, 0.7)'
},
// 自定义类名
tableClass: {
type: String,
default: ''
},
headerCellClassName: {
type: String,
default: ''
},
rowClassName: {
type: [String, Function],
default: ''
},
// 敏感值相关
hideText: {
type: String,
default: '隐藏'
},
viewText: {
type: String,
default: '查看'
}
},
methods: {
// 掩码处理
maskValue(value) {
if (!value) return '';
return '*'.repeat(Math.min(value.length, 8));
},
// 切换显示/隐藏
toggleValue(row, prop) {
this.$set(row, 'showValue', !row.showValue);
},
// 复选框变化
handleCheckboxChange(row) {
this.$set(row, 'selected', !row.selected);
},
// 分页事件
handleSizeChange(val) {
this.$emit('size-change', val);
},
handlePageChange(page) {
this.$emit('page-change', page);
},
// 选择事件
handleSelectionChange(selection) {
this.$emit('selection-change', selection);
},
// 行点击事件
handleRowClick(row, column, event) {
this.$emit('row-click', row, column, event);
},
// 获取表格实例
getTable() {
return this.$refs.tableRef;
},
// 清除选择
clearSelection() {
this.$refs.tableRef && this.$refs.tableRef.clearSelection();
},
// 切换选择
toggleRowSelection(row, selected) {
this.$refs.tableRef && this.$refs.tableRef.toggleRowSelection(row, selected);
}
}
};
</script>
<style lang="scss">
.custom-table-wrapper {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
overflow: hidden;
.custom-table {
width: 100%;
border: 1px solid #eef3fd;
border-bottom: none;
border-radius: 6px;
.el-table__body-wrapper {
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #a1c9fd;
border-radius: 3px;
}
&::-webkit-scrollbar-track {
background: #f0f3fe;
border-radius: 3px;
}
}
.el-table__header {
th {
color: #342f45;
background: #edf2fc !important;
}
}
}
}
.table-footer {
padding: 20px 0px 0px;
display: flex;
align-items: center;
justify-content: space-between;
}
</style>