Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/01-需求分析/PRD:Tool A - 医疗数据超级合并器 (The Super Merger).md
HaHafeng 66255368b7 feat(admin): Add user management and upgrade to module permission system
Features - User Management (Phase 4.1):
- Database: Add user_modules table for fine-grained module permissions
- Database: Add 4 user permissions (view/create/edit/delete) to role_permissions
- Backend: UserService (780 lines) - CRUD with tenant isolation
- Backend: UserController + UserRoutes (648 lines) - 13 API endpoints
- Backend: Batch import users from Excel
- Frontend: UserListPage (412 lines) - list/filter/search/pagination
- Frontend: UserFormPage (341 lines) - create/edit with module config
- Frontend: UserDetailPage (393 lines) - details/tenant/module management
- Frontend: 3 modal components (592 lines) - import/assign/configure
- API: GET/POST/PUT/DELETE /api/admin/users/* endpoints

Architecture Upgrade - Module Permission System:
- Backend: Add getUserModules() method in auth.service
- Backend: Login API returns modules array in user object
- Frontend: AuthContext adds hasModule() method
- Frontend: Navigation filters modules based on user.modules
- Frontend: RouteGuard checks requiredModule instead of requiredVersion
- Frontend: Remove deprecated version-based permission system
- UX: Only show accessible modules in navigation (clean UI)
- UX: Smart redirect after login (avoid 403 for regular users)

Fixes:
- Fix UTF-8 encoding corruption in ~100 docs files
- Fix pageSize type conversion in userService (String to Number)
- Fix authUser undefined error in TopNavigation
- Fix login redirect logic with role-based access check
- Update Git commit guidelines v1.2 with UTF-8 safety rules

Database Changes:
- CREATE TABLE user_modules (user_id, tenant_id, module_code, is_enabled)
- ADD UNIQUE CONSTRAINT (user_id, tenant_id, module_code)
- INSERT 4 permissions + role assignments
- UPDATE PUBLIC tenant with 8 module subscriptions

Technical:
- Backend: 5 new files (~2400 lines)
- Frontend: 10 new files (~2500 lines)
- Docs: 1 development record + 2 status updates + 1 guideline update
- Total: ~4900 lines of code

Status: User management 100% complete, module permission system operational
2026-01-16 13:42:10 +08:00

131 lines
5.7 KiB
Markdown
Raw Permalink 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.
# **PRDTool A \- 医疗数据超级合并器 (The Super Merger)**
| 文档版本 | V2.0 (基准锚定版) |
| :---- | :---- |
| **产品形态** | Web 端工具(分步向导式 Wizard |
| **核心价值** | **解决临床科研中“一对多”数据对齐难题。** 基于“访视Visit”和“时间窗”逻辑将散乱的化验、检查数据精准挂载到住院/门诊记录上。 |
| **目标用户** | 临床医生、科研助理 |
## **一、 产品流程图 (User Flow)**
1\. 数据装载 (Payload) \-\> 2\. 定基准 (Anchor & Window) \-\> 3\. 选列与预览 (Schema) \-\> 4\. 智能合并 \-\> 5\. 结果与流转
## **二、 核心功能需求 (Functional Requirements)**
### **1\. 步骤一:数据装载 (Payload)**
* **P0:** **多文件上传:** 支持拖拽上传 .xlsx, .csv。建议大小 \< 50MB/文件。
* **P0:** **自动预检 (Pre-flight Check)**
* 上传即解析表头。
* **红灯拦截:** 文件加密、表头为空、文件损坏 \-\> 禁止下一步。
* **P1:** **加载配置/模板:** 若用户之前保存过“肺癌门诊合并规则”,允许一键加载,跳过后续配置。
### **2\. 步骤二:定基准 (The Anchor) —— 核心算法逻辑**
此步骤决定了最终大表的“骨架”(行数)和“归类逻辑”。
#### **2.1 主表选择 (The Backbone)**
* **P0:** 用户必须从上传的文件中指定一个作为 **“主表 (Visit Base)”**。
* **定义:** 主表的每一行,代表最终大表的一个基准行(一次就诊/访视)。通常是《住院记录》或《门诊挂号》。
#### **2.2 关键列映射 (Key Mapping)**
* **P0:** **ID 列对齐:** 用户需指定主表的 Patient\_ID 列。系统自动在辅表中寻找同名列,允许人工修正。
* **P0:** **时间基准列:** 用户需指定主表的 Date 列(如“入院日期”)。这将作为时间窗的圆心。
#### **2.3 辅表匹配策略 (Matching Strategy)**
* **P0:** **时间窗配置 (Time Window)**
* 设定规则:辅表的检查时间必须在 \[主表时间 \- X天, 主表时间 \+ Y天\] 范围内。
* **默认值:** $\\pm 7$ 天。
* **P0:** **冲突处理 (Collision Handling)**
* *场景:* 单次时间窗内,辅表有多条记录(如做了两次血常规)。
* *选项 A (默认 \- 纵向展开)* 保留所有记录。主表信息复制,行数增加。
* *选项 B (最近匹配)* 仅保留离主表时间最近的一条,丢弃其他。
### **3\. 步骤三:选列与预览 (The Schema)**
此步骤决定了最终大表的“血肉”(列宽)。
#### **3.1 树状选择器 (Tree Picker)**
* **P0:** 展示所有文件的列结构。
* 📂 主表
* ✅ 住院号
* ✅ 诊断
* 📂 辅表 A (化验)
* ✅ 白细胞
* ⬜ 审核医生 (不勾选)
* **交互:** 支持按文件全选/反选。
#### **3.2 实时结构预览 (Live Schema Preview)**
* **P0:** 在屏幕右侧实时展示\*\*“最终表头结构”\*\*(仅表头,不计算数据)。
* **价值:** 让用户直观看到:“哦,原来我的表会变成这么长,包含这些列”。
### **4\. 步骤四:结果与流转 (The Result)**
* **P0:** **处理进度条:** 显示动态文案(“正在构建哈希索引...”、“正在进行时间窗碰撞...”)。
* **P0:** **黄金预览 (Golden Preview)**
* 必须展示合并结果的 **前 5-10 行** 真实数据。
* 用于用户肉眼核对 ID 是否对齐。
* **P0:** **质量看板:**
* 成功生成行数。
* 丢弃行数ID不匹配或时间窗外
* **P0:** **行动流转:**
* \[下载 Excel\]
* \[发送到 AI 结构化工具\] (流转 Token)
* \[发送到 编辑器清洗\] (流转 Token)
## **三、 核心算法逻辑 (Technical Logic)**
### **1\. 算法名称:基于时间窗的哈希流式连接 (Time-Windowed Stream Hash Join)**
### **2\. 执行伪代码**
// 1\. 内存构建 (Build Phase)
// 将辅表 (Small Tables) 读入内存 Map
const lookupMap \= {
"patient\_001": \[
{ type: "lab", date: "2023-01-02", data: {...} }, // 记录1
{ type: "lab", date: "2023-05-01", data: {...} } // 记录2
\]
};
// 2\. 流式探测 (Probe Phase)
// 逐行读取主表 (Main Table)
streamMainTable.on('data', (mainRow) \=\> {
const pId \= mainRow.id;
const tStart \= mainRow.date \- 7 days;
const tEnd \= mainRow.date \+ 7 days;
// 在辅表中寻找符合时间窗的记录
const matchLabs \= lookupMap\[pId\].filter(lab \=\>
lab.date \>= tStart && lab.date \<= tEnd
);
if (matchLabs.length \=== 0\) {
// 没匹配到,只输出主表信息
output.write({ ...mainRow, lab\_data: null });
} else {
// 匹配到了 (处理一对多)
matchLabs.forEach(lab \=\> {
output.write({ ...mainRow, ...lab.data }); // 纵向展开
});
}
});
## **四、 界面原型参考 (UI Reference)**
请参考 工具A\_超级合并器\_原型设计.tsx (V1.0) 中的 Step 2 和 Step 3 界面。
* **Step 2 重点:** 主表选择单选框、时间列下拉框、策略单选钮。
* **Step 3 重点:** 左右分栏布局(左侧树状勾选,右侧表格骨架预览)。
## **五、 风险规避检查 (Risk Check)**
1. **用户选错主表怎么办?**
* *对策:* 在 Step 2 界面增加显眼的 **Tip**:“主表通常是包含‘入院日期’或‘诊断信息’的表格”。
2. **时间格式乱七八糟怎么办?**
* *对策:* 后端在解析时间列时,必须使用强力的 Parser支持 2023/1/1, 2023-01-01, 44927 等格式)。如果解析失败,归为“时间无效”,不进行匹配。