Files
AIclinicalresearch/backend/debug-qc-field-mismatch.ts

156 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 调试脚本:诊断字段获取问题
*
* 问题:
* 1. Record 1 有 age=21但质控显示空
* 2. Record 3 应该有年龄但 API 返回无
*/
import { PrismaClient } from '@prisma/client';
import { RedcapAdapter } from './src/modules/iit-manager/adapters/RedcapAdapter.js';
import jsonLogic from 'json-logic-js';
const prisma = new PrismaClient();
async function main() {
console.log('='.repeat(60));
console.log('🔍 字段获取问题诊断');
console.log('='.repeat(60));
// 1. 获取项目配置
const project = await prisma.iitProject.findFirst({
where: { name: { contains: 'test0207' } },
});
if (!project) {
console.log('❌ 未找到项目');
await prisma.$disconnect();
return;
}
// 2. 获取质控规则配置
const skill = await prisma.iitSkill.findFirst({
where: { projectId: project.id, isActive: true },
});
if (!skill) {
console.log('❌ 未找到激活的 Skill');
await prisma.$disconnect();
return;
}
const config = skill.config as any;
const rules = config?.rules || [];
console.log('\n📋 质控规则中的字段配置:');
for (const rule of rules) {
console.log(` ${rule.name}:`);
console.log(` field: "${rule.field}"`);
console.log(` logic: ${JSON.stringify(rule.logic)}`);
}
// 3. 从 REDCap 获取原始数据(检查 Record 1 和 Record 3
const adapter = new RedcapAdapter(project.redcapUrl, project.redcapApiToken);
console.log('\n' + '='.repeat(60));
console.log('📊 检查 Record 1 的原始 REDCap 数据');
console.log('='.repeat(60));
// 获取 Record 1 的原始记录(不合并)
const rawRecords1 = await adapter.exportRecords({ records: ['1'] });
console.log(`\nRecord 1 原始记录数: ${rawRecords1.length} (多事件)`);
for (const r of rawRecords1) {
console.log(` 事件: ${r.redcap_event_name || '(无)'}`);
console.log(` age: ${r.age !== undefined ? r.age : '(字段不存在)'}`);
console.log(` date_of_birth: ${r.date_of_birth || '(空)'}`);
}
// 获取 Record 1 合并后的数据
const merged1 = await adapter.getRecordById('1');
console.log(`\nRecord 1 合并后数据:`);
console.log(` age: ${merged1?.age}`);
console.log(` date_of_birth: ${merged1?.date_of_birth}`);
console.log('\n' + '='.repeat(60));
console.log('📊 检查 Record 3 的原始 REDCap 数据');
console.log('='.repeat(60));
const rawRecords3 = await adapter.exportRecords({ records: ['3'] });
console.log(`\nRecord 3 原始记录数: ${rawRecords3.length} (多事件)`);
for (const r of rawRecords3) {
console.log(` 事件: ${r.redcap_event_name || '(无)'}`);
console.log(` age: ${r.age !== undefined ? r.age : '(字段不存在)'}`);
console.log(` date_of_birth: ${r.date_of_birth || '(空)'}`);
}
const merged3 = await adapter.getRecordById('3');
console.log(`\nRecord 3 合并后数据:`);
console.log(` age: ${merged3?.age}`);
console.log(` date_of_birth: ${merged3?.date_of_birth}`);
// 4. 模拟质控规则执行,看看哪里出问题
console.log('\n' + '='.repeat(60));
console.log('📊 模拟质控规则执行 (Record 1)');
console.log('='.repeat(60));
// 找到年龄规则
const ageRule = rules.find((r: any) => r.name.includes('年龄'));
if (ageRule && merged1) {
console.log(`\n规则: ${ageRule.name}`);
console.log(` field: "${ageRule.field}"`);
console.log(` logic: ${JSON.stringify(ageRule.logic)}`);
// 检查字段值
const fieldValue = merged1[ageRule.field];
console.log(`\n 从数据中获取 "${ageRule.field}" 的值: ${fieldValue} (类型: ${typeof fieldValue})`);
// 尝试执行 JSON Logic
try {
const result = jsonLogic.apply(ageRule.logic, merged1);
console.log(` JSON Logic 执行结果: ${result}`);
} catch (error: any) {
console.log(` JSON Logic 执行失败: ${error.message}`);
}
// 列出数据中所有可能的年龄相关字段
console.log(`\n 数据中的年龄相关字段:`);
for (const [key, value] of Object.entries(merged1)) {
if (key.toLowerCase().includes('age') || key === ageRule.field) {
console.log(` ${key}: ${value}`);
}
}
}
// 5. 检查 SkillRunner 如何获取记录
console.log('\n' + '='.repeat(60));
console.log('📊 检查 SkillRunner 获取记录的方式');
console.log('='.repeat(60));
// 查看 getRecordsToProcess 的实现逻辑
// 它可能使用不同的方法获取数据
const allRecordsMerged = await adapter.getAllRecordsMerged();
console.log(`\ngetAllRecordsMerged 返回 ${allRecordsMerged.length} 条记录`);
const r1FromAll = allRecordsMerged.find(r => r.record_id === '1');
const r3FromAll = allRecordsMerged.find(r => r.record_id === '3');
console.log(`\nRecord 1 from getAllRecordsMerged:`);
console.log(` age: ${r1FromAll?.age}`);
console.log(` date_of_birth: ${r1FromAll?.date_of_birth}`);
console.log(`\nRecord 3 from getAllRecordsMerged:`);
console.log(` age: ${r3FromAll?.age}`);
console.log(` date_of_birth: ${r3FromAll?.date_of_birth}`);
console.log('\n' + '='.repeat(60));
console.log('✅ 诊断完成');
console.log('='.repeat(60));
await prisma.$disconnect();
}
main().catch(async (error) => {
console.error('❌ 脚本出错:', error);
await prisma.$disconnect();
process.exit(1);
});