Files
klp-oa/klp-ui/src/components/KLPUI/KLPTable/index.vue
2025-08-28 15:06:03 +08:00

209 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="my-table-container">
<!-- 扩展层可后续统一添加如加载动画导出按钮等 -->
<div v-if="loading" class="table-loading">
<el-loading-spinner></el-loading-spinner>
<p class="loading-text">{{ loadingText || "加载中..." }}</p>
</div>
<!-- 原生 Table 核心透传 props/事件/插槽 -->
<el-table
:ref="tableRef"
v-bind="$attrs"
v-on="$listeners"
:class="['my-table', customClass]"
>
<!-- 1. 透传列定义插槽原生 columns 中通过 slot 自定义的表头/单元格 -->
<template
v-for="(column, index) in $attrs.columns || []"
v-slot:[`header-${column.prop}`]="scope"
>
<!-- 调用业务层定义的表头插槽 -->
<slot :name="`header-${column.prop}`" v-bind="scope"></slot>
</template>
<template
v-for="(column, index) in $attrs.columns || []"
v-slot:[column.prop]="scope"
>
<!-- 调用业务层定义的单元格插槽 -->
<slot :name="column.prop" v-bind="scope"></slot>
</template>
<!-- 2. 透传原生内置插槽 empty 空数据插槽append 底部插槽等 -->
<template v-slot:empty="scope">
<slot name="empty" v-bind="scope"></slot>
</template>
<template v-slot:append="scope">
<slot name="append" v-bind="scope"></slot>
</template>
<!-- 3. 透传自定义列插槽业务层直接用 <el-table-column> 嵌套的情况 -->
<slot v-bind:tableRef="tableRef"></slot>
<el-table-column
v-if="selectionColumn"
type="selection"
width="55"
align="center"
></el-table-column>
<el-table-column
v-if="indexColumn"
type="index"
width="55"
align="center"
></el-table-column>
<el-table-column
v-for="(column, index) in customColumns"
v-bind="column"
:width="column.width"
:prop="column.prop"
:align="column.align"
:label="column.label"
:min-width="column.minWidth"
:fixed="column.fixed"
:show-overflow-tooltip="column.showOverflowTooltip"
:sortable="column.sortable"
>
<template v-slot="scope">
<ColumnRender v-if="column.render" :column="column" :data="scope.row" :render="column.render"/>
<Eclipse v-else-if="column.eclipse" :text="scope.row[column.prop]"></Eclipse>
<span v-else>{{ scope.row[column.prop] }}</span>
</template>
</el-table-column>
</el-table>
<!-- 扩展层可后续统一添加分页如与 MyPagination 组件联动 -->
<slot name="pagination"></slot>
</div>
</template>
<script>
import ColumnRender from './ColumnRender.vue';
import Eclipse from './renderer/eclipse.vue';
export default {
name: "KLPTable", // 组件名,便于调试和文档生成
components: {
ColumnRender,
Eclipse
},
props: {
// 1. 扩展 props新增原生 Table 没有的属性(如加载状态)
loading: {
type: Boolean,
default: false
},
loadingText: {
type: String,
default: "加载中..."
},
// 2. 兼容原生 class 用法(原生 el-table 支持 class 属性,此处显式接收避免 $attrs 冲突)
customClass: {
type: String,
default: ""
},
customColumns: {
type: Array,
default: () => []
},
selectionColumn: {
type: Boolean,
default: false
},
indexColumn: {
type: Boolean,
default: false
}
},
data() {
return {
tableRef: "myTableRef" // 表格 ref便于后续通过 ref 调用原生方法
};
},
methods: {
// 核心方法净化scope移除可能导致循环引用的属性
sanitizeScope(scope) {
if (!scope) return {};
// 只保留安全的属性(根据实际需求调整)
const { row, column, $index, store } = scope;
// 深拷贝避免引用传递,同时过滤循环引用
return this.deepClone({ row, column, $index, store });
},
// 安全的深拷贝方法避免JSON.parse/stringify无法处理的类型
deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 避免处理Vue实例通常带有循环引用
if (obj._isVue) return { _isVue: true };
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = this.deepClone(obj[key]);
}
}
return clone;
},
// 3. 透传原生 Table 实例方法(如 clearSelection、doLayout 等)
// 业务层可通过 this.$refs.myTable.xxx() 调用原生方法
getTableInstance() {
return this.$refs[this.tableRef];
},
// 示例:透传原生 clearSelection 方法
clearSelection() {
const table = this.getTableInstance();
if (table && table.clearSelection) {
table.clearSelection();
}
},
// 可根据需要扩展更多原生方法(如 toggleRowSelection、sort 等)
toggleRowSelection(row, selected) {
const table = this.getTableInstance();
if (table && table.toggleRowSelection) {
table.toggleRowSelection(row, selected);
}
}
},
mounted() {
// 扩展点:后续可统一添加初始化逻辑(如权限控制、默认排序等)
console.log("MyTable 初始化完成,原生实例:", this.getTableInstance());
}
};
</script>
<style scoped>
.my-table-container {
width: 100%;
position: relative;
}
/* 扩展样式:加载状态遮罩(后续可统一调整) */
.table-loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 10;
}
.loading-text {
margin-top: 12px;
color: #666;
font-size: 14px;
}
/* 原生 Table 样式兼容:避免封装层影响原生样式 */
.my-table {
width: 100%;
}
</style>