Features: - Backend statistics API (cloud-native Prisma aggregation) - Results page with hybrid solution (AI consensus + human final decision) - Excel export (frontend generation, zero disk write, cloud-native) - PRISMA-style exclusion reason analysis with bar chart - Batch selection and export (3 export methods) - Fixed logic contradiction (inclusion does not show exclusion reason) - Optimized table width (870px, no horizontal scroll) Components: - Backend: screeningController.ts - add getProjectStatistics API - Frontend: ScreeningResults.tsx - complete results page (hybrid solution) - Frontend: excelExport.ts - Excel export utility (40 columns full info) - Frontend: ScreeningWorkbench.tsx - add navigation button - Utils: get-test-projects.mjs - quick test tool Architecture: - Cloud-native: backend aggregation reduces network transfer - Cloud-native: frontend Excel generation (zero file persistence) - Reuse platform: global prisma instance, logger - Performance: statistics API < 500ms, Excel export < 3s (1000 records) Documentation: - Update module status guide (add Week 4 features) - Update task breakdown (mark Week 4 completed) - Update API design spec (add statistics API) - Update database design (add field usage notes) - Create Week 4 development plan - Create Week 4 completion report - Create technical debt list Test: - End-to-end flow test passed - All features verified - Performance test passed - Cloud-native compliance verified Ref: Week 4 Development Plan Scope: ASL Module MVP - Title Abstract Screening Results Cloud-Native: Backend aggregation + Frontend Excel generation
139 lines
3.3 KiB
TypeScript
139 lines
3.3 KiB
TypeScript
/**
|
||
* 测试JSON解析器的修复效果
|
||
*
|
||
* 测试目的:验证中文引号等格式问题是否能被正确处理
|
||
*/
|
||
|
||
import { parseJSON } from '../src/common/utils/jsonParser.js';
|
||
|
||
console.log('\n🧪 JSON解析器修复测试\n');
|
||
|
||
// 测试用例
|
||
const testCases = [
|
||
{
|
||
name: '正常JSON(ASCII引号)',
|
||
input: '{"conclusion": "exclude", "confidence": 0.95}',
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: '中文引号JSON',
|
||
input: '{"conclusion": "exclude", "confidence": 0.95}',
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: '混合引号JSON',
|
||
input: '{"conclusion": "exclude", "confidence": 0.95}',
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: 'JSON代码块(中文引号)',
|
||
input: `\`\`\`json
|
||
{
|
||
"judgment": {
|
||
"P": "match",
|
||
"I": "match"
|
||
},
|
||
"conclusion": "include",
|
||
"confidence": 0.85,
|
||
"reason": "虽然对照组不是安慰剂,但研究质量高"
|
||
}
|
||
\`\`\``,
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: '带额外文字的JSON',
|
||
input: `这是筛选结果:
|
||
\`\`\`json
|
||
{"conclusion": "exclude", "confidence": 0.90}
|
||
\`\`\`
|
||
以上是我的判断。`,
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: '全角逗号和冒号',
|
||
input: '{"conclusion":"exclude","confidence":0.95}',
|
||
expectSuccess: true
|
||
},
|
||
{
|
||
name: '不完整的JSON(应失败)',
|
||
input: '{"conclusion": "exclude", "confidence":',
|
||
expectSuccess: false
|
||
},
|
||
{
|
||
name: '非JSON文本(应失败)',
|
||
input: 'This is not a JSON string at all.',
|
||
expectSuccess: false
|
||
},
|
||
{
|
||
name: '复杂嵌套JSON(中文引号)',
|
||
input: `{
|
||
"judgment": {
|
||
"P": "match",
|
||
"I": "partial",
|
||
"C": "mismatch",
|
||
"S": "match"
|
||
},
|
||
"evidence": {
|
||
"P": "研究对象为急性缺血性卒中患者",
|
||
"I": "干预措施为替格瑞洛",
|
||
"C": "对照组为氯吡格雷而非安慰剂",
|
||
"S": "随机对照试验"
|
||
},
|
||
"conclusion": "exclude",
|
||
"confidence": 0.92,
|
||
"reason": "虽然P、I、S维度匹配,但对照组不符合要求"
|
||
}`,
|
||
expectSuccess: true
|
||
}
|
||
];
|
||
|
||
// 运行测试
|
||
let passed = 0;
|
||
let failed = 0;
|
||
|
||
testCases.forEach((testCase, index) => {
|
||
console.log(`[测试 ${index + 1}/${testCases.length}] ${testCase.name}`);
|
||
|
||
const result = parseJSON(testCase.input);
|
||
const success = result.success === testCase.expectSuccess;
|
||
|
||
if (success) {
|
||
console.log(' ✅ 通过');
|
||
if (result.success) {
|
||
console.log(` 📄 解析结果: ${JSON.stringify(result.data).substring(0, 100)}...`);
|
||
}
|
||
passed++;
|
||
} else {
|
||
console.log(' ❌ 失败');
|
||
console.log(` 期望: ${testCase.expectSuccess ? '成功' : '失败'}`);
|
||
console.log(` 实际: ${result.success ? '成功' : '失败'}`);
|
||
if (!result.success) {
|
||
console.log(` 错误: ${result.error}`);
|
||
}
|
||
failed++;
|
||
}
|
||
console.log('');
|
||
});
|
||
|
||
// 总结
|
||
console.log('='.repeat(60));
|
||
console.log('📊 测试总结\n');
|
||
console.log(`✅ 通过: ${passed}/${testCases.length}`);
|
||
console.log(`❌ 失败: ${failed}/${testCases.length}`);
|
||
console.log(`📈 成功率: ${(passed / testCases.length * 100).toFixed(1)}%`);
|
||
|
||
if (passed === testCases.length) {
|
||
console.log('\n🎉 所有测试通过!JSON解析器修复成功!');
|
||
} else {
|
||
console.log('\n⚠️ 部分测试失败,需要进一步调试。');
|
||
}
|
||
|
||
console.log('='.repeat(60) + '\n');
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|