<template>
|
<div class="h100 flex f-d-c cur-table-box" v-loading="loading" element-loading-background="rgba(46, 81, 136, 0.9)">
|
<div class="h0 flex-1 table-content" ref="TableContent">
|
<el-table empty-text="暂无数据" ref="tableData" :height="tableHeight" :row-key="rowKey" :border="border"
|
:size="tableSize" :data="data" @selection-change="handleSelectionChange"
|
@current-change="handleTableCurrentChange" @row-click="handleTableRowClick" @sort-change="handleSortChange"
|
v-bind="otherConfig">
|
<template v-for="(item, index) in columns">
|
<!-- 选择框 -->
|
<el-table-column v-if="item.selection" type="selection" width="36" :fixed="item.fixed"
|
:reserve-selection="reserveSelection" align="center" header-align="center"
|
:key="`selection_${index}`"></el-table-column>
|
<!-- 自定义单选框 -->
|
<el-table-column v-else-if="item.singleSelection" width="50" :fixed="item.fixed" align="center"
|
header-align="center" :key="`singleSelection_${index}`">
|
<template slot-scope="scope">
|
<el-checkbox v-model="scope.row.isSingleSelected"
|
@change="handleSingleSelectionChange(scope.row)"></el-checkbox>
|
</template>
|
</el-table-column>
|
<!-- 序号 -->
|
<el-table-column v-else-if="item.index" align="center" type="index" width="48" :fixed="item.fixed" label="序号"
|
:index="item.indexMethod || indexMethod" :key="`index_${index}`"></el-table-column>
|
<!-- 多级表头 -->
|
<el-table-column v-else-if="item.multi" align="center" :label="item.label" :key="`multi_${index}`">
|
<el-table-column v-for="(child, childIndex) in item.children" :key="`child_${index}_${childIndex}`"
|
v-bind="child">
|
</el-table-column>
|
</el-table-column>
|
<!-- 自定义内容 -->
|
<slot v-else-if="item.slot" :name="item.slot"></slot>
|
|
<el-table-column v-else-if="item.sortable" sortable="custom" align="center" show-overflow-tooltip
|
v-bind="item" :fixed="item.fixed" :width="item.width" :key="`normal_sort${index}`"
|
:render-header="tableRenderHeader"></el-table-column>
|
<!-- 常规字段 -->
|
<el-table-column v-else align="center" show-overflow-tooltip v-bind="item" :fixed="item.fixed"
|
:width="item.width" :key="`normal_${index}`" :render-header="tableRenderHeader"></el-table-column>
|
</template>
|
</el-table>
|
</div>
|
|
<div v-show="isPaginationShow && pagination.total" class="pagination-content">
|
<el-pagination background :page-sizes="[10, 20, 50, 100]" layout="prev, pager, next" :pager-count="5"
|
:current-page.sync="pagination.current" :page-size="pagination.size" :total="pagination.total"
|
@size-change="handleSizeChange" @current-change="handleCurrentChange">
|
</el-pagination>
|
</div>
|
<!-- 自定义内容 -->
|
<slot name="custom-content"></slot>
|
</div>
|
</template>
|
|
|
<script setup>
|
import { onMounted, onUnmounted } from 'vue'
|
const emit = defineEmits(['getData', 'changeSelection', 'changeCurrent', 'changeSingleSelection', 'rowClick', 'changeSort'])
|
|
const { columns, data, pagination, } = defineProps({
|
columns: {
|
type: Array,
|
default: () => [],
|
},
|
data: {
|
type: Array,
|
default: () => [],
|
},
|
pagination: {
|
type: Object,
|
default: () => ({
|
current: 1,
|
size: 10,
|
total: 0,
|
}),
|
},
|
isPaginationShow: {
|
type: Boolean,
|
default: true,
|
},
|
tableSize: {
|
type: String,
|
default: 'small',
|
},
|
border: {
|
type: Boolean,
|
default: false
|
},
|
otherConfig: {
|
type: Object,
|
default: () => { },
|
},
|
loading: {
|
type: Boolean,
|
default: false,
|
},
|
// 支持跨页选择的两个配置项
|
rowKey: {
|
type: String,
|
default: ''
|
},
|
reserveSelection: {
|
type: Boolean,
|
default: false
|
}
|
})
|
|
const tableHeight = ref(0)
|
const TableContent = ref(null)
|
const tableData = ref(null)
|
|
onMounted(() => {
|
window.addEventListener('resize', this.handleWindowResize)
|
})
|
|
onUnmounted(() => {
|
window.removeEventListener('resize', this.handleWindowResize)
|
})
|
|
watch(
|
() => data,
|
(newData) => {
|
if (newData) {
|
nextTick(() => {
|
handleWindowResize()
|
})
|
}
|
}
|
)
|
|
watch(
|
() => columns,
|
(newColumns) => {
|
if (newColumns && newColumns.length) {
|
nextTick(() => {
|
tableData.value.doLayout()
|
})
|
}
|
},
|
{ deep: true }
|
)
|
|
// 切换页码
|
const handleCurrentChange = () => {
|
emit('getData')
|
},
|
// 切换每页条数
|
const handleSizeChange = (value) => {
|
pagination.size = value
|
emit('getData')
|
}
|
|
// 切换选择
|
const handleSelectionChange = (val) => {
|
emit('changeSelection', val)
|
}
|
// 单选
|
const handleTableCurrentChange = (currentRow) => {
|
emit('changeCurrent', currentRow)
|
}
|
// 自定义单选
|
const handleSingleSelectionChange = (currentRow) => {
|
emit('changeSingleSelection', currentRow)
|
}
|
// 点击行
|
const handleTableRowClick = (currentRow) => {
|
emit('rowClick', currentRow)
|
}
|
// 排序
|
const handleSortChange = (val) => {
|
emit('changeSort', val)
|
}
|
// 自定义表头渲染方法
|
const tableRenderHeader = (h, { column }) => {
|
const span = document.createElement('span')
|
span.innerText = column.label
|
document.body.appendChild(span)
|
const realWidth = span.getBoundingClientRect().width
|
let columnWidth = realWidth + 22 // 22: 左右padding 10*2 + border预留 2
|
if (column.sortable === 'custom') columnWidth += 30
|
column.minWidth = columnWidth
|
document.body.removeChild(span)
|
return h('span', column.label)
|
}
|
// 序号列自定义方法
|
const indexMethod = (index) => {
|
const { current, size } = this.pagination
|
return (current - 1) * size + index + 1
|
}
|
// 页面缩放重新计算 table高度
|
const handleWindowResize = () => {
|
tableHeight = TableContent.offsetHeight
|
}
|
</script>
|
|
<script>
|
export default {
|
name: 'GlobalTable'
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.cur-table-box {
|
::-webkit-scrollbar {
|
width: 6px;
|
height: 6px;
|
background-color: none;
|
}
|
|
::-webkit-scrollbar-thumb {
|
background: #4ACFFF;
|
border-radius: 3px;
|
}
|
|
::-webkit-scrollbar-track {
|
background: #1D486E;
|
}
|
}
|
|
.table-content {
|
::v-deep(.el-table) {
|
&::before {
|
content: none;
|
}
|
|
background: transparent !important;
|
border: none;
|
|
.el-table__header-wrapper {
|
tr {
|
height: 38px;
|
background: rgba(35, 53, 92, 0.8) !important;
|
box-sizing: border-box;
|
|
th {
|
background: transparent !important;
|
border-bottom: 1px solid rgba(103, 135, 214, 1);
|
|
.cell {
|
color: #AFBED8;
|
}
|
}
|
}
|
}
|
|
.el-table__body-wrapper {
|
table {
|
border-collapse: separate !important;
|
border-spacing: 0 10px !important;
|
}
|
|
tr {
|
height: 38px;
|
background: rgba(36, 57, 110, 0.2);
|
box-sizing: border-box;
|
cursor: pointer;
|
|
&:hover {
|
td {
|
color: #44C1EF;
|
background: transparent !important;
|
}
|
}
|
|
td {
|
padding: 0;
|
height: 38px;
|
line-height: 38px;
|
color: #D4E8F8;
|
border-top: 1px solid rgba(110, 135, 197, 0.32);
|
border-bottom: 1px solid rgba(110, 135, 197, 0.32);
|
box-sizing: border-box;
|
}
|
|
td:first-child {
|
border-left: 1px solid rgba(110, 135, 197, 0.32);
|
}
|
|
td:last-child {
|
border-right: 1px solid rgba(110, 135, 197, 0.32);
|
}
|
}
|
}
|
|
.el-table__empty-block {
|
background: rgba(36, 57, 110, 0.2);
|
|
.el-table__empty-text {
|
color: #D4E8F8;
|
}
|
}
|
}
|
}
|
|
.pagination-content {
|
margin: 10px 0;
|
color: #D4E8F8;
|
|
::v-deep(.el-pagination) {
|
.el-pagination__total {
|
color: #D4E8F8;
|
}
|
|
.btn-prev,
|
.btn-next {
|
color: rgba(216, 235, 238, 0.8) !important;
|
background: rgba(68, 193, 239, 0.1);
|
}
|
|
.el-pager {
|
|
.btn-quickprev,
|
.btn-quicknext,
|
.number {
|
color: rgba(216, 235, 238, 0.8) !important;
|
background: rgba(68, 193, 239, 0.1);
|
}
|
|
.active {
|
color: #FFFFFF;
|
background: #44C1EF !important;
|
opacity: 0.8;
|
}
|
}
|
}
|
}
|
</style>
|