[issues/1196]Table 列头拖动时合计行错位; 修改合计行使用TableSummary方式渲染;支持slot自定义合计行展示
/issues/1196 1、Table 列头拖动时合计行错位; 2、修改合计行使用TableSummary方式渲染; 3、支持slot自定义合计行展示; 4、列添加customSummaryRender自定义渲染函数pull/1201/head
parent
ec1649629d
commit
ca1491a5c4
|
@ -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,
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
</template>
|
||||
<!-- update-begin--author:liaozhiyang---date:22030717---for:【issues-179】antd3 一些警告以及报错(针对表格) -->
|
||||
</template>
|
||||
<template v-if="showSummaryRef" #summary="data">
|
||||
<slot name="summary" v-bind="data || {}">
|
||||
<TableSummary v-bind="getSummaryProps" />
|
||||
</slot>
|
||||
</template>
|
||||
</Table>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
|
@ -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,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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<Fn>,
|
||||
},
|
||||
summaryData: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
},
|
||||
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 (
|
||||
<TableSummary fixed>
|
||||
{(unref(getDataSource) || []).map(row => {
|
||||
return <TableSummaryRow key={row[props.rowKey]}>
|
||||
{unref(getColumns).map((col, index) => {
|
||||
return <TableSummaryCell
|
||||
{...getCellProps(col)}
|
||||
index={index}
|
||||
key={`${row[props.rowKey]}_${col.dataIndex}_${index}`}
|
||||
>
|
||||
{getValues(row, col, index)}
|
||||
</TableSummaryCell>
|
||||
})}
|
||||
</TableSummaryRow>
|
||||
})}
|
||||
</TableSummary>
|
||||
)
|
||||
}
|
||||
},
|
||||
});
|
|
@ -131,6 +131,8 @@ export interface ColumnProps<T> {
|
|||
*/
|
||||
customRender?: CustomRenderFunction<T> | VNodeChild | JSX.Element;
|
||||
|
||||
customSummaryRender?: CustomRenderFunction<T> | 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
|
||||
|
|
|
@ -453,6 +453,14 @@ export interface BasicColumn extends ColumnProps<Recordable> {
|
|||
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 = {
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<span style="color: red;">{text}</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '得分',
|
||||
dataIndex: 'score',
|
||||
width: 100,
|
||||
resizable: true
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
dataIndex: 'address',
|
||||
|
|
Loading…
Reference in New Issue