feat: refine report material workflow states

This commit is contained in:
hectorzhao
2026-09-03 12:50:33 +08:00
parent 55915ed826
commit 4ff6ed0786
12 changed files with 237 additions and 31 deletions
@@ -118,6 +118,59 @@ describe('report workbench pages', () => {
expect(screen.queryByText('选择本页全部可生成资料')).not.toBeInTheDocument();
});
it('uses explicit colors and text for material pool work states', async () => {
const materials = [
['pending', '待生成'],
['partial', '部分可生成'],
['incomplete', '资料不完整'],
['abandoned', '全部放弃'],
['no-route', '无有效通道'],
['generated', '已生成'],
].map(([id]) => ({
id: `signature:${id}`,
tenantId: 'tenant-1',
signatureId: `signature-${id}`,
applicationId: 'app-1',
reportType: 'signature' as const,
name: `资料${id}`,
materialVersion: 2,
changedAt: '2026-09-03T01:00:00.000Z',
tenant: { id: 'tenant-1', name: '测试企业' },
application: { id: 'app-1', name: '测试应用' },
}));
const target = (eligible: boolean, blockedReasons: string[] = []) => ({ eligible, blockedReasons });
adminApi.listPendingReportMaterials.mockResolvedValue({ items: materials, total: materials.length, page: 1, pageSize: 20 });
adminApi.preflightReportMaterialBatch.mockResolvedValue({
eligible: true,
eligibleTargetCount: 2,
skippedTargetCount: 5,
items: [
{ id: 'signature:pending', eligible: true, blockedReasons: [], targets: [target(true)] },
{ id: 'signature:partial', eligible: true, blockedReasons: ['缺少必填字段:营业执照'], targets: [target(true), target(false, ['缺少必填字段:营业执照'])] },
{ id: 'signature:incomplete', eligible: false, blockedReasons: ['缺少必填字段:营业执照'], targets: [target(false, ['缺少必填字段:营业执照'])] },
{ id: 'signature:abandoned', eligible: false, blockedReasons: ['该通道报备明细已放弃报备'], targets: [target(false, ['该通道报备明细已放弃报备'])] },
{ id: 'signature:no-route', eligible: false, blockedReasons: ['当前应用没有启用且可路由的通道'], targets: [] },
{ id: 'signature:generated', eligible: false, blockedReasons: ['同一资料版本已在批次 RB-1 生成'], targets: [target(false, ['同一资料版本已在批次 RB-1 生成'])] },
],
});
render(
<MemoryRouter>
<AdminReportMaterialsPage />
</MemoryRouter>,
);
expect(await screen.findByText('V2待生成')).toHaveClass('ui-tag--warning');
expect(screen.getByText('V2部分可生成')).toHaveClass('ui-tag--warning');
expect(screen.getByText('V2资料不完整')).toHaveClass('ui-tag--danger');
expect(screen.getByText('全部放弃')).toHaveClass('ui-tag--neutral');
expect(screen.getByText('无有效通道')).toHaveClass('ui-tag--neutral');
expect(screen.getByText('V2已生成')).toHaveClass('ui-tag--success');
screen.getAllByText('缺少必填字段:营业执照').forEach((message) =>
expect(message).toHaveClass('status-danger'),
);
});
it('shows and copies the channel brief returned by the batch detail API', async () => {
const batch = {
id: 'batch-1',