diff --git a/docs/assets/guide/en/data_analysis/pivot_table_dataAnalysis.md b/docs/assets/guide/en/data_analysis/pivot_table_dataAnalysis.md index 0523e5584c..682cfd9b1e 100644 --- a/docs/assets/guide/en/data_analysis/pivot_table_dataAnalysis.md +++ b/docs/assets/guide/en/data_analysis/pivot_table_dataAnalysis.md @@ -84,14 +84,16 @@ dataConfig: { subTotalsDimensions: ['province'], grandTotalLabel: 'row total', subTotalLabel: 'Subtotal', - showGrandTotalsOnTop: true //totals show on top + showGrandTotalsOnTop: true, //totals show on top + showSubTotalsOnTreeNode: false // When subtotals are disabled in pivot tables, this option allows aggregated values to be displayed on collapsed tree nodes. Default value is false. }, column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['quarter'], grandTotalLabel: 'column total', - subTotalLabel: 'Subtotal' + subTotalLabel: 'Subtotal', + showSubTotalsOnTreeNode: false // When subtotals are disabled in pivot tables, this option allows aggregated values to be displayed on collapsed tree nodes. Default value is false. } } }, @@ -250,9 +252,10 @@ dataConfig:{ }] } ``` - In this data record, the sales indicator is a non-numeric value. If the product requirement is to directly display `"NULL"` in the table cell, then the aggregation rule can be set to `VTable.TYPES.AggregationType.NONE`, so that VTable's internal will not perform aggregation calculations, but directly take the `sales` field value as the display value of the cell. - 2. AggregationType.RECORD usage scenario is mainly used to match all data based on the user's input data record and use it as the display data of the cell. Usage scenarios include: needing to collect data sets for mini-chart displays, specific demo see: https://visactor.io/vtable/demo/cell-type/pivot-sparkline +In this data record, the sales indicator is a non-numeric value. If the product requirement is to directly display `"NULL"` in the table cell, then the aggregation rule can be set to `VTable.TYPES.AggregationType.NONE`, so that VTable's internal will not perform aggregation calculations, but directly take the `sales` field value as the display value of the cell. + +2. AggregationType.RECORD usage scenario is mainly used to match all data based on the user's input data record and use it as the display data of the cell. Usage scenarios include: needing to collect data sets for mini-chart displays, specific demo see: https://visactor.io/vtable/demo/cell-type/pivot-sparkline #### Custom Aggregation Type Introduction @@ -313,7 +316,7 @@ const option={ { indicatorKey: 'Average Product Price (Registered Aggregation Class)', //Indicator name field: 'sales', //Indicator based field - aggregationType: 'avgPrice', //Registered aggregation type + aggregationType: 'avgPrice', //Registered aggregation type } ] } @@ -323,6 +326,7 @@ const option={ VTable's internal aggregation rules code address: https://github.com/VisActor/VTable/blob/develop/packages/vtable/src/ts-types/dataset/aggregation.ts, can be referred to! The methods that need to be implemented for the aggregation type are: + - constructor: The constructor function, used to initialize the aggregator. - push: Add data records to the aggregator, used to calculate the aggregated value. - deleteRecord: Delete records from the aggregator and update the aggregated value, called by VTable's delete interface deleteRecords. @@ -591,4 +595,4 @@ Interface definition: * @param isResetTree Whether to reset the table header tree structure. When true, the table header tree structure will be reset, when false, the table header tree structure will remain unchanged */ updateFilterRules(filterRules: FilterRules, isResetTree: boolean = false) => void -``` \ No newline at end of file +``` diff --git a/docs/assets/guide/zh/data_analysis/pivot_table_dataAnalysis.md b/docs/assets/guide/zh/data_analysis/pivot_table_dataAnalysis.md index af413d0cdf..4d41ba4c14 100644 --- a/docs/assets/guide/zh/data_analysis/pivot_table_dataAnalysis.md +++ b/docs/assets/guide/zh/data_analysis/pivot_table_dataAnalysis.md @@ -84,14 +84,16 @@ dataConfig: { subTotalsDimensions: ['province'], grandTotalLabel: '行总计', subTotalLabel: '小计', - showGrandTotalsOnTop: true //汇总值显示在上 + showGrandTotalsOnTop: true, //汇总值显示在上 + showSubTotalsOnTreeNode: false // 当在透视表中禁用小计时,此选项允许在折叠的树节点上显示聚合值。默认值为 false }, column: { showGrandTotals: true, showSubTotals: true, subTotalsDimensions: ['quarter'], grandTotalLabel: '列总计', - subTotalLabel: '小计' + subTotalLabel: '小计', + showSubTotalsOnTreeNode: false // 当在透视表中禁用小计时,此选项允许在折叠的树节点上显示聚合值。默认值为 false } } }, @@ -163,7 +165,7 @@ dataConfig: { 通常情况下指标应该是 `number` 类型,这样内部才能进行计算。 -如果指标是字符串型或者 `null`,且需要在单元格中进行展示,可以配置 `aggregationType` 为 `VTable.TYPES.AggregationType.NONE` 来显示数据源字段的原始值; 或者在指标format函数中结合接口`getCellOriginRecord`获取到单元格对应的数据源条目,然后进行特殊处理。 +如果指标是字符串型或者 `null`,且需要在单元格中进行展示,可以配置 `aggregationType` 为 `VTable.TYPES.AggregationType.NONE` 来显示数据源字段的原始值; 或者在指标 format 函数中结合接口`getCellOriginRecord`获取到单元格对应的数据源条目,然后进行特殊处理。 如果用到了自定义渲染 `customLayout`,在 `customLayout` 函数中想获取单元格对应的所有数据 `records`,可以配置 `aggregationType` 为 `VTable.TYPES.AggregationType.RECORD`。 @@ -218,7 +220,7 @@ dataConfig: { { indicatorKey: '商品均价(注册聚合类)', //指标名称 field: 'sales', //指标依据字段 - aggregationType: 'avgPrice', //自己注册的聚合类型 + aggregationType: 'avgPrice', //自己注册的聚合类型 } ] } @@ -252,7 +254,7 @@ dataConfig:{ } ``` - 其中该条数据 record 中 sales 指标是个非数值型的值,如果产品需求要将`"NULL"`直接显示到表格单元格中,那么可以设置聚合规则为`VTable.TYPES.AggregationType.NONE`,这样 VTable 的内部不会进行聚合计算,而是直接取`sales`字段值作为单元格展示值。 +其中该条数据 record 中 sales 指标是个非数值型的值,如果产品需求要将`"NULL"`直接显示到表格单元格中,那么可以设置聚合规则为`VTable.TYPES.AggregationType.NONE`,这样 VTable 的内部不会进行聚合计算,而是直接取`sales`字段值作为单元格展示值。 2. AggregationType.RECORD 使用场景主要用于根据用户传入数据 record 匹配到所有数据,将其作为单元格的展示数据,用法场景如:需要搜集数据集作为迷你图展示,具体 demo 见:https://visactor.io/vtable/demo/cell-type/pivot-sparkline @@ -315,20 +317,21 @@ const option={ { indicatorKey: '商品均价(注册聚合类)', //指标名称 field: 'sales', //指标依据字段 - aggregationType: 'avgPrice', //自己注册的聚合类型 + aggregationType: 'avgPrice', //自己注册的聚合类型 } ] } } ``` -VTable内部的几种聚合规则代码地址:https://github.com/VisActor/VTable/blob/develop/packages/vtable/src/ts-types/dataset/aggregation.ts,可予以参考! +VTable 内部的几种聚合规则代码地址:https://github.com/VisActor/VTable/blob/develop/packages/vtable/src/ts-types/dataset/aggregation.ts,可予以参考! 其中聚合类型需要实现的几个方法分别为: + - constructor:构造函数,用于初始化聚合器。 - push:将数据记录添加到聚合器中,用于计算聚合值。 -- deleteRecord:从聚合器中删除记录,并更新聚合值,调用vtable的删除接口deleteRecords会调用该接口。 -- updateRecord:更新数据记录,并更新聚合值,调用接口updateRecords会调用该接口。 +- deleteRecord:从聚合器中删除记录,并更新聚合值,调用 vtable 的删除接口 deleteRecords 会调用该接口。 +- updateRecord:更新数据记录,并更新聚合值,调用接口 updateRecords 会调用该接口。 - recalculate:重新计算聚合值,目前复制粘贴单元格值会调用该方法。 - value:获取聚合值。 - reset:重置聚合器。 @@ -593,4 +596,4 @@ VTable 官网示例:https://visactor.io/vtable/demo/table-type/pivot-table. * @param isResetTree 是否重置表头树结构。 当为true时,会重置表头树结构,当为false时,表头树结构维持不变 */ updateFilterRules(filterRules: FilterRules, isResetTree: boolean = false) => void -``` \ No newline at end of file +``` diff --git a/docs/assets/option/en/table/pivotTable.md b/docs/assets/option/en/table/pivotTable.md index adcaa0d7ea..43e8cd36e4 100644 --- a/docs/assets/option/en/table/pivotTable.md +++ b/docs/assets/option/en/table/pivotTable.md @@ -229,6 +229,8 @@ export interface Total { grandTotalLabel?: string; //Default 'Subtotal' subTotalLabel?: string; + // When subtotals are disabled in pivot tables, this option allows aggregated values to be displayed on collapsed tree nodes. Default value is false. + showSubTotalsOnTreeNode?: boolean; } ``` @@ -268,6 +270,7 @@ export interface CalculatedFieldRule { calculateFun?: (dependFieldsValue: any) => any; } ``` + ### updateAggregationOnEditCell (boolean) Whether to update total and subtotal after editing cell value. Default value is false. @@ -460,4 +463,5 @@ columnWidthConfigForRowHeader": [ } ] ``` -Matching key is the key of the row dimension: dimensionKey。 \ No newline at end of file + +Matching key is the key of the row dimension: dimensionKey。 diff --git a/docs/assets/option/zh/table/pivotTable.md b/docs/assets/option/zh/table/pivotTable.md index 0107e7b6a6..34b21b536b 100644 --- a/docs/assets/option/zh/table/pivotTable.md +++ b/docs/assets/option/zh/table/pivotTable.md @@ -233,6 +233,8 @@ export interface Total { grandTotalLabel?: string; // 默认'小计' subTotalLabel?: string; + // 当在透视表中禁用小计时,此选项允许在折叠的树节点上显示聚合值。默认值为 false + showSubTotalsOnTreeNode?: boolean; } ``` @@ -272,9 +274,10 @@ export interface CalculateddFieldRule { calculateFun?: (dependFieldsValue: any) => any; } ``` + ### updateAggregationOnEditCell (boolean) -是否在修改单元格后更新小计和总计。默认值为false. +是否在修改单元格后更新小计和总计。默认值为 false. 具体情况请参考[demo](../demo/data-analysis/pivot-analysis-updateTotalData) @@ -450,6 +453,7 @@ export interface IIndicatorHeaderNode { ## columnWidthConfigForRowHeader(Array) 依据行维度信息设置行表头列宽, 设置示例: + ``` columnWidthConfigForRowHeader": [ { @@ -463,5 +467,5 @@ columnWidthConfigForRowHeader": [ } ] ``` -匹配关键是行维度的key:dimensionKey。 +匹配关键是行维度的 key:dimensionKey。 diff --git a/packages/vtable/src/dataset/dataset.ts b/packages/vtable/src/dataset/dataset.ts index 54062a4b46..31612adf66 100644 --- a/packages/vtable/src/dataset/dataset.ts +++ b/packages/vtable/src/dataset/dataset.ts @@ -1179,10 +1179,13 @@ export class Dataset { // 如果是平铺树结构 小计需要处理补充到rowKey中 if (rowKey[0] === this.rowGrandTotalLabel) { } else if ( - this.totals?.row?.subTotalsDimensions && - this.totals?.row?.subTotalsDimensions?.length >= 1 && - rowKey[rowKey.length - 1] !== this.rowSubTotalLabel && - this.totals.row.subTotalsDimensions.find((dimension: string) => dimension === rowDimensionKey) //如果维度key在subTotalsDimensions中 则需要补充小计标签名到rowKey中 + ( + (this.totals?.row?.subTotalsDimensions && + this.totals?.row?.subTotalsDimensions?.length >= 1 && + this.totals.row.subTotalsDimensions.find((dimension: string) => dimension === rowDimensionKey)) || + this.totals?.row?.showSubTotalsOnTreeNode + ) && + rowKey[rowKey.length - 1] !== this.rowSubTotalLabel ) { rowKey.push(this.rowSubTotalLabel); } @@ -1205,10 +1208,11 @@ export class Dataset { if (colKey.length < this.columns.length && this.columnHierarchyType === 'grid-tree') { if (colKey[0] === this.colGrandTotalLabel) { } else if ( - this.totals?.column?.subTotalsDimensions && - this.totals?.column?.subTotalsDimensions?.length >= 1 && - colKey[colKey.length - 1] !== this.colSubTotalLabel && - this.totals.column.subTotalsDimensions.find((dimension: string) => dimension === colDimensionKey) //如果维度key在subTotalsDimensions中 则需要补充小计标签名到colKey中 + ((this.totals?.column?.subTotalsDimensions && + this.totals?.column?.subTotalsDimensions?.length >= 1 && + this.totals.column.subTotalsDimensions.find((dimension: string) => dimension === colDimensionKey)) || + this.totals?.column?.showSubTotalsOnTreeNode) && + colKey[colKey.length - 1] !== this.colSubTotalLabel ) { colKey.push(this.colSubTotalLabel); } @@ -1542,12 +1546,20 @@ export class Dataset { } const colKey = flatColKey.split(this.stringJoinChar); if ( - that.totals?.column?.subTotalsDimensions && + (that.totals?.column?.subTotalsDimensions && that.totals?.column?.subTotalsDimensions?.length > 0 && - that.totals.column.showSubTotals !== false + (that.totals.column.showSubTotals !== false || that.totals.column.showSubTotalsOnTreeNode)) || + (that.totals.column.showSubTotalsOnTreeNode && that.columns.length > 0) ) { - for (let i = 0, len = that.totals?.column?.subTotalsDimensions?.length; i < len; i++) { - const dimension = that.totals.column.subTotalsDimensions[i]; + // 确定要处理的列维度 + let colSubTotalDimensions = that.totals?.column?.subTotalsDimensions || []; + if (that.totals?.column?.showSubTotalsOnTreeNode && colSubTotalDimensions.length === 0) { + // 如果设置了showSubTotalsOnTreeNode但没有配置subTotalsDimensions,则使用所有列维度 + colSubTotalDimensions = that.columns.map(col => col); + } + + for (let i = 0, len = colSubTotalDimensions.length; i < len; i++) { + const dimension = colSubTotalDimensions[i]; const dimensionIndex = that.columns.indexOf(dimension); if (dimensionIndex >= 0) { const colTotalKey = colKey.slice(0, dimensionIndex + 1); @@ -1687,7 +1699,9 @@ export class Dataset { (that?.totals?.column?.subTotalsDimensions && that?.totals?.column?.subTotalsDimensions?.length >= 1) || (that?.totals?.row?.subTotalsDimensions && that?.totals?.row?.subTotalsDimensions?.length >= 1) || that?.totals?.column?.showGrandTotals || - that?.totals?.row?.showGrandTotals + that?.totals?.row?.showGrandTotals || + that?.totals?.row?.showSubTotalsOnTreeNode || + that?.totals?.column?.showSubTotalsOnTreeNode // || // that.rows.length === 0 || //todo 这里原有逻辑暂时注释掉 // that.columns.length === 0 @@ -1698,12 +1712,20 @@ export class Dataset { const rowKey = flatRowKey.split(this.stringJoinChar); Object.keys(that.tree[flatRowKey]).forEach(flatColKey => { if ( - that.totals?.row?.subTotalsDimensions && + (that.totals?.row?.subTotalsDimensions && that.totals?.row?.subTotalsDimensions?.length > 0 && - that.totals.row.showSubTotals !== false + (that.totals.row.showSubTotals !== false || that.totals.row.showSubTotalsOnTreeNode)) || + (that.totals.row.showSubTotalsOnTreeNode && that.rows.length > 0) ) { - for (let i = 0, len = that.totals?.row?.subTotalsDimensions?.length; i < len; i++) { - const dimension = that.totals.row.subTotalsDimensions[i]; + // 确定要处理的行维度 + let rowSubTotalDimensions = that.totals?.row?.subTotalsDimensions || []; + if (that.totals?.row?.showSubTotalsOnTreeNode && rowSubTotalDimensions.length === 0) { + // 如果设置了showSubTotalsOnTreeNode但没有配置subTotalsDimensions,则使用所有行维度 + rowSubTotalDimensions = that.rows.map(row => row); + } + + for (let i = 0, len = rowSubTotalDimensions.length; i < len; i++) { + const dimension = rowSubTotalDimensions[i]; const dimensionIndex = that.rows.indexOf(dimension); if (dimensionIndex >= 0 && dimensionIndex < that.rows.length - 1) { const rowTotalKey = rowKey.slice(0, dimensionIndex + 1); diff --git a/packages/vtable/src/ts-types/new-data-set.ts b/packages/vtable/src/ts-types/new-data-set.ts index 78432dcd93..22332c25c5 100644 --- a/packages/vtable/src/ts-types/new-data-set.ts +++ b/packages/vtable/src/ts-types/new-data-set.ts @@ -39,6 +39,8 @@ export interface Total { showGrandTotals: boolean; /** 是否显示小计; 如果配置了total对象,showSubTotals默认为true */ showSubTotals: boolean; + /** 是否在树节点上显示聚合数据; 不需要开启showSubTotals小计就能折叠后显示聚合数据 */ + showSubTotalsOnTreeNode?: boolean; // // 计算总计方法 // calcGrandTotals?: CalcTotals;