template
<template>
<div :class="config?.style ? 'table-demo-fix' : 'table-demo'">
<div class="tableTitle" v-if='config?.headerName'>{{config.headerName}}</div>
<el-table
:class="config?.headerName?'':'ocTable'"
:data="data"
:border="setBorder"
v-bind="$attrs"
row-key="id"
stripe
:show-summary="config?.showSummary"
:height="config?.height"
style="width: 100%"
v-loading="config?.loading"
@selection-change="onSelectionChange"
:span-method="objectSpanMethod"
:row-class-name="tableRowClassName"
:summary-method="getSummaries"
>
<el-table-column type="selection" :reserve-selection="true" width="40" v-if="config?.isSelection" />
<el-table-column type="index" label="序号" width="60" v-if="config?.isSerialNo" :align="'center'" />
<el-table-column
v-for="(item, index) in header"
:key="index"
show-overflow-tooltip
:prop="item.key"
:width="item.colWidth"
:label="item.title"
:align="item.align || 'left'"
>
<template v-slot="scope">
<template v-if="item.type === 'image'">
<el-image
:style="{ width: `${item.width}px`, height: `${item.height}px` }"
:src="scope.row[item.key]"
:zoom-rate="1.2"
:preview-src-list="[scope.row[item.key]]"
preview-teleported
fit="cover"
/>
</template>
<template v-else-if="item.type === 'time'">
{{ formatDateTime(scope.row[item.key]) }}
</template>
<template v-else-if="item.type === 'select'">
<span v-if="!item.tagType">{{ filterName(item.options, scope.row[item.key], item.tag1, item.tag2) }}</span>
<el-tag v-else :type="item.tagType">{{ filterName(item.options, scope.row[item.key], item.tag1, item.tag2) }}</el-tag>
</template>
<!-- 自定义内容显示 type=='scope' -->
<template v-else-if="item.type === 'scope'">
<slot name="tableSlot" :tableSlotobj="scope.row" :key="item.key"></slot>
</template>
<!-- 添加第二个自定义插槽 -->
<template v-else-if="item.type === 'tabScope'">
<slot name="table" :tableSlotobj="scope.row" :key="item.key"></slot>
</template>
<!-- 自定义操作按钮 type=='btnScope' -->
<template v-else-if="item.type === 'btnScope'">
<slot name="btnSlot" :btnScopeObj="scope.row" :key="item.key" :item="item" :index="scope.$index"></slot>
</template>
<template v-else>
{{ scope.row[item.key] }}
</template>
</template>
</el-table-column>
<el-table-column
label="操作"
:width="config?.operate?.width"
v-if="config?.operate?.isOperate"
fixed="right"
:align="config?.operate?.align || 'center'"
class-name="toolClass"
>
<template
<template v-for="(item, index) in config?.operate?.btns" :key="index">
<el-button :type="item.type" text @click="btnClick(item, row)">
{{ item.title }}
</el-button>
</template>
</template>
</el-table-column>
<template
<el-empty description="暂无数据" />
</template>
</el-table>
<!-- config.total不写的时候 不显示分页 -->
<el-pagination
v-if="config?.total != null"
small
:current-page="state.page.pageNum"
:page-size="state.page.pageSize"
:pager-count="5"
:page-sizes="[10, 20, 30]"
:total="config.total"
layout="total, sizes, prev, pager, next, jumper"
background
@size-change="onHandleSizeChange"
@current-change="onHandleCurrentChange"
>
</el-pagination>
</div>
</template>
script
<script setup lang="ts" name="netxTable">
import '/@/theme/tableTool.scss'
import { formatDateTime } from '/@/utils/formatTime'
// 定义父组件传过来的值
const props = defineProps({
// 列表内容
data: {
type: Array<EmptyObjectType>,
default: () => [],
},
// 表头内容
header: {
type: Array<EmptyObjectType>,
default: () => [],
},
// 配置项
config: {
type: Object,
default: () => {},
},
})
// 定义变量内容
const state = reactive({
page: {
pageNum: 1,
pageSize: props.config?.params?.Count | 10,
},
})
const emit = defineEmits(['toolEvent', 'selectChange', 'pageChange', 'changePage','objectSpanMethod','getSummaries','tableRowClassName'])
// 监听分页变化
watch(
() => state.page,
() => {
let { pageNum, pageSize }: any = state.page
let Start = (pageNum - 1) * pageSize
let Count = pageSize
emit('changePage', { Start, Count })
},
{ deep: true}
)
// 设置边框显示/隐藏
const setBorder = computed(() => {
return props.config?.isBorder ? true : false
})
// 条数改变
const onHandleSizeChange = (val: number) => {
state.page.pageSize = val
}
// 页数改变
const onHandleCurrentChange = (val: number) => {
state.page.pageNum = val
}
// 选中
const onSelectionChange = (val: EmptyObjectType[]) => {
emit('selectChange', val)
}
//处理下拉回写数据
const filterName = (data: Array<EmptyObjectType>, row: String | Number | boolean, tag1: string, tag2: string) => {
let name = []
if (tag1 && tag2) {
name = data.filter((i: any) => {
return row == i[tag1]
})
if (name.length) {
return name[0][tag2]
} else {
return ''
}
} else {
name = data.filter((i: any) => {
return i.key == row
})
if (name.length) {
return name[0].value
} else {
return ''
}
}
}
//按钮事件
const btnClick = (item: any, row: any) => {
emit('toolEvent', item, row)
}
// 表格合并单元格
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }:any)=> {
emit('objectSpanMethod',{ row, column, rowIndex, columnIndex } )
}
// 合并行或列的计算方法合计
const getSummaries = (param:any) => {
emit('getSummaries',param )
return props.config?.summaryList
}
// table row更改颜色
const tableRowClassName = ({row, rowIndex}:any) => {
emit('tableRowClassName',{ row,rowIndex,} )
}
</script>
style
<style scoped lang="scss">
.table-demo {
height: calc(100% - 70px);
background:
:deep(.el-table--fit) {
height: calc(100% - 40px) !important;
.el-table__inner-wrapper {
min-height: calc(100% - 10px) !important;
}
}
.el-pagination {
background-color:
}
.ocTable {
margin-top: 10px;
}
.el-pagination {
float: right;
}
}
.tableTitle{
width: 100%;
height: 40px;
line-height: 40px;
font-size: 18px;
text-align: center;
font-weight: bold;
border: 1px solid rgb(235,238,245);
border-bottom: none;
color: rgb(144,147,153);
margin-top: 8px;
}
.table-demo-fix {
height: calc(100%);
background:
.el-pagination {
background-color:
}
.ocTable {
margin-top: 10px;
}
.el-pagination {
float: right;
}
}
</style>
父组件的使用
<template>
<div>
<Table ref="tableRef" v-bind="state.tableData" @toolEvent="toolEvent" @changePage="changePage">
<template
{{tableSlot.tableSlotobj.IsValidation ? tableSlot.tableSlotobj.IsCharges ? '直接放行' : '收取费用' : ''}}
</template>
<template
{{tableSlot.tableSlotobj.IsValidation ? tableSlot.tableSlotobj.IsCharges ? '' : tableSlot.tableSlotobj.IsRules ? '固定金额' : '阶梯金额' : ''}}
</template>
</Table>
</div>
</template>
<script lang="ts" setup>
const Table = defineAsyncComponent(() => import('/@/components/table/index.vue'))
const tableRef = ref()
const state = reactive({
tableData: {
// 列表数据(必传)
data: [],
// 表头内容(必传,注意格式)
header: [
{ key: 'Name', colWidth: '', title: '名称', type: 'text' },
{ key: 'IsValidation', colWidth: '', title: '是否验证', type: 'select',options: [{key: true,value:'是'},{key:false,value:'否'}] },
{ key: 'IsCharges', colWidth: '', title: '是否收费', type: 'scope'},
{ key: 'IsRules', colWidth: '', title: '规则', type: 'tabScope',options: [{key: null,value:''},{key: true,value:'固定金额'},{key:false,value:'阶梯金额'}] },
{ key: 'CreateTime', colWidth: '160', title: '创建时间', type: 'time' },
{ key: 'ModifiedTime', colWidth: '160', title: '最后一次修改时间', type: 'time' },
],
// 配置项(必传)
config: {
total: 0, // 列表总数
params: {
Count: 10, //结束页
Start: 0, //开始页
} as any,
loading: false, // loading 加载
isBorder: true, // 是否显示表格边框
isSerialNo: true, // 是否显示表格序号
isSelection: false, // 是否显示表格多选
style: false,
operate: {
isOperate: true, // 是否显示表格操作栏
btns: [
{
title: '编辑',
type: 'primary',
},
{
title: '删除',
type: 'danger',
},
],
},
},
},
})
const toolEvent = (item: any, row: any) => {
if (item.title == '编辑') {
onEdit(row)
} else {
onDelete(row)
}
}
const onEdit = (val: Object) => {
console.log("%c 🇸🇦: onEdit -> val ", "font-size:16px;background-color:#99b8fc;color:white;", val)
}
const onDelete = (row: any) => {
console.log("%c 🌽: onDelete -> row ", "font-size:16px;background-color:#d15a51;color:white;", row)
}
</script>