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
8.1 KiB
8.1 KiB
技术设计文档:工具 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" (本地优先) 架构。
核心策略:
- 数据驻留: 数据加载后主要存储在浏览器的 IndexedDB (Dexie.js) 和 内存 (Zustand) 中。
- 计算下放: 复杂的计算逻辑(如 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']) - 确定“填充值”
- 算法逻辑:
- 预检查 (Guard): 计算 Unique(pivotKeyCol).length * valueCols.length。如果生成的潜在列数 > 1000,抛出错误“生成的列数过多,请先筛选数据”。
- 分组 (Grouping): 使用 _.groupBy(data, indexCol) 按主键分组。
- 转换 (Transformation): 遍历每组数据:
- 创建一个新行对象,保留主键。
- 遍历该组的每一条记录,获取 pivotKeyCol 的值(例如 "2023-01-01")。
- 遍历 valueCols,将值映射为 ValueCol_PivotKey (例如 "wbc_2023-01-01")。
- 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)
- Week 1: 核心网格与存储
- 搭建 React + AG Grid 环境。
- 实现 SheetJS 导入与 Dexie.js 持久化逻辑。
- Week 2: 扁平化工具栏与 Web Worker
- 搭建 Web Worker 通信架构。
- 实现 Formula 计算和 Math.js 集成。
- 实现 Undo/Redo 栈(Immer)。
- Week 3: 复杂计算 (Pivot)
- 重点攻坚: 在 Web Worker 中实现 Pivot 算法。
- 实现 Pivot 的 UI 配置弹窗。
- Week 4: 智能侧边栏与导出
- 开发直方图/频次图组件 (AntD Charts)。
- 实现分箱、映射、填补缺失值逻辑。
- 对接后端保存接口。