在开发后台管理系统中,经常会碰到合计行的需求,element有直接的属性可以使用,antdvue的需要手动去生成 

https://www.antdv.com/components/table-cn/#components-table-demo-summary

 如图为实现合计后的效果

        1。首先给table配置column的时候,要明确哪些字段需要使用合计,如上图,只有总板数需要使用合计,那给总板数的配置加上标识符 即可,我这里为了方便辨识,直接增加了 summary:true

{ title: '总板数', resizable: true, dataIndex: 'totalBoard', width: 150, align: 'center', ellipsis: true, summary: true },

        2.搭好基础结构,直接上代码

               2.1当需要合计时才去遍历表格数据使用reduce计算总合计数量

          <template #summary>
            <a-table-summary fixed>
              <a-table-summary-row>
                <a-table-summary-cell :index="0"> 合计</a-table-summary-cell>
                <a-table-summary-cell v-for="(item, index) in columns" :key="index" :index="1">
                // 当列配置了summary为true才合计
                  <template v-if="item?.summary">
                    <a-typography-text>
                     {{ dataSource.reduce((prev: number, next: : any }) => {
    return prev + next.totalBoard
  }, 0)}}
                    </a-typography-text>
                  </template>
                </a-table-summary-cell>
              </a-table-summary-row>
            </a-table-summary>
          </template>

                2.2代码优化

        当字段为动态时,并且模板里写太多ts语法看起来太臃肿,所以抽成计算属性更好维护

                

    // 模板
          <template #summary>
            <a-table-summary fixed>
              <a-table-summary-row>
                <a-table-summary-cell :index="0"> 合计</a-table-summary-cell>
                <a-table-summary-cell v-for="(item, index) in contentTableParam.columns" :key="index" :index="1">
                  <template v-if="item?.summary">
                    <a-typography-text>
                      {{ combinedNums(item.dataIndex) }}
                    </a-typography-text>
                  </template>
                </a-table-summary-cell>
              </a-table-summary-row>
            </a-table-summary>
          </template>



/**
 * @returns 计算合计行
 */
const combinedNums = computed(() => (field: any) => {
  return contentTableParam.dataSource.reduce((prev: number, next: { [x: string]: any }) => {
    return prev + next[field]
  }, 0)
})

组件抽取部分

首先组件封装思路:因为业务的表格涉及到部分表格开启了选择框,部分未开启,选择框会坐固定,所以要分两种情况来判断

1.组件需要接收的参数ts类型

import type { TablePaginationConfig } from 'ant-design-vue'
import type { Rule } from 'ant-design-vue/es/form'

export type ColumnType = {
  title: string // 标题
  dataIndex?: string // 列数据在数据项中对应的路径
  key?: string // Vue 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性
  resizable?: boolean // 	是否可拖动调整宽度,此时 width 必须是 number 类型
  width: number // 列宽度
  align?: string // 对齐方式
  ellipsis?: boolean // 超过宽度将自动省略
  sorter?: boolean // 开启排序
  sortDirections?: Array<string> // 支持的排序方式,取值为 'ascend' 'descend'
  summary?: boolean // 是否开启列合计
  fixed?: 'left' | 'right' // 对其方式
}

export type interContentTable = {
  name?: string // 使用Table排序必填
  isOper: boolean // table扩展项
  rowSelection?: boolean // 是否开启选择框
  rowSelectionType?: 'radio' | 'checkbox' // 是否开启选择框
  tableConfig?: boolean // table排序
  loading?: boolean
  rowKey: string // key
  isCalcHeight?: boolean // table高度自适应
  selectedRowKeys?: Array<string | number> // 选中key
  pagination?: TablePaginationConfig
  columns: ColumnType[]
  dataSource: Record<string, any>[]
}

2.组件template和ts代码 

