修复模板分类批量导入格式识别

- 修复模板库批量导入只使用严格 JSON.parse 导致合法 colors/names 内容被误判非法的问题。

- 支持 [[colors], [names]] 数组格式和 {colors, names} 对象格式,并兼容带“批量导入分类:”前缀、代码块、未加引号 keys、单引号、中文逗号/冒号和尾随逗号的粘贴内容。

- 增加导入数据校验:分类名称不能为空,颜色必须是 0-255 的 RGB 三元组,缺失颜色继续使用默认灰色并保留预览提示。

- 补充 TemplateRegistry 测试,覆盖对象格式、数组格式和常见粘贴格式;同步 AGENTS 和 doc 中的模板导入说明与测试计划。

- 已验证 TemplateRegistry 组件测试、TypeScript 类型检查、生产构建、服务重启、前后端健康检查和 git diff 检查。
This commit is contained in:
2026-05-03 17:45:49 +08:00
parent 0b4e10209a
commit 7f8722410c
7 changed files with 111 additions and 17 deletions

View File

@@ -107,6 +107,45 @@ describe('TemplateRegistry', () => {
expect(screen.getByText('分类A')).toBeInTheDocument();
});
it('imports the array colors/names format into the edit modal', async () => {
apiMock.getTemplates.mockResolvedValueOnce([]);
render(<TemplateRegistry />);
fireEvent.click(screen.getByText('新建方案'));
fireEvent.click(screen.getByText('批量导入'));
fireEvent.change(screen.getByPlaceholderText('[[[255,0,0], [0,255,0]], ["分类A", "分类B"]]'), {
target: { value: '[[[255,0,0], [0,255,0]], ["分类A", "分类B"]]' },
});
expect(screen.getByText(/将导入 2 个分类maskid 从 1 开始分配/)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '导入' }));
expect(screen.getByText('分类A')).toBeInTheDocument();
expect(screen.getByText('分类B')).toBeInTheDocument();
});
it('imports pasted color/name content with a label prefix and loose object keys', async () => {
apiMock.getTemplates.mockResolvedValueOnce([]);
render(<TemplateRegistry />);
fireEvent.click(screen.getByText('新建方案'));
fireEvent.click(screen.getByText('批量导入'));
fireEvent.change(screen.getByPlaceholderText('[[[255,0,0], [0,255,0]], ["分类A", "分类B"]]'), {
target: {
value: `批量导入分类:{
colors: [[25500], [02550],],
names: ['分类A', '分类B',],
}`,
},
});
expect(screen.getByText(/将导入 2 个分类maskid 从 1 开始分配/)).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '导入' }));
expect(screen.getByText('分类A')).toBeInTheDocument();
expect(screen.getByText('分类B')).toBeInTheDocument();
});
it('shows JSON import errors inline instead of blocking alerts', async () => {
apiMock.getTemplates.mockResolvedValueOnce([]);