feat: 重构 Skill 管理与编辑工作台

- 统一列表、分类、新建与详情页的产品交互

- 提供 Markdown 实时编辑、源码与脚本资源工作台

- 实现能力自动保存、导入导出及完整状态反馈
This commit is contained in:
2026-07-27 18:54:57 +08:00
parent 2a9e882ac6
commit 0dc5c3ca55
78 changed files with 16413 additions and 799 deletions

View File

@@ -0,0 +1,55 @@
import { describe, expect, it } from 'vitest';
import {
isSkillAccessDeniedError,
isSkillCapabilityConflictError,
isSkillFileConflictError,
resolveSkillApiErrorMessage,
} from './skill-api-error';
describe('skill API conflict errors', () => {
it('recognizes response bodies thrown directly by the request client', () => {
expect(
isSkillFileConflictError({
errorCode: 4091,
message: '文件已被其他操作更新',
}),
).toBe(true);
expect(
isSkillCapabilityConflictError({
errorCode: 4093,
message: '能力配置已被其他操作更新',
}),
).toBe(true);
});
it('also recognizes Axios-shaped conflicts and ignores ordinary errors', () => {
expect(
isSkillFileConflictError({ response: { data: {}, status: 409 } }),
).toBe(true);
expect(
isSkillCapabilityConflictError({
response: { data: { errorCode: 4093 }, status: 400 },
}),
).toBe(true);
expect(isSkillFileConflictError({ errorCode: 500 })).toBe(false);
});
it('recognizes direct and Axios-shaped access denials', () => {
expect(isSkillAccessDeniedError({ errorCode: 403 })).toBe(true);
expect(
isSkillAccessDeniedError({ response: { data: {}, status: 401 } }),
).toBe(true);
expect(isSkillAccessDeniedError({ errorCode: 500 })).toBe(false);
});
it('keeps backend business messages for recoverable category actions', () => {
expect(
resolveSkillApiErrorMessage(
{ response: { data: { message: '请先迁移该分类下的 Skill' } } },
'删除失败',
),
).toBe('请先迁移该分类下的 Skill');
expect(resolveSkillApiErrorMessage(undefined, '删除失败')).toBe('删除失败');
});
});