diff --git a/mock/demo/table-demo.ts b/mock/demo/table-demo.ts
index fbb51f6..082e021 100644
--- a/mock/demo/table-demo.ts
+++ b/mock/demo/table-demo.ts
@@ -30,6 +30,8 @@ const demoList = (() => {
avatar: Random.image('400x400', Random.color(), Random.color(), Random.first()),
imgArr: getRandomPics(Math.ceil(Math.random() * 3) + 1),
imgs: getRandomPics(Math.ceil(Math.random() * 3) + 1),
+ age: Math.ceil(Math.random() * 3) + 1,
+ score: Math.ceil(Math.random() * 80) + 1,
date: `@date('yyyy-MM-dd')`,
time: `@time('HH:mm')`,
'no|100000-10000000': 100000,
diff --git a/src/components/Table/src/BasicTable.vue b/src/components/Table/src/BasicTable.vue
index 58da9a9..00fdc45 100644
--- a/src/components/Table/src/BasicTable.vue
+++ b/src/components/Table/src/BasicTable.vue
@@ -41,6 +41,11 @@
+
+
+
+
+
@@ -55,6 +60,7 @@
import CustomSelectHeader from './components/CustomSelectHeader.vue'
import expandIcon from './components/ExpandIcon';
import HeaderCell from './components/HeaderCell.vue';
+ import TableSummary from './components/TableSummary';
import { InnerHandlers } from './types/table';
import { usePagination } from './hooks/usePagination';
import { useColumns } from './hooks/useColumns';
@@ -67,12 +73,12 @@
import { useTableHeader } from './hooks/useTableHeader';
import { useTableExpand } from './hooks/useTableExpand';
import { createTableContext } from './hooks/useTableContext';
- import { useTableFooter } from './hooks/useTableFooter';
+ // import { useTableFooter } from './hooks/useTableFooter';
import { useTableForm } from './hooks/useTableForm';
import { useDesign } from '/@/hooks/web/useDesign';
import { useCustomSelection } from "./hooks/useCustomSelection";
- import { omit } from 'lodash-es';
+ import { omit, pick } from 'lodash-es';
import { basicProps } from './props';
import { isFunction } from '/@/utils/is';
import { warn } from '/@/utils/log';
@@ -82,6 +88,7 @@
Table,
BasicForm,
HeaderCell,
+ TableSummary,
CustomSelectHeader,
},
props: basicProps,
@@ -227,7 +234,20 @@
const { getHeaderProps } = useTableHeader(getProps, slots, handlers);
- const { getFooterProps } = useTableFooter(getProps, slots, getScrollRef, tableElRef, getDataSourceRef);
+ const getSummaryProps = computed(() => {
+ return pick(unref(getProps), ['summaryFunc', 'summaryData', 'hasExpandedRow', 'rowKey']);
+ });
+
+ const getIsEmptyData = computed(() => {
+ return (unref(getDataSourceRef) || []).length === 0;
+ });
+
+ const showSummaryRef = computed(() => {
+ const summaryProps = unref(getSummaryProps);
+ return (summaryProps.summaryFunc || summaryProps.summaryData) && !unref(getIsEmptyData);
+ });
+
+ // const { getFooterProps } = useTableFooter(getProps, slots, getScrollRef, tableElRef, getDataSourceRef);
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = useTableForm(getProps, slots, fetch, getLoading);
@@ -249,7 +269,7 @@
columns: toRaw(unref(getViewColumns)),
pagination: toRaw(unref(getPaginationInfo)),
dataSource,
- footer: unref(getFooterProps),
+ // footer: unref(getFooterProps),
...unref(getExpandOption),
// 【QQYUN-5837】动态计算 expandIconColumnIndex
expandIconColumnIndex: getExpandIconColumnIndex.value,
@@ -407,6 +427,9 @@
isCustomSelection,
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
slotNamesGroup,
+ getSummaryProps,
+ getIsEmptyData,
+ showSummaryRef,
};
},
});
diff --git a/src/components/Table/src/components/TableSummary.tsx b/src/components/Table/src/components/TableSummary.tsx
new file mode 100644
index 0000000..34ce3ac
--- /dev/null
+++ b/src/components/Table/src/components/TableSummary.tsx
@@ -0,0 +1,155 @@
+import type { PropType, VNode } from 'vue';
+import { defineComponent, unref, computed, isVNode } from 'vue';
+import { cloneDeep, pick } from 'lodash-es';
+import { isFunction } from '/@/utils/is';
+import type { BasicColumn } from '../types/table';
+import { INDEX_COLUMN_FLAG } from '../const';
+import { propTypes } from '/@/utils/propTypes';
+import { useTableContext } from '../hooks/useTableContext';
+import { TableSummary, TableSummaryRow, TableSummaryCell } from 'ant-design-vue';
+
+const SUMMARY_ROW_KEY = '_row';
+const SUMMARY_INDEX_KEY = '_index';
+export default defineComponent({
+ name: 'BasicTableSummary',
+ components: { TableSummary, TableSummaryRow, TableSummaryCell },
+ props: {
+ summaryFunc: {
+ type: Function as PropType,
+ },
+ summaryData: {
+ type: Array as PropType,
+ },
+ rowKey: propTypes.string.def('key'),
+ // 是否有展开列
+ hasExpandedRow: propTypes.bool,
+ },
+ setup(props) {
+ const table = useTableContext();
+
+ const getDataSource = computed((): Recordable[] => {
+ const { summaryFunc, summaryData } = props;
+ if (summaryData?.length) {
+ summaryData.forEach((item, i) => (item[props.rowKey] = `${i}`));
+ return summaryData;
+ }
+ if (!isFunction(summaryFunc)) {
+ return [];
+ }
+ let dataSource = cloneDeep(unref(table.getDataSource()));
+ dataSource = summaryFunc(dataSource);
+ dataSource.forEach((item, i) => {
+ item[props.rowKey] = `${i}`;
+ });
+ return dataSource;
+ });
+
+ const getColumns = computed(() => {
+ const dataSource = unref(getDataSource);
+ let columns: BasicColumn[] = cloneDeep(table.getColumns({ sort: true }));
+ columns = columns.filter((item) => !item.defaultHidden);
+ const index = columns.findIndex((item) => item.flag === INDEX_COLUMN_FLAG);
+ const hasRowSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_ROW_KEY));
+ const hasIndexSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_INDEX_KEY));
+
+ // 是否有序号列
+ let hasIndexCol = false;
+ // 是否有选择列
+ let hasSelection = table.getRowSelection() && hasRowSummary;
+
+ if (index !== -1) {
+ if (hasIndexSummary) {
+ hasIndexCol = true;
+ columns[index].customSummaryRender = ({ record }) => record[SUMMARY_INDEX_KEY];
+ columns[index].ellipsis = false;
+ } else {
+ Reflect.deleteProperty(columns[index], 'customSummaryRender');
+ }
+ }
+
+ if (hasSelection) {
+ const isFixed = columns.some((col) => col.fixed === 'left' || col.fixed === true);
+ columns.unshift({
+ width: 60,
+ title: 'selection',
+ key: 'selectionKey',
+ align: 'center',
+ ...(isFixed ? { fixed: 'left' } : {}),
+ customSummaryRender: ({ record }) => hasIndexCol ? '' : record[SUMMARY_ROW_KEY],
+ });
+ }
+
+ if (props.hasExpandedRow) {
+ const isFixed = columns.some((col) => col.fixed === 'left');
+ columns.unshift({
+ width: 50,
+ title: 'expandedRow',
+ key: 'expandedRowKey',
+ align: 'center',
+ ...(isFixed ? { fixed: 'left' } : {}),
+ customSummaryRender: () => '',
+ });
+ }
+ return columns;
+ });
+
+ function isRenderCell(data: any) {
+ return data && typeof data === 'object' && !Array.isArray(data) && !isVNode(data);
+ }
+
+ const getValues = (row: Recordable, col: BasicColumn, index: number) => {
+ const value = row[col.dataIndex as string];
+ let childNode: VNode | JSX.Element | string | number | undefined | null;
+ childNode = value;
+ if (col.customSummaryRender) {
+ const renderData = col.customSummaryRender({
+ text: value,
+ value,
+ record: row,
+ index,
+ column: cloneDeep(col)
+ })
+ if (isRenderCell(renderData)) {
+ childNode = renderData.children
+ } else {
+ childNode = renderData
+ }
+ if (typeof childNode === 'object' && !Array.isArray(childNode) && !isVNode(childNode)) {
+ childNode = null;
+ }
+ if (Array.isArray(childNode) && childNode.length === 1) {
+ childNode = childNode[0];
+ }
+ return childNode;
+ }
+ return childNode;
+ }
+
+ const getCellProps = (col: BasicColumn) => {
+ const cellProps = pick(col, ['colSpan', 'rowSpan', 'align']);
+ return {
+ ...cellProps
+ }
+ }
+
+ return () => {
+ return (
+
+ {(unref(getDataSource) || []).map(row => {
+ return
+ {unref(getColumns).map((col, index) => {
+ return
+ {getValues(row, col, index)}
+
+ })}
+
+ })}
+
+ )
+ }
+ },
+});
diff --git a/src/components/Table/src/types/column.ts b/src/components/Table/src/types/column.ts
index 8f820f4..bcae5dc 100644
--- a/src/components/Table/src/types/column.ts
+++ b/src/components/Table/src/types/column.ts
@@ -131,6 +131,8 @@ export interface ColumnProps {
*/
customRender?: CustomRenderFunction | VNodeChild | JSX.Element;
+ customSummaryRender?: CustomRenderFunction | VNodeChild | JSX.Element;
+
/**
* Sort function for local sort, see Array.sort's compareFunction. If you need sort buttons only, set to true
* @type boolean | Function
diff --git a/src/components/Table/src/types/table.ts b/src/components/Table/src/types/table.ts
index c3a463d..cc3fabe 100644
--- a/src/components/Table/src/types/table.ts
+++ b/src/components/Table/src/types/table.ts
@@ -453,6 +453,14 @@ export interface BasicColumn extends ColumnProps {
ifShow?: boolean | ((column: BasicColumn) => boolean);
//compType-用于记录类型
compType?: string;
+ customSummaryRender?: (opt: {
+ value: any;
+ text: any;
+ record: Recordable;
+ index: number;
+ renderIndex?: number;
+ column: BasicColumn;
+}) => any | VNodeChild | JSX.Element;
}
export type ColumnChangeParam = {
diff --git a/src/views/demo/table/FooterTable.vue b/src/views/demo/table/FooterTable.vue
index e81780b..4f68bae 100644
--- a/src/views/demo/table/FooterTable.vue
+++ b/src/views/demo/table/FooterTable.vue
@@ -18,16 +18,28 @@
prev += next.no;
return prev;
}, 0);
+ const totalAge = tableData.reduce((prev, next) => {
+ prev += next.age;
+ return prev;
+ }, 0);
+ const totalScore = tableData.reduce((prev, next) => {
+ prev += next.score;
+ return prev;
+ }, 0);
return [
{
_row: '合计',
_index: '平均值',
no: totalNo,
+ age: Math.round(totalAge / tableData.length),
+ score: Math.round(totalScore / tableData.length)
},
{
_row: '合计',
_index: '平均值',
no: totalNo,
+ age: Math.round(totalAge / tableData.length),
+ score: Math.round(totalScore / tableData.length)
},
];
}
diff --git a/src/views/demo/table/tableData.tsx b/src/views/demo/table/tableData.tsx
index 5356c92..8bc8ab2 100644
--- a/src/views/demo/table/tableData.tsx
+++ b/src/views/demo/table/tableData.tsx
@@ -8,6 +8,7 @@ export function getBasicColumns(): BasicColumn[] {
dataIndex: 'id',
fixed: 'left',
width: 200,
+ resizable: true
},
{
title: '姓名',
@@ -18,6 +19,23 @@ export function getBasicColumns(): BasicColumn[] {
{ text: 'Female', value: 'female' },
],
},
+ {
+ title: '年龄',
+ dataIndex: 'age',
+ width: 100,
+ resizable: true,
+ customSummaryRender: ({text}) => {
+ return (
+ {text}
+ )
+ }
+ },
+ {
+ title: '得分',
+ dataIndex: 'score',
+ width: 100,
+ resizable: true
+ },
{
title: '地址',
dataIndex: 'address',