From fa5bb4a5aced4effd88ca9fbcfc14b4d1af7b921 Mon Sep 17 00:00:00 2001 From: wpxp123456 <2677556700@qq.com> Date: Wed, 10 Dec 2025 10:58:00 +0800 Subject: [PATCH] fix(formula): optimize the behavior when selecting merged cells during formula editing (#6270) --- packages/core/src/sheets/sheet-skeleton.ts | 29 +++++++++++++++---- .../ref-selections.render-service.ts | 26 +++++++++++++++-- .../base-selection-render.service.ts | 3 +- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/core/src/sheets/sheet-skeleton.ts b/packages/core/src/sheets/sheet-skeleton.ts index f283875db1..e6c98a7fb0 100644 --- a/packages/core/src/sheets/sheet-skeleton.ts +++ b/packages/core/src/sheets/sheet-skeleton.ts @@ -40,7 +40,7 @@ import { DocumentDataModel } from '../docs/data-model/document-data-model'; import { IConfigService } from '../services/config/config.service'; import { IContextService } from '../services/context/context.service'; import { LocaleService } from '../services/locale/locale.service'; -import { isCellCoverable, ObjectMatrix, searchArray, Tools } from '../shared'; +import { isCellCoverable, ObjectMatrix, Rectangle, searchArray, Tools } from '../shared'; import { ImageCacheMap } from '../shared/cache/image-cache'; import { getIntersectRange } from '../shared/range'; import { Skeleton } from '../skeleton'; @@ -489,7 +489,8 @@ export class SheetSkeleton extends Skeleton { * @param range * @returns {IRange} expanded range because merge info. */ - expandRangeByMerge(range: IRange): IRange { + // eslint-disable-next-line max-lines-per-function + expandRangeByMerge(range: IRange, inRefSelectionMode?: boolean): IRange { let { startRow, startColumn, endRow, endColumn } = range; const mergeData = this._worksheetData.mergeData; if (!mergeData) { @@ -502,7 +503,10 @@ export class SheetSkeleton extends Skeleton { } let isSearching = true; - const searchedMarge = new ObjectMatrix(); + const searchedMerge = new ObjectMatrix(); + + let searchedMergeSize = 0; + let lastSearchedMergeCell: Nullable = null; // the loop breaks when there are not merged cells intersect with the current range // NOTE: what about the performance issue? @@ -517,7 +521,7 @@ export class SheetSkeleton extends Skeleton { endColumn: mainEndColumn, } = mergeData[i]; - if (searchedMarge.getValue(mainStartRow, mainStartColumn)) { + if (searchedMerge.getValue(mainStartRow, mainStartColumn)) { continue; } @@ -540,12 +544,27 @@ export class SheetSkeleton extends Skeleton { startColumn = Math.min(startColumn, mainStartColumn); endRow = Math.max(endRow, mainEndRow); endColumn = Math.max(endColumn, mainEndColumn); - searchedMarge.setValue(mainStartRow, mainStartColumn, true); + searchedMerge.setValue(mainStartRow, mainStartColumn, true); isSearching = true; + searchedMergeSize++; + lastSearchedMergeCell = rect2; } } } + /** + * If the selected cell is merged cell, we need to adjust the selection range to the merged main cell in the formula reference selection scenario. + * Must ensure that only one merged cell is involved in the selection and that the merged cell fully contains the selection range. + */ + if (inRefSelectionMode && searchedMergeSize === 1 && Rectangle.contains(lastSearchedMergeCell!, range)) { + return { + startRow: lastSearchedMergeCell!.startRow, + startColumn: lastSearchedMergeCell!.startColumn, + endRow: lastSearchedMergeCell!.startRow, + endColumn: lastSearchedMergeCell!.startColumn, + }; + } + return { startRow, startColumn, diff --git a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts index 059faf8a1b..7a2366f145 100644 --- a/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts +++ b/packages/sheets-formula-ui/src/services/render-services/ref-selections.render-service.ts @@ -325,9 +325,31 @@ export class RefSelectionsRenderService extends BaseSelectionRenderService imple selectCell.endColumn = this._skeleton.getColumnCount() - 1; } - const selectionWithStyle: ISelectionWithStyle = { range: selectCell, primary: selectCell, style: null }; + let selectionWithStyle: ISelectionWithStyle = { range: selectCell, primary: selectCell, style: null }; + // If the selected cell is merged cell, we need to adjust the selection range to the merged main cell in the formula reference selection scenario. + if (selectCell.isMerged || selectCell.isMergedMainCell) { + selectionWithStyle = { + range: { + ...selectCell, + startRow: selectCell.startRow, + endRow: selectCell.startRow, + startColumn: selectCell.startColumn, + endColumn: selectCell.startColumn, + }, + primary: { + ...selectCell, + actualRow: selectCell.startRow, + actualColumn: selectCell.startColumn, + startRow: selectCell.startRow, + endRow: selectCell.startRow, + startColumn: selectCell.startColumn, + endColumn: selectCell.startColumn, + }, + style: null, + }; + } selectionWithStyle.range.rangeType = rangeType; - // const selectionCellWithCoord = this._getSelectionWithCoordByOffset(offsetX, offsetY, scaleX, scaleY, scrollXY); + const selectionCellWithCoord = attachSelectionWithCoord(selectionWithStyle, this._skeleton); this._startRangeWhenPointerDown = { ...selectionCellWithCoord.rangeWithCoord }; diff --git a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts index 599f281dc0..bbffd54a53 100644 --- a/packages/sheets-ui/src/services/selection/base-selection-render.service.ts +++ b/packages/sheets-ui/src/services/selection/base-selection-render.service.ts @@ -732,8 +732,9 @@ export class BaseSelectionRenderService extends Disposable implements ISheetSele }; if (this._shouldDetectMergedCells) { - newSelectionRange = skeleton.expandRangeByMerge(newSelectionRange); + newSelectionRange = skeleton.expandRangeByMerge(newSelectionRange, this.inRefSelectionMode()); } + const newSelection: ISelectionWithStyle = { range: newSelectionRange, primary: undefined, style: null }; const newSelectionRangeWithCoord = attachSelectionWithCoord(newSelection, skeleton); newSelectionRangeWithCoord.rangeWithCoord.unitId = unitId;