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:
@@ -1,29 +1,29 @@
|
||||
# 工具C - 缺失值处ç<E2809E>†åŠŸèƒ½å¼€å<E282AC>‘计åˆ?- 更新说明
|
||||
# 工具C - 缺失值处理功能开发计划 - 更新说明
|
||||
|
||||
## ðŸ“<EFBFBD> 更新日期ï¼?025-12-10
|
||||
## 📝 更新日期:2025-12-10
|
||||
|
||||
## âœ?已完æˆ<C3A6>的更新
|
||||
## ✅ 已完成的更新
|
||||
|
||||
### 1. Phase 1功能清单
|
||||
**新增���*�
|
||||
- 5. **å‰<EFBFBD>å<EFBFBD>‘å¡«å……**(Forward Fillï¼?
|
||||
- 适用于:时间åº<EFBFBD>列数æ<EFBFBD>®ã€<EFBFBD>有顺åº<EFBFBD>的观察数æ<EFBFBD>?
|
||||
- 实现:`df[column].fillna(method='ffill')`,用å‰<EFBFBD>一个é<EFBFBD>žç¼ºå¤±å€¼å¡«å…?
|
||||
- 示例:[10, NaN, NaN, 20] �[10, 10, 10, 20]
|
||||
**新增第5、6项**:
|
||||
- 5. **前向填充**(Forward Fill)
|
||||
- 适用于:时间序列数据、有顺序的观察数据
|
||||
- 实现:`df[column].fillna(method='ffill')`,用前一个非缺失值填充
|
||||
- 示例:[10, NaN, NaN, 20] → [10, 10, 10, 20]
|
||||
|
||||
- 6. **å<EFBFBD>Žå<EFBFBD>‘å¡«å……**(Backward Fillï¼?
|
||||
- 适用于:时间åº<EFBFBD>列数æ<EFBFBD>®ã€<EFBFBD>有顺åº<EFBFBD>的观察数æ<EFBFBD>?
|
||||
- 实现:`df[column].fillna(method='bfill')`,用å<EFBFBD>Žä¸€ä¸ªé<EFBFBD>žç¼ºå¤±å€¼å¡«å…?
|
||||
- 示例:[10, NaN, NaN, 20] �[10, 20, 20, 20]
|
||||
- 6. **后向填充**(Backward Fill)
|
||||
- 适用于:时间序列数据、有顺序的观察数据
|
||||
- 实现:`df[column].fillna(method='bfill')`,用后一个非缺失值填充
|
||||
- 示例:[10, NaN, NaN, 20] → [10, 20, 20, 20]
|
||||
|
||||
### 2. Phase 2功能清单
|
||||
**移除**:å‰<C3A5>å<EFBFBD>?å<>Žå<C5BD>‘填充(已移到Phase 1ï¼?
|
||||
**ä¿<EFBFBD>ç•™**:分组填补ã€<C3A3>线性æ<C2A7>’值ã€<C3A3>KNNå¡«è¡¥ã€<C3A3>组å<E2809E>ˆå¡«è¡?
|
||||
**移除**:前向/后向填充(已移到Phase 1)
|
||||
**保留**:分组填补、线性插值、KNN填补、组合填补
|
||||
|
||||
### 3. UI设计更新
|
||||
Tab 2填补方法新增�
|
||||
- âš?å‰<C3A5>å<EFBFBD>‘填充(用å‰<C3A5>一个值填充,适å<E2809A>ˆæ—¶é—´åº<C3A5>列ï¼?
|
||||
- âš?å<>Žå<C5BD>‘填充(用å<C2A8>Žä¸€ä¸ªå€¼å¡«å……,适å<E2809A>ˆæ—¶é—´åº<C3A5>列ï¼?
|
||||
Tab 2填补方法新增:
|
||||
- ⚪ 前向填充(用前一个值填充,适合时间序列)
|
||||
- ⚪ 后向填充(用后一个值填充,适合时间序列)
|
||||
|
||||
### 4. Python函数签名更新
|
||||
```python
|
||||
@@ -40,112 +40,112 @@ method: 'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill'
|
||||
```
|
||||
|
||||
### 6. 测试用例更新
|
||||
ä»?4ä¸ªå¢žåŠ åˆ°18个:
|
||||
- **新增TC-6**:å‰<C3A5>å<EFBFBD>‘å¡«å…?
|
||||
- **新增TC-7**:å<C5A1>Žå<C5BD>‘å¡«å…?
|
||||
- **新增TC-11**:å‰<EFBFBD>å<EFBFBD>‘填充边界(首行NAï¼?
|
||||
- **新增TC-12**:å<EFBFBD>Žå<EFBFBD>‘填充边界(末行NAï¼?
|
||||
- 原TC-6~TC-14 é‡<EFBFBD>æ–°ç¼–å<EFBFBD>·ä¸?TC-8~TC-18
|
||||
从14个增加到18个:
|
||||
- **新增TC-6**:前向填充
|
||||
- **新增TC-7**:后向填充
|
||||
- **新增TC-11**:前向填充边界(首行NA)
|
||||
- **新增TC-12**:后向填充边界(末行NA)
|
||||
- 原TC-6~TC-14 重新编号为 TC-8~TC-18
|
||||
|
||||
### 7. 测试数据准备更新
|
||||
**新增**:时间åº<C3A5>列列:éš<C3A9>访血压(有顺åº<C3A5>,缺失18%ï¼? 用于测试å‰?å<>Žå<C5BD>‘å¡«å……
|
||||
**新增**:时间序列列:随访血压(有顺序,缺失18%)- 用于测试前/后向填充
|
||||
|
||||
### 8. 时间估算更新
|
||||
| 项目 | 原计åˆ?| 新计åˆ?| å¢žåŠ æ—¶é—´ |
|
||||
| 项目 | 原计划 | 新计划 | 增加时间 |
|
||||
|------|--------|--------|---------|
|
||||
| Pythonå<EFBFBD>Žç«¯ - 简å<E282AC>•å¡«è¡?| 40分钟 | 50分钟 | +10分钟 |
|
||||
| Python后端 - 简单填补 | 40分钟 | 50分钟 | +10分钟 |
|
||||
| 前端UI - Tab 2 | 40分钟 | 50分钟 | +10分钟 |
|
||||
| 测试 | 40分钟�4个用例)| 50分钟�8个用例)| +10分钟 |
|
||||
| **总计** | **çº?-6å°<C3A5>æ—¶** | **çº?-7å°<C3A5>æ—¶** | **+30分钟** |
|
||||
| 测试 | 40分钟(14个用例)| 50分钟(18个用例)| +10分钟 |
|
||||
| **总计** | **约5-6小时** | **约6-7小时** | **+30分钟** |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 功能完整清å<E280A6>•(Phase 1ï¼?
|
||||
## 🎯 功能完整清单(Phase 1)
|
||||
|
||||
| 编号 | 功能 | 适用场景 | 实现方法 |
|
||||
|------|------|----------|----------|
|
||||
| 1 | å<EFBFBD>‡å€¼å¡«è¡?| 数值型å<E280B9>˜é‡<C3A9>ï¼Œæ£æ€<C3A6>分å¸?| `fillna(mean())` |
|
||||
| 2 | ä¸ä½<EFBFBD>æ•°å¡«è¡?| 数值型å<E280B9>˜é‡<C3A9>,å<C592><C3A5>æ€<C3A6>分å¸?| `fillna(median())` |
|
||||
| 3 | ä¼—æ•°å¡«è¡¥ | 分类å<C2BB>˜é‡<C3A9>ã€<C3A3>离散数å€?| `fillna(mode()[0])` |
|
||||
| 4 | 固定值填�| 任何类型,用户指�| `fillna(value)` |
|
||||
| 5 | **å‰<EFBFBD>å<EFBFBD>‘å¡«å……** â?| **æ—¶é—´åº<EFBFBD>列ã€<EFBFBD>éš<EFBFBD>访数æ<EFBFBD>?* | **`fillna(method='ffill')`** |
|
||||
| 6 | **å<EFBFBD>Žå<EFBFBD>‘å¡«å……** â?| **æ—¶é—´åº<EFBFBD>列ã€<EFBFBD>预测数æ<EFBFBD>?* | **`fillna(method='bfill')`** |
|
||||
| 7 | MICE多é‡<EFBFBD>æ<EFBFBD>’è¡¥ | 缺失çŽ?%-30%,需考虑å<E28098>˜é‡<C3A9>关系 | `IterativeImputer` |
|
||||
| 1 | 均值填补 | 数值型变量,正态分布 | `fillna(mean())` |
|
||||
| 2 | 中位数填补 | 数值型变量,偏态分布 | `fillna(median())` |
|
||||
| 3 | 众数填补 | 分类变量、离散数值 | `fillna(mode()[0])` |
|
||||
| 4 | 固定值填补 | 任何类型,用户指定 | `fillna(value)` |
|
||||
| 5 | **前向填充** ⭐ | **时间序列、随访数据** | **`fillna(method='ffill')`** |
|
||||
| 6 | **后向填充** ⭐ | **时间序列、预测数据** | **`fillna(method='bfill')`** |
|
||||
| 7 | MICE多重插补 | 缺失率5%-30%,需考虑变量关系 | `IterativeImputer` |
|
||||
|
||||
---
|
||||
|
||||
## 📋 完整测试用例清å<E280A6>•ï¼?8个)
|
||||
## 📋 完整测试用例清单(18个)
|
||||
|
||||
| 编号 | 功能 | 测试场景 | 预期结果 |
|
||||
|------|------|----------|----------|
|
||||
| TC-1 | å<EFBFBD>‡å€¼å¡«è¡?| å¯?年龄"列使用å<C2A8>‡å€¼å¡«è¡?| 创建新列,缺失值被å<C2AB>‡å€¼å¡«å…?âœ?|
|
||||
| TC-2 | ä¸ä½<EFBFBD>æ•°å¡«è¡?| å¯?体é‡<C3A9>"列使用ä¸ä½<C3A4>æ•°å¡«è¡¥ | 创建新列,缺失值被ä¸ä½<C3A4>æ•°å¡«å…?âœ?|
|
||||
| TC-3 | 众数填补 | �婚姻状况"列使用众数填�| 创建新列,缺失值被众数填充 �|
|
||||
| TC-4 | 固定值填补(数值) | å¯?年龄"列填充固定å€?0" | 创建新列,所有缺失值å<C2BC>˜ä¸? âœ?|
|
||||
| TC-5 | 固定值填补(文本ï¼?| å¯?婚姻状况"列填å…?未知" | 创建新列,所有缺失值å<C2BC>˜ä¸?未知" âœ?|
|
||||
| **TC-6** | **å‰<EFBFBD>å<EFBFBD>‘å¡«å……** â?| **对éš<EFBFBD>访血压列使用å‰<EFBFBD>å<EFBFBD>‘å¡«å……** | **缺失值被å‰<EFBFBD>一个é<EFBFBD>žç¼ºå¤±å€¼å¡«å…?âœ?* |
|
||||
| **TC-7** | **å<EFBFBD>Žå<EFBFBD>‘å¡«å……** â?| **对éš<EFBFBD>访血压列使用å<EFBFBD>Žå<EFBFBD>‘å¡«å……** | **缺失值被å<EFBFBD>Žä¸€ä¸ªé<EFBFBD>žç¼ºå¤±å€¼å¡«å…?âœ?* |
|
||||
| TC-8 | MICEå¡«è¡¥ | 选择"收缩åŽ?+"èˆ’å¼ åŽ?,执行MICE | 创建2个新列(_MICEå<45>Žç¼€ï¼‰âœ… |
|
||||
| TC-9 | 新列ä½<EFBFBD>置验è¯<EFBFBD> â?| å¯?列A"填补,查看新列ä½<C3A4>ç½?| 新列紧邻原列å<E28094>³ä¾§ âœ?|
|
||||
| TC-10 | MICE新列ä½<EFBFBD>ç½® â?| å¯?列A"+"列C"执行MICE | å<>„新列紧邻其原列 âœ?|
|
||||
| **TC-11** | **å‰<EFBFBD>å<EFBFBD>‘填充边界** â?| **对首行为NA的列å‰<EFBFBD>å<EFBFBD>‘å¡«å……** | **首行NAä¿<EFBFBD>æŒ<EFBFBD>NAï¼ˆæ— å‰<EFBFBD>值)âœ?* |
|
||||
| **TC-12** | **å<EFBFBD>Žå<EFBFBD>‘填充边界** â?| **对末行为NA的列å<EFBFBD>Žå<EFBFBD>‘å¡«å……** | **末行NAä¿<EFBFBD>æŒ<EFBFBD>NAï¼ˆæ— å<EFBFBD>Žå€¼ï¼‰âœ?* |
|
||||
| TC-13 | 统计信æ<EFBFBD>¯å‡†ç¡®æ€?| 选择任æ„<C3A6>列,查看统计 | 显示æ£ç¡®çš„缺失数ã€<C3A3>å<EFBFBD>‡å€¼ç‰ |
|
||||
| TC-14 | åˆ é™¤åŠŸèƒ½ä¿<EFBFBD>ç•™ | Tab 1åˆ é™¤ç¼ºå¤±è¡?| 功能æ£å¸¸ï¼Œä¸ŽåŽŸåŠŸèƒ½ä¸€è‡?|
|
||||
| TC-15 | 空列处ç<EFBFBD>† | å¯¹æ— ç¼ºå¤±åˆ—æ‰§è¡Œå¡«è¡?| æ<><C3A6>示或å¤<C3A5>制原åˆ?|
|
||||
| TC-16 | 全缺失列处ç<EFBFBD>† | 对全缺失列执行填è¡?| æ<><C3A6>示è¦å‘Šï¼Œåˆ›å»ºæ–°åˆ?|
|
||||
| TC-17 | é‡<EFBFBD>å¤<EFBFBD>新列å<EFBFBD><EFBFBD>处ç<EFBFBD>?| 新列å<E28094><C3A5>å·²å˜åœ¨ | è‡ªåŠ¨æ·»åŠ å<C2A0>Žç¼€æˆ–æ<E28093><C3A6>ç¤?|
|
||||
| TC-18 | 原始数æ<EFBFBD>®ä¿<EFBFBD>ç•™ â?| å¡«è¡¥å<C2A5>Žï¼Œæ£€æŸ¥åŽŸåˆ?| 原列数æ<C2B0>®å®Œå…¨ä¸<C3A4>å<EFBFBD>˜ âœ?|
|
||||
| TC-1 | 均值填补 | 对"年龄"列使用均值填补 | 创建新列,缺失值被均值填充 ✅ |
|
||||
| TC-2 | 中位数填补 | 对"体重"列使用中位数填补 | 创建新列,缺失值被中位数填充 ✅ |
|
||||
| TC-3 | 众数填补 | 对"婚姻状况"列使用众数填补 | 创建新列,缺失值被众数填充 ✅ |
|
||||
| TC-4 | 固定值填补(数值) | 对"年龄"列填充固定值"0" | 创建新列,所有缺失值变为0 ✅ |
|
||||
| TC-5 | 固定值填补(文本) | 对"婚姻状况"列填充"未知" | 创建新列,所有缺失值变为"未知" ✅ |
|
||||
| **TC-6** | **前向填充** ⭐ | **对随访血压列使用前向填充** | **缺失值被前一个非缺失值填充 ✅** |
|
||||
| **TC-7** | **后向填充** ⭐ | **对随访血压列使用后向填充** | **缺失值被后一个非缺失值填充 ✅** |
|
||||
| TC-8 | MICE填补 | 选择"收缩压"+"舒张压",执行MICE | 创建2个新列(_MICE后缀)✅ |
|
||||
| TC-9 | 新列位置验证 ⭐ | 对"列A"填补,查看新列位置 | 新列紧邻原列右侧 ✅ |
|
||||
| TC-10 | MICE新列位置 ⭐ | 对"列A"+"列C"执行MICE | 各新列紧邻其原列 ✅ |
|
||||
| **TC-11** | **前向填充边界** ⭐ | **对首行为NA的列前向填充** | **首行NA保持NA(无前值)✅** |
|
||||
| **TC-12** | **后向填充边界** ⭐ | **对末行为NA的列后向填充** | **末行NA保持NA(无后值)✅** |
|
||||
| TC-13 | 统计信息准确性 | 选择任意列,查看统计 | 显示正确的缺失数、均值等 |
|
||||
| TC-14 | 删除功能保留 | Tab 1删除缺失行 | 功能正常,与原功能一致 |
|
||||
| TC-15 | 空列处理 | 对无缺失列执行填补 | 提示或复制原列 |
|
||||
| TC-16 | 全缺失列处理 | 对全缺失列执行填补 | 提示警告,创建新列 |
|
||||
| TC-17 | 重复新列名处理 | 新列名已存在 | 自动添加后缀或提示 |
|
||||
| TC-18 | 原始数据保留 ⭐ | 填补后,检查原列 | 原列数据完全不变 ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 💡 适用场景说明
|
||||
|
||||
### å‰<EFBFBD>å<EFBFBD>‘填充(Forward Fillï¼? 新增
|
||||
**最适å<EFBFBD>ˆåœºæ™¯**ï¼?
|
||||
1. **多次éš<EFBFBD>访数æ<EFBFBD>®**:患者在ä¸<C3A4>å<EFBFBD>Œæ—¶é—´ç‚¹çš„æµ‹é‡<C3A9>,如果æŸ<C3A6>次éš<C3A9>访缺失,用上次的å€?
|
||||
- 示例:血压éš<EFBFBD>访(120 â†?NaN â†?NaN â†?130)→ ï¼?20 â†?120 â†?120 â†?130ï¼?
|
||||
2. **è§‚å¯Ÿæ€§ç ”ç©?*:å<C5A1>‡è®¾å<C2BE>˜é‡<C3A9>åœ¨çŸæœŸå†…相对稳å®?
|
||||
3. **ä¼ æ„Ÿå™¨æ•°æ<EFBFBD>?*:设备临时故障,用最å<E282AC>Žä¸€æ¬¡æ£å¸¸å€?
|
||||
### 前向填充(Forward Fill)- 新增
|
||||
**最适合场景**:
|
||||
1. **多次随访数据**:患者在不同时间点的测量,如果某次随访缺失,用上次的值
|
||||
- 示例:血压随访(120 → NaN → NaN → 130)→ (120 → 120 → 120 → 130)
|
||||
2. **观察性研究**:假设变量在短期内相对稳定
|
||||
3. **传感器数据**:设备临时故障,用最后一次正常值
|
||||
|
||||
**ä¸<EFBFBD>适å<EFBFBD>ˆåœºæ™¯**ï¼?
|
||||
- å<EFBFBD>˜åŒ–å¿«çš„æŒ‡æ ‡ï¼ˆå¦‚è¡€ç³–æ³¢åŠ¨å¤§ï¼?
|
||||
**不适合场景**:
|
||||
- 变化快的指标(如血糖波动大)
|
||||
- 首次观察即缺失(无前值可用)
|
||||
|
||||
### å<EFBFBD>Žå<EFBFBD>‘填充(Backward Fillï¼? 新增
|
||||
**最适å<EFBFBD>ˆåœºæ™¯**ï¼?
|
||||
1. **预测性数æ<EFBFBD>?*:已知未æ<C2AA>¥çš„值,å<C592>‘å‰<C3A5>å¡«å……
|
||||
2. **计划性事ä»?*:如手术日期,å<C592>‘å‰<C3A5>填充到准备æœ?
|
||||
### 后向填充(Backward Fill)- 新增
|
||||
**最适合场景**:
|
||||
1. **预测性数据**:已知未来的值,向前填充
|
||||
2. **计划性事件**:如手术日期,向前填充到准备期
|
||||
3. **数据补录**:后期补充的数据向前填充
|
||||
|
||||
**ä¸<EFBFBD>适å<EFBFBD>ˆåœºæ™¯**ï¼?
|
||||
**不适合场景**:
|
||||
- 末次观察缺失(无后值可用)
|
||||
- å› æžœå…³ç³»è¦<EFBFBD>æ±‚ä¸¥æ ¼çš„ç ”ç©?
|
||||
- 因果关系要求严格的研究
|
||||
|
||||
---
|
||||
|
||||
## âœ?更新确认清å<E280A6>•
|
||||
## ✅ 更新确认清单
|
||||
|
||||
请确认以下更新是否符合您的需求:
|
||||
|
||||
- [x] 前向/后向填充功能加入Phase 1(本次开发)
|
||||
- [x] Tab 2增加2个填补选项(共6种方法)
|
||||
- [x] Python函数支æŒ<EFBFBD> `'ffill'` å’?`'bfill'` 方法
|
||||
- [x] 测试用例ä»?4ä¸ªå¢žåŠ åˆ°18ä¸?
|
||||
- [x] å¼€å<EFBFBD>‘时间从5-6å°<C3A5>æ—¶å¢žåŠ åˆ?-7å°<C3A5>æ—¶
|
||||
- [x] Python函数支持 `'ffill'` 和 `'bfill'` 方法
|
||||
- [x] 测试用例从14个增加到18个
|
||||
- [x] 开发时间从5-6小时增加到6-7小时
|
||||
- [x] 适用场景说明清晰(医学研究背景)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 如确认无误,即可开始开发!
|
||||
|
||||
**å¼€å<EFBFBD>‘顺åº?*ï¼?
|
||||
1. Pythonå<EFBFBD>Žç«¯ - 简å<E282AC>•填补(å<CB86>«å‰<C3A5>/å<>Žå<C5BD>‘å¡«å……ï¼?
|
||||
**开发顺序**:
|
||||
1. Python后端 - 简单填补(含前/后向填充)
|
||||
2. Python后端 - MICE填补
|
||||
3. Node.js后端API转发
|
||||
4. å‰<EFBFBD>端UIï¼?个Tab,Tab 2å<32>?ç§<C3A7>方法)
|
||||
4. 前端UI(3个Tab,Tab 2含6种方法)
|
||||
5. API集成
|
||||
6. 18个测试用例验�
|
||||
6. 18个测试用例验证
|
||||
|
||||
**预计总时间:6-7小时**
|
||||
|
||||
@@ -198,6 +198,5 @@ method: 'mean' | 'median' | 'mode' | 'constant' | 'ffill' | 'bfill'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user