完善遮罩删除范围选择

- 删除/清空已保存标注前预检后端 annotation id,跳过本地陈旧 id,避免重复 DELETE 产生 404 控制台红字

- 左侧工具栏新增 DEL 删除选中遮罩入口,调整清空遮罩弹窗文案为“清空所有传播帧”,并加入按帧范围选择入口

- 区域合并和重叠区域去除在存在传播帧时弹出当前帧/所有传播帧选择,传播帧同步后保留原 lineage metadata

- 多 polygon 或分离区域组成的 mask 选中后显示全部顶点与插点手柄,同帧传播链分散 mask 点选时联动高亮

- 调整工具栏分组分隔线位置,只在清空遮罩下方保留 tool-group-separator 测试标记

- 更新 VideoWorkspace、CanvasArea、ToolsPalette 回归测试和相关项目文档
This commit is contained in:
2026-05-03 22:14:00 +08:00
parent 275be62db5
commit 5ae1d15336
12 changed files with 215 additions and 55 deletions

View File

@@ -871,11 +871,12 @@ describe('CanvasArea', () => {
fireEvent.click(paths[1]);
const vertexHandles = screen.getAllByTestId('konva-circle')
.filter((element) => element.getAttribute('data-fill') === '#ffffff');
expect(vertexHandles).toHaveLength(6);
fireEvent.mouseUp(vertexHandles[0], { clientX: 120, clientY: 120 });
expect(useStore.getState().masks[0].segmentation).toEqual([
[10, 10, 50, 10, 50, 40],
[120, 120, 150, 100, 150, 140],
[120, 120, 50, 10, 50, 40],
[100, 100, 150, 100, 150, 140],
]);
});
@@ -979,6 +980,8 @@ describe('CanvasArea', () => {
fireEvent.click(paths[0]);
fireEvent.click(paths[1]);
fireEvent.click(screen.getByRole('button', { name: '合并选中' }));
expect(screen.getByText('选择操作范围')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '处理所有传播帧' }));
await waitFor(() => expect(onDeleteMaskAnnotations).toHaveBeenCalledWith(expect.arrayContaining(['2', '20'])));
const masks = useStore.getState().masks;
@@ -1094,6 +1097,8 @@ describe('CanvasArea', () => {
fireEvent.click(paths[0]);
fireEvent.click(paths[1]);
fireEvent.click(screen.getByRole('button', { name: '从主区域去除' }));
expect(screen.getByText('选择操作范围')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '处理所有传播帧' }));
await waitFor(() => expect(useStore.getState().masks.find((mask) => mask.id === 'annotation-10')?.saveStatus).toBe('dirty'));
expect(onDeleteMaskAnnotations).not.toHaveBeenCalled();