feat: polish reporting templates and shared controls

This commit is contained in:
hectorzhao
2026-07-15 16:31:49 +08:00
parent 28fb8e9038
commit a7a4e8d9f6
21 changed files with 488 additions and 119 deletions
+28 -5
View File
@@ -79,7 +79,7 @@ function createPrismaMock() {
drainageItems: [],
reportTasks: [],
}]),
findUnique: jest.fn().mockResolvedValue({ id: 'sig-1', tenantId: 'tenant-1', auditStatus: 'pending' }),
findUnique: jest.fn().mockResolvedValue({ id: 'sig-1', tenantId: 'tenant-1', applicationId: 'app-1', name: '签名A', auditStatus: 'pending' }),
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'sig-new', tenantId: 'tenant-1', ...data })),
update: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'sig-1', tenantId: 'tenant-1', ...data })),
},
@@ -121,7 +121,7 @@ function createPrismaMock() {
signature: { id: 'sig-1', name: '签名A' },
variables: [{ name: 'name', required: true }],
}]),
findUnique: jest.fn().mockResolvedValue({ id: 'tpl-1', tenantId: 'tenant-1', auditStatus: 'pending' }),
findUnique: jest.fn().mockResolvedValue({ id: 'tpl-1', tenantId: 'tenant-1', applicationId: 'app-1', signatureId: 'sig-1', content: '【签名A】您好${name}', auditStatus: 'pending' }),
update: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'tpl-1', tenantId: 'tenant-1', ...data })),
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'tpl-new', ...data })),
},
@@ -832,7 +832,7 @@ describe('SmsConfigService', () => {
applicationId: 'app-1',
signatureId: 'sig-1',
name: '运营添加模板',
content: '您的验证码为${code}',
content: '【签名A】您的验证码为${code}',
variables: [{ name: 'code', example: '123456', required: true }],
}, { initialAuditStatus: 'approved' })).resolves.toEqual(expect.objectContaining({ id: 'tpl-new' }));
@@ -842,6 +842,7 @@ describe('SmsConfigService', () => {
applicationId: 'app-1',
signatureId: 'sig-1',
name: '运营添加模板',
content: '【签名A】您的验证码为${code}',
auditStatus: 'approved',
variables: {
create: [{ name: 'code', example: '123456', required: true }],
@@ -868,7 +869,7 @@ describe('SmsConfigService', () => {
applicationId: 'app-1',
signatureId: 'sig-1',
name: '模板B',
content: '验证码${code}',
content: '【签名A】验证码${code}',
variables: [{ name: 'code', example: '123456', required: true }],
})).resolves.toEqual(expect.objectContaining({ id: 'tpl-1', name: '模板B' }));
@@ -879,7 +880,7 @@ describe('SmsConfigService', () => {
applicationId: 'app-1',
signatureId: 'sig-1',
name: '模板B',
content: '验证码${code}',
content: '【签名A】验证码${code}',
variables: {
create: [{ name: 'code', example: '123456', required: true }],
},
@@ -887,4 +888,26 @@ describe('SmsConfigService', () => {
include: { variables: true, application: true, tenant: true, signature: true },
});
});
it('requires the selected signature at the start of template content', async () => {
const prisma = createPrismaMock();
const service = new SmsConfigService(prisma as never);
await expect(service.createTemplate({
tenantId: 'tenant-1',
applicationId: 'app-1',
name: '缺少签名模板',
content: '您的验证码为${code}',
})).rejects.toThrow('短信模板必须选择短信签名');
await expect(service.createTemplate({
tenantId: 'tenant-1',
applicationId: 'app-1',
signatureId: 'sig-1',
name: '签名不匹配模板',
content: '【其他签名】您的验证码为${code}',
})).rejects.toThrow('模板内容必须以所选短信签名 【签名A】 开头');
expect(prisma.smsTemplate.create).not.toHaveBeenCalled();
});
});