el-table 数据去重后合并表尾合计行,金额千分位分割并保留两位小数,表尾合计行表格合并

时间:2024-11-19 11:27:18

问题背景

最近在做后台管理项目el-table 时候需要进行表尾合计修改合计后文字的样式合并单元格

想实现的效果

在这里插入图片描述

  1. 合并表尾单元格前三列为1格;
  2. 对某些指定的单元格进行表尾合计;
  3. 合计后的文本样式加粗;
  4. 涉及到金额需要千分位分割并保留两位小数;

涉及到的属性方法

先看下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合计行单元格合并、合并行金额四舍五入保留两位小数、合计行样式修改