<template>
<div>
<el-table
:data="props.tableData"
v-loading="loading"
:border="props.border"
:header-cell-style="props.headerCellStyle"
:height="props.height"
empty-text="暂无数据"
@selection-change="handleSelectionChange"
:cell-style="cellStyle"
style="width: 100%"
:fit="true"
>
<el-table-column type="selection" width="55" v-if="mutiSelect" />
<el-table-column
v-for="(column, index) in props.columns"
:key="index"
:prop="column.prop"
:label="column.label"
:fixed="column.fixed"
:min-width="column.width || 'auto'"
:render-header="column.renderHeader"
align="center"
>
<template #default="{ row }">
<div class="cell-content">
<div v-if="column.render" class="flexAA">
<div
class="flexAB"
v-for="(rendered, subIndex) in Array.isArray(column.render(row)) ? column.render(row) : [column.render(row)]"
:key="subIndex"
>
<component :is="rendered" />
</div>
</div>
<div v-else>{{ row[column.prop] }}</div>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
background
layout="prev, pager, next"
:total="props.total"
:page-size="pageSize"
:current-page="currentPage"
@current-change="handlePageChange"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineEmits, defineProps, watch } from 'vue';
interface Column {
prop: string; // 字段名称
label: string; // 标题
fixed?: string; // 固定列
width?: any; // 列宽度
render?: (row: any) => any; // 渲染函数
renderHeader?: (h: any, context: { column: Column }) => any; // 表头渲染函数
}
interface Props {
columns: Column[];
tableData: Array<any>; // 表格数据
initialPage?: number;
pageSize?: number;
border?: boolean; // 是否显示边框
height?: string | number; // 表格高度
headerCellStyle?: object; // 表头样式
total: number; // 数据总数
mutiSelect: boolean;
}
const props = defineProps<Props>();
const emits = defineEmits(['selectChange', 'handlePageChange']);
const loading = ref(false);
const currentPage = ref<any>(props.initialPage ?? 1);
const pageSize = ref<any>(props.pageSize ?? 10);
const selectedRows = ref<any[]>([]);
const mutiSelect = ref(props.mutiSelect);
// 单元格样式
const cellStyle = {
textAlign: 'center'
};
const handlePageChange = (page: number) => {
currentPage.value = page;
emits('handlePageChange', page);
};
const handleSelectionChange = (selection: any[]) => {
selectedRows.value = selection;
emits('selectChange', selection);
};
watch(
() => props.initialPage,
page => {
currentPage.value = page;
}
);
</script>
<style scoped lang="less">
/* 添加组件的样式 */
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
/* 单元格内容居中 /
.cell-content {
display: inline-flex;
justify-content: center;
align-items: center;
padding: 10px;
word-break: break-all; / 确保长内容会换行 /
white-space: normal;
flex-wrap: wrap; / 允许内容换行 /
width: 100%; / 让单元格占满整个列 */
}
/deep/.el-table__inner-wrapper {
.el-table__header-wrapper {
.el-table__header {
.el-table__cell {
.cell {
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
}
/* Flex布局调整 */
.flexAA {
display: flex;
flex-direction: row;
}
.flexAB {
display: flex;
flex-direction: column;
}
</style>
使用
import TableWithPagination from '@/components/table/tabble.vue';
<TableWithPagination
:headerCellStyle="headerCellStyle"
:columns="columns"
:tableData="tableData"
:mutiSelect="false"
:initialPage="qform.page"
@handlePageChange="currentPage"
@selectChange="selectChange"
:border="false"
:total="total"
:height="getHeight"
></TableWithPagination>
const total = ref(0);
const getHeight = ref(window.innerHeight - 384); //计算高度
const tableData = ref([]);
const headerCellStyle = reactive({
'text-align': 'center',
background: '#F3F8FF',
height: '44px',
color: '#26355C',
'font-size': '14px',
'font-weight': '400',
'font-family': 'MyFontSourceHanSansMedium'
});
const columns = ref([
{ prop: 'instanceName', label: '代理名称' },
{
prop: 'openAt',
label: '购买时间',
render: (row: any) => [h('span', {}, dayjs(row.openAt).format('YYYY-MM-DD HH:mm'))]
},
{
prop: 'username',
label: '账号/密码',
width: '400',
renderHeader: () => {
return [
h('span', {}, '账号/密码'),
h(
ElTooltip,
{
content: '注意!使用翻译会导致数据信息展示错乱!',
placement: 'top'
},
{
default: () =>
h('img', {
src: '/images/cloudAgent4.png', // 替换为你的提示图标路径
alt: '提示',
style: 'width: 16px; height: 16px; margin-left: 5px; cursor: pointer;'
})
}
)
];
},
render: (row: any) => [h('span', {}, ${row.username}/${row.pwd || '-'}
)]
},
{
prop: 'flowTotal',
label: '购买流量',
render: (row: any) => [
h('img', {
src: '/images/flow.png',
alt: 'Image',
style: 'width: 16px; height: 16px; margin-right: 5px;'
}),
h('span', {}, ${row.flowTotal}
)
]
},
{
prop: 'endtime',
label: '状态',
render: (row: any) => [
h(
'span',
{
style: row.endTime * 1000 > dayjs().valueOf() ? 'color: green' : 'color: red'
},
row.endTime * 1000 > dayjs().valueOf() ? '正常' : '过期'
)
]
},
{
prop: 'endTime',
label: '到期时间',
render: (row: any) => [h('span', {}, dayjs(row.endTime * 1000).format('YYYY-MM-DD HH:mm'))]
}
]);