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

@@ -9,61 +9,61 @@
## 📋 测试总结
### �核心确认
### ✅ 核心确认
| 项目 | 状�| 说明 |
| 项目 | 状态 | 说明 |
|------|------|------|
| **å<EFBFBD>Žç«¯ä»£ç <EFBFBD>存在æ€?* | âœ?确认 | 完整的Tool B代ç <C3A7>已实现,å…?*1495行代ç ?* |
| **æ•°æ<EFBFBD>®åº“表** | âœ?确认 | 4张表已åˆå»ºï¼Œé¢„设数æ<C2B0>®å·²å†™å…?|
| **路由注册** | âœ?确认 | `/api/v1/dc/tool-b` 已在主æœ<EFBFBD>务器注册 |
| **æœ<EFBFBD>务å<EFBFBD>¯åЍ** | âœ?正常 | æœ<C3A6>务器è¿<C3A8>行在3000端å<C2AF>£ |
| **API端点** | âœ?å<>¯ç”¨ | 6个端ç¹å…¨éƒ¨å®žçŽ?|
| **后端代码存在性** | ✅ 确认 | 完整的Tool B代码已实现共**1495行代码** |
| **数据库表** | ✅ 确认 | 4张表已创建预设数据已写入 |
| **路由注册** | ✅ 确认 | `/api/v1/dc/tool-b` 已在主服务器注册 |
| **服务启动** | ✅ 正常 | 服务器运行在3000端口 |
| **API端点** | ✅ 可用 | 6个端点全部实现 |
---
## ðŸ<EFBFBD>—ï¸<>Žç«¯ä»£ç <C3A7>结构验è¯<C3A8>
## 🏗️ 后端代码结构验证
### 代码文件清单
```
backend/src/modules/dc/tool-b/
├── controllers/
â”? └── ExtractionController.ts (6个API端ç¹å®žçް)
│ └── ExtractionController.ts (6个API端点实现)
├── services/
â”? ├── HealthCheckService.ts (å<EFBFBD>¥åº·æ£€æŸ¥é€»è¾)
â”? ├── TemplateService.ts (模æ<EFBFBD>¿ç®¡ç<EFBFBD>)
â”? ├── DualModelExtractionService.ts (å<EFBFBD>Œæ¨¡åžæ<EFBFBD><EFBFBD>å<EFBFBD>?
â”? └── ConflictDetectionService.ts (冲çª<EFBFBD>检æµ?
│ ├── HealthCheckService.ts (健康检查逻辑)
│ ├── TemplateService.ts (模板管理)
│ ├── DualModelExtractionService.ts (双模型提取)
│ └── ConflictDetectionService.ts (冲突检测)
├── routes/
â”? └── index.ts (路由é…<EFBFBD>ç½®)
│ └── index.ts (路由配置)
├── utils/
└── workers/
```
### 代码统计
- **总代ç <EFBFBD>行æ•?*: 1495è¡?
- **核心æœ<EFBFBD>务**: 4ä¸?
- **API控制�*: 1�
- **API端点**: 6�
- **总代码行数**: 1495
- **核心服务**: 4
- **API控制器**: 1
- **API端点**: 6
### 路由注册确认
�`backend/src/index.ts` 中已注册�
`backend/src/index.ts` 中已注册:
```typescript
// ============================================
// 【业务模块】DC - 数据清洗整理
// ============================================
await registerDCRoutes(fastify);
logger.info('âœ?DCæ•°æ<C2B0>®æ¸…洗模å<C2A1>—路由已注å†? /api/v1/dc/tool-b');
logger.info('✅ DC数据清洗模块路由已注册: /api/v1/dc/tool-b');
```
---
## 🧪 API端点测试
### 1. âœ?获å<C2B7>模æ<C2A1>¿åˆ—表
### 1. ✅ 获取模板列表
**端点**: `GET /api/v1/dc/tool-b/templates`
@@ -72,7 +72,7 @@ logger.info('
curl http://localhost:3000/api/v1/dc/tool-b/templates
```
**å“<EFBFBD>应状æ€?*: âœ?200 OK
**响应状态**: ✅ 200 OK
**响应数据**:
```json
@@ -84,13 +84,13 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
"id": "ff58df52-36a7-4e09-b153-decd6f867da2",
"diseaseType": "diabetes",
"reportType": "admission",
"displayName": "ç³–å°¿ç—?入院记录模æ<C2A1>¿",
"displayName": "糖尿病-入院记录模板",
"fields": [
{ "name": "主诉", "desc": "æ£è€…就诊的主è¦<EFBFBD>症状æˆåŽŸå?, "width": "w-48" },
{ "name": "现çå<EFBFBD>?, "desc": "本次ç¾ç—…çš„å<E2809E>展过ç¨?, "width": "w-64" },
{ "name": "æ¢å¾å<EFBFBD>?, "desc": "既往疾病和治疗情å†?, "width": "w-40" },
{ "name": "空è¹è¡ç³?, "desc": "å<EFBFBD>•ä½<EFBFBD>mmol/L", "width": "w-32" },
{ "name": "糖化血红蛋ç™?, "desc": "å<EFBFBD>ä½<EFBFBD>%", "width": "w-32" }
{ "name": "主诉", "desc": "患者就诊的主要症状或原因", "width": "w-48" },
{ "name": "现病史", "desc": "本次疾病的发展过程", "width": "w-64" },
{ "name": "既往史", "desc": "既往疾病和治疗情况", "width": "w-40" },
{ "name": "空腹血糖", "desc": "单位mmol/L", "width": "w-32" },
{ "name": "糖化血红蛋白", "desc": "单位%", "width": "w-32" }
],
"promptTemplate": "..."
},
@@ -98,7 +98,7 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
"id": "80c1abf4-66b0-4183-9531-9f4d207e249b",
"diseaseType": "hypertension",
"reportType": "outpatient",
"displayName": "高è¡åŽ?é¨è¯Šè®°å½æ¨¡æ<EFBFBD>¿",
"displayName": "高血压-门诊记录模板",
"fields": [...]
},
{
@@ -114,17 +114,17 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
```
**验证结果**:
- âœ?è¿”åž3个预设模æ<C2A1>?
- âœ?æ•°æ<C2B0>®ç»“构完整(id, diseaseType, reportType, displayName, fields, promptTemplateï¼?
- âœ?模æ<C2A1>¿å­—段é…<C3A9>置正确(name, desc, widthï¼?
- ✅ 返回3个预设模板
- ✅ 数据结构完整(id, diseaseType, reportType, displayName, fields, promptTemplate
- ✅ 模板字段配置正确(name, desc, width
---
### 2. â<EFBFBD><>¥åº·æ£€æŸ¥ï¼ˆå¾…æµè¯•)
### 2. ⏳ 健康检查(待测试)
**端点**: `POST /api/v1/dc/tool-b/health-check`
**请求�*:
**请求体**:
```json
{
"fileKey": "uploads/test-medical-records.xlsx",
@@ -151,19 +151,19 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
```
**测试要求**:
- 需è¦<EFBFBD>先上传一个Excelæ‡ä»¶åˆ°å­˜å¨æœ<EFBFBD>åŠ?
- æ‡ä»¶éœ€è¦<EFBFBD>包å<EFBFBD>«å¾…结构åŒçš„ç—…åŽ†æ‡æœ¬åˆ?
- 需要先上传一个Excel文件到存储服务
- 文件需要包含待结构化的病历文本列
---
### 3. â<EFBFBD>ˆå»ºæ<C2BA><C3A6>å<EFBFBD>任务(待æµè¯•ï¼?
### 3. ⏳ 创建提取任务(待测试)
**端点**: `POST /api/v1/dc/tool-b/tasks`
**请求�*:
**请求体**:
```json
{
"projectName": "2025糖尿病研�,
"projectName": "2025糖尿病研究",
"sourceFileKey": "uploads/test-medical-records.xlsx",
"textColumn": "病历文本",
"diseaseType": "diabetes",
@@ -186,12 +186,12 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
```
**测试要求**:
- 需è¦<EFBFBD>é…<EFBFBD>ç½®LLM Gateway(DeepSeekå’ŒQwençš„API密é¥ï¼?
- 需要配置LLM GatewayDeepSeekQwen的API密钥
- 任务创建后会异步处理,需要通过进度端点查询
---
### 4. â<EFBFBD>?查询任务进度(待测试ï¼?
### 4. ⏳ 查询任务进度(待测试)
**端点**: `GET /api/v1/dc/tool-b/tasks/:taskId/progress`
@@ -217,7 +217,7 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
---
### 5. â<EFBFBD>?获å<C2B7>任务数æ<C2B0>®é¡¹ï¼ˆå¾…æµè¯•)
### 5. ⏳ 获取任务数据项(待测试)
**端点**: `GET /api/v1/dc/tool-b/tasks/:taskId/items?page=1&limit=20&status=conflict`
@@ -230,9 +230,9 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
{
"id": "item-uuid",
"rowIndex": 1,
"originalText": "患者主诉头�..",
"modelAResult": { "主诉": "头晕", "空腹血�: "8.5" },
"modelBResult": { "主è¯": "头æä¹<EFBFBD>åŠ", "空è¹è¡ç³?: "8.2" },
"originalText": "患者主诉头晕...",
"modelAResult": { "主诉": "头晕", "空腹血糖": "8.5" },
"modelBResult": { "主诉": "头晕乏力", "空腹血糖": "8.2" },
"conflicts": [
{
"field": "主诉",
@@ -256,11 +256,11 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
---
### 6. â<EFBFBD>?解决冲çª<C3A7>(待æµè¯•ï¼?
### 6. ⏳ 解决冲突(待测试)
**端点**: `POST /api/v1/dc/tool-b/items/:itemId/resolve`
**请求�*:
**请求体**:
```json
{
"field": "主诉",
@@ -290,11 +290,11 @@ curl http://localhost:3000/api/v1/dc/tool-b/templates
需要在 `backend/.env` 中配置:
```env
# LLMé…<EFBFBD>置(必需,å<EFBFBD>¦åˆ™æ— æ³•æµè¯•å<EFBFBD>Œæ¨¡åžæ<EFBFBD><EFBFBD>å<EFBFBD>ï¼?
# LLM配置(必需,否则无法测试双模型提取)
DEEPSEEK_API_KEY=sk-xxx
QWEN_API_KEY=sk-xxx
# å­˜å¨é…<EFBFBD>置(å<EFBFBD>¯é€‰ï¼Œé»˜è®¤æœ¬åœ°å­˜å¨ï¼?
# 存储配置(可选,默认本地存储)
STORAGE_TYPE=local
LOCAL_STORAGE_PATH=./uploads
@@ -304,17 +304,17 @@ DATABASE_URL=postgresql://postgres:postgres123@localhost:5432/ai_clinical_resear
### 2. 测试数据准备
需è¦<EFBFBD>准备一个æµè¯•Excelæ‡ä»¶ï¼?
需要准备一个测试Excel文件
| 患者ID | 病历文本 |
|--------|----------|
| P001 | æ£è€…男性,55å²<EFBFBD>,主诉:å<EFBFBD>£å¹²å¤šé¥?å¹´ã€çŽ°ç—…å<E280A6>²ï¼šæ£è€?å¹´å‰<C3A5>无明显诱å å‡ºçްå<C2B0>£å¹²ã€<C3A3>多饮ã€<C3A3>多尿,伴ä¹<C3A4>åŠ?.. |
| P002 | æ£è€…女性,62å²<EFBFBD>,主诉:头æ™?å¨ã€æ—¢å¾€æœ‰é«˜è¡€åŽç—…å<E280A6>?0å¹?.. |
| P001 | 患者男性55岁主诉口干多饮2年。现病史患者2年前无明显诱因出现口干、多饮、多尿伴乏力... |
| P002 | 患者女性62岁主诉头晕1周。既往有高血压病史10年... |
| ... | ... |
### 3. LLM Gateway测试
在æµè¯•å<EFBFBD>Œæ¨¡åžæ<EFBFBD><EFBFBD>å<EFBFBD>å‰<EFBFBD>,建议先æµè¯•LLM Gateway是å<C2AF>¦æ­£å¸¸ï¼?
在测试双模型提取前建议先测试LLM Gateway是否正常
```bash
# 测试DeepSeek
@@ -336,78 +336,78 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发
| 平台能力 | 使用情况 | 复用位置 |
|---------|---------|---------|
| **Storage** | �使用 | `HealthCheckService.ts`, `ExtractionController.ts` |
| **Logger** | âœ?使用 | 所有æœ<C3A6>åŠ¡åŒæŽ§åˆ¶å™?|
| **Prisma** | âœ?使用 | `TemplateService.ts`, æ•°æ<EFBFBD>®åº“æ“<EFBFBD>ä½?|
| **Cache** | âš ï¸<EFBFBD> 待用 | å<>¯ç”¨äºŽç¼“存模æ<C2A1>¿åˆ—è¡?|
| **Jobs** | âš ï¸<EFBFBD> 待用 | å<>¯ç”¨äºŽå¼æ­¥æ<C2A5><C3A6>å<EFBFBD>ä»»åŠ?|
| **LLM Gateway** | �使用 | `DualModelExtractionService.ts` |
| **Storage** | ✅ 使用 | `HealthCheckService.ts`, `ExtractionController.ts` |
| **Logger** | ✅ 使用 | 所有服务和控制器 |
| **Prisma** | ✅ 使用 | `TemplateService.ts`, 数据库操作 |
| **Cache** | ⚠️ 待用 | 可用于缓存模板列表 |
| **Jobs** | ⚠️ 待用 | 可用于异步提取任务 |
| **LLM Gateway** | ✅ 使用 | `DualModelExtractionService.ts` |
---
## 🎯 下一步测试计�
## 🎯 下一步测试计划
### Phase 1: 基础API测试需要测试数据
1. âœ?**模æ<C2A1>¿åˆ—表** - 已完æˆ?
2. â<EFBFBD>?**å<>¥åº·æ£€æŸ?* - 需è¦<C3A8>上传æµè¯•Excel
3. â<EFBFBD>?**创建任务** - 需è¦<EFBFBD>é…<EFBFBD>ç½®LLM密é¥
4. â<EFBFBD>?**查询进度** - ä¾<EFBFBD>èµæ­¥éª¤3
5. â<EFBFBD>?**获å<C2B7>æ•°æ<C2B0>®é¡?* - ä¾<C3A4>èµæ­¥éª¤3
6. â<EFBFBD>?**解决冲çª<C3A7>** - ä¾<EFBFBD>èµæ­¥éª¤3
1. **模板列表** - 已完成
2. **健康检查** - 需要上传测试Excel
3. **创建任务** - 需要配置LLM密钥
4. **查询进度** - 依赖步骤3
5. **获取数据项** - 依赖步骤3
6. **解决冲突** - 依赖步骤3
### Phase 2: 集成测试(完整流程)
1. 上传Excel文件
2. å<EFBFBD>¥åº·æ£€æŸ?
2. 健康检查
3. 创建提取任务
4. 轮询进度直到完成
5. 获å<EFBFBD>冲çª<EFBFBD>é¡?
5. 获取冲突项
6. 逐个解决冲突
7. 导出最终结�
7. 导出最终结果
### Phase 3: 压力测试
1. 大文件测试1000+行)
2. 并发任务测试
3. é•¿æ‡æœ¬æ<EFBFBD><EFBFBD>å<EFBFBD>æµè¯?
3. 长文本提取测试
4. 异常场景测试
---
## �结论
## ✅ 结论
### 后端状态总结
| 组件 | å¼€å<E282AC>è¿åº?| 测试状æ€?|
| 组件 | 开发进度 | 测试状态 |
|------|---------|---------|
| **æ•°æ<EFBFBD>®åº“Schema** | âœ?100% | âœ?已验è¯<C3A8>(4è¡?预设数æ<C2B0>®ï¼?|
| **æœ<EFBFBD>务å±ä»£ç ?* | âœ?100% | âš ï¸<C3AF> 需è¦<C3A8>完整æµ<C3A6>ç¨æµè¯?|
| **API端点** | âœ?100% | 🟡 模æ<C2A1>¿APIå·²æµè¯•,其ä»å¾…æµ |
| **路由注册** | �100% | �已验�|
| **å¹³å<EFBFBD>°èƒ½åŠé†æˆ<EFBFBD>** | âœ?100% | âš ï¸<EFBFBD> LLM Gateway待验è¯?|
| **数据库Schema** | 100% | ✅ 已验证4表+预设数据) |
| **服务层代码** | ✅ 100% | ⚠️ 需要完整流程测试 |
| **API端点** | 100% | 🟡 模板API已测试其他待测 |
| **路由注册** | 100% | ✅ 已验证 |
| **平台能力集成** | 100% | ⚠️ LLM Gateway待验证 |
### å<EFBFBD>¯ä»¥æ˜Žç¡®åŠçŸ¥ç”¨æˆ·ï¼?
### 可以明确告知用户:
âœ?**DC模å<EFBFBD>—Tool Bçš„å<E2809E>Žç«¯API代ç <C3A7>å·?00%完æˆ<C3A6>ï¼?*
**DC模块Tool B的后端API代码已100%完成!**
- **代ç <EFBFBD>é‡?*: 1495行完整实çŽ?
- **API端点**: 6个端ç¹å…¨éƒ¨å°±ç»?
- **æ•°æ<EFBFBD>®åº?*: 4张表+预设数æ<C2B0>®å·²éªŒè¯?
- **代码量**: 1495行完整实现
- **API端点**: 6个端点全部就绪
- **数据库**: 4张表+预设数据已验证
- **服务启动**: 正常运行
- **基础测试**: 模板API测试通过
### 当å‰<EFBFBD>å<EFBFBD>¯ä»¥å¼€å§çš„工作ï¼?
### 当前可以开始的工作:
1. âœ?**å‰<C3A5>端开å<E282AC>?* - å<>Žç«¯API已就绪,å<C592>¯ä»¥å¼€å§å‰<C3A5>端对æŽ?
2. â<EFBFBD>?**完整æµ<C3A6>ç¨æµè¯•** - 需è¦<EFBFBD>准备æµè¯•æ•°æ<EFBFBD>®åŒLLMé…<EFBFBD>ç½®
3. â<EFBFBD>?**用户验收测试** - å‰<EFBFBD>端完æˆ<EFBFBD>å<EFBFBD>Žè¿è¡Œç«¯åˆ°ç«¯æµè¯•
1. **前端开发** - 后端API已就绪可以开始前端对接
2. **完整流程测试** - 需要准备测试数据和LLM配置
3. **用户验收测试** - 前端完成后进行端到端测试
---
## 📝 测试记录
**测试执行�*: AI Assistant
**测试执行者**: AI Assistant
**测试日期**: 2025-12-02
**测试环境**:
- OS: Windows 10
@@ -415,7 +415,7 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发
- PostgreSQL: 16
- 服务端口: 3000
**下次更新时间**: 完æˆ<C3A6>完整æµ<C3A6>ç¨æµè¯•å<E280A2>?
**下次更新时间**: 完成完整流程测试后
---
@@ -475,6 +475,5 @@ Tool B后端代码**100%复用**了平台通用能力层,无任何重复开发