feat(api): 完善家谱系统API客户端契约
- 实现家谱管理相关方法,包括创建、详情、概览、我的家谱和选项查询 - 添加家谱加入申请功能,支持申请、审核、取消和待审核列表操作 - 集成通知详情获取方法和通知ID安全验证机制 - 完善功德记录、谱文、相册、视频、祭祀活动的完整CRUD操作契约 - 实现家谱成员管理功能,包含成员列表、更新、移除和转让所有者操作 - 优化路径ID验证逻辑,拒绝不安全的数值ID并提供明确错误提示 - 更新测试用例以验证所有新增API方法的路径和请求体白名单机制
This commit is contained in:
@@ -74,6 +74,32 @@ test('字辈列表要求管理接口返回稳定的直接字段', () => {
|
||||
}), null);
|
||||
});
|
||||
|
||||
test('字辈响应保留页面闭环所需字段并保持所有业务 ID 为字符串', () => {
|
||||
assert.deepEqual(GenerationPages.normalizeGenerationPoem({
|
||||
poemId: '2060000000000000000',
|
||||
genealogyId: '2061000000000000000',
|
||||
genealogyNo: 'G20260728001',
|
||||
genealogyName: '叶氏家谱',
|
||||
generationNo: 3,
|
||||
generationText: '万',
|
||||
description: '第三世',
|
||||
sortOrder: 30,
|
||||
status: '0',
|
||||
remark: '祖训'
|
||||
}), {
|
||||
poemId: '2060000000000000000',
|
||||
genealogyId: '2061000000000000000',
|
||||
genealogyNo: 'G20260728001',
|
||||
genealogyName: '叶氏家谱',
|
||||
generationNo: 3,
|
||||
generationText: '万',
|
||||
status: '0',
|
||||
description: '第三世',
|
||||
sortOrder: 30,
|
||||
remark: '祖训'
|
||||
});
|
||||
});
|
||||
|
||||
test('字辈批量输入按 Apifox 限制校验', () => {
|
||||
assert.equal(GenerationPages.validateGenerationPoemBody({ generationNo: 0, generationText: '万' }), '世代序号必须是 1 到 2147483647 之间的整数');
|
||||
assert.equal(GenerationPages.validateGenerationPoemBody({ generationNo: 3, generationText: '' }), '请填写字辈文字');
|
||||
@@ -81,16 +107,103 @@ test('字辈批量输入按 Apifox 限制校验', () => {
|
||||
assert.equal(GenerationPages.validateGenerationPoemBody({ generationNo: 3, generationText: '万', sortOrder: 2147483648 }), '排序值必须在 -2147483648 到 2147483647 之间');
|
||||
assert.equal(GenerationPages.validateBatchBody({ poemText: '', disableMissing: false }), '请填写批量字辈内容');
|
||||
assert.deepEqual(GenerationPages.splitPoemText('德,承;家、亦/传|芳\n远'), ['德', '承', '家', '亦', '传', '芳', '远']);
|
||||
assert.equal(GenerationPages.validateBatchBody({ poemText: '甲'.repeat(51), disableMissing: false }), '单个字辈不能超过 50 个字符');
|
||||
assert.deepEqual(GenerationPages.splitPoemText('德承家亦'), ['德', '承', '家', '亦']);
|
||||
assert.equal(GenerationPages.validateBatchBody({ poemText: '甲'.repeat(51) + ' 德', disableMissing: false }), '单个字辈不能超过 50 个字符');
|
||||
assert.equal(GenerationPages.validateBatchBody({ poemText: Array(502).fill('甲').join(' '), disableMissing: false }), '一次最多导入 500 个世代');
|
||||
assert.equal(GenerationPages.validateBatchBody({ poemText: '德承家亦', disableMissing: false }), '');
|
||||
});
|
||||
|
||||
test('家谱内容权限决定读取正常列表还是包含停用项的管理列表', () => {
|
||||
assert.deepEqual(GenerationPages.normalizeGenerationAccess({ canEditContent: false }), {
|
||||
canEditContent: false,
|
||||
listMethod: 'generationPoems'
|
||||
});
|
||||
assert.deepEqual(GenerationPages.normalizeGenerationAccess({ canEditContent: true }), {
|
||||
canEditContent: true,
|
||||
listMethod: 'generationPoemsManagement'
|
||||
});
|
||||
});
|
||||
|
||||
test('批量预览逐项校验动作、状态、ID 与汇总计数', () => {
|
||||
assert.deepEqual(GenerationPages.normalizePreview({
|
||||
createCount: 1,
|
||||
updateCount: 0,
|
||||
keepCount: 0,
|
||||
disableCount: 1,
|
||||
items: [
|
||||
{
|
||||
generationNo: 1,
|
||||
newGenerationText: '德',
|
||||
newStatus: '0',
|
||||
action: 'create'
|
||||
},
|
||||
{
|
||||
poemId: '2060000000000000000',
|
||||
generationNo: 2,
|
||||
oldGenerationText: '承',
|
||||
oldStatus: '0',
|
||||
newStatus: '1',
|
||||
action: 'disable',
|
||||
warning: '保存后该世代会停用,不会删除历史记录'
|
||||
}
|
||||
]
|
||||
}), {
|
||||
createCount: 1,
|
||||
updateCount: 0,
|
||||
keepCount: 0,
|
||||
disableCount: 1,
|
||||
items: [
|
||||
{
|
||||
generationNo: 1,
|
||||
newGenerationText: '德',
|
||||
newStatus: '0',
|
||||
action: 'create'
|
||||
},
|
||||
{
|
||||
poemId: '2060000000000000000',
|
||||
generationNo: 2,
|
||||
oldGenerationText: '承',
|
||||
oldStatus: '0',
|
||||
newStatus: '1',
|
||||
action: 'disable',
|
||||
warning: '保存后该世代会停用,不会删除历史记录'
|
||||
}
|
||||
]
|
||||
});
|
||||
assert.equal(GenerationPages.normalizePreview({ createCount: 0, updateCount: 0, keepCount: 0, disableCount: 0, items: [] }), null);
|
||||
assert.equal(GenerationPages.normalizePreview({
|
||||
createCount: 1,
|
||||
updateCount: 0,
|
||||
keepCount: 0,
|
||||
disableCount: 0,
|
||||
items: [{ generationNo: 1, action: 'create' }]
|
||||
}), null);
|
||||
assert.equal(GenerationPages.normalizePreview({
|
||||
createCount: 2,
|
||||
updateCount: 0,
|
||||
keepCount: 0,
|
||||
disableCount: 0,
|
||||
items: [{ generationNo: 1, newGenerationText: '德', newStatus: '0', action: 'create' }]
|
||||
}), null);
|
||||
});
|
||||
|
||||
test('停用缺失世代的批量保存确认文案明确不会删除历史', () => {
|
||||
assert.equal(
|
||||
GenerationPages.buildBatchConfirmMessage(true),
|
||||
'确认按当前预览保存字辈,并停用未出现在文本中的后续世代吗?历史记录不会删除。'
|
||||
);
|
||||
assert.equal(GenerationPages.buildBatchConfirmMessage(false), '确认按当前预览保存字辈吗?');
|
||||
});
|
||||
|
||||
test('字辈批量示例明确使用 Apifox 支持的分隔符', () => {
|
||||
const page = fs.readFileSync(path.join(__dirname, '..', 'profile-generation.html'), 'utf8');
|
||||
const styles = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'profile-module.css'), 'utf8');
|
||||
|
||||
assert.match(page, /placeholder="例如:德 承 家 亦(用空格或标点分隔)"/);
|
||||
assert.doesNotMatch(page, /placeholder="例如:德承家亦"/);
|
||||
assert.match(page, /data-generation-management[^>]+hidden/);
|
||||
assert.match(page, /data-generation-add[^>]+disabled|disabled[^>]+data-generation-add/);
|
||||
assert.match(styles, /\[data-generation-management\]\[hidden\]\s*\{[^}]*display:\s*none\s*!important/s);
|
||||
});
|
||||
|
||||
test('字辈管理接口的 403 不是登录失效', () => {
|
||||
|
||||
Reference in New Issue
Block a user