问题背景
最近在做后台管理项目el-table 时候需要进行表尾合计
,修改合计后文字的样式
,合并单元格
。
想实现的效果
- 合并表尾单元格前三列为1格;
- 对某些指定的单元格进行表尾合计;
- 合计后的文本样式加粗;
- 涉及到金额需要千分位分割并保留两位小数;
涉及到的属性方法
先看下element-plus 中关于 el-table
中能实现上面效果涉及到的属性和方法。
<el-table
ref="tableRef"
:show-summary="true"
:summary-method="getSummaries"
:span-method="spanMethod"
>
</el-table>
- show-summary: 是否在表尾显示合计行;
- summary-method:自定义的合计计算方法;
- span-method:合并行或列的计算方法;
el-table表尾合计行 官方文档
表尾合计
对某些指定的单元格进行表尾合计;涉及到金额需要千分位分割并保留两位小数;
<script setup lang="ts">
import { ref, unref, reactive, onMounted } from 'vue'
import type { TableColumnCtx } from 'element-plus'
// 模拟接口返回的数据
const data = [
{ blocCustNm: 'A', blocLmt: 600, totLnchAmt: 10, totBsnBal: 20, aprvAmt: 30, lnchAmt: 40, bsnBal: 50 },
{ blocCustNm: 'B', blocLmt: 200, totLnchAmt: 20, totBsnBal: 30, aprvAmt: 40, lnchAmt: 50, bsnBal: 60 },
{ blocCustNm: '', blocLmt: 300, totLnchAmt: 30, totBsnBal: 40, aprvAmt: 50, lnchAmt: 60, bsnBal: 70 }, // blocCustNm为空
{ blocCustNm: '', blocLmt: 200, totLnchAmt: 30, totBsnBal: 40, aprvAmt: 50, lnchAmt: 60, bsnBal: 70 }, // blocCustNm为空
{ blocCustNm: 'A', blocLmt: 400, totLnchAmt: 40, totBsnBal: 50, aprvAmt: 60, lnchAmt: 70, bsnBal: 80 }, // blocCustNm重复
{ blocCustNm: 'C', blocLmt: 500, totLnchAmt: 50, totBsnBal: 60, aprvAmt: 70, lnchAmt: 80, bsnBal: 90 }
]
// 千分位分割,保留小数
function toFixedThousandFilter(num:undefined|number|string, fixed = 2) {
if (num === undefined || num === 'undefined' || num === null || num === 'null') return ''
return (null || 0).toFixed(fixed).replace(/^-?\d+/g, (m) => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}
interface Product{
blocLmt:string // 集团额度(万元)
totLnchAmt:string // 总投放金额(万元)
totBsnBal:string // 总业务余额(万元)
aprvAmt:string // 审批金额(万元)
lnchAmt:string // 投放金额(万元)
bsnBal:string // 业务余额(万元)
}
interface SummaryMethodProps<T = Product> {
columns: TableColumnCtx<T>[]
data: T[]
}
const getSummaries = (param: SummaryMethodProps) => {
const { columns, data } = param
const sums:string[] = []
const uniqueBlocCustNm = new Set<string>() // 存储已经处理过的blocCustNm,避免重复计算同个集团客户
const sumArr = ['totLnchAmt', 'totBsnBal', 'aprvAmt', 'lnchAmt', 'bsnBal'] // 只对接口返回的这几个字段进行表尾合计
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
} else if (column.property === 'blocLmt') {
let blocLmtSum = 0 // 集团额度总额
data.filter((item: anyObj) => {
if (!item.blocCustNm || !uniqueBlocCustNm.has(item.blocCustNm)) {
blocLmtSum += Number(item[column.property])
if (item.blocCustNm) {
uniqueBlocCustNm.add(item.blocCustNm)
}
}
})
sums[index] = toFixedThousandFilter(blocLmtSum)
} else if (sumArr.includes(column.property)) {
const values = data.map((item: anyObj) => Number(item[column.property]))
sums[index] = getTotalSum(values)
}
})
return sums
}
//封装公共累加方法
const getTotalSum = (values:number[]):string => {
if (values.every((value) => Number.isNaN(value))) {
return '-'
}
const total = values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)
return toFixedThousandFilter(total)
}
</script>
合并表尾单元格前三列为1格
// 合并前三列单元格
const tableRef = ref()
const spanMethod = () => {
const current = tableRef.value.$el.querySelector('.el-table__footer-wrapper').querySelector('.el-table__footer')
const cell = current.rows[0].cells
cell[0].style.textAlign = 'center' // 合计行第一列字段居中显示
cell[1].style.display = 'none'
cell[2].style.display = 'none' // 隐藏被合并的单元格,不隐藏的话会占位。
cell[0].colSpan = '3' // 合并单元格
return [1, 1] // 其它单元格按默认显示
}
参考:el-table合计行单元格合并、合并行金额四舍五入保留两位小数、合计行样式修改