feat(iit): Complete V3.1 QC engine + GCP business reports + AI timeline + bug fixes

V3.1 QC Engine:
- QcExecutor unified entry + D1-D7 dimension engines + three-level aggregation
- HealthScoreEngine + CompletenessEngine + ProtocolDeviationEngine + QcAggregator
- B4 flexible cron scheduling (project-level cronExpression + pg-boss dispatcher)
- Prisma migrations for qc_field_status, event_status, project_stats

GCP Business Reports (Phase A - 4 reports):
- D1 Eligibility: record_summary full list + qc_field_status D1 overlay
- D2 Completeness: data entry rate and missing rate aggregation
- D3/D4 Query Tracking: severity distribution from qc_field_status
- D6 Protocol Deviation: D6 dimension filtering
- 4 frontend table components + ReportsPage 5-tab restructure

AI Timeline Enhancement:
- SkillRunner outputs totalRules (33 actual rules vs 1 skill)
- iitQcCockpitController severity mapping fix (critical->red, warning->yellow)
- AiStreamPage expandable issue detail table with Chinese labels
- Event label localization (eventLabel from backend)

Business-side One-click Batch QC:
- DashboardPage batch QC button with SyncOutlined icon
- Auto-refresh QcReport cache after batch execution

Bug Fixes:
- dimension_code -> rule_category in 4 SQL queries
- D1 eligibility data source: record_summary full + qc_field_status overlay
- Timezone UTC -> Asia/Shanghai (QcReportService toBeijingTime helper)
- Pass rate calculation: passed/totalEvents instead of passed/totalRecords

Docs:
- Update IIT module status with GCP reports and bug fix milestones
- Update system status doc v6.6 with IIT progress

Tested: Backend compiles, frontend linter clean, batch QC verified
Made-with: Cursor
This commit is contained in:
2026-03-01 22:49:49 +08:00
parent 0b29fe88b5
commit 2030ebe28f
50 changed files with 8687 additions and 1492 deletions

View File

@@ -243,6 +243,43 @@ export async function iitQcCockpitRoutes(fastify: FastifyInstance) {
},
}, iitQcCockpitController.refreshReport.bind(iitQcCockpitController));
// V3.1: D1-D7 维度统计
fastify.get('/:projectId/qc-cockpit/dimensions', {
schema: {
description: 'D1-D7 各维度详细统计',
tags: ['IIT Admin - 质控驾驶舱'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getDimensions.bind(iitQcCockpitController));
// V3.1: 按受试者缺失率
fastify.get('/:projectId/qc-cockpit/completeness', {
schema: {
description: '按受试者返回缺失率',
tags: ['IIT Admin - 质控驾驶舱'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getCompleteness.bind(iitQcCockpitController));
// V3.1: 字段级质控结果(分页)
fastify.get('/:projectId/qc-cockpit/field-status', {
schema: {
description: '字段级质控结果(分页,支持 recordId/eventId/status 筛选)',
tags: ['IIT Admin - 质控驾驶舱'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
querystring: {
type: 'object',
properties: {
recordId: { type: 'string' },
eventId: { type: 'string' },
status: { type: 'string', enum: ['PASS', 'FAIL', 'WARNING'] },
page: { type: 'string', default: '1' },
pageSize: { type: 'string', default: '50' },
},
},
},
}, iitQcCockpitController.getFieldStatus.bind(iitQcCockpitController));
// AI 工作时间线
fastify.get('/:projectId/qc-cockpit/timeline', iitQcCockpitController.getTimeline.bind(iitQcCockpitController));
@@ -251,4 +288,59 @@ export async function iitQcCockpitRoutes(fastify: FastifyInstance) {
// 质控趋势近N天通过率折线
fastify.get('/:projectId/qc-cockpit/trend', iitQcCockpitController.getTrend.bind(iitQcCockpitController));
// V3.1: D6 方案偏离列表
fastify.get('/:projectId/qc-cockpit/deviations', iitQcCockpitController.getDeviations.bind(iitQcCockpitController));
// ============================================================
// GCP 业务报表路由
// ============================================================
fastify.get('/:projectId/qc-cockpit/report/eligibility', {
schema: {
description: 'D1 筛选入选表 — 入排合规性评估',
tags: ['IIT Admin - GCP 报表'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getEligibilityReport.bind(iitQcCockpitController));
fastify.get('/:projectId/qc-cockpit/report/completeness', {
schema: {
description: 'D2 数据完整性总览 — L1 项目 + L2 受试者 + L3 事件级统计',
tags: ['IIT Admin - GCP 报表'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getCompletenessReport.bind(iitQcCockpitController));
fastify.get('/:projectId/qc-cockpit/report/completeness/fields', {
schema: {
description: 'D2 字段级懒加载 — 按 recordId + eventId 返回缺失字段清单',
tags: ['IIT Admin - GCP 报表'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
querystring: {
type: 'object',
properties: {
recordId: { type: 'string' },
eventId: { type: 'string' },
},
required: ['recordId', 'eventId'],
},
},
}, iitQcCockpitController.getCompletenessFields.bind(iitQcCockpitController));
fastify.get('/:projectId/qc-cockpit/report/equery-log', {
schema: {
description: 'D3/D4 eQuery 全生命周期跟踪 — 统计 + 分组 + 全量明细',
tags: ['IIT Admin - GCP 报表'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getEqueryLogReport.bind(iitQcCockpitController));
fastify.get('/:projectId/qc-cockpit/report/deviations', {
schema: {
description: 'D6 方案偏离报表 — 结构化超窗数据 + 汇总统计',
tags: ['IIT Admin - GCP 报表'],
params: { type: 'object', properties: { projectId: { type: 'string' } }, required: ['projectId'] },
},
}, iitQcCockpitController.getDeviationReport.bind(iitQcCockpitController));
}