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
This commit is contained in:
2026-01-16 13:42:10 +08:00
parent 98d862dbd4
commit 66255368b7
560 changed files with 70424 additions and 52353 deletions

View File

@@ -1,95 +1,105 @@
# **PRD<EFBFBD>ool C \- 遘醍<EFBFBD>疲焚謐ョ郛冶セ大<EFBFBD>?(The Research Editor)**
# **PRDTool C \- 科研数据编辑器 (The Research Editor)**
| <EFBFBD>。」迚域悽 | V2.1 (謇∝ケウ蛹?\+ 髟ソ螳ス霓ャ謐「迚? |
| 文档版本 | V2.1 (扁平化 \+ 长宽转换版) |
| :---- | :---- |
| **莠ァ蜩∝ス「諤?* | Web 遶ッ蝨ィ郤ソ郛冶セ大勣<E5A4A7><E58BA3>ocal-First 譫カ譫<EFBFBD>シ檎アサ Excel 菴馴ェ鯉シ?|
| **譬ク蠢<EFBFBD>サキ蛟?* | 謠蝉セ帶ッ?Excel 譖エ諛らァ醍<EFBDA7>皮噪霓サ驥冗コァ貂<EFBDA7>エ怜キ・蜈キ縲る€夊ソ<E5A48A>€懈堰蟷ウ蛹門キ・蜈キ譬鞘€晏柱窶懈匱閭ス萓ァ霎ケ譬鞘€晢シ瑚ョゥ蛹サ逕溷惠荳榊<E88DB3>莉」遐∫噪諠<E599AA><E8ABA0>荳句ョ梧<EFBDAE>蜿倬㍼蜉<E38DBC>蟾・縲∬エィ驥乗イサ逅<EFBDBB>柱譬キ譛ャ遲幃€€?|
| **逶ョ譬<EFBFBD>畑謌キ** | 蟇ケ謨ー謐ョ雍ィ驥乗怏豢∫剿逧<EFBFBD>ァ醍<EFBFBD>比ココ蜻倥€∽クエ蠎雁現逕?|
| **产品形态** | Web 端在线编辑器Local-First 架构,类 Excel 体验) |
| **核心价值** | 提供比 Excel 更懂科研的轻量级清洗工具。通过“扁平化工具栏”和“智能侧边栏”,让医生在不写代码的情况下完成变量加工、质量治理和样本筛选。 |
| **目标用户** | 对数据质量有洁癖的科研人员、临床医生 |
## **荳€縲?莠ァ蜩∵オ∫ィ句<EFBDA8>?(User Flow)**
## **一、 产品流程图 (User Flow)**
謨ー謐ョ蟇シ蜈・(荳贋シ<E8B48B>/豬∬スャ) \-\> 諤ァ閭ス蜃<EFBDBD><E89C83>荳朱剄驥<E58984><E9A9A5>キ \-\> 蝨ィ郤ソ貂<EFBDBF><EFBFBD>(蟾・蜈キ譬丞<E8ADAC>€謫堺ス<E5A0BA> \+ 萓ァ霎ケ譬丞<E8ADAC>謫堺ス<E5A0BA>) \-\> 迚域悽蠢ォ辣ァ \-\> 蟇シ蜃コ蛻<EFBDBA>梵髮?
## **莠後€?譬ク蠢<EFBDB8>粥閭ス髴€豎?(Functional Requirements)**
数据导入(上传/流转) \-\> 性能准入与降采样 \-\> 在线清洗(工具栏全局操作 \+ 侧边栏列操作) \-\> 版本快照 \-\> 导出分析集
### **1\. 鬘カ驛ィ謇∝ケウ蟾・蜈キ譬?(The Flat Toolbar) 窶披€?譬ク蠢<EFBDB8>コ、莠<EFBDA4>**
## **二、 核心功能需求 (Functional Requirements)**
*荳榊<E88DB3>菴ソ逕ィ螟肴揩逧?Tab 蛻<><EFBFBD>シ梧<EFBDBC>ク蠢<EFBDB8>ァ醍<EFBDA7>泌粥閭ス荳€蟄玲賜蠑€<E8A091>梧園隗∝叉謇€蠕励€?
### **1\. 顶部扁平工具栏 (The Flat Toolbar) —— 核心交互**
*不再使用复杂的 Tab 分组,核心科研功能一字排开,所见即所得。*
#### **1.1 变量加工 (Variable Processing)**
* **P0: 逕滓<EFBFBD>譁ー蜿倬<EFBFBD>?(Generate Variable):**
* **蜉溯<EFBFBD><EFBFBD>?* 蠑ケ遯玲署萓帛<E89093>蠑乗桷蟒コ蝎ィ縲?
* **謾ッ謖<EFBFBD>シ?* 蜉<>蜃丈ケ倬勁縲∵峡蜿キ縲∽サ・蜿?ln() (蟇ケ謨ー)縲xp() 遲牙現蟄ヲ蟶ク逕ィ蜃ス謨ー縲?
* **蝨コ譎ッ<EFBFBD>?* 隶。邂<EFBDA1> BMI \= weight / (height/100)^2縲?
* **P0: 隶。邂玲慮髣エ蟾?(Time Delta):**
* **蜉溯<EFBFBD><EFBFBD>?* 騾画叫 襍キ蟋区律譛溷<E8AD9B>?蜥?扈捺據譌・譛溷<E8AD9B><E6BAB7><EFBFBD>蜉ィ逕滓<E98095>蟾ョ蛟シ縲?
* **蜊穂ス搾シ?* 謾ッ謖∵<E8AC96>?螟ゥ縲∵怦縲∝ケエ 霎灘<E99C8E>縲?
* **蝨コ譎ッ<EFBFBD>?* 隶。邂<EFBDA1> 蟷エ鮴<EFBDB4>€∽ス城劼螟ゥ謨ー縲 ̄FS/OS縲?
* **P0: 髟ソ螳ス霓ャ謐「 (Reshape/Pivot) 窶披€?\[V2.1 譁ー蠅杤]:**
* **蜉溯<EFBFBD><EFBFBD>?* 蟆<>€應ク€莠コ螟夊。鯉シ磯柄陦ィ<E999A6>€晁スャ謐「荳コ窶應ク€莠コ荳€陦鯉シ亥ョス陦ィ<E999A6>€€?
* **P0: 生成新变量 (Generate Variable):**
* **功能:** 弹窗提供公式构建器。
* **支持:** 加减乘除、括号、以及 ln() (对数)、exp() 等医学常用函数。
* **场景:** 计算 BMI \= weight / (height/100)^2
* **P0: 计算时间差 (Time Delta):**
* **功能:** 选择 起始日期列 和 结束日期列,自动生成差值。
* **单位:** 支持按 天、月、年 输出。
* **场景:** 计算 年龄、住院天数、PFS/OS
* **P0: 长宽转换 (Reshape/Pivot) —— \[V2.1 新增\]:**
* **功能:** 将“一人多行(长表)”转换为“一人一行(宽表)”。
* **配置项:**
1. **蜚ッ荳€ID (Index):** 螯?逞<>ココID縲?
2. **蛹コ蛻<EFBFBD><EFBFBD>?(Columns):** 螯?蟆ア隸頑慮髣エ 謌?谺。蠎<EFBDA1> (逕ィ莠守函謌仙錘郛€)縲?
3. **蛟シ蛻<EFBFBD> (Values):** 螯?逋ス扈<EFBDBD><E68988>? B雜?(髴€<C280>銅蟷ウ逧<EFBDB3>焚謐ョ)縲?
* **蝨コ譎ッ<EFBFBD>?* 螟<>炊驥榊、肴オ矩㍼謨ー謐ョ<E8AC90>御クコ SPSS 驥榊、肴オ矩㍼譁ケ蟾ョ蛻<EFBDAE>梵蛛壼㊥螟<E38AA5>€?
1. **唯一ID (Index):** 如 病人ID。
2. **区分列 (Columns):** 如 就诊时间 或 次序 (用于生成后缀)。
3. **值列 (Values):** 如 白细胞, B超 (需要铺平的数据)。
* **场景:** 处理重复测量数据,为 SPSS 重复测量方差分析做准备。
#### **1.2 数据治理 (Data Governance)**
* **P0: <EFBFBD><EFBFBD>謨ー謐ョ髮?(Split Dataset):**
* **蜉溯<EFBFBD><EFBFBD>?* 謖画汾荳€蛻礼噪蜚ッ荳€蛟シ<E89B9F>亥ヲや€應クュ蠢オD窶晢シ会シ悟ー<E6829F>、ァ陦ィ諡<EFBDA8><E8ABA1>荳コ螟壻ク?Excel 譁<>サカ謌?Sheet縲?
* **P0: 霍ィ蛻苓ァ<EFBFBD><EFBFBD>€譟?(Cross-column Logic):**
* **蜉溯<EFBFBD><EFBFBD>?* 螳壻ケ蛾€サ霎題ァ<E9A18C><EFBDA7><EFBFBD>亥ヲ<E4BAA5> IF 諤ァ蛻ォ='逕? AND 諤€蟄?'譏?<3F>会シ悟惠鄂第<E98482>シ荳ュ鬮倅コョ髞呵ッッ陦後€?
#### **1.3 譬キ譛ャ遲幃€?(Cohort Selection)**
* **P0: 拆分数据集 (Split Dataset):**
* **功能:** 按某一列的唯一值如“中心ID”将大表拆分为多个 Excel 文件或 Sheet
* **P0: 跨列规则检查 (Cross-column Logic):**
* **功能:** 定义逻辑规则(如 IF 性别='男' AND 怀孕='是'),在网格中高亮错误行。
#### **1.3 样本筛选 (Cohort Selection)**
* **P0: 构建入排标准 (Cohort Builder):**
* **蜉溯<EFBFBD><EFBFBD>?* 鬮倡コァ遲幃€牙勣縲よ髪謖∝、壽擅莉カ扈<EFBDB6><EFBFBD><E7B28B>ND/OR<EFBFBD>€?
* **霎灘<EFBFBD><EFBFBD>?* 遲幃€臥サ捺棡蜿ッ窶懷嘗蟄倅クコ譁ー謨ー謐ョ髮<EFBDAE>€<C280>窶懈<E7AAB6><E68788>ョー荳コ謗帝勁窶昴€?
### **2\. 蜿ウ萓ァ譎コ閭ス萓ァ霎ケ譬?(Smart Insight Panel) 窶披€?莠、莠堤<E88EA0><EFBFBD>**
* **功能:** 高级筛选器。支持多条件组合AND/OR)。
* **输出:** 筛选结果可“另存为新数据集”或“标记为排除”。
*蠖鍋畑謌キ轤ケ蜃サ陦ィ譬シ逧<EFBDBC>汾荳€蛻玲慮<E78EB2>御セァ霎ケ譬剰<E8ADAC>蜉ィ貊大<E8B28A><E5A4A7><EFBFBD>ケ謐ョ蛻礼アサ蝙区署萓帷音螳夂噪貂<E599AA>エ怜キ・蜈キ縲?
### **2\. 右侧智能侧边栏 (Smart Insight Panel) —— 交互灵魂**
#### **2.1 騾我クュ窶懈焚蛟シ蝙銀€<C280><E6998F>亥ヲょケエ鮴<EFBDB4>€∫區扈<E58D80><E68988><EFBFBD>?*
*当用户点击表格的某一列时,侧边栏自动滑出,根据列类型提供特定的清洗工具。*
* **P0: 扈溯ョ。讎りァ茨シ?* 譏セ遉コ蛻<EFBDBA><EFBFBD>峩譁ケ蝗?(Histogram)縲∵怙螟ァ蛟シ縲∵怙蟆丞€シ縲?
#### **2.1 选中“数值型”列(如年龄、白细胞)**
* **P0: 统计概览:** 显示分布直方图 (Histogram)、最大值、最小值。
* **P0: 异常值检测:**
* 閾ェ蜉ィ譬<EFBFBD>ョー蛛冗ヲサ蛻<EFBFBD><EFBFBD>シ亥ヲ<EFBFBD> \> 3マ<33>シ臥噪蛟シ縲?
* 謠蝉セ帶潔髓ョ<EFBFBD>壼、<EFBFBD>炊蠑ょクク<EFBFBD>域髪謖∵穐譁ュ謌也スョ遨コ<EFBFBD>€?
* 自动标记偏离分布(如 \> 3σ的值。
* 提供按钮:处理异常(支持截断或置空)。
* **P0: 生成分类变量 (Binning):**
* **蜉溯<EFBFBD><EFBFBD>?* 蟆<>ソ樒サュ謨ー蛟シ霓ャ荳コ蛻<EFBDBA>アサ縲?
* **莠、莠抵シ?* 隶セ鄂ョ蛻<EFBDAE><EFBFBD>亥ヲ<E4BAA5> 60<36>会シ檎函謌先眠蛻暦シ<E69AA6><60, \>=60<EFBFBD>€?
* **P0: 郛コ螟ア蛟シ蝪ォ陦・<EFBFBD><EFBFBD>** 謠蝉セ<E89D89><>€シ縲∽クュ菴肴焚 蝪ォ陦・騾蛾。ケ縲?
#### **2.2 騾我クュ窶懈枚譛?蛻<>アサ窶晏<E7AAB6><E6998F>亥ヲよ€ァ蛻ォ縲∬ッ頑妙<E9A091><E5A699>**
* **功能:** 将连续数值转为分类。
* **交互:** 设置切点(如 60生成新列\<60, \>=60)。
* **P0: 缺失值填补:** 提供 均值、中位数 填补选项。
#### **2.2 选中“文本/分类”列(如性别、诊断)**
* **P0: 统计概览:** 显示频次图 (Bar Chart)。
* **P0: 数值映射 (Recode):**
* **功能:** 将文本转为统计数值。
* **交互:** 列出所有唯一值Male, Female用户输入目标值1, 0
* **P0: 设为敏感字段 (Masking):** 一键脱敏(替换为 \*\*\*\*\*\*)。
* **P1: 智能纯化 (Smart Clean):** 若检测到 \>10、\<0.01 等含符号数值,提供一键提取数字功能。
* **P0: 扈溯ョ。讎りァ茨シ?* 譏セ遉コ鬚第ャ。蝗?(Bar Chart)縲?
* **P0: 謨ー蛟シ譏<EFBDBC>蟆?(Recode):**
* **蜉溯<E89C89><E6BAAF>?* 蟆<>枚譛ャ霓ャ荳コ扈溯ョ。謨ー蛟シ縲?
* **莠、莠抵シ?* 蛻怜<E89BBB>€譛牙髪荳€蛟シ<E89B9F><EFBDBC>ale, Female<6C>会シ檎畑謌キ霎灘<E99C8E>逶ョ譬<EFBDAE>€<C280><EFBDBC>1, 0<>€?
* **P0: 隶セ荳コ謨乗─蟄玲ョオ (Masking):** 荳€髞ョ閼ア謨擾シ域崛謐「荳?\*\*\*\*\*\*<2A>€?
* **P1: 譎コ閭ス郤ッ蛹<EFBDAF> (Smart Clean):** 闍・譽€豬句芦 \>10縲―<0.01 遲牙性隨ヲ蜿キ謨ー蛟シ<E89B9F>梧署萓帑ク€髞ョ謠仙叙謨ー蟄怜粥閭ス縲?
### **3\. 超级网格 (The Grid)**
* **P0: <EFBFBD>ァ牙渚鬥茨シ?*
* **遨コ蛟シ<EFBFBD><EFBFBD>** 閭梧勹譏セ遉コ豺。郤「濶イ縲?
* **閼乗焚謐ョ<EFBFBD><EFBFBD>** 邀サ蝙倶ク榊源驟咲噪蛟シ譏セ遉コ邏ォ濶イ譁<EFBDB2>ュ励€?
* **蛻怜、エ蝗セ譬<EFBFBD>シ?* 譏守。ョ譬<EFBDAE><EFBFBD>序驥冗アサ蝙具シ<E585B7># 謨ー蛟? A 譁<>悽, <20>套 譌・譛滂シ峨€?
* **P0: 蝓コ遑€謫堺ス懶シ?* 蛻怜ョス諡匁郷縲∝<E7B8B2>謗貞コ上€∝曙蜃サ蜊募<E89C8A>譬シ郛冶セ代€?
### **4\. 諤ァ閭ス荳主ッシ蜃?(System)**
* **P0: 视觉反馈:**
* **空值:** 背景显示淡红色。
* **脏数据:** 类型不匹配的值显示紫色文字。
* **列头图标:** 明确标识变量类型(\# 数值, A 文本, 📅 日期)。
* **P0: 基础操作:** 列宽拖拽、列排序、双击单元格编辑。
### **4\. 性能与导出 (System)**
* **P0: 性能准入 (Guardrails):**
* 陦梧焚 \< 5<EFBFBD>シ壼<EFBFBD>驥丞刈霓ス縲?
* 陦梧焚 \> 5<EFBFBD>シ壽署遉コ髯埼㊦譬キ鬚<EFBFBD>ァ茨シ梧<EFBFBD>蠑募ッシ菴ソ逕ィ蜷守ォッ謇ケ螟<EFBFBD>炊縲?
* **P1: 閾ェ蜉ィ蠢ォ辣ァ (Auto-Save):** 豈?10 谺。謫堺ス懆<EFBFBD>蜉ィ菫晏ュ伜芦 IndexedDB<44>碁亟豁「豬剰ァ亥勣蟠ゥ貅<EFBDA9>ク「螟ア縲?
* **P0: 蟇シ蜃コ螳壻ケ会シ?*
* 蟇シ蜃コ Excel/CSV縲?
* **<EFBFBD><EFBFBD>。ケ<EFBFBD><EFBFBD>** 蟇シ蜃コ譌カ髯<EFBDB6>クヲ蜿倬㍼邀サ蝙句ョ壻ケ会シ<E4BC9A>etadata<EFBFBD>€?
## **荳峨€?逡碁擇蜴溷梛蜿り€?(UI Reference)**
* 行数 \< 5万:全量加载。
* 行数 \> 5万:提示降采样预览,或引导使用后端批处理。
* **P1: 自动快照 (Auto-Save):** 10 次操作自动保存到 IndexedDB防止浏览器崩溃丢失。
* **P0: 导出定义:**
* 导出 Excel/CSV
* **加分项:** 导出时附带变量类型定义Metadata)。
隸キ蜿り€?蟾・蜈キC\_遘醍<E98198>疲焚謐ョ郛冶セ大勣\_蜴溷梛隶セ隶。\_V2\_貍皮、コ.html縲?
* **蟶<>€<EFBDB1>?* 鬘カ驛ィ蜊戊。悟キ・蜈キ譬?\+ 荳ュ髣エ蜈ィ螻冗ス第<EFBDBD>シ \+ 蜿ウ萓ァ蜿ッ謚伜匠萓ァ霎ケ譬上€?
* **莠、莠抵シ?* 轤ケ蜃サ窶憺柄螳ス霓ャ謐「窶晄潔髓ョ蠑ケ蜃コ驟咲スョ讓。諤∵。<E288B5>€?
## **蝗帙€?鬟朱勦隗<E58BA6>∩ (Risk Mitigation)**
## **三、 界面原型参考 (UI Reference)**
1. **隶。邂礼イセ蠎ヲ荳「螟ア<E89E9F>?*
* *隗」豕包シ? 蠢<>。サ髮<EFBDBB><E9ABAE> math.js 蠎楢ソ幄。梧園譛画焚蟄ヲ霑千ョ励€?
2. **Pivot 蟇シ閾エ蜀<EFBDB4>ュ俶コ「蜃コ<E89C83>?*
* *髣ョ鬚假シ? 髟ソ螳ス霓ャ謐「蜿ッ閭ス莨壼ッシ閾エ蛻玲焚辷<E7849A><EFBFBD><E3819A>olumn Explosion<6F>€?
* *隗」豕包シ? 蝨ィ謇ァ陦?Pivot 蜑搾シ碁「<E7A281>ョ。邂礼サ捺棡蛻玲焚縲ょヲよ棡蛻玲<E89BBB>?\> 1000<30>碁仆豁「謫堺ス懷ケカ謠千、コ逕ィ謌キ蜃丞ー鯛€懷玄蛻<E78E84><E89BBB>窶晉噪蜚ッ荳€蛟シ謨ー驥上€
请参考 工具C\_科研数据编辑器\_原型设计\_V2\_演示.html。
* **布局:** 顶部单行工具栏 \+ 中间全屏网格 \+ 右侧可折叠侧边栏。
* **交互:** 点击“长宽转换”按钮弹出配置模态框。
## **四、 风险规避 (Risk Mitigation)**
1. **计算精度丢失:**
* *解法:* 必须集成 math.js 库进行所有数学运算。
2. **Pivot 导致内存溢出:**
* *问题:* 长宽转换可能会导致列数爆炸Column Explosion
* *解法:* 在执行 Pivot 前,预计算结果列数。如果列数 \> 1000阻止操作并提示用户减少“区分列”的唯一值数量。