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,80 +1,80 @@
# Week 4结果展示与导出 - 开发计划(云原生架构)
> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𧋦嚗?* v1.0
> **<EFBFBD>𥕦遣<EFBFBD><EFBFBD>嚗?* 2025-11-21
> **<EFBFBD><EFBFBD><EFBFBD>嚗?* 2憭抬<E686AD>Day 16-17嚗?
> **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?* <20>?鈭穃<E988AD><E7A983><EFBFBD><E785BA>?
> **文档版本:** v1.0
> **创建日期:** 2025-11-21
> **计划周期:** 2天Day 16-17
> **架构原则:** ✅ 云原生优先
> **最后更新:** 2025-11-21
---
## 📋 文档说明
<EFBFBD><EFBFBD><EFBFBD> Week 4 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>𤑳<EFBFBD>霂衣<EFBFBD><EFBFBD>嚗屸<EFBFBD>敺芯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>摰䂿緵蝑偦<EFBFBD><EFBFBD><EFBFBD>𦦵<EFBFBD>蝏蠘恣撅閧內<EFBFBD>袏xcel撖澆枂<EFBFBD><EFBFBD><EFBFBD>?
本文档是 Week 4 功能开发的详细计划遵循云原生开发规范实现筛选结果的统计展示和Excel导出功能。
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?蝏蠘恣璁<E681A3><E79281><EFBFBD><E59A97>餅㺭<E9A485><E3BAAD><EFBFBD><EFBFBD><E4BAA6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E696A4><EFBFBD><EFBFBD>憭齿瓲嚗?
- <EFBFBD>?PRISMA撘𤩺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>霈?
- <EFBFBD>?蝏𤘪<E89D8F><F0A498AA>𡑒”Tab<61><62>揢銝擧䰻<E693A7>?
- <EFBFBD>?Excel<EFBFBD><EFBFBD>撖澆枂
- <EFBFBD>?摰峕㟲<E5B395><EFBFBD><E8A098>剔㴓嚗<E3B493><E59A97>隡罱<E99AA1>蝑偦<E89D91><EFBFBD>憭齿瓲<E9BDBF><EFBFBD>霈﹦<E99C88>撖澆枂嚗?
**核心目标**
- ✅ 统计概览(总数、纳入率、排除率、待复核)
- PRISMA式排除原因统计
- ✅ 结果列表Tab切换与查看
- Excel批量导出
- ✅ 完整功能闭环(上传→筛选→复核→统计→导出)
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?**鈭穃<E988AD><E7A983><EFBFBD><E785BA>?*嚗𡁻<E59A97>敺歧鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8><EFBFBD>(../../../04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md)
- <EFBFBD>?**憭滨鍂撟喳蝱<E596B3><EFBFBD>**嚗帋蝙<E5B88B><EFBFBD><EFBFBD>`prisma`<EFBFBD><EFBFBD>logger`蝑?
- <EFBFBD>?**<2A><EFBFBD>隞嗉氜<E59789>?*嚗鍃xcel<65>滨垢<E6BBA8><E59EA2><EFBFBD><EFBFBD>𤈛SS摮睃<E691AE>
- <EFBFBD>?**<2A>𡒊垢<F0A1928A>𡁜<EFBFBD>霈∠<E99C88>**嚗𡁶<E59A97>霈⊥㺭<E28AA5><EFBFBD>蝡航<E89DA1><E888AA>?
**架构原则**
- **云原生优先**:遵循[云原生开发规范](../../../04-开发规范/08-云原生开发规范.md)
- **复用平台能力**:使用全局`prisma``logger`
- **零文件落盘**Excel前端生成或OSS存储
- **后端聚合计算**:统计数据后端聚合
---
## <EFBFBD>㴓 銝<><E98A9D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>雿?
## 🎯 一、功能定位
### 1.1 "摰⊥瓲撌乩<EFBFBD><EFBFBD>? vs "<22><EFBFBD>蝏𤘪<E89D8F>" <20><EFBFBD>
### 1.1 "审核工作台" vs "初筛结果" 区别
| 蝏游漲 | 摰⊥瓲撌乩<E6928C><E4B9A9><EFBFBD>ScreeningWorkbench嚗?| <20><EFBFBD>蝏𤘪<E89D8F>嚗𠄎creeningResults嚗?|
| 维度 | 审核工作台(ScreeningWorkbench | 初筛结果ScreeningResults |
|------|--------------------------------|---------------------------|
| **摰帋<EFBFBD>** | 摰墧𧒄<EFBFBD>烐綉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>犖撌亙<EFBFBD><EFBFBD>?| <20><><EFBFBD><E89D8F><EFBFBD>𨅯<EFBFBD>蝷箝<E89DB7><E7AE9D><EFBFBD><E99C88><E288AA><EFBFBD><E58390><EFBFBD>誩紡<E8AAA9>?|
| **定位** | 实时监控、冲突处理、人工复核 | 最终结果展示、统计分析、批量导出 |
| **使用时机** | 筛选进行中 | 筛选完成后 |
| **<EFBFBD><EFBFBD><EFBFBD><EFBFBD>** | 餈𥕦漲頧株砭<EFBFBD><EFBFBD><EFBFBD>鞉辺憭齿瓲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鈭?| 蝏蠘恣璁<E681A3><E79281><EFBFBD><EFBFBD>RISMA<4D><EFBFBD><E9A48C><EFBFBD><EFBFBD>誩紡<E8AAA9>?|
| **銵冽聢敶<EFBFBD>** | <EFBFBD><EFBFBD>銵冽聢嚗㇄S + Qwen撖寞<E69296>嚗?| <20><EFBFBD>銵冽聢嚗<E881A2>遬蝷箸<E89DB7><EFBFBD><E89D8F>蝑吔<E89D91> |
| **撘箄<EFBFBD><EFBFBD><EFBFBD>** | 撌乩<EFBFBD>瘚?| 蝏𤘪<E89D8F><EFBFBD><E79899>?|
| **核心功能** | 进度轮询、逐条复核、冲突高亮 | 统计概览、PRISMA总结、批量导出 |
| **表格形式** | 双行表格DS + Qwen对比 | 单行表格(显示最终决策) |
| **强调重点** | 工作流 | 结果汇总 |
**瘥𥪜鸘**嚗?
**比喻**
```
摰⊥瓲撌乩<EFBFBD><EFBFBD>?= <20>煺漣頧阡𡢿嚗<F0A1A2BF><EFBFBD><EFBFBD><E587BD><EFBFBD><E589B9><EFBFBD><EFBFBD><EFBFBD>
审核工作台 = 生产车间(正在筛选、复核)
初筛结果 = 成品仓库(已完成、统计、导出)
```
### 1.2 用户流程
```
霈曄蔭銝𤾸鍳<EFBFBD>?<3F>?摰⊥瓲撌乩<E6928C><E4B9A9>?<3F>?<3F><EFBFBD>蝏𤘪<E89D8F>
(<EFBFBD>滨蔭) (摰墧𧒄<EFBFBD>烐綉) (蝏𤘪<E89D8F><EFBFBD><E79899>?
<EFBFBD>? <EFBFBD>? <EFBFBD>?
设置与启动 → 审核工作台 → 初筛结果
(配置) (实时监控) (结果汇总)
填写PICOS 逐条复核 批量导出
上传Excel 冲突处理 统计分析
```
---
## <EFBFBD><EFBFBD>儭?鈭䎚<E988AD><E48E9A><EFBFBD><EFBFBD>舀沲<E88880><E6B2B2><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>
## 🏗️ 二、技术架构(云原生)
### 2.1 核心架构决策
#### <EFBFBD><EFBFBD>1嚗𡁏㺭<EFBFBD>株繮<EFBFBD>𣇉<EFBFBD><EFBFBD>?<3F>?<3F>𡒊垢<F0A1928A>𡁜<EFBFBD>API <EFBFBD>?
#### 决策1数据获取策略 → 后端聚合API
**<EFBFBD><EFBFBD>A**嚗<><E59A97><EFBFBD><EFBFBD>鍂嚗㚁<E59A97><E39A81>滨垢<E6BBA8><EFBFBD><E79195><EFBFBD><E588B8>唳旿嚗<E697BF><E59A97>蝡航恣蝞?
**方案A**(不采用):前端获取全量数据,前端计算
```typescript
// <EFBFBD>?銝滨泵<E6BBA8><E6B3B5><EFBFBD><EFBFBD><EFBFBD>嚗𡁜<E59A97>蝡航繮<E888AA><EFBFBD><E7A18B>𤩺㺭<F0A4A9BA><EFBFBD><E6AEB7><EFBFBD>銝𠰴<E98A9D><F0A0B0B4><EFBFBD>
// ❌ 不符合云原生:前端获取全量数据(可能上千条)
const { data } = await aslApi.getScreeningResultsList(projectId, {
pageSize: 9999 // 获取全部
});
// 前端计算统计...
```
**<EFBFBD><EFBFBD>B**嚗<><E59A97><EFBFBD><EFBFBD>嚗𡁜<E59A97>蝡航<E89DA1><E888AA>PI <EFBFBD>?
**方案B**采用后端聚合API
```typescript
// <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD><EFBFBD>𡒊垢<F0A1928A>𡁜<EFBFBD><EFBFBD><E59A97>撠𤑳<E692A0>蝏靝<E89D8F>颲?
// ✅ 符合云原生:后端聚合,减少网络传输
GET /api/v1/asl/projects/:projectId/statistics
// 后端使用Prisma聚合
@@ -85,50 +85,50 @@ const stats = await prisma.aslScreeningResult.groupBy({
});
```
**<EFBFBD>㗇𥋘<EFBFBD><EFBFBD>眏**嚗?
- <EFBFBD>?<3F>𡒊垢<F0A1928A>𡁜<EFBFBD>嚗峕<E59A97><EFBFBD>憟?
- <EFBFBD>?<3F><EFBFBD>蝵𤑳<E89DB5>隡㰘<E99AA1><EFBFBD><E59A97>MB蝥折<E89DA5><E68A98>袁B蝥改<E89DA5>
- <EFBFBD>?<3F><EFBFBD>撅閙<E69285>批撩嚗<E692A9>𣈲<EFBFBD><F0A388B2>凒憭齿<E686AD><E9BDBF><EFBFBD><EFBFBD>霈∴<E99C88>
- <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983>?霈∠<E99C88><E288A0><EFBFBD><E3B098>唳旿"<22><EFBFBD>
**选择理由**
- ✅ 后端聚合,性能好
- ✅ 减少网络传输从MB级降到KB级
- ✅ 可扩展性强(支持更复杂的统计)
- ✅ 符合云原生"计算靠近数据"原则
---
#### <EFBFBD><EFBFBD>2嚗鍃xcel撖澆枂蝑𣇉裦 <20>?<3F>滨垢<E6BBA8><E59EA2><EFBFBD>嚗㇈VP嚗争<E59A97>
#### 决策2Excel导出策略 → 前端生成MVP
**<EFBFBD><EFBFBD>A**嚗<><E59A97><EFBFBD>決VP嚗㚁<E59A97><E39A81>滨垢<E6BBA8><E59EA2><EFBFBD> <20>?
**方案A**采用MVP前端生成 ✅
```typescript
// <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞嗉氜<E59789><EFBFBD><EFBFBD><E691B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E886A5><EFBFBD>銝?
// ✅ 符合云原生:零文件落盘,完全在浏览器内存中
import * as XLSX from 'xlsx';
function exportToExcel(results) {
const ws = XLSX.utils.json_to_sheet(exportData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, '蝑偦<EFBFBD><EFBFBD><EFBFBD>?);
XLSX.writeFile(wb, 'screening-results.xlsx'); // 瘚讛<EFBFBD><EFBFBD><EFBFBD>頧?
XLSX.utils.book_append_sheet(wb, ws, '筛选结果');
XLSX.writeFile(wb, 'screening-results.xlsx'); // 浏览器下载
}
```
**隡条<EFBFBD>**嚗?
- <EFBFBD>?**<2A><EFBFBD>隞嗉氜<E59789>?*嚗<><E59A97><EFBFBD>典銁瘚讛<E7989A><E8AE9B><EFBFBD>摮䀝葉<E4809D><E89189><EFBFBD>嚗?
- <EFBFBD>?**<2A>𣳇<EFBFBD><F0A3B387>𡒊垢摮睃<E691AE>**嚗<><E59A97><EFBFBD>删鍂OSS蝛粹𡢿嚗?
- <EFBFBD>?**摰墧𧒄<E5A2A7><F0A79284><EFBFBD>**嚗<><E59A97><EFBFBD>郊蝑匧<E89D91>嚗?
- <EFBFBD>?**蝚血<E89D9A>鈭穃<E988AD><E7A983><EFBFBD><E7AC94>?*嚗<><E59A97><EFBFBD>𥒚erverless<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嚗?
- <EFBFBD>?**<2A>鞉𧋦雿?*嚗<><E59A97><EFBFBD><E798A8><EFBFBD>蝡航<E89DA1>皞琜<E79A9E>
**优点**
- **零文件落盘**(完全在浏览器内存中生成)
- **无需后端存储**不占用OSS空间
- **实时生成**(无异步等待)
- **符合云原生原则**避免Serverless文件操作)
- **成本低**(不消耗后端资源)
**<EFBFBD>𣂼<EFBFBD>**嚗?
- <EFBFBD>𩤃<EFBFBD> <20><><EFBFBD>唳旿<E594B3>𧶏<EFBFBD><5000<EFBFBD>?
- <EFBFBD>𩤃<EFBFBD> <20><><EFBFBD><EFBFBD>笔漲嚗?1000<EFBFBD>∠漲2-3蝘?
**限制**
- ⚠️ 适用数据量:<5000
- ⚠️ 生成速度:<1000条约2-3
- ⚠️ 不支持复杂格式多Sheet、图表
**<EFBFBD><EFBFBD>B**嚗<>𧊋<EFBFBD><EFBFBD>撅𤏪<E69285>嚗𡁜<E59A97>蝡舐<E89DA1><E88890>?+ OSS摮睃<E691AE> <20><EFBFBD>
**方案B**(未来扩展):后端生成 + OSS存储 ⏸️
```typescript
// <EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>箏𦛚嚗𡁜<E59A97><F0A1819C>唳旿<E594B3>?5000<30><EFBFBD><E28AA5><EFBFBD><EFBFBD><E996AC><EFBFBD><EFBFBD>聢撘𤩺𧒄
// 1. <EFBFBD>𡒊垢<EFBFBD><EFBFBD><EFBFBD>Excel嚗<EFBFBD><EFBFBD>摮䀝葉嚗?
// ⏸️ 技术债务:当数据量>5000条或需要复杂格式时
// 1. 后端生成Excel内存中
import ExcelJS from 'exceljs';
const workbook = new ExcelJS.Workbook();
// ... 生成Excel
// 2. 潃?銝𠹺<E98A9D><F0A0B9BA>記SS嚗<53><EFBFBD>典像<E585B8><EFBFBD><E595A3><EFBFBD><E586BD><EFBFBD>
// 2. ⭐ 上传到OSS使用平台存储服务
import { storage } from '@/common/storage';
const buffer = await workbook.xlsx.writeBuffer();
const url = await storage.upload(`asl/exports/${Date.now()}.xlsx`, buffer);
@@ -137,97 +137,97 @@ const url = await storage.upload(`asl/exports/${Date.now()}.xlsx`, buffer);
res.send({ success: true, url });
```
**閫血<EFBFBD><EFBFBD>∩辣**嚗?
- <EFBFBD>閙活撖澆枂<EFBFBD>唳旿<EFBFBD>?>5000<EFBFBD>?
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>xcel<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Sheet<EFBFBD><EFBFBD>㦛銵函<EFBFBD>嚗?
**触发条件**
- 单次导出数据量 >5000
- 需要复杂Excel格式多Sheet、图表等
- 用户反馈前端导出卡顿
**霈啣<EFBFBD>雿滨蔭**嚗靀<E59A97><E99D80><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C> - 隡睃<E99AA1>蝥?](../../06-<EFBFBD><EFBFBD><EFBFBD><EFBFBD>箏𦛚/<2F><><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C>.md)
**记录位置**[技术债务清单 - 优先级4](../../06-技术债务/技术债务清单.md)
---
### 2.2 鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 2.2 云原生架构检查
<EFBFBD><EFBFBD>[鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8><EFBFBD>(../../../04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md)嚗峕𧋦撘<F0A78BA6><E69298>𤏸恣<F0A48FB8><EFBFBD>敺迎<E695BA>
基于[云原生开发规范](../../../04-开发规范/08-云原生开发规范.md),本开发计划遵循:
| <EFBFBD><EFBFBD>仿★ | 閬<><E996AC> | <20>祈恣<E7A588><EFBFBD><E98DA6>?| <20><EFBFBD>?|
| 检查项 | 要求 | 本计划实现 | 状态 |
|--------|------|-----------|------|
| **摮睃<EFBFBD>** | 雿輻鍂`storage.upload()`嚗䔶<EFBFBD><EFBFBD>fs.writeFile()` | Excel<EFBFBD>滨垢<EFBFBD><EFBFBD><EFBFBD>嚗屸妟<EFBFBD><EFBFBD> | <EFBFBD>?|
| **<EFBFBD>唳旿摨?* | 雿輻鍂<E8BCBB><EFBFBD>`prisma`摰硺<E691B0> | 蝏蠘恣API雿輻鍂<E8BCBB><EFBFBD>`prisma` | <EFBFBD>?|
| **<EFBFBD>蹂遙<EFBFBD>?* | 撘<>郊憭<E9838A><E686AD>嚗䔶<E59A97><E494B6><EFBFBD>霂瑟<E99C82> | 蝏蠘恣API <500ms嚗峕<EFBFBD><EFBFBD><EFBFBD><EFBFBD> | <EFBFBD>?|
| **<EFBFBD><EFBFBD>** | 雿輻鍂`logger`嚗䔶<EFBFBD><EFBFBD>console.log` | <EFBFBD>𡒊垢雿輻鍂`logger.info/error` | <EFBFBD>?|
| **<EFBFBD>滨蔭** | 雿輻鍂`process.env` | <EFBFBD>䭾鰵憓鮋<EFBFBD>蝵?| <20>?|
| **霈∠<EFBFBD>** | 憭齿<EFBFBD>霈∠<EFBFBD><EFBFBD>𡒊垢摰峕<EFBFBD> | 蝏蠘恣<E8A098>𡁜<EFBFBD><F0A1819C>𡒊垢摰峕<E691B0> | <EFBFBD>?|
| **存储** | 使用`storage.upload()`,不用`fs.writeFile()` | Excel前端生成,零落盘 | |
| **数据库** | 使用全局`prisma`实例 | 统计API使用全局`prisma` | |
| **长任务** | 异步处理,不阻塞请求 | 统计API <500ms,无需异步 | |
| **日志** | 使用`logger`,不用`console.log` | 后端使用`logger.info/error` | |
| **配置** | 使用`process.env` | 无新增配置 | ✅ |
| **计算** | 复杂计算后端完成 | 统计聚合后端完成 | |
---
## <EFBFBD><EFBFBD> 銝剹<E98A9D><E589B9><EFBFBD>挽霈?
## 📐 三、页面设计
### 3.1 整体布局
```
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <20><><EFBFBD>嚗𡁏<E59A97>憸䀹<E686B8><EFBFBD><E996AC>蝑?- 蝏𤘪<E89D8F> <EFBFBD>?
<EFBFBD>? 霂湔<E99C82>嚗𡁶<E59A97><F0A181B6><EFBFBD><E58EA9>𦦵<EFBFBD><E99C88><EFBD9E>RISMA瘚<41><E7989A><EFBFBD><EFBFBD><E695B4><EFBFBD>𤩺<EFBFBD>雿𨅯<E99BBF>撖澆枂 <EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
┌─────────────────────────────────────────────────────────┐
│ 标题:标题摘要初筛 - 结果
│ 说明筛选结果统计、PRISMA流程图、批量操作和导出
└─────────────────────────────────────────────────────────┘
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <20><> 蝏蠘恣璁<E681A3><E79281>嚗?銝芸㨃<E88AB8>?+ 敺<><E695BA><EFBFBD><EFBFBD>蝷綽<E89DB7> <EFBFBD>?
<EFBFBD>? <20>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?<3F>餅㺭 <20>?<3F>?撌脩熙<E884A9><EFBFBD> <20>?撌脫<E6928C><E884AB><EFBFBD> <20>?敺<><E695BA><EFBFBD><EFBFBD> <EFBFBD>?
<EFBFBD>? <20>? 199 <EFBFBD>?<3F>? 85 <EFBFBD>?<3F>? 90 <EFBFBD>?<3F>? 24 <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>? 蝭? <20>?<3F>?42.7% <EFBFBD>?<3F>?45.2% <EFBFBD>?<3F>?12.1% <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>?
<EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>𩤃<EFBFBD> <20>鞟內嚗朞<E59A97><E69C9E>?24 蝭<><E89DAD><EFBFBD><EFBFBD>憭齿瓲嚗諹窈<E8ABB9><EFBFBD>"摰⊥瓲撌乩<E6928C><E4B9A9>?憭<><E686AD> <EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
┌─────────────────────────────────────────────────────────┐
│ 📊 统计概览4个卡片 + 待复核提示)
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ │ 总数 │ │ 已纳入│ │ 已排除│ │ 待复核│
│ │ 199 │ │ 85 │ │ 90 │ │ 24
│ │ 篇 │ │ 42.7% │ │ 45.2% │ │ 12.1%
│ └───────┘ └───────┘ └───────┘ └───────┘
│ ⚠️ 提示:还有 24 篇文献待复核,请前往"审核工作台"处理
└─────────────────────────────────────────────────────────┘
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <20><> <20>㘾膄<E398BE><EFBFBD>蝏蠘恣嚗<E681A3><E59A97><EFBFBD>嗅㦛嚗? <EFBFBD>?
<EFBFBD>? <20>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?P銝滚龪<E6BB9A><EFBFBD>鈭箇黎嚗? <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 40蝭?(44%) <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?I銝滚龪<E6BB9A><EFBFBD>撟脤<E6929F>嚗? <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 25蝭?(28%) <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?S銝滚龪<E6BB9A><EFBFBD><E3B5AA>𠉛弦霈曇恣嚗争<E59A97><E4BA89><EFBFBD><EFBFBD><EFBFBD>?15蝭?(17%) <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?<3F><EFBFBD><E597A1><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> 10蝭?(11%) <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <EFBFBD>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
┌─────────────────────────────────────────────────────────┐
│ 📈 排除原因统计(柱状图)
│ ┌─────────────────────────────────────────────┐
│ │ P不匹配人群 ████████████████ 40(44%)
│ │ I不匹配干预 ████████ 25(28%)
│ │ S不匹配研究设计████ 15篇 (17%)
│ │ 其他原因 ██ 10(11%)
│ └─────────────────────────────────────────────┘
└─────────────────────────────────────────────────────────┘
<EFBFBD>𢞖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
<EFBFBD>? <20><> 蝏𤘪<E89D8F><F0A498AA>𡑒”嚗㇍abs + <20><EFBFBD>銵冽聢 + <20><EFBFBD><E5AFA5><EFBFBD>嚗? <EFBFBD>?
<EFBFBD>? <20>𢞖<EFBFBD><F0A29E96><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?
<EFBFBD>? <20>?[<5B><EFBFBD> 199] [撌脩熙<E884A9>?85] [撌脫<E6928C><E884AB>?90] [敺<><E695BA><EFBFBD>?24] <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?
<EFBFBD>? <20>?[撖澆枂<E6BE86><EFBFBD>] [撖澆枂敶枏<E695B6>憿琶 [撖澆枂<E6BE86>劐葉憿鉛 <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20><EFBFBD><E98EBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?
<EFBFBD>? <20>?<3F>?摨誩噡 | <20><><EFBFBD> | <20><><EFBFBD><E89D8F>蝑?| <20>㘾膄<E398BE><EFBFBD> | <20><EFBFBD> <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?<3F>?1 | ... | 撌脩熙<EFBFBD>? | - | [<EFBFBD><EFBFBD>] <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?<3F>?2 | ... | 撌脫<EFBFBD><EFBFBD>? | P銝滚龪<E6BB9A>? | [<EFBFBD><EFBFBD>] <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20>?<3F>?3 | ... | <EFBFBD><EFBFBD><EFBFBD>? | <EFBFBD><EFBFBD> | [憭齿瓲] <EFBFBD>? <EFBFBD>?
<EFBFBD>? <20><EFBFBD><E5A999><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? <20>?
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
┌─────────────────────────────────────────────────────────┐
│ 📋 结果列表Tabs + 单行表格 + 批量操作)
│ ┌─────────────────────────────────────────────────┐ │
│ │ [全部 199] [已纳入 85] [已排除 90] [待复核 24]
│ ├─────────────────────────────────────────────────┤ │
│ │ [导出全部] [导出当前页] [导出选中项]
│ ├─────────────────────────────────────────────────┤ │
│ │ ☑ 序号 | 标题 | 最终决策 | 排除原因 | 操作
│ │ ☐ 1 | ... | 已纳入 | - | [查看]
│ │ ☐ 2 | ... | 已排除 | P不匹配 | [查看]
│ │ ☐ 3 | ... | 待复核 | 冲突 | [复核]
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 3.2 表格设计
**<EFBFBD><EFBFBD>銋?*嚗<><E59A97>銵諹”<E8ABB9><EFBFBD><E6BD98><EFBFBD>鈭𤾸恣<F0A4BEB8>詨極雿𨅯蝱<F0A885AF><E89DB1><EFBFBD>銵䕘<E98AB5>嚗?
**列定义**(单行表格,区别于审核工作台的双行):
| 列名 | 宽度 | 说明 |
|------|------|------|
| <EFBFBD>㗇𥋘 | 50px | Checkbox憭𡁻<EFBFBD>?|
| 选择 | 50px | Checkbox多选 |
| 序号 | 60px | 行号 |
| 文献标题 | 400px | Tooltip显示全文 |
| <EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝑?| 100px | Tag<EFBFBD>曄內嚗<EFBFBD><EFBFBD>?<3F>㘾膄/敺<><E695BA>嚗?|
| 最终决策 | 100px | Tag显示(纳入/排除/待定) |
| 排除原因 | 150px | 显示具体原因 |
| 蝵桐縑摨?| 80px | DeepSeek蝵桐縑摨?|
| 置信度 | 80px | DeepSeek置信度 |
| 操作 | 100px | 查看详情按钮 |
**<EFBFBD>喲睸<EFBFBD><EFBFBD>**嚗?
- **摰⊥瓲撌乩<EFBFBD><EFBFBD>?*嚗𡁜<E59A97>銵諹”<E8ABB9><EFBFBD><E6BD98>曄內DS+Qwen撖寞<E69296><EFBFBD>撩靚<E692A9><E99D9A>蝒?
- **<EFBFBD><EFBFBD>蝏𤘪<EFBFBD>**嚗?*<2A><EFBFBD>銵冽聢**嚗峕遬蝷箸<E89DB7><EFBFBD><E89D8F>蝑吔<E89D91>撘箄<E69298>蝏𤘪<E89D8F>
**关键区别**
- **审核工作台**双行表格显示DS+Qwen对比强调冲突
- **初筛结果****单行表格**,显示最终决策,强调结果
---
## <EFBFBD><20><EFBFBD><E49C98><EFBFBD>蝡臬<E89DA1><E887AC>?
## 🔧 四、后端开发
### 4.1 新增统计API
@@ -238,7 +238,7 @@ GET /api/v1/asl/projects/:projectId/statistics
#### 请求参数
```
<EFBFBD>?
```
#### 响应格式
@@ -253,9 +253,9 @@ GET /api/v1/asl/projects/:projectId/statistics
"conflict": 24,
"reviewed": 175,
"exclusionReasons": {
"P銝滚龪<EFBFBD><EFBFBD>鈭箇黎嚗?: 40,
"I<EFBFBD><EFBFBD><EFBFBD>?: 25,
"S銝滚龪<EFBFBD><EFBFBD><EFBFBD>𠉛弦霈曇恣嚗?: 15,
"P不匹配(人群)": 40,
"I不匹配干预": 25,
"S不匹配(研究设计)": 15,
"其他原因": 10
},
"includedRate": "42.7",
@@ -270,7 +270,7 @@ GET /api/v1/asl/projects/:projectId/statistics
// backend/src/modules/asl/controllers/screeningController.ts
/**
* <EFBFBD><EFBFBD>憿寧𤌍蝑偦<EFBFBD><EFBFBD>霈⊥㺭<EFBFBD><EFBFBD>鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡒊垢<EFBFBD>𡁜<EFBFBD>嚗?
* 获取项目筛选统计数据(云原生:后端聚合)
* GET /api/v1/asl/projects/:projectId/statistics
*/
export async function getProjectStatistics(
@@ -290,7 +290,7 @@ export async function getProjectStatistics(
return reply.status(404).send({ error: 'Project not found' });
}
// 2. 潃?鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>雿輻鍂Prisma<6D>𡁜<EFBFBD><F0A1819C>亥砭嚗<E7A0AD>僎銵䕘<E98AB5>
// 2. ⭐ 云原生使用Prisma聚合查询并行
const [
total,
includedCount,
@@ -367,13 +367,13 @@ export async function getProjectStatistics(
}
/**
* <EFBFBD>𨭌<EFBFBD>賣㺭嚗帋<EFBFBD>AI<EFBFBD>斗鱏銝剜<EFBFBD><EFBFBD>𡝗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
* 辅助函数从AI判断中提取排除原因
*/
function extractAutoReason(result: any): string {
if (result.dsPJudgment === 'mismatch') return 'P銝滚龪<EFBFBD><EFBFBD>鈭箇黎嚗?;
if (result.dsIJudgment === 'mismatch') return 'I銝滚龪<EFBFBD><EFBFBD><EFBFBD>?;
if (result.dsCJudgment === 'mismatch') return 'C銝滚龪<EFBFBD><EFBFBD>撖寧<EFBFBD>嚗?;
if (result.dsSJudgment === 'mismatch') return 'S銝滚龪<EFBFBD><EFBFBD><EFBFBD>𠉛?;
if (result.dsPJudgment === 'mismatch') return 'P不匹配(人群)';
if (result.dsIJudgment === 'mismatch') return 'I不匹配干预';
if (result.dsCJudgment === 'mismatch') return 'C不匹配(对照)';
if (result.dsSJudgment === 'mismatch') return 'S不匹配研究设计';
return '其他原因';
}
```
@@ -382,7 +382,7 @@ function extractAutoReason(result: any): string {
```typescript
// backend/src/modules/asl/routes/index.ts
// 瘛餃<EFBFBD><EFBFBD>啗楝<EFBFBD>望釣<EFBFBD>?
// 添加到路由注册
fastify.get(
'/projects/:projectId/statistics',
screeningController.getProjectStatistics
@@ -391,9 +391,9 @@ fastify.get(
---
## <EFBFBD>凃 鈭𢛵<E988AD><F0A29BB5><EFBFBD>蝡臬<E89DA1><E887AC>?
## 💻 五、前端开发
### 5.1 API<EFBFBD>蝡?
### 5.1 API客户端
```typescript
// frontend-v2/src/modules/asl/api/index.ts
@@ -440,7 +440,7 @@ import { ScreeningResult } from '../types';
/**
* 导出筛选结果到Excel云原生前端生成零文件落盘
*
* @param results 蝑偦<EFBFBD><EFBFBD><EFBFBD>𨀣㺭蝏?
* @param results 筛选结果数组
* @param options 导出选项
*/
export function exportScreeningResults(
@@ -455,25 +455,25 @@ export function exportScreeningResults(
'序号': idx + 1,
'文献标题': r.literature.title,
'摘要': r.literature.abstract || '',
'雿𡏭<EFBFBD>?: r.literature.authors || '',
'作者': r.literature.authors || '',
'期刊': r.literature.journal || '',
'发表年份': r.literature.publicationYear || '',
'PMID': r.literature.pmid || '',
'DOI': r.literature.doi || '',
'DeepSeek决策': r.dsConclusion || '',
'DeepSeek蝵桐縑摨?: r.dsConfidence ? `${(r.dsConfidence * 100).toFixed(0)}%` : '',
'DeepSeek置信度': r.dsConfidence ? `${(r.dsConfidence * 100).toFixed(0)}%` : '',
'DeepSeek理由': r.dsReason || '',
'Qwen决策': r.qwenConclusion || '',
'Qwen蝵桐縑摨?: r.qwenConfidence ? `${(r.qwenConfidence * 100).toFixed(0)}%` : '',
'Qwen置信度': r.qwenConfidence ? `${(r.qwenConfidence * 100).toFixed(0)}%` : '',
'Qwen理由': r.qwenReason || '',
'<EFBFBD><EFBFBD><EFBFBD>': r.conflictStatus === 'conflict' ? '<EFBFBD>? : '<EFBFBD>?,
'<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝑?: r.finalDecision || '<EFBFBD><EFBFBD>',
'是否冲突': r.conflictStatus === 'conflict' ? '是' : '否',
'最终决策': r.finalDecision || '待定',
'排除原因': r.exclusionReason || '',
'憭齿瓲鈭?: r.finalDecisionBy || '',
'复核人': r.finalDecisionBy || '',
'复核时间': r.finalDecisionAt ? new Date(r.finalDecisionAt).toLocaleString('zh-CN') : '',
}));
// 2. 潃?<3F><><EFBFBD>Excel嚗<6C><E59A97><EFBFBD>典銁<E585B8><E98A81><EFBFBD>銝哨<E98A9D><E593A8><EFBFBD>隞嗉氜<E59789><EFBFBD>
// 2. ⭐ 生成Excel完全在内存中零文件落盘
const ws = XLSX.utils.json_to_sheet(exportData);
// 设置列宽
@@ -481,33 +481,33 @@ export function exportScreeningResults(
{ wch: 6 }, // 序号
{ wch: 50 }, // 标题
{ wch: 60 }, // 摘要
{ wch: 30 }, // 雿𡏭<E99BBF>?
{ wch: 30 }, // 作者
{ wch: 30 }, // 期刊
{ wch: 10 }, // 年份
{ wch: 12 }, // PMID
{ wch: 25 }, // DOI
{ wch: 12 }, // DS决策
{ wch: 12 }, // DS蝵桐縑摨?
{ wch: 12 }, // DS置信度
{ wch: 40 }, // DS理由
{ wch: 12 }, // Qwen决策
{ wch: 12 }, // Qwen蝵桐縑摨?
{ wch: 12 }, // Qwen置信度
{ wch: 40 }, // Qwen理由
{ wch: 10 }, // 冲突
{ wch: 12 }, // <20><><EFBFBD><E89D8F>蝑?
{ wch: 12 }, // 最终决策
{ wch: 30 }, // 排除原因
{ wch: 15 }, // 憭齿瓲鈭?
{ wch: 15 }, // 复核人
{ wch: 20 }, // 复核时间
];
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, '<EFBFBD><EFBFBD><EFBFBD>?);
XLSX.utils.book_append_sheet(wb, ws, '筛选结果');
// 3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
// 3. 生成文件名
const timestamp = new Date().toISOString().slice(0, 10);
const filterSuffix = options.filter && options.filter !== 'all' ? `_${options.filter}` : '';
const filename = `${options.projectName || '<EFBFBD><EFBFBD><EFBFBD>?}${filterSuffix}_${timestamp}.xlsx`;
const filename = `${options.projectName || '筛选结果'}${filterSuffix}_${timestamp}.xlsx`;
// 4. 潃?閫血<E996AB>瘚讛<E7989A><E8AE9B><EFBFBD>頧踝<E9A0A7><E8B89D><EFBFBD>隞嗉氜<E59789><EFBFBD>
// 4. ⭐ 触发浏览器下载(零文件落盘)
XLSX.writeFile(wb, filename);
}
```
@@ -541,7 +541,7 @@ const ScreeningResults = () => {
const page = parseInt(searchParams.get('page') || '1', 10);
const pageSize = 20;
// 1. 潃?<3F><EFBFBD>蝏蠘恣<E8A098>唳旿嚗<E697BF><E59A97><EFBFBD><EFBFBD>嚗𡁜<E59A97>蝡航<E89DA1><E888AA><EFBFBD><EFBFBD>
// 1. ⭐ 获取统计数据(云原生:后端聚合)
const { data: statsData, isLoading: statsLoading } = useQuery({
queryKey: ['projectStatistics', projectId],
queryFn: () => aslApi.getProjectStatistics(projectId!),
@@ -562,7 +562,7 @@ const ScreeningResults = () => {
enabled: !!projectId,
});
// 3. 潃?撖澆枂Excel嚗<6C><E59A97>蝡舐<E89DA1><E88890><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>
// 3. ⭐ 导出Excel前端生成云原生
const handleExport = async (filter: string = 'all') => {
try {
message.loading('正在生成Excel...', 0);
@@ -579,7 +579,7 @@ const ScreeningResults = () => {
return;
}
// 潃?<3F>滨垢<E6BBA8><E59EA2><EFBFBD>Excel嚗<6C><EFBFBD><E5A69F><EFBFBD><EFBFBD>嚗?
// ⭐ 前端生成Excel零文件落盘
exportScreeningResults(data.items, {
filter,
projectName: `项目${projectId!.slice(0, 8)}`,
@@ -593,7 +593,7 @@ const ScreeningResults = () => {
}
};
// 4. <EFBFBD><EFBFBD>撖澆枂<EFBFBD>劐葉憿?
// 4. 批量导出选中项
const handleExportSelected = () => {
if (selectedRowKeys.length === 0) {
message.warning('请先选择要导出的记录');
@@ -611,8 +611,8 @@ const ScreeningResults = () => {
message.success(`成功导出 ${selectedResults.length} 条记录`);
};
// 銵冽聢<EFBFBD><EFBFBD>銋剹<EFBFBD><EFBFBD>ab<EFBFBD>滨蔭蝑?..
// <EFBFBD><EFBFBD><EFBFBD>港誨<EFBFBD><EFBFBD><EFBFBD>摰鮋<EFBFBD>摰䂿緵嚗?
// 表格列定义、Tab配置等...
// (完整代码见实际实现)
};
export default ScreeningResults;
@@ -620,177 +620,177 @@ export default ScreeningResults;
---
## <EFBFBD><EFBFBD> <20><EFBFBD><E58786><EFBFBD><EFBFBD>睲遙<E79DB2><EFBFBD>閫?
## 📅 六、开发任务分解
### Phase 1嚗𡁜<EFBFBD>蝡舐<EFBFBD>PI嚗㇄ay 16銝𠰴<E98A9D>嚗争𪃸儭?2撠𤩺𧒄
### Phase 1后端统计APIDay 16上午 2小时
**隞餃𦛚**嚗?
1. <EFBFBD>?`screeningController.ts` 銝剖<EFBFBD><EFBFBD>?`getProjectStatistics`
**任务**
1. `screeningController.ts` 中实现 `getProjectStatistics`
2. 使用Prisma聚合查询并行查询优化
3. 实现排除原因提取逻辑 `extractAutoReason`
4. <EFBFBD>?`routes/index.ts` 銝剜釣<EFBFBD>諹楝<EFBFBD>?
4. `routes/index.ts` 中注册路由
5. Postman测试API
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?API餈𥪜<EFBFBD><EFBFBD>蝏蠘恣<EFBFBD>唳旿
- <EFBFBD>?<3F><EFBFBD><E689AF>臬末嚗?500ms嚗?
- <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983><EFBFBD><E7AC94><EFBFBD><E8BEB7>𡒊垢<F0A1928A>𡁜<EFBFBD>嚗?
**验收标准**
- API返回正确统计数据
- ✅ 性能良好(<500ms
- ✅ 符合云原生原则(后端聚合)
**<EFBFBD><EFBFBD>辣皜<EFBFBD><EFBFBD>**嚗?
**文件清单**
- `backend/src/modules/asl/controllers/screeningController.ts`
- `backend/src/modules/asl/routes/index.ts`
---
### Phase 2嚗𡁜<EFBFBD>蝡涉PI摰<EFBFBD>蝡荔<EFBFBD>Day 16銝𠰴<E98A9D>嚗争𪃸儭?30<33><30><EFBFBD>
### Phase 2前端API客户端Day 16上午 30分钟
**隞餃𦛚**嚗?
1. <EFBFBD>?`api/index.ts` 銝剜溶<EFBFBD>?`getProjectStatistics`
2. <EFBFBD>?`types/index.ts` 銝剜溶<EFBFBD>?`ProjectStatistics` 蝐餃<EFBFBD>
**任务**
1. `api/index.ts` 中添加 `getProjectStatistics`
2. `types/index.ts` 中添加 `ProjectStatistics` 类型
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?API<EFBFBD>鍂甇<EFBFBD>
- <EFBFBD>?TypeScript蝐餃<EFBFBD><EFBFBD>
**验收标准**
- API调用正常
- TypeScript类型正确
**<EFBFBD><EFBFBD>辣皜<EFBFBD><EFBFBD>**嚗?
**文件清单**
- `frontend-v2/src/modules/asl/api/index.ts`
- `frontend-v2/src/modules/asl/types/index.ts`
---
### Phase 3嚗𡁶<EFBFBD>霈⊥<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Day 16銝𠰴<E98A9D>嚗争𪃸儭?1.5撠𤩺𧒄
### Phase 3统计概览卡片Day 16上午 1.5小时
**隞餃𦛚**嚗?
1. 摰䂿緵蝏蠘恣<EFBFBD><EFBFBD><EFBFBD>辣嚗?銝芸㨃<E88AB8><E3A883><EFBFBD>
2. 摰䂿緵"敺<><E695BA><EFBFBD>?<3F>鞟內Alert
3. 摰䂿緵PRISMA<EFBFBD>㘾膄蝏蠘恣嚗<EFBFBD><EFBFBD><EFBFBD>嗅㦛嚗?
**任务**
1. 实现统计卡片组件4个卡片
2. 实现"待复核"提示Alert
3. 实现PRISMA排除统计(柱状图)
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?蝏蠘恣<E8A098>唳旿甇<E697BF><EFBFBD>曄內
- <EFBFBD>?<3F>㘾膄<E398BE><EFBFBD><E7AC94>梁𠶖<E6A281><EFBFBD><E69AB9>?
- <EFBFBD>?"敺<><E695BA><EFBFBD>?<3F>鞟內<E99E9F>垍𤌍
**验收标准**
- ✅ 统计数据正确显示
- ✅ 排除原因柱状图清晰
- ✅ "待复核"提示醒目
**<EFBFBD><EFBFBD>辣皜<EFBFBD><EFBFBD>**嚗?
**文件清单**
- `frontend-v2/src/modules/asl/pages/ScreeningResults.tsx`
---
### Phase 4嚗𡁶<EFBFBD><EFBFBD>𨅯<EFBFBD>銵汽ab嚗㇄ay 16銝见<E98A9D>嚗争𪃸儭?3撠𤩺𧒄
### Phase 4结果列表TabDay 16下午 3小时
**隞餃𦛚**嚗?
1. 摰䂿緵Tab<EFBFBD><EFBFBD>揢嚗<EFBFBD><EFBFBD><EFBFBD>?撌脩熙<E884A9>?撌脫<E6928C><E884AB>?敺<><E695BA><EFBFBD><EFBFBD>
**任务**
1. 实现Tab切换全部/已纳入/已排除/待复核)
2. 创建单行表格(区别于审核工作台)
3. 摰䂿緵Checkbox憭𡁻<EFBFBD>?
4. 摰䂿緵霂行<EFBFBD><EFBFBD><EFBFBD>Modal嚗<EFBFBD><EFBFBD><EFBFBD>典恣<EFBFBD>詨極雿𨅯蝱<EFBFBD><EFBFBD>rawer嚗?
3. 实现Checkbox多选
4. 实现详情查看Modal复用审核工作台的Drawer
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?Tab<EFBFBD><EFBFBD>揢甇<EFBFBD>
- <EFBFBD>?銵冽聢<E586BD>唳旿甇<E697BF>
- <EFBFBD>?<3F><EFBFBD><E887AC><EFBFBD>
- <EFBFBD>?<3F>舀䰻<E88880>贝祕<E8B49D>?
**验收标准**
- Tab切换正常
- ✅ 表格数据正确
- ✅ 可多选行
- ✅ 可查看详情
**<EFBFBD><EFBFBD>辣皜<EFBFBD><EFBFBD>**嚗?
**文件清单**
- `frontend-v2/src/modules/asl/pages/ScreeningResults.tsx`
---
### Phase 5嚗鍃xcel撖澆枂嚗㇄ay 17銝𠰴<E98A9D>嚗争𪃸儭?2撠𤩺𧒄
### Phase 5Excel导出Day 17上午 2小时
**隞餃𦛚**嚗?
**任务**
1. 创建 `excelExport.ts` 工具文件
2. 摰䂿緵<EFBFBD>滨垢撖澆枂<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?`xlsx`嚗?
3. 瘛餃<EFBFBD>撖澆枂<EFBFBD>厰僼嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?撖澆枂敶枏<E695B6>憿?撖澆枂<E6BE86>劐葉憿對<E686BF>
4. <EFBFBD><EFBFBD><EFBFBD>誘撖澆枂嚗<EFBFBD><EFBFBD><EFBFBD>?隞<><EFBFBD>?隞<><E99A9E><EFBFBD><EFBFBD>
2. 实现前端导出逻辑(使用 `xlsx`
3. 添加导出按钮(导出全部/导出当前页/导出选中项)
4. 支持过滤导出(全部/仅纳入/仅排除)
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?<3F>臬紡<E887AC>xcel
- <EFBFBD>?<3F>唳旿摰峕㟲
- <EFBFBD>?<3F><EFBFBD>隞嗉氜<E59789><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>
- <EFBFBD>?<3F><><EFBFBD><EFBFBD>笔漲<3蝘𡜐<E89D98><1000<EFBFBD><EFBFBD>
**验收标准**
- ✅ 可导出Excel
- ✅ 数据完整
- ✅ 零文件落盘(云原生)
- ✅ 生成速度<3秒<1000条)
**<EFBFBD><EFBFBD>辣皜<EFBFBD><EFBFBD>**嚗?
**文件清单**
- `frontend-v2/src/modules/asl/utils/excelExport.ts`
- `frontend-v2/src/modules/asl/pages/ScreeningResults.tsx`
---
### Phase 6嚗𡁻<EFBFBD><EFBFBD><EFBFBD>霂蓥<EFBFBD>隡睃<EFBFBD>嚗㇄ay 17銝见<EFBFBD>-Day 18嚗争𪃸儭?4撠𤩺𧒄
### Phase 6集成测试与优化Day 17下午-Day 18)⏱️ 4小时
**隞餃𦛚**嚗?
1. 摰峕㟲瘚<EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD><EFBFBD>隡罱<EFBFBD>蝑偦<EFBFBD><EFBFBD>憭齿瓲<EFBFBD>埝䰻<EFBFBD><EFBFBD><EFBFBD><EFBFBD>撖澆枂嚗?
**任务**
1. 完整流程测试(上传→筛选→复核→查看结果→导出)
2. 异常场景测试(无数据、网络错误)
3. UI/UX优化加载状态、错误提示
4. <EFBFBD><EFBFBD>瘚贝<EFBFBD><EFBFBD><EFBFBD>PI<EFBFBD><EFBFBD>xcel撖澆枂嚗?
5. 鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
4. 性能测试统计API、Excel导出
5. 云原生规范检查
**撉峕𤣰<EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>?瘚<><E7989A>摰峕㟲<E5B395>𣳇獈憛?
- <EFBFBD>?撘<>虜憭<E8999C><E686AD><EFBFBD><E691B0>
- <EFBFBD>?<3F><EFBFBD>颲暹<E9A2B2>
- <EFBFBD>?蝚血<E89D9A>鈭穃<E988AD><E7A983><EFBFBD><E8A098>?
**验收标准**
- ✅ 流程完整无阻塞
- ✅ 异常处理完善
- ✅ 性能达标
- ✅ 符合云原生规范
---
## <EFBFBD>?銝<><E98A9D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E59786>?
## ✅ 七、验收标准
### 7.1 功能验收
- [<EFBFBD><EFBFBD> 蝏蠘恣璁<E681A3><E79281><EFBFBD><EFBFBD><EFBFBD><EFBFBD>曄內嚗<E585A7><E59A97>餅㺭<E9A485><E3BAAD><EFBFBD><EFBFBD><E4B993><EFBFBD><EFBFBD><EFBFBD><E6898E><EFBFBD>憭齿瓲嚗?
- [<EFBFBD><EFBFBD> <20>㘾膄<E398BE><EFBFBD>蝏蠘恣<E8A098><E681A3><EFBC86><E59A97><EFBFBD>嗅㦛嚗?
- [<EFBFBD><EFBFBD><><E695BA><EFBFBD><EFBFBD>蝷粹<E89DB7><E7B2B9>?
- [<EFBFBD><EFBFBD> Tab<EFBFBD><EFBFBD>揢甇<EFBFBD>虜嚗<EFBFBD><EFBFBD><EFBFBD>?撌脩熙<E884A9>?撌脫<E6928C><E884AB>?敺<><E695BA><EFBFBD><EFBFBD>
- [✅] 统计概览卡片正确显示(总数、纳入、排除、待复核)
- [✅] 排除原因统计准确(柱状图)
- [✅] 待复核提示醒目
- [✅] Tab切换正常(全部/已纳入/已排除/待复核)
- [✅] 表格数据正确(单行表格)
- [<EFBFBD><EFBFBD> Checkbox憭𡁻<EFBFBD>㗇迤撣?
- [<EFBFBD><EFBFBD> <20>舀䰻<E88880>贝祕<E8B49D>?
- [<EFBFBD><EFBFBD> <20>臬紡<E887AC>慟xcel嚗<6C><E59A97><EFBFBD>?<3F>劐葉嚗?
- [✅] Checkbox多选正常
- [✅] 可查看详情
- [✅] 可导出Excel全部/选中)
- [✅] Excel数据完整
### 7.2 性能验收
- [✅] 统计API响应时间 <500ms
- [<EFBFBD><EFBFBD> Excel撖澆枂嚗?1000<30><EFBFBD><3蝘?
- [✅] Excel导出(<1000条<3秒
- [✅] 表格分页加载正常
### 7.3 鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
### 7.3 云原生验收
<EFBFBD><EFBFBD>[鈭穃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𤏸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>騟(../../../04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md)嚗?
基于[云原生开发规范检查清单](../../../04-开发规范/08-云原生开发规范.md)
**<EFBFBD>𡒊垢API**嚗?
- [<5B><> 雿輻鍂<E8BCBB><EFBFBD> `prisma` 摰硺<E691B0><EFBFBD><E59A97>new PrismaClient嚗?
**后端API**
- [✅] 使用全局 `prisma` 实例(不new PrismaClient
- [✅] 统计使用Prisma聚合查询不查全量数据
- [<5B><> <20>䭾𧋦<E4ADBE><EFBFBD>隞嗅<E99A9E><E59785><EFBFBD><E58981>s.writeFile嚗?
- [<5B><> 雿輻鍂 `logger` 霈啣<E99C88><E595A3><EFBFBD><EFBFBD><E59A97><EFBFBD>onsole.log嚗?
- [✅] 无本地文件存储无fs.writeFile
- [✅] 使用 `logger` 记录日志不用console.log
- [✅] 统一错误处理
**<EFBFBD>滨垢摰䂿緵**嚗?
- [<5B><> Excel<65>滨垢<E6BBA8><E59EA2><EFBFBD><EFBFBD><EFBFBD><E5A69F><EFBFBD><EFBFBD>嚗?
- [<5B><> 雿輻鍂 `xlsx` 摨橒<E691A8><E6A992><EFBFBD>蝔喳<E89D94>嚗?
- [<5B><> <20>见末<E8A781><E69CAB><EFBFBD><EFBFBD>蝷?
**前端实现**
- [✅] Excel前端生成零文件落盘
- [✅] 使用 `xlsx` 库(成熟稳定)
- [✅] 友好的用户提示
---
## <EFBFBD><EFBFBD> <20><EFBFBD><E68092>𧒄<EFBFBD>港摯蝞?
## 📊 八、时间估算
| <EFBFBD>嗆挾 | 隞餃𦛚 | 憸<><EFBFBD>埈𧒄 | 韐蠘提鈭?|
| 阶段 | 任务 | 预计耗时 | 负责人 |
|------|------|---------|--------|
| Phase 1 | <EFBFBD>𡒊垢蝏蠘恣API | 2撠𤩺𧒄 | <20>𡒊垢撘<E59EA2><E69298>?|
| Phase 2 | <EFBFBD>滨垢API摰<EFBFBD>蝡?| 0.5撠𤩺𧒄 | <20>滨垢撘<E59EA2><E69298>?|
| Phase 3 | 蝏蠘恣璁<EFBFBD><EFBFBD> | 1.5撠𤩺𧒄 | <20>滨垢撘<E59EA2><E69298>?|
| Phase 4 | 蝏𤘪<EFBFBD><EFBFBD>𡑒”Tab | 3撠𤩺𧒄 | <20>滨垢撘<E59EA2><E69298>?|
| Phase 5 | Excel撖澆枂 | 2撠𤩺𧒄 | <20>滨垢撘<E59EA2><E69298>?|
| Phase 6 | <EFBFBD><EFBFBD><EFBFBD>瘚贝<EFBFBD> | 4撠𤩺𧒄 | <20><EFBFBD><EFBFBD><E69298>?|
| **<EFBFBD>餉恣** | | **13撠𤩺𧒄** | **蝥?憭?* |
| Phase 1 | 后端统计API | 2小时 | 后端开发 |
| Phase 2 | 前端API客户端 | 0.5小时 | 前端开发 |
| Phase 3 | 统计概览 | 1.5小时 | 前端开发 |
| Phase 4 | 结果列表Tab | 3小时 | 前端开发 |
| Phase 5 | Excel导出 | 2小时 | 前端开发 |
| Phase 6 | 集成测试 | 4小时 | 全栈开发 |
| **总计** | | **13小时** | **约2天** |
---
## <EFBFBD><EFBFBD> 銋腈<E98A8B><E88588><EFBFBD><EFBFBD>獢?
## 🔗 九、相关文档
- [鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8><EFBFBD>(../../../04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md) - <EFBFBD>
- [云原生开发规范](../../../04-开发规范/08-云原生开发规范.md) - 必读
- [任务分解](./03-任务分解.md) - Week 4任务清单
- [<EFBFBD>敶枏<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(../00-璅<E79285>敶枏<E695B6><E69E8F><EFBFBD><E59786><EFBFBD><EFBFBD><E69298><EFBFBD><E78390>?md) - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
- [模块当前状态](../00-模块当前状态与开发指南.md) - 模块真实状态
- [技术债务清单](../06-技术债务/技术债务清单.md) - Excel后端导出方案
- [<EFBFBD>唳旿摨栞挽霈(../02-<2D><><EFBFBD>航挽霈?01-<2D>唳旿摨栞挽霈?md) - <EFBFBD>唳旿銵函<EFBFBD><EFBFBD>?
- [API霈曇恣閫<EFBFBD><EFBFBD>](../02-<EFBFBD><EFBFBD><EFBFBD>航挽霈?02-API霈曇恣閫<E681A3><E996AB>.md) - API<EFBFBD><EFBFBD>
- [数据库设计](../02-技术设计/01-数据库设计.md) - 数据表结构
- [API设计规范](../02-技术设计/02-API设计规范.md) - API规范
---
@@ -798,45 +798,45 @@ export default ScreeningResults;
### 债务1Excel后端导出优化
**閫血<EFBFBD><EFBFBD>∩辣**嚗?
- <EFBFBD>閙活撖澆枂<EFBFBD>唳旿<EFBFBD>?>5000<EFBFBD>?
- <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>xcel<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Sheet<EFBFBD><EFBFBD>㦛銵函<EFBFBD>嚗?
**触发条件**
- 单次导出数据量 >5000
- 需要复杂Excel格式多Sheet、图表等
- 用户反馈前端导出卡顿
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗?
- <EFBFBD>𡒊垢<EFBFBD><EFBFBD><EFBFBD>Excel嚗<EFBFBD><EFBFBD>?`ExcelJS`嚗?
- 銝𠹺<EFBFBD><EFBFBD>記SS嚗<EFBFBD><EFBFBD>?`storage.upload()`嚗?
**解决方案**
- 后端生成Excel使用 `ExcelJS`
- 上传到OSS使用 `storage.upload()`
- 返回下载URL
**霈啣<EFBFBD>雿滨蔭**嚗靀<E59A97><E99D80><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C> - 隡睃<E99AA1>蝥?](../06-<EFBFBD><EFBFBD><EFBFBD><EFBFBD>箏𦛚/<2F><><EFBFBD><EFBFBD>箏𦛚皜<F0A69B9A><E79A9C>.md)
**记录位置**[技术债务清单 - 优先级4](../06-技术债务/技术债务清单.md)
**<EFBFBD><EFBFBD>埈𧒄**嚗?-2憭?
**预计耗时**1-2天
---
## <EFBFBD><20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>穃遣霈?
## 💡 十一、开发建议
### 撖孵<EFBFBD><EFBFBD>睲犖<EFBFBD>?
### 对开发人员
1. **<EFBFBD><EFBFBD><EFBFBD>霂颱<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗靀鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8><EFBFBD>(../../../04-撘<><E69298>𤏸<EFBFBD><F0A48FB8>?08-鈭穃<E988AD><E7A983><EFBFBD><E7AC94>𤏸<EFBFBD><F0A48FB8>?md)
1. **先阅读云原生规范**[云原生开发规范](../../../04-开发规范/08-云原生开发规范.md)
2. **复用平台能力**:使用全局`prisma``logger`
3. **避免文件落盘**Excel前端生成
4. **<EFBFBD>𡒊垢<EFBFBD>𡁜<EFBFBD>霈∠<EFBFBD>**嚗𡁶<E59A97>霈⊥㺭<E28AA5><EFBFBD>蝡臬<E89DA1><E887AC>?
4. **后端聚合计算**:统计数据后端完成
5. **性能优化**Prisma聚合查询使用并行
### 对AI助手
1. **隡睃<EFBFBD>鈭穃<EFBFBD><EFBFBD>?*嚗𡁏<E59A97><F0A1818F>㕑挽霈∩<E99C88><E288A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鈭穃<E988AD><E7A983><EFBFBD><EFBFBD>?
2. **<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>劐誨<EFBFBD>?*嚗𡁜<E59A97><F0A1819C>典恣<E585B8>詨極雿𨅯蝱<F0A885AF><E89DB1><EFBFBD>隞?
3. **瘜冽<EFBFBD><EFBFBD><EFBFBD>**嚗𡁜<E59A97>蝑𤤿<E89D91><F0A4A4BF>𨀣糓<F0A880A3><EFBFBD>銵冽聢嚗<E881A2><EFBFBD>詨極雿𨅯蝱<F0A885AF><EFBFBD>銵諹”<E8ABB9>?
4. **瘚贝<EFBFBD><EFBFBD><EFBFBD><EFBFBD>**嚗𡁜<E59A97><F0A1819C><EFBFBD>蝔𧢲<E89D94>霂?
1. **优先云原生**:所有设计优先考虑云原生架构
2. **参考现有代码**:复用审核工作台的组件
3. **注意区别**:初筛结果是单行表格,审核工作台是双行表格
4. **测试充分**:完整流程测试
---
**<EFBFBD><EFBFBD>﹝蝏湔擪<EFBFBD>?*嚗鋫I<E98BAB><EFBFBD><E7AE84><EFBFBD>讃撘<E8AE83><E69298>穃𣪧<E7A983>?
**<EFBFBD><EFBFBD><EFBFBD>擧凒<EFBFBD>?*嚗?025-11-21
**<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?*嚗尠<E59A97> 撌脩霈歹<E99C88><E6ADB9><EFBFBD>憪见<E686AA><E8A781>?
**<EFBFBD>憪𧢲𧒄<EFBFBD>?*嚗𡁜<E59A97>摰?
**文档维护者**AI智能文献开发团队
**最后更新**2025-11-21
**文档状态**:✅ 已确认,可开始开发
**开始时间**:待定