feat(iit): QC deep fix + V3.1 architecture plan + project member management

QC System Deep Fix:
- HardRuleEngine: add null tolerance + field availability pre-check (skipped status)
- SkillRunner: baseline data merge for follow-up events + field availability check
- QcReportService: record-level pass rate calculation + accurate LLM XML report
- iitBatchController: legacy log cleanup (eventId=null) + upsert RecordSummary
- seed-iit-qc-rules: null/empty string tolerance + applicableEvents config

V3.1 Architecture Design (docs only, no code changes):
- QC engine V3.1 plan: 5-level data structure (CDISC ODM) + D1-D7 dimensions
- Three-batch implementation strategy (A: foundation, B: bubbling, C: new engines)
- Architecture team review: 4 whitepapers reviewed + feedback doc + 4 critical suggestions
- CRA Agent strategy roadmap + CRA 4-tool explanation doc for clinical experts

Project Member Management:
- Cross-tenant member search and assignment (remove tenant restriction)
- IIT project detail page enhancement with tabbed layout (KB + members)
- IitProjectContext for business-side project selection
- System-KB route access control adjustment for project operators

Frontend:
- AdminLayout sidebar menu restructure
- IitLayout with project context provider
- IitMemberManagePage new component
- Business-side pages adapt to project context

Prisma:
- 2 new migrations (user-project RBAC + is_demo flag)
- Schema updates for project member management

Made-with: Cursor
This commit is contained in:
2026-03-01 15:27:05 +08:00
parent c3f7d54fdf
commit 0b29fe88b5
61 changed files with 6877 additions and 524 deletions

View File

@@ -27,60 +27,95 @@ const INCLUSION_RULES = [
name: '年龄范围检查',
field: 'age',
logic: {
and: [
{ '>=': [{ var: 'age' }, 16] },
{ '<=': [{ var: 'age' }, 35] }
or: [
{ '==': [{ var: 'age' }, null] },
{ '==': [{ var: 'age' }, ''] },
{
and: [
{ '>=': [{ var: 'age' }, 16] },
{ '<=': [{ var: 'age' }, 35] }
]
}
]
},
message: '年龄不在 16-35 岁范围内',
severity: 'error',
category: 'inclusion'
category: 'inclusion',
applicableEvents: [] as string[],
},
{
id: 'inc_002',
name: '出生日期范围检查',
field: 'birth_date',
logic: {
and: [
{ '>=': [{ var: 'birth_date' }, '1989-01-01'] },
{ '<=': [{ var: 'birth_date' }, '2008-01-01'] }
or: [
{ '==': [{ var: 'birth_date' }, null] },
{ '==': [{ var: 'birth_date' }, ''] },
{
and: [
{ '>=': [{ var: 'birth_date' }, '1989-01-01'] },
{ '<=': [{ var: 'birth_date' }, '2008-01-01'] }
]
}
]
},
message: '出生日期不在 1989-01-01 至 2008-01-01 范围内',
severity: 'error',
category: 'inclusion'
category: 'inclusion',
applicableEvents: [] as string[],
},
{
id: 'inc_003',
name: '月经周期规律性检查',
field: 'menstrual_cycle',
logic: {
and: [
{ '>=': [{ var: 'menstrual_cycle' }, 21] },
{ '<=': [{ var: 'menstrual_cycle' }, 35] }
or: [
{ '==': [{ var: 'menstrual_cycle' }, null] },
{ '==': [{ var: 'menstrual_cycle' }, ''] },
{
and: [
{ '>=': [{ var: 'menstrual_cycle' }, 21] },
{ '<=': [{ var: 'menstrual_cycle' }, 35] }
]
}
]
},
message: '月经周期不在 21-35 天范围内28±7天',
severity: 'error',
category: 'inclusion'
category: 'inclusion',
applicableEvents: [] as string[],
},
{
id: 'inc_004',
name: 'VAS 评分检查',
field: 'vas_score',
logic: { '>=': [{ var: 'vas_score' }, 4] },
logic: {
or: [
{ '==': [{ var: 'vas_score' }, null] },
{ '==': [{ var: 'vas_score' }, ''] },
{ '>=': [{ var: 'vas_score' }, 4] }
]
},
message: 'VAS 疼痛评分 < 4 分,不符合入组条件',
severity: 'error',
category: 'inclusion'
category: 'inclusion',
applicableEvents: [] as string[],
},
{
id: 'inc_005',
name: '知情同意书签署检查',
field: 'informed_consent',
logic: { '==': [{ var: 'informed_consent' }, 1] },
logic: {
or: [
{ '==': [{ var: 'informed_consent' }, null] },
{ '==': [{ var: 'informed_consent' }, ''] },
{ '==': [{ var: 'informed_consent' }, 1] }
]
},
message: '未签署知情同意书',
severity: 'error',
category: 'inclusion'
category: 'inclusion',
applicableEvents: [] as string[],
}
];
@@ -92,37 +127,65 @@ const EXCLUSION_RULES = [
id: 'exc_001',
name: '继发性痛经排除',
field: 'secondary_dysmenorrhea',
logic: { '!=': [{ var: 'secondary_dysmenorrhea' }, 1] },
logic: {
or: [
{ '==': [{ var: 'secondary_dysmenorrhea' }, null] },
{ '==': [{ var: 'secondary_dysmenorrhea' }, ''] },
{ '!=': [{ var: 'secondary_dysmenorrhea' }, 1] }
]
},
message: '存在继发性痛经(盆腔炎、子宫内膜异位症、子宫腺肌病等)',
severity: 'error',
category: 'exclusion'
category: 'exclusion',
applicableEvents: [] as string[],
},
{
id: 'exc_002',
name: '妊娠哺乳期排除',
field: 'pregnancy_lactation',
logic: { '!=': [{ var: 'pregnancy_lactation' }, 1] },
logic: {
or: [
{ '==': [{ var: 'pregnancy_lactation' }, null] },
{ '==': [{ var: 'pregnancy_lactation' }, ''] },
{ '!=': [{ var: 'pregnancy_lactation' }, 1] }
]
},
message: '妊娠或哺乳期妇女,不符合入组条件',
severity: 'error',
category: 'exclusion'
category: 'exclusion',
applicableEvents: [] as string[],
},
{
id: 'exc_003',
name: '严重疾病排除',
field: 'severe_disease',
logic: { '!=': [{ var: 'severe_disease' }, 1] },
logic: {
or: [
{ '==': [{ var: 'severe_disease' }, null] },
{ '==': [{ var: 'severe_disease' }, ''] },
{ '!=': [{ var: 'severe_disease' }, 1] }
]
},
message: '合并有心脑血管、肝、肾、造血系统等严重疾病或精神病',
severity: 'error',
category: 'exclusion'
category: 'exclusion',
applicableEvents: [] as string[],
},
{
id: 'exc_004',
name: '月经周期不规律排除',
field: 'irregular_menstruation',
logic: { '!=': [{ var: 'irregular_menstruation' }, 1] },
logic: {
or: [
{ '==': [{ var: 'irregular_menstruation' }, null] },
{ '==': [{ var: 'irregular_menstruation' }, ''] },
{ '!=': [{ var: 'irregular_menstruation' }, 1] }
]
},
message: '月经周期不规律或间歇性痛经发作',
severity: 'error',
category: 'exclusion'
category: 'exclusion',
applicableEvents: [] as string[],
}
];
@@ -242,7 +305,7 @@ async function main() {
// 1. 先获取项目 ID
const project = await prisma.iitProject.findFirst({
where: { name: 'test0102' }
where: { name: { in: ['test0207', 'test0102'] } }
});
if (!project) {