<template>
  <!-- 如果开启了选择框,则遍历列 -->
  <template v-if="origin.rowSelection">
    <a-table-summary fixed>
      <a-table-summary-row>
        <a-table-summary-cell :index="0"> 合计</a-table-summary-cell>
        // 注意,因为table列的对齐方式可配置并且选择框默认占一列,所以这里的index一定要跟i+1相同才可以保证合计列和配置了对齐方式之后的列依然在一列上
        <a-table-summary-cell v-for="(item, index) in origin.columns" :key="item.dataIndex" :index="index + 1">
          <template v-if="item?.summary">
            <a-typography-text>
              {{ combinedNums(item.dataIndex).toFixed(3) }}
            </a-typography-text>
          </template>
        </a-table-summary-cell>
      </a-table-summary-row>
    </a-table-summary>
  </template>
  <!-- 如果未开启选择框,循环长度 -->
  <template v-if="!origin.rowSelection">
    <a-table-summary fixed>
      <a-table-summary-row>
        // 注意,因为table列的对齐方式可配置,所以 这里的index一定要跟i相同才可以保证合计列和配置了对齐方式之后的列依然在一列上
        <a-table-summary-cell :index="0"> 合计</a-table-summary-cell>
        <a-table-summary-cell v-for="i in origin.columns.length" :key="i" :index="i">
          <template v-if="origin.columns[i]?.summary">
            <a-typography-text>
              {{ combinedNums(origin.columns[i].dataIndex).toFixed(3) }}
            </a-typography-text>
          </template>
        </a-table-summary-cell>
      </a-table-summary-row>
    </a-table-summary>
  </template>
</template>

<script setup lang="ts">
import { interContentTable } from '@/type/interface/content'
import { withDefaults, computed } from 'vue'



interface propsType {
  origin: interContentTable
}

const _props = withDefaults(defineProps<propsType>(), {
  origin: () => ({ isOper: false, loading: false, rowKey: '', columns: [], dataSource: [] }),
})

/**
 * @returns 计算合计行
 */
const combinedNums = computed(() => (field: any) => {
  return _props.origin.dataSource.reduce((prev: number, next: { [x: string]: any }) => {
    return prev + Number(next[field])
  }, 0)
})
</script>

<style scoped lang="less"></style>

3.使用组件

<a-table>
    <template #summary>
        <TemplateSummary :origin="contentTableParam" />
    </template>
  </a-table>

<script setup lang="ts" name="goDownPlanList">
import { ref, reactive, getCurrentInstance, nextTick, computed, Ref, onActivated } from 'vue'
import TemplateSummary from '@/components/template-summary/index.vue'
import type { ColumnType } from '@/type/interface/content'

const contentTableParam = reactive({
  isOper: true,
  emptyText: true, // 是否自定义空数据展示
  rowSelection: true, // 选择框
  rowKey: 'id',
  columnWidth: 80,
  selectedRowKeys: [] as string[],
  name: 'GODOWNPLAN_LIST_MAIN',
  tableConfig: true, // 表单配置
  isCalcHeight: true, // 是否自动计算table高度
  loading: false,
  isSlotOption: ['summary'],
  pagination: {
    pageSize: 20,
    total: 0,
    current: 1,
  },
  scroll: {
    scrollToFirstRowOnChange: false,
    y: 300,
  },
  columns: [
    { title: '单号', dataIndex: 'planCode', resizable: true, width: 250, align: 'center', ellipsis: true },
    { title: '状态', resizable: true, key: 'statusName', dataIndex: 'statusName', width: 120, align: 'center', ellipsis: true },
    { title: '类型', resizable: true, dataIndex: 'typeName', width: 150, align: 'center', ellipsis: true },
    { title: '仓库', key: 'warehouse', dataIndex: 'warehouseCode', resizable: true, width: 200, align: 'center', ellipsis: true },
    { title: '货主', resizable: true, key: 'cargoOwner', dataIndex: 'cargoOwnerCode', width: 230, align: 'center', ellipsis: true },
    { title: '操作', key: 'operation', fixed: 'right', width: 150, align: 'center' },
  ] as ColumnType[],
  dataSource: [],
})
</script>

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