Files
AIclinicalresearch/docs/03-业务模块/DC-数据清洗整理/02-技术设计/技术设计文档:工具 C - 科研数据编辑器.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

176 lines
8.1 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.
# **技术设计文档:工具 C \- 科研数据编辑器 (The Research Editor)**
| 文档类型 | Technical Design Document (TDD) |
| :---- | :---- |
| **对应 PRD** | **PRD\_工具C\_科研数据编辑器\_V2.1.md** |
| **版本** | **V2.1** (新增 Pivot 算法与 Web Worker 架构) |
| **状态** | Final Draft |
| **核心目标** | 构建一个高性能的 Web 端数据编辑器,支持 5 万行级数据的实时清洗、变量加工(含长宽转换)与逻辑治理,提供“零延迟”操作体验。 |
## **1\. 总体架构设计 (Architecture Overview)**
为了满足 **PRD V2.1** 中“即时反馈”、“撤销重做”以及复杂的“长宽转换”需求,工具 C 采用 **"Local-First" (本地优先)** 架构。
核心策略:
1. **数据驻留:** 数据加载后主要存储在浏览器的 **IndexedDB (Dexie.js)****内存 (Zustand)** 中。
2. **计算下放:** 复杂的计算逻辑(如 Pivot、公式解析下放至 **Web Worker**,避免阻塞 UI 主线程。
### **1.1 系统架构图**
graph TD
subgraph Browser\_Layer \[浏览器端 (React SPA)\]
UI\_Shell\[UI 壳层: 扁平化 Toolbar \+ 智能 Sidebar\]
subgraph Core\_Engine \[核心引擎\]
GridComponent\[AG Grid (视图层)\]
StateManager\[Zustand Store (状态层)\]
subgraph Worker\_Thread \[Web Worker 线程\]
ComputeEngine\[计算引擎 (Math.js / Pivot Alg)\]
StatEngine\[统计引擎 (直方图/频次)\]
end
HistoryManager\[Immer Patches (撤销栈)\]
end
subgraph Local\_Storage \[持久化层\]
Dexie\[Dexie.js (IndexedDB Wrapper)\]
end
end
subgraph Server\_Layer \[服务端 (Node.js)\]
API\[Fastify API\]
S3\[对象存储 (MinIO/OSS)\]
end
User \--1.操作(如Pivot)--\> UI\_Shell
UI\_Shell \--2.发送消息(postMessage)--\> Worker\_Thread
Worker\_Thread \--3.计算结果--\> StateManager
StateManager \--4.更新视图--\> GridComponent
StateManager \--5.异步备份--\> Dexie
User \--6.保存/导出--\> API
## **2\. 技术选型 (Tech Stack)**
| 层级 | 技术组件 | 选型理由 |
| :---- | :---- | :---- |
| **表格核心** | **AG Grid Community** | 唯一能免费支持虚拟滚动、列拖拽、高性能渲染的 React 表格库。 |
| **本地数据库** | **Dexie.js (IndexedDB)** | 相比 localStorage (5MB限制)IndexedDB 容量大且异步,适合存储 5万+ 行的 JSON 数据集。 |
| **状态管理** | **Zustand \+ Immer** | Zustand 轻量高效Immer 用于处理不可变数据结构,其 produce 和 patches 功能是实现 Undo/Redo 的核心。 |
| **计算引擎** | **Math.js \+ Web Worker** | 解决 JS 浮点数精度问题 (0.1+0.2\!=0.3)Web Worker 用于将 Pivot 等重计算移出主线程。 |
| **数据处理** | **Lodash** | 基础的数据操作(分组、过滤、深拷贝)。 |
| **可视化** | **Ant Design Charts** | 在智能侧边栏中绘制直方图 (Histogram) 和频次图 (Bar)。 |
## **3\. 核心模块详细设计**
### **3.1 核心计算引擎 (Compute Engine \- Web Worker)**
#### **A. 长宽转换 (Pivot / Reshaping Algorithm) \- V2.1 核心难点**
这是最复杂的计算任务,必须在 Web Worker 中执行,否则页面会卡死。
* **输入参数:**
* data: 原始对象数组 Row\[\]
* indexCol: 主键列名 (e.g., 'patient\_id') \- 确定“行”
* pivotKeyCol: 区分列名 (e.g., 'visit\_date') \- 确定“列后缀”
* valueCols: 值列名数组 (e.g., \['wbc', 'bmi'\]) \- 确定“填充值”
* **算法逻辑:**
1. **预检查 (Guard):** 计算 Unique(pivotKeyCol).length \* valueCols.length。如果生成的潜在列数 \> 1000抛出错误“生成的列数过多请先筛选数据”。
2. **分组 (Grouping):** 使用 \_.groupBy(data, indexCol) 按主键分组。
3. **转换 (Transformation):** 遍历每组数据:
* 创建一个新行对象,保留主键。
* 遍历该组的每一条记录,获取 pivotKeyCol 的值(例如 "2023-01-01")。
* 遍历 valueCols将值映射为 ValueCol\_PivotKey (例如 "wbc\_2023-01-01")。
4. **Schema生成:** 动态生成新的 ColumnDefs。
* **输出:** { newRows, newColumnDefs }
#### **B. 公式变量 (Formula)**
* 使用 math.evaluate(formula, row)。
* **安全沙箱:** 限制公式中可访问的变量仅为当前行的数据,防止 XSS。
* **异常处理:** 处理除以零 (Infinity) 和非数字计算 (NaN) 的情况,统一返回 null 或错误标记。
### **3.2 智能侧边栏引擎 (Insight Engine)**
* **触发:** 监听 AG Grid 的 onColumnHeaderClicked 事件。
* **去抖 (Debounce):** 200ms 延迟计算,防止快速切换列时 UI 闪烁。
* **统计逻辑:**
* **数值列:** 计算 Min, Max, Mean, SD并使用 Freedman-Diaconis 规则计算直方图的 Bins。
* **文本列:** 计算 Top 10 频率最高的词。
### **3.3 历史记录与撤销 (History Manager)**
* **Undo/Redo 策略:**
* **普通操作 (编辑/替换):** 记录 patches (Immer)。
* **结构性操作 (Pivot/拆分/生成新变量):** 由于表结构完全改变,记录 patches 成本过高且难以回滚。策略改为:**在执行此类操作前,强制保存一个全量快照 (Checkpoint)**。撤销时直接重载快照。
## **4\. 数据流与存储设计**
### **4.1 浏览器端存储 (Dexie Schema)**
用于暂存用户正在编辑的数据,实现“自动快照”和“崩溃恢复”。
const db \= new Dexie('ResearchEditorDB');
db.version(2).stores({
// 项目元数据
projects: '++id, name, lastModified, rowCount',
// 数据块 (Chunks): 将 5万行数据切分为多个 Chunk 存储,避免单次读写过大导致浏览器崩溃
dataChunks: '\[projectId+chunkIndex\], projectId',
// 操作历史 (用于恢复现场)
history: 'projectId, stack',
// 完整快照 (用于 Pivot 等大操作的回滚)
checkpoints: '++id, projectId, createdAt'
});
### **4.2 后端存储 (PostgreSQL \+ OSS)**
后端仅负责存储“已保存”的快照,不参与实时编辑。
model DatasetSnapshot {
id String @id @default(uuid())
taskId String // 关联任务
version Int // 版本号
// 存储为大的 JSON Blob或者指向 OSS 文件路径 (推荐 OSS)
// 内容包含rows\[\], columnDefs\[\], metadata
ossKey String
createdAt DateTime @default(now())
}
## **5\. API 接口定义**
* POST /api/editor/init: 初始化编辑器会话,从 OSS 加载原始文件(如果是从工具 A/B 流转过来的)。
* POST /api/editor/save: 保存当前快照。
* POST /api/editor/export: 请求后端生成 Excel/SPSS 文件。
* *Payload:* { rows: \[...\], format: 'spss' }
* *说明:* 如果数据量小,直接前端 SheetJS 生成;数据量大 (\>5MB) 发给后端生成。
## **6\. 性能准入与边界 (Performance Guardrails)**
| 数据量级 | 策略 |
| :---- | :---- |
| **\< 50,000 行** | **全量加载模式**。所有数据都在内存/IndexedDB操作极快。 |
| **\> 50,000 行** | **降采样模式 (Downsampling)**。前端仅加载前 5 万行用于预览和规则制定。导出时将清洗规则Recipe发送给后端由后端 Worker 对全量数据进行批处理。 |
## **7\. 开发计划 (Milestones)**
1. **Week 1: 核心网格与存储**
* 搭建 React \+ AG Grid 环境。
* 实现 SheetJS 导入与 Dexie.js 持久化逻辑。
2. **Week 2: 扁平化工具栏与 Web Worker**
* 搭建 Web Worker 通信架构。
* 实现 Formula 计算和 Math.js 集成。
* 实现 Undo/Redo 栈Immer
3. **Week 3: 复杂计算 (Pivot)**
* **重点攻坚:** 在 Web Worker 中实现 Pivot 算法。
* 实现 Pivot 的 UI 配置弹窗。
4. **Week 4: 智能侧边栏与导出**
* 开发直方图/频次图组件 (AntD Charts)。
* 实现分箱、映射、填补缺失值逻辑。
* 对接后端保存接口。