feat(asl): Complete Day 5 - Fulltext Screening Backend API Development

- Implement 5 core API endpoints (create task, get progress, get results, update decision, export Excel)
- Add FulltextScreeningController with Zod validation (652 lines)
- Implement ExcelExporter service with 4-sheet report generation (352 lines)
- Register routes under /api/v1/asl/fulltext-screening
- Create 31 REST Client test cases
- Add automated integration test script
- Fix PDF extraction fallback mechanism in LLM12FieldsService
- Update API design documentation to v3.0
- Update development plan to v1.2
- Create Day 5 development record
- Clean up temporary test files
This commit is contained in:
2025-11-23 10:52:07 +08:00
parent 08aa3f6c28
commit 88cc049fb3
232 changed files with 7780 additions and 441 deletions

View File

@@ -0,0 +1,272 @@
###
# 全文复筛API测试
# 使用REST Client插件运行VS Code
###
@baseUrl = http://localhost:3001
@apiPrefix = /api/v1/asl/fulltext-screening
### ========================================
### 准备工作:获取已有项目和文献
### ========================================
### 1. 获取项目列表
GET {{baseUrl}}/api/v1/asl/projects
Content-Type: application/json
### 2. 获取项目文献列表替换projectId
@projectId = 55941145-bba0-4b15-bda4-f0a398d78208
GET {{baseUrl}}/api/v1/asl/projects/{{projectId}}/literatures?page=1&limit=10
Content-Type: application/json
### ========================================
### API 1: 创建全文复筛任务
### ========================================
### 测试1.1: 创建任务(正常情况)
# @name createTask
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "{{projectId}}",
"literatureIds": [
"e9c18ba3-9ad7-4cc9-ac78-b74a7ec91b12",
"e44ea8d9-6ba8-4b88-8d24-4fb46b3584e0"
],
"modelA": "deepseek-v3",
"modelB": "qwen-max",
"promptVersion": "v1.0.0"
}
### 保存taskId
@taskId = {{createTask.response.body.data.taskId}}
### 测试1.2: 创建任务(缺少必填参数)
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "{{projectId}}"
}
### 测试1.3: 创建任务projectId不存在
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "00000000-0000-0000-0000-000000000000",
"literatureIds": ["lit-001"]
}
### 测试1.4: 创建任务literatureIds为空
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "{{projectId}}",
"literatureIds": []
}
### ========================================
### API 2: 获取任务进度
### ========================================
### 测试2.1: 获取任务进度(正常情况)
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}
Content-Type: application/json
### 测试2.2: 获取任务进度taskId不存在
GET {{baseUrl}}{{apiPrefix}}/tasks/00000000-0000-0000-0000-000000000000
Content-Type: application/json
### 测试2.3: 等待5秒后再次查询进度
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}
Content-Type: application/json
### ========================================
### API 3: 获取任务结果
### ========================================
### 测试3.1: 获取所有结果(默认参数)
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results
Content-Type: application/json
### 测试3.2: 获取所有结果第一页每页10条
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?page=1&pageSize=10
Content-Type: application/json
### 测试3.3: 仅获取冲突项
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?filter=conflict
Content-Type: application/json
### 测试3.4: 仅获取待审核项
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?filter=pending
Content-Type: application/json
### 测试3.5: 仅获取已审核项
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?filter=reviewed
Content-Type: application/json
### 测试3.6: 按优先级降序排序
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?sortBy=priority&sortOrder=desc
Content-Type: application/json
### 测试3.7: 按创建时间升序排序
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?sortBy=createdAt&sortOrder=asc
Content-Type: application/json
### 测试3.8: 分页测试第2页
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?page=2&pageSize=5
Content-Type: application/json
### 测试3.9: 无效的filter参数
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?filter=invalid
Content-Type: application/json
### 测试3.10: 无效的pageSize超过最大值
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?pageSize=999
Content-Type: application/json
### ========================================
### API 4: 人工审核决策
### ========================================
### 先获取一个结果ID
# @name getFirstResult
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/results?pageSize=1
Content-Type: application/json
### 保存resultId
@resultId = {{getFirstResult.response.body.data.results[0].resultId}}
### 测试4.1: 更新决策为纳入
PUT {{baseUrl}}{{apiPrefix}}/results/{{resultId}}/decision
Content-Type: application/json
{
"finalDecision": "include",
"reviewNotes": "经人工审核,确认纳入"
}
### 测试4.2: 更新决策为排除(带排除原因)
PUT {{baseUrl}}{{apiPrefix}}/results/{{resultId}}/decision
Content-Type: application/json
{
"finalDecision": "exclude",
"exclusionReason": "关键字段field9结局指标数据不完整",
"reviewNotes": "仅报告P值缺少均值±SD"
}
### 测试4.3: 排除但不提供排除原因(应该失败)
PUT {{baseUrl}}{{apiPrefix}}/results/{{resultId}}/decision
Content-Type: application/json
{
"finalDecision": "exclude"
}
### 测试4.4: 无效的finalDecision值
PUT {{baseUrl}}{{apiPrefix}}/results/{{resultId}}/decision
Content-Type: application/json
{
"finalDecision": "maybe"
}
### 测试4.5: resultId不存在
PUT {{baseUrl}}{{apiPrefix}}/results/00000000-0000-0000-0000-000000000000/decision
Content-Type: application/json
{
"finalDecision": "include"
}
### ========================================
### API 5: 导出Excel
### ========================================
### 测试5.1: 导出Excel正常情况
GET {{baseUrl}}{{apiPrefix}}/tasks/{{taskId}}/export
Accept: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
### 测试5.2: 导出ExceltaskId不存在
GET {{baseUrl}}{{apiPrefix}}/tasks/00000000-0000-0000-0000-000000000000/export
Accept: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
### ========================================
### 完整流程测试
### ========================================
### 完整流程1: 创建任务
# @name fullFlowTask
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "{{projectId}}",
"literatureIds": [
"e9c18ba3-9ad7-4cc9-ac78-b74a7ec91b12"
],
"modelA": "deepseek-v3",
"modelB": "qwen-max"
}
@fullFlowTaskId = {{fullFlowTask.response.body.data.taskId}}
### 完整流程2: 等待2秒后查询进度
GET {{baseUrl}}{{apiPrefix}}/tasks/{{fullFlowTaskId}}
Content-Type: application/json
### 完整流程3: 获取结果
# @name fullFlowResults
GET {{baseUrl}}{{apiPrefix}}/tasks/{{fullFlowTaskId}}/results
Content-Type: application/json
@fullFlowResultId = {{fullFlowResults.response.body.data.results[0].resultId}}
### 完整流程4: 审核决策
PUT {{baseUrl}}{{apiPrefix}}/results/{{fullFlowResultId}}/decision
Content-Type: application/json
{
"finalDecision": "include",
"reviewNotes": "完整流程测试 - 确认纳入"
}
### 完整流程5: 导出Excel
GET {{baseUrl}}{{apiPrefix}}/tasks/{{fullFlowTaskId}}/export
Accept: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
### ========================================
### 压力测试(批量文献)
### ========================================
### 批量测试: 创建包含多篇文献的任务
POST {{baseUrl}}{{apiPrefix}}/tasks
Content-Type: application/json
{
"projectId": "{{projectId}}",
"literatureIds": [
"e9c18ba3-9ad7-4cc9-ac78-b74a7ec91b12",
"e44ea8d9-6ba8-4b88-8d24-4fb46b3584e0",
"c8f9e2d1-3a4b-5c6d-7e8f-9a0b1c2d3e4f"
],
"modelA": "deepseek-v3",
"modelB": "qwen-max"
}
### ========================================
### 清理测试数据(可选)
### ========================================
### 注意:以下操作会删除测试数据,请谨慎使用
### 查询所有任务
GET {{baseUrl}}/api/v1/asl/projects/{{projectId}}/literatures
Content-Type: application/json
###