Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/02-技术设计/技术设计文档:工具 A - 医疗数据超级合并器 (The Super Merger).md
HaHafeng d4d33528c7 feat(dc): Complete Phase 1 - Portal workbench page development
Summary:
- Implement DC module Portal page with 3 tool cards
- Create ToolCard component with decorative background and hover animations
- Implement TaskList component with table layout and progress bars
- Implement AssetLibrary component with tab switching and file cards
- Complete database verification (4 tables confirmed)
- Complete backend API verification (6 endpoints ready)
- Optimize UI to match prototype design (V2.html)

Frontend Components (~715 lines):
- components/ToolCard.tsx - Tool cards with animations
- components/TaskList.tsx - Recent tasks table view
- components/AssetLibrary.tsx - Data asset library with tabs
- hooks/useRecentTasks.ts - Task state management
- hooks/useAssets.ts - Asset state management
- pages/Portal.tsx - Main portal page
- types/portal.ts - TypeScript type definitions

Backend Verification:
- Backend API: 1495 lines code verified
- Database: dc_schema with 4 tables verified
- API endpoints: 6 endpoints tested (templates API works)

Documentation:
- Database verification report
- Backend API test report
- Phase 1 completion summary
- UI optimization report
- Development task checklist
- Development plan for Tool B

Status: Phase 1 completed (100%), ready for browser testing
Next: Phase 2 - Tool B Step 1 and 2 development
2025-12-02 21:53:24 +08:00

121 lines
4.8 KiB
Markdown
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.
# **技术设计文档:工具 A \- 医疗数据超级合并器 (The Super Merger)**
| 文档类型 | Technical Design Document (TDD) |
| :---- | :---- |
| **对应 PRD** | **PRD\_工具A\_超级合并器\_V2.md** |
| **版本** | **V2.0** (架构升级:访视基准 \+ 时间窗) |
| **状态** | Draft |
| **核心目标** | 构建一个基于 Web 的 ETL 工具,解决临床科研中“一对多”数据对齐难题,实现基于时间窗的精准合并。 |
## **1\. 总体架构设计 (Architecture Overview)**
鉴于处理 Excel 文件(解析、合并、写入)是 CPU 密集型和内存敏感型操作,为了避免阻塞 Node.js 主线程,我们采用 **“异步任务队列 \+ 流式处理”** 的架构模式。
### **1.1 系统架构图**
graph TD
Client\[React 前端 (Wizard UI)\]
subgraph API\_Server \[Fastify API 服务\]
UploadAPI\[上传接口\]
TaskAPI\[任务状态接口\]
ConfigAPI\[配置接口\]
end
subgraph Async\_Worker \[后台处理 Worker\]
BullMQ\[BullMQ 队列\]
Merger\[智能合并引擎 (Time-Window Joiner)\]
ExcelParser\[ExcelJS 解析器\]
DateEngine\[日期归一化引擎\]
end
subgraph Storage \[数据存储\]
PG\[(PostgreSQL 业务库)\]
FileSys\[临时文件存储 (Local/S3)\]
Redis\[(Redis 缓存/队列)\]
end
Client \--1.上传文件--\> UploadAPI
UploadAPI \--保存临时文件--\> FileSys
Client \--2.提交基准与时间窗配置--\> ConfigAPI
ConfigAPI \--创建任务--\> PG
ConfigAPI \--推入队列--\> BullMQ
BullMQ \--消费任务--\> Merger
Merger \--读取辅表(全量)--\> FileSys
Merger \--读取主表(流式)--\> FileSys
Merger \--流式合并与写入--\> FileSys
Merger \--更新状态--\> PG
Client \--3.轮询/WS 进度--\> TaskAPI
Client \--4.下载结果--\> API\_Server
## **2\. 技术选型 (Tech Stack)**
基于现有技术栈的针对性选择:
| 层级 | 技术组件 | 选型理由 |
| :---- | :---- | :---- |
| **前端** | **React 19 \+ Ant Design 5** | 利用 AntD 的 Steps, Upload, Tree (树状选择器) 快速构建 UI。 |
| **后端框架** | **Fastify 5.x** | 高性能 HTTP 框架,适合高并发 I/O。 |
| **Excel 处理** | **ExcelJS** | **核心组件**。支持流式读写 (Streaming I/O),这是处理大数据量不崩的关键。 |
| **日期处理** | **Day.js \+ CustomParseFormat** | **新增**。处理“时间地狱”的核心库,需要极强的容错解析能力。 |
| **任务队列** | **BullMQ \+ Redis** | 必须异步处理。合并逻辑复杂,耗时较长,必须用队列。 |
| **数据库** | **PostgreSQL 15 \+ Prisma** | 存储任务状态、文件元数据。**不建议将原始 Excel 数据存入 PG**。 |
| **验证库** | **Zod** | 用于校验前端提交的复杂映射配置结构。 |
### **2.1 关键技术决策 (ADR): 为什么不用 Python (Pandas)?**
虽然 Python Pandas 在数据合并上代码更简洁,但针对**本工具**的场景,我们决定坚持使用 **Node.js**,理由如下:
1. **流式处理优势:** Pandas 倾向于全量加载内存,容易 OOM。Node.js 的 Stream API 天然支持背压,能稳定处理“数据膨胀”问题。
2. **架构一致性:** 避免引入 Python Runtime 带来的运维成本和 IPC 开销。
3. **结论:** 对于精确匹配和逻辑清洗Node.js 性能足够且更可控。
## **3\. 数据库设计 (Database Schema)**
### **Prisma Schema 定义**
// 任务状态枚举
enum TaskStatus {
PENDING
PROCESSING
COMPLETED
FAILED
}
// 合并任务表
model MergeTask {
id String @id @default(uuid())
userId String
status TaskStatus @default(PENDING)
progress Int @default(0)
// 核心配置字段 (V2 更新)
// 结构: {
// anchorFileId: string,
// anchorKeys: { id: "住院号", time: "入院日期" },
// window: { daysBefore: 7, daysAfter: 7 },
// files: \[{ id: "f2", timeCol: "报告时间", columns: \["白细胞"\] }\]
// }
config Json?
resultUrl String?
report Json? // 质量报告 { totalRows: 1000, dropped: 50, matchRate: "95%" }
errorMsg String?
createdAt DateTime @default(now())
files SourceFile\[\]
}
// 源文件表
model SourceFile {
id String @id @default(uuid())
taskId String
task MergeTask @relation(fields: \[taskId\], references: \[id\])
filename String
filepath String
headers Json // \["住院号", "姓名", "入院日期"\]
rowCount Int
fileSize Int
uploadedAt DateTime @default(now())
}