同步传播链编辑并保护模板切换

- 修改激活模板时,如果当前项目已有 mask,先提示确认并清空所有本地 mask 和已保存后端标注;无 mask 项目可直接切换。

- 模板库详情页将“+ 新建分类”改为带编辑图标的“编辑模板”,并打开完整模板编辑弹窗。

- 区域合并会按 propagation lineage 找到其它传播帧的对应主区域和参与区域,逐帧执行 union,只删除实际参与合并的对应 mask。

- 重叠区域去除会按 propagation lineage 同步到其它传播帧的对应区域,保留参与扣除 mask,不再只改当前帧。

- 当前帧清空遮罩会同步删除这些 mask 的关联自动传播结果,并新增左侧工具栏清空入口。

- 传播链同步编辑保留 source、source_annotation_id、source_mask_id、propagation_seed_key 等 metadata,避免时间轴帧属性变色。

- 补充模板切换确认、模板编辑按钮、左侧清空入口、传播链合并/去除和清空传播链的前端回归测试。

- 更新 AGENTS、接口契约、冻结需求、设计冻结和测试计划文档。
This commit is contained in:
2026-05-03 19:10:12 +08:00
parent 2da73f9acd
commit 4d6bbf2b80
15 changed files with 524 additions and 93 deletions

View File

@@ -238,7 +238,7 @@ describe('TemplateRegistry', () => {
expect(screen.queryByPlaceholderText('类别')).not.toBeInTheDocument();
});
it('shows the semantic tree title and opens the add-class modal from the detail view', async () => {
it('shows the semantic tree title and opens the edit-template modal from the detail view', async () => {
apiMock.getTemplates.mockResolvedValueOnce([
{
id: 't1',
@@ -269,7 +269,9 @@ describe('TemplateRegistry', () => {
expect(screen.queryByText(/Painter's Algorithm Weight/)).not.toBeInTheDocument();
expect(screen.queryByText('器官')).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /新建分类/ }));
expect(screen.queryByRole('button', { name: /新建分类/ })).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '编辑模板' }));
fireEvent.click(screen.getByRole('button', { name: /添加分类/ }));
expect(screen.getByDisplayValue('新类别')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '保存' }));