7.2 KiB
7.2 KiB
2026-02-08 事件级质控与报告优化开发记录
开发日期: 2026-02-08
开发人员: AI Assistant
版本: V3.1
状态: ✅ 基本测试成功
📋 开发概述
本次开发主要完成了 IIT Manager Agent 质控系统的重大架构升级,从"记录级合并质控"改为"事件级独立质控",同时优化了质控报告生成逻辑和 AI 对话能力。
🎯 核心改动
1. 事件级质控架构(V3.1)
问题背景:
- REDCap 纵向研究中,一个 record_id 可能有多个事件(如筛选期、随访1、随访2等)
- 之前的质控将所有事件的数据合并到一条记录,导致数据覆盖问题
- 不同事件的表单应该独立质控
解决方案:
| 改动文件 | 改动内容 |
|---|---|
RedcapAdapter.ts |
新增 getAllRecordsByEvent() 方法,按 record+event 返回独立数据单元 |
RedcapAdapter.ts |
新增 getFormEventMapping() 和 getEvents() 获取事件配置 |
RedcapAdapter.ts |
新增 getFormCompletionStatusByEvent() 按事件获取表单完成状态 |
HardRuleEngine.ts |
QCRule 接口新增 applicableEvents 和 applicableForms 字段 |
SoftRuleEngine.ts |
SoftRuleCheck 接口同样新增事件/表单适用性字段 |
SkillRunner.ts |
重构 runByTrigger() 按 record+event 独立执行质控 |
SkillRunner.ts |
新增 filterApplicableRules() 方法,按事件/表单动态过滤规则 |
SkillRunner.ts |
SkillRunResult 新增 eventName、eventLabel、forms 字段 |
SkillRunner.ts |
saveQcLog() 现在保存 eventId 到数据库 |
架构变化:
之前(记录级合并):
Record 1 = Event A 数据 + Event B 数据 + ... (合并可能覆盖)
之后(事件级独立):
Record 1 + Event A = 独立质控单元 1
Record 1 + Event B = 独立质控单元 2
...
2. 质控报告优化
问题背景:
- 报告从多个事件收集问题,导致同一规则重复出现
- 报告使用缓存,不是最新数据
- 显示限制导致部分问题被隐藏
解决方案:
| 改动文件 | 改动内容 |
|---|---|
QcReportService.ts |
SQL 查询改用 DISTINCT ON (record_id, event_id) |
QcReportService.ts |
新增 deduplicateIssues() 按 recordId+ruleId 去重 |
QcReportService.ts |
统计计数也按 recordId+ruleId 去重(使用 Set) |
QcReportService.ts |
移除所有 slice 显示限制,显示所有问题 |
QcReportService.ts |
兼容新旧两种 issues 格式(数组 vs { items: [...] }) |
3. 批量操作 API 更新
| 改动文件 | 改动内容 |
|---|---|
iitBatchController.ts |
batchQualityCheck 改用 SkillRunner.runByTrigger() |
ToolsService.ts |
batch_quality_check 工具同样改用事件级质控 |
4. 前端优化
| 改动文件 | 改动内容 |
|---|---|
QcReportDrawer.tsx |
导出 XML 前自动刷新报告(确保获取最新数据) |
QcReportDrawer.tsx |
文件名添加时分(HHMM格式)便于区分 |
IitQcCockpitPage.tsx |
删除重复的"全量质控"按钮(保留配置页的) |
5. AI 对话增强
| 改动文件 | 改动内容 |
|---|---|
ChatService.ts |
增强意图识别,支持更多质控查询表达方式 |
PromptBuilder.ts |
修复 this 上下文丢失导致的 500 错误 |
🐛 修复的 Bug
Bug 1: formatPatientData undefined 错误
现象: 点击记录详情时返回 500 错误
原因: buildClinicalSlice 函数导出时丢失了 this 上下文
修复: 将 this.formatPatientData 改为 PromptBuilder.formatPatientData
Bug 2: 质控报告重复问题
现象: Record 1 显示 14 条违规,实际应该是 5 条
原因: 同一规则在多个事件中执行,结果都被收集到报告中
修复: 按 recordId + ruleId 去重,只保留最新结果
Bug 3: 报告记录数不正确
现象: 显示 13 条记录,实际有 14 条
原因: 从 iitRecordSummary 获取记录数,该表可能缺少记录
修复: 从质控日志获取独立 record_id 数量
Bug 4: AI 无法回答质控问题
现象: 问"严重违规有几项",AI 说"没有相关信息"
原因: 意图识别规则不够全面
修复: 增加更多匹配模式(质控问题、严重违规、record问题等)
📁 涉及文件清单
后端核心文件
backend/src/modules/iit-manager/
├── adapters/
│ └── RedcapAdapter.ts ✅ 新增 3 个方法
├── engines/
│ ├── HardRuleEngine.ts ✅ QCRule 接口扩展
│ ├── SoftRuleEngine.ts ✅ SoftRuleCheck 接口扩展
│ └── SkillRunner.ts ✅ 事件级质控核心重构
├── services/
│ ├── QcReportService.ts ✅ 去重 + 移除限制
│ ├── ChatService.ts ✅ 意图识别增强
│ ├── PromptBuilder.ts ✅ 修复 this 上下文
│ └── ToolsService.ts ✅ batch_quality_check 更新
backend/src/modules/admin/iit-projects/
└── iitBatchController.ts ✅ 使用 SkillRunner
前端文件
frontend-v2/src/modules/admin/
├── components/qc-cockpit/
│ └── QcReportDrawer.tsx ✅ 自动刷新 + 文件名优化
└── pages/
└── IitQcCockpitPage.tsx ✅ 删除重复按钮
🧪 测试验证
测试结果
| 测试项 | 结果 | 备注 |
|---|---|---|
| 事件级质控执行 | ✅ | 14 条记录 × 5 个事件 = 70 个质控单元 |
| 规则动态过滤 | ✅ | 配置 applicableForms 后规则只在相关事件执行 |
| 报告去重 | ✅ | 168 条问题去重后变为 69 条 |
| XML 导出 | ✅ | 自动刷新 + 显示所有问题 |
| AI 质控查询 | ✅ | 能正确回答"严重违规有几项" |
| 详情页 500 错误 | ✅ | formatPatientData 修复后正常 |
📝 配置说明
规则适用性配置示例
// 在 Skill 配置中设置规则的适用表单
{
"id": "inc_001",
"name": "年龄范围检查",
"applicableForms": ["basic_demography_form"], // 只在人口学表单执行
"applicableEvents": [] // 空数组 = 适用所有事件
}
执行配置更新脚本
cd backend
npx tsx update-skill-applicable-forms.ts
🔄 后续优化建议
- 规则配置 UI:在管理端添加规则 → 表单映射的可视化配置界面
- 事件标签显示:在报告中显示事件的中文标签(如"筛选期")而非唯一标识
- 增量质控:只对有变化的事件执行质控,避免全量重算
- 质控历史:保留历史质控结果,支持趋势分析
📚 相关文档
总结: 本次开发完成了 IIT 质控系统从"记录级"到"事件级"的架构升级,解决了数据合并覆盖、报告重复、AI 无法回答等多个问题,为 REDCap 纵向研究提供了更精确的质控能力。