From acc183a1f352137208a74701a61becfc53ad3f60 Mon Sep 17 00:00:00 2001 From: along Date: Mon, 24 Mar 2025 17:38:30 +0800 Subject: [PATCH 1/5] feat: add select/cornerHeaderSelectMode config --- .../src/state/select/update-position.ts | 38 ++++++++++++++++--- packages/vtable/src/state/state.ts | 10 +++++ packages/vtable/src/ts-types/base-table.ts | 9 ++++- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/packages/vtable/src/state/select/update-position.ts b/packages/vtable/src/state/select/update-position.ts index 27fcf04656..75526a6fbd 100644 --- a/packages/vtable/src/state/select/update-position.ts +++ b/packages/vtable/src/state/select/update-position.ts @@ -259,11 +259,39 @@ export function updateSelectPosition( skipBodyMerge: true }); } else { - state.select.ranges.push({ - start: { col: table.leftRowSeriesNumberCount, row: 0 }, - end: { col: table.colCount - 1, row: table.rowCount - 1 }, - skipBodyMerge: true - }); + const { cornerHeaderSelectMode } = state.select; + if (cornerHeaderSelectMode === 'body') { + state.select.ranges.push({ + start: { + col: table.leftRowSeriesNumberCount, + row: 0 + }, + end: { col: table.colCount - 1, row: table.rowCount - 1 }, + skipBodyMerge: true + }); + } else if (cornerHeaderSelectMode === 'cell') { + // 选中普通单元格 + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: cellRange.end.row }, + skipBodyMerge: skipBodyMerge || undefined + }); + } else { + // inline + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: table.rowCount - 1 }, + skipBodyMerge: true + }); + } + // 选中全部 + // state.select.ranges.push({ + // start: { col: table.leftRowSeriesNumberCount, row: 0 }, + // end: { col: table.colCount - 1, row: table.rowCount - 1 }, + // skipBodyMerge: true + // }); } } else if (col >= 0 && row >= 0) { // 选中普通单元格 diff --git a/packages/vtable/src/state/state.ts b/packages/vtable/src/state/state.ts index a52d5c754c..969317978a 100644 --- a/packages/vtable/src/state/state.ts +++ b/packages/vtable/src/state/state.ts @@ -89,6 +89,12 @@ export class StateManager { * 'body': 不选择表头,点击行表头则选择该行所有 body 单元格,点击列表头则选择该列所有 body 单元格。 */ headerSelectMode?: 'inline' | 'cell' | 'body'; + /** 点击表头corner单元格效果 + * 'inline': 点击corner选择列表头则整列选中; + * 'cell': 仅仅选择当前点击的corner表头单元格; + * 'body': 点击corner列表头则选择该列所有 body 单元格。 + */ + cornerHeaderSelectMode?: 'inline' | 'cell' | 'body'; highlightInRange?: boolean; selecting: boolean; customSelectRanges?: { @@ -434,6 +440,7 @@ export class StateManager { // enableColumnHighlight, /** 点击表头单元格时连带body整行或整列选中 或仅选中当前单元格,默认或整行或整列选中*/ headerSelectMode, + cornerHeaderSelectMode, disableSelect, disableHeaderSelect, highlightMode, @@ -443,6 +450,7 @@ export class StateManager { { /** 点击表头单元格时连带body整行或整列选中 或仅选中当前单元格,默认或整行或整列选中*/ headerSelectMode: 'inline', + cornerHeaderSelectMode: 'body', disableSelect: false, disableHeaderSelect: false, highlightMode: 'cell', @@ -475,6 +483,8 @@ export class StateManager { this.select.singleStyle = !disableSelect; this.select.disableHeader = disableHeaderSelect; this.select.headerSelectMode = headerSelectMode; + + this.select.cornerHeaderSelectMode = cornerHeaderSelectMode; this.select.highlightInRange = highlightInRange; this.select.disableCtrlMultiSelect = this.table.options.keyboardOptions?.ctrlMultiSelect === false; } diff --git a/packages/vtable/src/ts-types/base-table.ts b/packages/vtable/src/ts-types/base-table.ts index 2ed220bea7..1737535cf3 100644 --- a/packages/vtable/src/ts-types/base-table.ts +++ b/packages/vtable/src/ts-types/base-table.ts @@ -389,6 +389,12 @@ export interface BaseTableConstructorOptions { * 'body': 不选择表头,点击行表头则选择该行所有 body 单元格,点击列表头则选择该列所有 body 单元格。 */ headerSelectMode?: 'inline' | 'cell' | 'body'; + /** 点击表头corner单元格效果 + * 'inline': 点击corner选择列表头则整列选中; + * 'cell': 仅仅选择当前点击的corner表头单元格; + * 'body': 点击corner列表头则选择该列所有 body 单元格。 + */ + cornerHeaderSelectMode?: 'inline' | 'cell' | 'body'; /** 不响应鼠标select交互 */ disableSelect?: boolean | ((col: number, row: number, table: BaseTableAPI) => boolean); /** 单独设置表头不响应鼠标select交互 */ @@ -557,10 +563,9 @@ export interface BaseTableConstructorOptions { // 图片资源请求时是否使用anonymous模式 imageAnonymous?: boolean; - // 滚动到边界是否继续触发滚动事件 scrollEventAlwaysTrigger?: boolean; - + // 开启透视结构缓存 enablePivotPathCache?: boolean; }; // 部分特殊配置,兼容xTable等作用 From 13b813e94ddb0a6d863f47abc57d21396598908e Mon Sep 17 00:00:00 2001 From: along Date: Tue, 25 Mar 2025 16:58:26 +0800 Subject: [PATCH 2/5] feat: add select/cornerHeaderSelectMode config --- ...grid-tree-select-cornerHeaderSelectMode.ts | 383 ++++++++++++++++++ .../src/state/select/update-position.ts | 7 +- packages/vtable/src/state/state.ts | 5 +- packages/vtable/src/ts-types/base-table.ts | 5 +- 4 files changed, 392 insertions(+), 8 deletions(-) create mode 100644 packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts diff --git a/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts b/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts new file mode 100644 index 0000000000..e7521b6681 --- /dev/null +++ b/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts @@ -0,0 +1,383 @@ +import * as VTable from '../../src'; +import { bindDebugTool } from '../../src/scenegraph/debug-tool'; +const PivotTable = VTable.PivotTable; +const CONTAINER_ID = 'vTable'; + +export function createTable() { + fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/test-demo-data/supermarket-flat.json') + .then(res => res.json()) + .then(data => { + const option: VTable.PivotTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records: data, + menu: { + contextMenuItems: ['复制单元格内容', '查询详情'] + }, + // columnTree: [ + // { + // dimensionKey: '220524114340021', + // value: '办公用品', + // // hierarchyState: 'collapse', + // children: [ + // { + // dimensionKey: '220524114340022', + // value: '公司', + // // hierarchyState: 'expand',//设置默认展开 + // children: [ + // { + // dimensionKey: '220524114340023', + // value: '一级', + // children: [ + // { + // dimensionKey: '2205241143400232', + // value: '一级' + // }, + // { + // dimensionKey: '2205241143400232', + // value: '二级' + // }, + // { + // dimensionKey: '2205241143400232', + // value: '三级' + // } + // ] + // }, + // { + // dimensionKey: '220524114340023', + // value: '二级', + // children: [ + // { + // dimensionKey: '2205241143400232', + // value: '一级' + // }, + // { + // dimensionKey: '2205241143400232', + // value: '二级' + // }, + // { + // dimensionKey: '2205241143400232', + // value: '三级' + // } + // ] + // }, + // { + // dimensionKey: '220524114340023', + // value: '三级' + // } + // ] + // }, + // { + // dimensionKey: '220524114340022', + // value: '消费者', + // children: [ + // { + // dimensionKey: '220524114340023', + // value: '一级1' + // // hierarchyState: 'expand', + // }, + // { + // dimensionKey: '220524114340023', + // value: '二级1' + // }, + // { + // dimensionKey: '220524114340023', + // value: '三级1' + // } + // ] + // }, + // { + // dimensionKey: '220524114340022', + // value: '小型企业' + // } + // ] + // }, + // { + // dimensionKey: '220524114340021', + // //title: '220524114340021', + // value: '家具', + // children: [ + // { + // dimensionKey: '220524114340022', + // value: '公司1' + // // hierarchyState: 'expand', + // }, + // { + // dimensionKey: '220524114340022', + // value: '消费者1' + // }, + // { + // dimensionKey: '220524114340022', + // value: '小型企业1' + // } + // ] + // }, + // { + // dimensionKey: '220524114340021', + // //title: '220524114340021', + // value: '餐饮', + // children: [ + // { + // dimensionKey: '220524114340022', + // value: '公司2' + // // hierarchyState: 'expand', + // }, + // { + // dimensionKey: '220524114340022', + // value: '消费者2' + // }, + // { + // dimensionKey: '220524114340022', + // value: '小型企业2' + // } + // ] + // }, + // { + // dimensionKey: '220524114340021', + // //title: '220524114340021', + // value: '技术', + // children: [ + // { + // dimensionKey: '220524114340022', + // value: '公司3' + // // hierarchyState: 'expand', + // }, + // { + // dimensionKey: '220524114340022', + // value: '消费者3' + // }, + // { + // dimensionKey: '220524114340022', + // value: '小型企业3' + // } + // ] + // } + // ], + // rowTree: [ + // { + // dimensionKey: '220524114340020', + // value: '东北', + // children: [ + // { + // dimensionKey: '220524114340031', + // value: '黑龙江', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // }, + // { + // dimensionKey: '220524114340031', + // value: '吉林', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // }, + // { + // dimensionKey: '220524114340031', + // value: '辽宁', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // } + // ] + // }, + // { + // dimensionKey: '220524114340020', + // value: '华北' + // }, + // { + // dimensionKey: '220524114340020', + // value: '中南', + // children: [ + // { + // dimensionKey: '220524114340031', + // value: '广东', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // }, + // { + // dimensionKey: '220524114340031', + // value: '广西', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // }, + // { + // dimensionKey: '220524114340031', + // value: '湖南', + // children: [ + // { + // indicatorKey: '220524114340013', + // value: '销售额' + // }, + // { + // indicatorKey: '220524114340014', + // value: '利润' + // } + // ] + // } + // ] + // } + // ], + columns: [ + { + dimensionKey: '220524114340021', + title: '类别', + headerFormat(value) { + return `${value}`; + } + // width: 200 + } + // { + // dimensionKey: '220524114340022', + // title: '子类别' + + // // headerType: 'MULTILINETEXT', + // }, + // { + // dimensionKey: '220524114340023', + // title: '邮寄方式' + // } + ], + rows: [ + { + dimensionKey: '220524114340020', + title: '地区', + headerFormat(value) { + return `${value}地区`; + }, + headerStyle: { + textBaseline: 'top' + }, + // 指标菜单 + dropDownMenu: ['升序排序I', '降序排序I', '冻结列I'], + // corner菜单 + cornerDropDownMenu: ['升序排序C', '降序排序C', '冻结列C'], + drillDown: true + }, + { + dimensionKey: '220524114340031', + title: '省份' + } + ], + indicators: [ + { + indicatorKey: '220524114340013', + title: '销售额', + width: 'auto', + format(value, col, row, table) { + // if (rec.rowDimensions[0].value === '东北') return `${rec.dataValue}%`; + if (!value) { + return '--'; + } + return Math.floor(parseFloat(value)); + }, + headerStyle: { + color: 'red' + } + // headerType: 'MULTILINETEXT', + }, + { + indicatorKey: '220524114340014', + title: '利润', + format(value) { + // if (rec.rowDimensions[0].value === '东北') return `${rec.dataValue}%`; + if (!value) { + return '--'; + } + return Math.floor(parseFloat(value)); + }, + width: 'auto', + headerStyle: {} + } + ], + indicatorTitle: '指标', + corner: { + titleOnDimension: 'column', + headerStyle: { + textAlign: 'center', + borderColor: 'red', + color: 'red', + underline: true, + fontSize: 16, + fontWeight: 'bold', + fontFamily: 'sans-serif' + } + }, + select: { + headerSelectMode: 'body', // 为 body 时,优先选中body + cornerHeaderSelectMode: 'all' // 默认选中整个图表 + }, + dataConfig: { + totals: { + row: { + showGrandTotals: true, + showSubTotals: true, + subTotalsDimensions: ['220524114340020'], + grandTotalLabel: '行总计', + subTotalLabel: '小计' + } + // column: { + // showGrandTotals: true, + // showSubTotals: true, + // subTotalsDimensions: ['220524114340022'], + // grandTotalLabel: '列总计', + // subTotalLabel: '小计' + // } + } + }, + heightMode: 'autoHeight', + defaultHeaderColWidth: 100, + autoWrapText: true, + widthMode: 'autoWidth', + rowHierarchyType: 'grid-tree', + rowExpandLevel: 1, + rowHierarchyIndent: 20, + theme: VTable.themes.ARCO, + indicatorsAsCol: false, + // hideIndicatorName:true, + dragHeaderMode: 'all', + bottomFrozenRowCount: 2 + }; + const tableInstance = new PivotTable(option); + // 只为了方便控制太调试用,不要拷贝 + window.tableInstance = tableInstance; + }) + // eslint-disable-next-line no-console + .catch(e => console.log(e)); +} diff --git a/packages/vtable/src/state/select/update-position.ts b/packages/vtable/src/state/select/update-position.ts index 75526a6fbd..08bd658623 100644 --- a/packages/vtable/src/state/select/update-position.ts +++ b/packages/vtable/src/state/select/update-position.ts @@ -248,8 +248,8 @@ export function updateSelectPosition( } else if ((table.internalProps.layoutMap as SimpleHeaderLayoutMap).isCornerHeader(col, row)) { // 选中表头行号单元格 extendSelectRange = false; - - if (state.select.headerSelectMode === 'body') { + const { cornerHeaderSelectMode } = state.select; + if (state.select.headerSelectMode === 'body' || cornerHeaderSelectMode === 'body') { state.select.ranges.push({ start: { col: table.rowHeaderLevelCount + table.leftRowSeriesNumberCount, @@ -259,8 +259,7 @@ export function updateSelectPosition( skipBodyMerge: true }); } else { - const { cornerHeaderSelectMode } = state.select; - if (cornerHeaderSelectMode === 'body') { + if (cornerHeaderSelectMode === 'all') { state.select.ranges.push({ start: { col: table.leftRowSeriesNumberCount, diff --git a/packages/vtable/src/state/state.ts b/packages/vtable/src/state/state.ts index 969317978a..c71c307610 100644 --- a/packages/vtable/src/state/state.ts +++ b/packages/vtable/src/state/state.ts @@ -93,8 +93,9 @@ export class StateManager { * 'inline': 点击corner选择列表头则整列选中; * 'cell': 仅仅选择当前点击的corner表头单元格; * 'body': 点击corner列表头则选择该列所有 body 单元格。 + * 'all': 点击corner选择整个图表 */ - cornerHeaderSelectMode?: 'inline' | 'cell' | 'body'; + cornerHeaderSelectMode?: 'inline' | 'cell' | 'body' | 'all'; highlightInRange?: boolean; selecting: boolean; customSelectRanges?: { @@ -450,7 +451,7 @@ export class StateManager { { /** 点击表头单元格时连带body整行或整列选中 或仅选中当前单元格,默认或整行或整列选中*/ headerSelectMode: 'inline', - cornerHeaderSelectMode: 'body', + cornerHeaderSelectMode: 'all', // 点击 corner 默认选中整个图表 disableSelect: false, disableHeaderSelect: false, highlightMode: 'cell', diff --git a/packages/vtable/src/ts-types/base-table.ts b/packages/vtable/src/ts-types/base-table.ts index 1737535cf3..3a51173d6f 100644 --- a/packages/vtable/src/ts-types/base-table.ts +++ b/packages/vtable/src/ts-types/base-table.ts @@ -392,9 +392,10 @@ export interface BaseTableConstructorOptions { /** 点击表头corner单元格效果 * 'inline': 点击corner选择列表头则整列选中; * 'cell': 仅仅选择当前点击的corner表头单元格; - * 'body': 点击corner列表头则选择该列所有 body 单元格。 + * 'body': 点击corner列表头则选择该列所有 body 单元格; + * 'all': 点击corner选择整个图表。 */ - cornerHeaderSelectMode?: 'inline' | 'cell' | 'body'; + cornerHeaderSelectMode?: 'inline' | 'cell' | 'body' | 'all'; /** 不响应鼠标select交互 */ disableSelect?: boolean | ((col: number, row: number, table: BaseTableAPI) => boolean); /** 单独设置表头不响应鼠标select交互 */ From aceb077b85a3eb2253e7a7117e153e064ffcc936 Mon Sep 17 00:00:00 2001 From: along Date: Tue, 25 Mar 2025 17:53:10 +0800 Subject: [PATCH 3/5] docs: add select/cornerHeaderSelectMode demo and related docs --- .../option/en/common/option-secondary.md | 17 +++++++++++++-- .../option/zh/common/option-secondary.md | 21 +++++++++++++------ packages/vtable/examples/menu.ts | 4 ++++ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/docs/assets/option/en/common/option-secondary.md b/docs/assets/option/en/common/option-secondary.md index 894a21bff9..0b91964b75 100644 --- a/docs/assets/option/en/common/option-secondary.md +++ b/docs/assets/option/en/common/option-secondary.md @@ -194,7 +194,6 @@ Align excel advanced capabilities Fill handle, when set to true, when a cell is selected, the fill handle will be displayed on the lower right side of the cell. You can drag the fill handle to edit the value of the cell. Or double-click the fill handle to change the value of the cell you want to edit. - #${prefix} hover(Object) Hover interaction configuration, specific configuration items as follows: @@ -231,6 +230,20 @@ Possible values: 'body': Do not select the table header. Clicking a row header selects all body cells in the row. Clicking a column header selects all body cells in the column. +##${prefix} cornerHeaderSelectMode ('inline' | 'cell' | 'body' | 'all') = 'all' + +When clicking on the corner header cell, the selection mode to be applied. + +Possible values: + +'inline': Clicking the corner header selects the entire column; + +'cell': Select only the currently clicked corner header cell; + +'body': Clicking the corner header selects all body cells; + +'all': Clicking the corner header selects the entire table. + ##${prefix} disableSelect (boolean | ((col: number, row: number, table: BaseTableAPI) => boolean)) = false Do not respond to mouse select interaction. @@ -653,4 +666,4 @@ Validate when the drag to move position ends. ``` validateDragOrderOnEnd?: (source: CellAddress, target: CellAddress) => boolean; -``` \ No newline at end of file +``` diff --git a/docs/assets/option/zh/common/option-secondary.md b/docs/assets/option/zh/common/option-secondary.md index b0cef896ce..9290e53fb5 100644 --- a/docs/assets/option/zh/common/option-secondary.md +++ b/docs/assets/option/zh/common/option-secondary.md @@ -192,8 +192,6 @@ export interface SelectAllOnCtrlAOption { 填充柄,设置为 true 后,当选中单元格后,填充柄会显示在单元格右下方,可以拖动填充柄来编辑单元格的值。或者双击填充柄来改变需要编辑单元格的值。 - - #${prefix} hover(Object) hover 交互配置,具体配置项如下: @@ -227,6 +225,20 @@ hover 交互响应模式:十字交叉、整列、整行或者单个单元格 'body': 不选择表头,点击行表头则选择该行所有 body 单元格,点击列表头则选择该列所有 body 单元格。 +##${prefix} cornerHeaderSelectMode ('inline' | 'cell' | 'body' | 'all') = 'all' + +点击角头 corner 单元格时的选中方式。 + +可选值: + +'inline': 点击 corner 角头整列选中; + +'cell': 仅仅选择当前点击的 corner 角头单元格; + +'body': 点击 corner 角头,选择所有 body 单元格; + +'all': 点击 corner 角头,选中整个图表。 + ##${prefix} disableSelect (boolean | ((col: number, row: number, table: BaseTableAPI) => boolean)) = false 不响应鼠标 select 交互。 @@ -638,7 +650,7 @@ animationAppear?: boolean | { ##${prefix} frozenColDragHeaderMode(string) = 'fixedFrozenCount' -拖拽表头移动位置 针对冻结部分的规则 默认为 fixedFrozenCount。基本表格ListTable类型设置才有效! +拖拽表头移动位置 针对冻结部分的规则 默认为 fixedFrozenCount。基本表格 ListTable 类型设置才有效! - "disabled"(禁止调整冻结列位置):不允许其他列的表头移入冻结列,也不允许冻结列移出,冻结列保持不变。 - "adjustFrozenCount"(根据交互结果调整冻结数量):允许其他列的表头移入冻结列,及冻结列移出,并根据拖拽的动作调整冻结列的数量。当其他列的表头被拖拽进入冻结列位置时,冻结列数量增加;当其他列的表头被拖拽移出冻结列位置时,冻结列数量减少。 @@ -651,6 +663,3 @@ animationAppear?: boolean | { ``` validateDragOrderOnEnd?: (source: CellAddress, target: CellAddress) => boolean; ``` - - - diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index c91c6946fa..547ff6ede7 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -217,6 +217,10 @@ export const menus = [ path: 'pivot', name: 'pivot-grid-tree-totals' }, + { + path: 'pivot', + name: 'pivot-grid-tree-select-cornerHeaderSelectMode' + }, { path: 'pivot', name: 'pivot-tree-lazy-load' From 27a219ce8f89ded26d7ca586a0c8071fc91443f7 Mon Sep 17 00:00:00 2001 From: along Date: Wed, 26 Mar 2025 09:16:19 +0800 Subject: [PATCH 4/5] feat: add select/cornerHeaderSelectMode config --- .../src/state/select/update-position.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/vtable/src/state/select/update-position.ts b/packages/vtable/src/state/select/update-position.ts index 08bd658623..03429842ae 100644 --- a/packages/vtable/src/state/select/update-position.ts +++ b/packages/vtable/src/state/select/update-position.ts @@ -259,16 +259,7 @@ export function updateSelectPosition( skipBodyMerge: true }); } else { - if (cornerHeaderSelectMode === 'all') { - state.select.ranges.push({ - start: { - col: table.leftRowSeriesNumberCount, - row: 0 - }, - end: { col: table.colCount - 1, row: table.rowCount - 1 }, - skipBodyMerge: true - }); - } else if (cornerHeaderSelectMode === 'cell') { + if (cornerHeaderSelectMode === 'cell') { // 选中普通单元格 const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); state.select.ranges.push({ @@ -276,7 +267,7 @@ export function updateSelectPosition( end: { col: cellRange.end.col, row: cellRange.end.row }, skipBodyMerge: skipBodyMerge || undefined }); - } else { + } else if (cornerHeaderSelectMode === 'inline') { // inline const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); state.select.ranges.push({ @@ -284,6 +275,16 @@ export function updateSelectPosition( end: { col: cellRange.end.col, row: table.rowCount - 1 }, skipBodyMerge: true }); + } else { + // all 或者用户传的其他的什么值 :'' | 'test',虽然类型会提示用户不能为其他的值, + state.select.ranges.push({ + start: { + col: table.leftRowSeriesNumberCount, + row: 0 + }, + end: { col: table.colCount - 1, row: table.rowCount - 1 }, + skipBodyMerge: true + }); } // 选中全部 // state.select.ranges.push({ From 5aaa266b2f17f0881393dfb4d7cf866b7e4183c8 Mon Sep 17 00:00:00 2001 From: along Date: Mon, 7 Apr 2025 15:58:48 +0800 Subject: [PATCH 5/5] feat: add select/cornerHeaderSelectMode config --- ...-rowSeriesNumber-cornerHeaderSelectMode.ts | 111 ++++++++++++++++++ packages/vtable/examples/menu.ts | 4 + ...grid-tree-select-cornerHeaderSelectMode.ts | 13 +- .../src/state/select/update-position.ts | 107 +++++++++++------ packages/vtable/src/state/state.ts | 11 +- 5 files changed, 208 insertions(+), 38 deletions(-) create mode 100644 packages/vtable/examples/list/list-rowSeriesNumber-cornerHeaderSelectMode.ts diff --git a/packages/vtable/examples/list/list-rowSeriesNumber-cornerHeaderSelectMode.ts b/packages/vtable/examples/list/list-rowSeriesNumber-cornerHeaderSelectMode.ts new file mode 100644 index 0000000000..6db59b695b --- /dev/null +++ b/packages/vtable/examples/list/list-rowSeriesNumber-cornerHeaderSelectMode.ts @@ -0,0 +1,111 @@ +import * as VTable from '../../src'; +import { bindDebugTool } from '../../src/scenegraph/debug-tool'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' : 'front-end engineer', + city: 'beijing' + })); +}; + +export function createTable() { + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'id', + title: 'ID', + width: '1%', + minWidth: 200, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + + { + field: 'tel', + title: 'telephone', + width: 150 + }, + { + field: 'work', + title: 'job', + width: 200 + }, + { + field: 'city', + title: 'city', + width: 150 + } + ]; + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + tooltip: { + isShowOverflowTextTooltip: true + }, + pagination: { + perPageCount: 10, + currentPage: 0 + }, + rowSeriesNumber: { + title: '行号', + dragOrder: true, + headerStyle: { + bgColor: '#EEF1F5', + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8' + } + }, + select: { + // headerSelectMode: 'body', + cornerHeaderSelectMode: 'cell' + } + // bottomFrozenRowCount: 1 + // autoWrapText: true, + // heightMode: 'autoHeight', + // widthMode: 'adaptive' + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + // bindDebugTool(tableInstance.scenegraph.stage, { customGrapicKeys: ['col', 'row'] }); + // tableInstance.on('sort_click', args => { + // tableInstance.updateSortState( + // { + // field: args.field, + // order: Date.now() % 3 === 0 ? 'desc' : Date.now() % 3 === 1 ? 'asc' : 'normal' + // }, + // false + // ); + // return false; //return false代表不执行内部排序逻辑 + // }); +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index 547ff6ede7..88c4060648 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -111,6 +111,10 @@ export const menus = [ path: 'list', name: 'list-rowSeriesNumber' }, + { + path: 'list', + name: 'list-rowSeriesNumber-cornerHeaderSelectMode' + }, { path: 'list', name: 'list-transpose-rowSeriesNumber' diff --git a/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts b/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts index e7521b6681..690af47a8d 100644 --- a/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts +++ b/packages/vtable/examples/pivot/pivot-grid-tree-select-cornerHeaderSelectMode.ts @@ -341,7 +341,7 @@ export function createTable() { }, select: { headerSelectMode: 'body', // 为 body 时,优先选中body - cornerHeaderSelectMode: 'all' // 默认选中整个图表 + cornerHeaderSelectMode: 'cell' // 默认选中整个图表 }, dataConfig: { totals: { @@ -361,6 +361,17 @@ export function createTable() { // } } }, + rowSeriesNumber: { + title: '行号', + dragOrder: true, + headerStyle: { + bgColor: '#EEF1F5', + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8' + } + }, heightMode: 'autoHeight', defaultHeaderColWidth: 100, autoWrapText: true, diff --git a/packages/vtable/src/state/select/update-position.ts b/packages/vtable/src/state/select/update-position.ts index 03429842ae..6dda85c6df 100644 --- a/packages/vtable/src/state/select/update-position.ts +++ b/packages/vtable/src/state/select/update-position.ts @@ -174,6 +174,7 @@ export function updateSelectPosition( state.select.ranges = []; scenegraph.deleteAllSelectBorder(); } + if (state.select.headerSelectMode !== 'cell' && table.isColumnHeader(col, row)) { // 选中行表头 const cellRange = table.getCellRange(col, row); @@ -210,7 +211,8 @@ export function updateSelectPosition( // 选中表头行号单元格 extendSelectRange = false; - if (state.select.headerSelectMode === 'body') { + const { cornerHeaderSelectMode } = state.select; + if (cornerHeaderSelectMode === 'body') { state.select.ranges.push({ start: { col: table.leftRowSeriesNumberCount, @@ -219,6 +221,22 @@ export function updateSelectPosition( end: { col: table.colCount - 1, row: table.rowCount - 1 }, skipBodyMerge: true }); + } else if (cornerHeaderSelectMode === 'inline') { + // inline 选中行号所在单元格下所有列 + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: table.rowCount - 1 }, + skipBodyMerge: true + }); + } else if (cornerHeaderSelectMode === 'cell') { + // 选中行号单元格 + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: cellRange.end.row }, + skipBodyMerge: skipBodyMerge || undefined + }); } else { state.select.ranges.push({ start: { col: 0, row: 0 }, @@ -226,6 +244,23 @@ export function updateSelectPosition( skipBodyMerge: true }); } + // 旧逻辑 + // if (state.select.headerSelectMode === 'body') { + // state.select.ranges.push({ + // start: { + // col: table.leftRowSeriesNumberCount, + // row: table.columnHeaderLevelCount + // }, + // end: { col: table.colCount - 1, row: table.rowCount - 1 }, + // skipBodyMerge: true + // }); + // } else { + // state.select.ranges.push({ + // start: { col: 0, row: 0 }, + // end: { col: table.colCount - 1, row: table.rowCount - 1 }, + // skipBodyMerge: true + // }); + // } } else if ((table.internalProps.layoutMap as SimpleHeaderLayoutMap).isSeriesNumberInBody(col, row)) { // 选中内容行号单元格 extendSelectRange = false; @@ -249,7 +284,8 @@ export function updateSelectPosition( // 选中表头行号单元格 extendSelectRange = false; const { cornerHeaderSelectMode } = state.select; - if (state.select.headerSelectMode === 'body' || cornerHeaderSelectMode === 'body') { + + if (cornerHeaderSelectMode === 'body') { state.select.ranges.push({ start: { col: table.rowHeaderLevelCount + table.leftRowSeriesNumberCount, @@ -258,40 +294,41 @@ export function updateSelectPosition( end: { col: table.colCount - 1, row: table.rowCount - 1 }, skipBodyMerge: true }); + } else if (cornerHeaderSelectMode === 'cell') { + // 选中普通单元格 + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: cellRange.end.row }, + skipBodyMerge: skipBodyMerge || undefined + }); + } else if (cornerHeaderSelectMode === 'inline') { + // inline + const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); + state.select.ranges.push({ + start: { col: cellRange.start.col, row: cellRange.start.row }, + end: { col: cellRange.end.col, row: table.rowCount - 1 }, + skipBodyMerge: true + }); + } else if (cornerHeaderSelectMode === 'all') { + // all 或者用户传的其他的什么值 :'' | 'test',虽然类型会提示用户不能为其他的值, + state.select.ranges.push({ + start: { + col: table.leftRowSeriesNumberCount, + row: 0 + }, + end: { col: table.colCount - 1, row: table.rowCount - 1 }, + skipBodyMerge: true + }); } else { - if (cornerHeaderSelectMode === 'cell') { - // 选中普通单元格 - const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); - state.select.ranges.push({ - start: { col: cellRange.start.col, row: cellRange.start.row }, - end: { col: cellRange.end.col, row: cellRange.end.row }, - skipBodyMerge: skipBodyMerge || undefined - }); - } else if (cornerHeaderSelectMode === 'inline') { - // inline - const cellRange = skipBodyMerge ? { start: { col, row }, end: { col, row } } : table.getCellRange(col, row); - state.select.ranges.push({ - start: { col: cellRange.start.col, row: cellRange.start.row }, - end: { col: cellRange.end.col, row: table.rowCount - 1 }, - skipBodyMerge: true - }); - } else { - // all 或者用户传的其他的什么值 :'' | 'test',虽然类型会提示用户不能为其他的值, - state.select.ranges.push({ - start: { - col: table.leftRowSeriesNumberCount, - row: 0 - }, - end: { col: table.colCount - 1, row: table.rowCount - 1 }, - skipBodyMerge: true - }); - } - // 选中全部 - // state.select.ranges.push({ - // start: { col: table.leftRowSeriesNumberCount, row: 0 }, - // end: { col: table.colCount - 1, row: table.rowCount - 1 }, - // skipBodyMerge: true - // }); + state.select.ranges.push({ + start: { + col: table.leftRowSeriesNumberCount, + row: 0 + }, + end: { col: table.colCount - 1, row: table.rowCount - 1 }, + skipBodyMerge: true + }); } } else if (col >= 0 && row >= 0) { // 选中普通单元格 diff --git a/packages/vtable/src/state/state.ts b/packages/vtable/src/state/state.ts index c71c307610..228b7cae4a 100644 --- a/packages/vtable/src/state/state.ts +++ b/packages/vtable/src/state/state.ts @@ -441,7 +441,6 @@ export class StateManager { // enableColumnHighlight, /** 点击表头单元格时连带body整行或整列选中 或仅选中当前单元格,默认或整行或整列选中*/ headerSelectMode, - cornerHeaderSelectMode, disableSelect, disableHeaderSelect, highlightMode, @@ -451,7 +450,8 @@ export class StateManager { { /** 点击表头单元格时连带body整行或整列选中 或仅选中当前单元格,默认或整行或整列选中*/ headerSelectMode: 'inline', - cornerHeaderSelectMode: 'all', // 点击 corner 默认选中整个图表 + /** 不默认设置该值了,从用户传的 cornerHeaderSelectMode 中获取 */ + // cornerHeaderSelectMode: '', disableSelect: false, disableHeaderSelect: false, highlightMode: 'cell', @@ -460,6 +460,13 @@ export class StateManager { this.table.options.select ); + /** 设置 cornerHeaderSelectMode */ + const cornerHeaderSelectMode = this.table.options.select?.cornerHeaderSelectMode + ? this.table.options.select?.cornerHeaderSelectMode + : this.table.options.select?.headerSelectMode === 'body' + ? this.table.options.select?.headerSelectMode + : 'all'; + // if (enableRowHighlight && enableColumnHighlight) { // this.select.highlightScope = HighlightScope.cross; // } else if (enableRowHighlight) {