From 89cef4e9a9b1ffb11ab72c33e8b283bf59377f47 Mon Sep 17 00:00:00 2001 From: roymondchen Date: Thu, 11 Jun 2026 17:25:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(editor):=20=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E4=B8=8E=E4=BB=A3=E7=A0=81=E5=9D=97=E5=8E=86=E5=8F=B2=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E4=B8=8D=E5=86=8D=E5=90=88=E5=B9=B6=E7=9B=B8=E9=82=BB?= =?UTF-8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 每条操作独立展示,与页面历史的合并策略区分开。 --- .../layouts/history-list/HistoryListPanel.vue | 4 +- packages/editor/src/services/history.ts | 9 ++--- packages/editor/src/utils/history.ts | 40 +++++-------------- .../editor/tests/unit/utils/history.spec.ts | 16 +++++--- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/packages/editor/src/layouts/history-list/HistoryListPanel.vue b/packages/editor/src/layouts/history-list/HistoryListPanel.vue index b4a64339..0a703a27 100644 --- a/packages/editor/src/layouts/history-list/HistoryListPanel.vue +++ b/packages/editor/src/layouts/history-list/HistoryListPanel.vue @@ -100,8 +100,8 @@ /** * 历史记录面板:在顶部 NavMenu 上点击图标打开 popover,分三个 tab: * - 页面:当前活动页面的历史栈,连续修改同一节点的多步会被合并成一组 - * - 数据源:以 dataSource.id 分组,每组内部相邻的连续 update 自动合并 - * - 代码块:同上,按 codeBlock.id 分组并合并相邻 update + * - 数据源:以 dataSource.id 分桶,每条操作记录独立展示 + * - 代码块:同上,按 codeBlock.id 分桶,每条操作记录独立展示 * * 数据通过 historyService 暴露的聚合 API 读取,UI 仅用于只读展示, * 同时支持点击任意一条记录跳转至该状态: diff --git a/packages/editor/src/services/history.ts b/packages/editor/src/services/history.ts index 5107e525..062dd7a8 100644 --- a/packages/editor/src/services/history.ts +++ b/packages/editor/src/services/history.ts @@ -526,11 +526,8 @@ class History extends BaseService { } /** - * 取出全部代码块的历史栈,按 codeBlockId 分组。 - * 同一栈内相邻、同 opType 且作用于同一 id 的多步会被合并为一个 group: - * - 这正是"代码块/数据源各自按 id 分栈"的天然表现,再叠加"连续修改同目标的相邻步骤合并展示"。 - * - 合并后 group 暴露子步骤数组,UI 可展开查看每一步的 changeRecords。 - * - applied 字段:组内最后一步是否处于已应用段。 + * 取出全部代码块的历史栈,按 codeBlockId 分桶展示。 + * 同一栈内每条操作记录独立成组,不做相邻 update 合并。 */ public getCodeBlockHistoryGroups(): CodeBlockHistoryGroup[] { const groups: CodeBlockHistoryGroup[] = []; @@ -622,7 +619,7 @@ class History extends BaseService { } /** - * 取出全部数据源的历史栈,按 dataSourceId 分组。同上。 + * 取出全部数据源的历史栈,按 dataSourceId 分桶展示。同上,每条操作独立成组。 */ public getDataSourceHistoryGroups(): DataSourceHistoryGroup[] { const groups: DataSourceHistoryGroup[] = []; diff --git a/packages/editor/src/utils/history.ts b/packages/editor/src/utils/history.ts index f2d8985d..86aabd30 100644 --- a/packages/editor/src/utils/history.ts +++ b/packages/editor/src/utils/history.ts @@ -121,8 +121,7 @@ export const markStackSaved = (undoRedo?: UndoRed /** * 把单个「按 id 分栈」的历史栈(代码块 / 数据源)拆成若干 group: - * - 把"新增/删除"独立成组(语义上属于一次性事件,不应与 update 合并); - * - 连续 'update' 合并到同一组,组内 steps 顺序就是发生顺序。 + * 每条操作记录独立成组,不做相邻 update 合并(与页面历史的合并策略不同)。 * * 代码块与数据源除 `kind` 外结构完全一致,统一由本方法处理;`kind` 决定返回的具体分组类型。 */ @@ -139,38 +138,19 @@ export const mergeStackSteps = { - type Group = { - kind: K; - id: Id; - opType: HistoryOpType; - steps: { step: S; index: number; applied: boolean; isCurrent?: boolean }[]; - applied: boolean; - isCurrent?: boolean; - }; - const groups: Group[] = []; - let current: Group | null = null; const currentIndex = cursor - 1; - list.forEach((step, index) => { - const { opType } = step; + return list.map((step, index) => { const applied = index < cursor; const isCurrent = index === currentIndex; - if (opType === 'update' && current?.opType === 'update') { - current.steps.push({ step, index, applied, isCurrent }); - current.applied = applied; - if (isCurrent) current.isCurrent = true; - } else { - current = { - kind, - id, - opType, - steps: [{ step, index, applied, isCurrent }], - applied, - isCurrent, - }; - groups.push(current); - } + return { + kind, + id, + opType: step.opType, + steps: [{ step, index, applied, isCurrent }], + applied, + isCurrent, + }; }); - return groups; }; /** diff --git a/packages/editor/tests/unit/utils/history.spec.ts b/packages/editor/tests/unit/utils/history.spec.ts index cbd48637..8d155310 100644 --- a/packages/editor/tests/unit/utils/history.spec.ts +++ b/packages/editor/tests/unit/utils/history.spec.ts @@ -122,18 +122,20 @@ describe('markStackSaved', () => { }); describe('mergeStackSteps', () => { - test('连续 update 合并为一组', () => { + test('连续 update 各自独立成组', () => { const list = [ { opType: 'update', uuid: '1' }, { opType: 'update', uuid: '2' }, ] as CodeBlockStepValue[]; const groups = mergeStackSteps('code-block', 'code_1', list, 2); - expect(groups).toHaveLength(1); - expect(groups[0].steps).toHaveLength(2); + expect(groups).toHaveLength(2); + expect(groups[0].steps).toHaveLength(1); + expect(groups[1].steps).toHaveLength(1); expect(groups[0].opType).toBe('update'); + expect(groups[1].opType).toBe('update'); }); - test('add / update 不合并', () => { + test('add / update 各自独立成组', () => { const list = [ { opType: 'add', uuid: '1' }, { opType: 'update', uuid: '2' }, @@ -148,10 +150,12 @@ describe('mergeStackSteps', () => { { opType: 'update', uuid: '2' }, ] as CodeBlockStepValue[]; const groups = mergeStackSteps('code-block', 'code_1', list, 1); - expect(groups[0].applied).toBe(false); + expect(groups[0].applied).toBe(true); expect(groups[0].steps[0].applied).toBe(true); expect(groups[0].steps[0].isCurrent).toBe(true); - expect(groups[0].steps[1].applied).toBe(false); + expect(groups[0].isCurrent).toBe(true); + expect(groups[1].applied).toBe(false); + expect(groups[1].steps[0].applied).toBe(false); }); });