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,43 +1,43 @@
|
||||
# ASL模块 - Week 2 Day 2 完成报告
|
||||
|
||||
**日期**: 2025-11-19
|
||||
**任务**: 文献导入é¡?+ Excel模æ<C2A1>¿ä¸‹è½½
|
||||
**状æ€?*: âœ?100% 完æˆ<C3A6>
|
||||
**任务**: 文献导入页 + Excel模板下载
|
||||
**状态**: ✅ 100% 完成
|
||||
|
||||
---
|
||||
|
||||
## 📋 今日目标回顾
|
||||
|
||||
æ ¹æ<EFBFBD>®Week 2å¼€å<E282AC>‘计划,Day 2的主è¦<C3A8>ç›®æ ‡æ˜¯ï¼?
|
||||
1. âœ?Excel模æ<EFBFBD>¿ç”Ÿæˆ<EFBFBD>与下è½?
|
||||
2. âœ?Excelä¸Šä¼ ä¸Žå†…å˜è§£æž?
|
||||
3. âœ?å—æ®µéªŒè¯<C3A8>与去é‡?
|
||||
4. âœ?æ–‡çŒ®é¢„è§ˆè¡¨æ ¼
|
||||
5. âœ?完整æ<C2B4><C3A6>交æµ<C3A6>程(创建项ç›?导入文献ï¼?
|
||||
根据Week 2开发计划,Day 2的主要目标是:
|
||||
1. ✅ Excel模板生成与下载
|
||||
2. ✅ Excel上传与内存解析
|
||||
3. ✅ 字段验证与去重
|
||||
4. ✅ 文献预览表格
|
||||
5. ✅ 完整提交流程(创建项目+导入文献)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 核心成果
|
||||
|
||||
### 1. Excel工具函数模å<EFBFBD>— â<C3A2>â<C3A2>â<C3A2>â<C3A2>â?
|
||||
### 1. Excel工具函数模块 ⭐⭐⭐⭐⭐
|
||||
|
||||
**文件**: `frontend-v2/src/modules/asl/utils/excelUtils.ts`
|
||||
|
||||
**包含功能**:
|
||||
- âœ?`downloadExcelTemplate()` - 生æˆ<EFBFBD>并下载Excel模æ<EFBFBD>¿
|
||||
- âœ?`parseExcelFile()` - 内å˜è§£æž<EFBFBD>Excel文件
|
||||
- âœ?`validateLiterature()` - 验è¯<EFBFBD>å<EFBFBD>•æ<EFBFBD>¡æ–‡çŒ®
|
||||
- âœ?`validateLiteratures()` - 批é‡<EFBFBD>验è¯<EFBFBD>文献
|
||||
- âœ?`deduplicateLiteratures()` - 去é‡<EFBFBD>逻辑(DOI + Titleï¼?
|
||||
- âœ?`processExcelFile()` - 完整处ç<EFBFBD>†æµ<EFBFBD>程
|
||||
- ✅ `downloadExcelTemplate()` - 生成并下载Excel模板
|
||||
- ✅ `parseExcelFile()` - 内存解析Excel文件
|
||||
- ✅ `validateLiterature()` - 验证单条文献
|
||||
- ✅ `validateLiteratures()` - 批量验证文献
|
||||
- ✅ `deduplicateLiteratures()` - 去重逻辑(DOI + Title)
|
||||
- ✅ `processExcelFile()` - 完整处理流程
|
||||
|
||||
**技术亮�*:
|
||||
**技术亮点**:
|
||||
```typescript
|
||||
// 内å˜è§£æž<EFBFBD>,ä¸<EFBFBD>è<EFBFBD>½ç›˜ï¼ˆäº‘原生è¦<EFBFBD>求ï¼?
|
||||
// 内存解析,不落盘(云原生要求)
|
||||
const buffer = await data.toBuffer();
|
||||
const workbook = XLSX.read(buffer, { type: 'array' });
|
||||
|
||||
// 智能去é‡<EFBFBD>(优先DOI,其次Titleï¼?
|
||||
// 智能去重(优先DOI,其次Title)
|
||||
if (lit.doi && lit.doi.trim() !== '') {
|
||||
key = `doi:${lit.doi.toLowerCase().trim()}`;
|
||||
} else {
|
||||
@@ -47,34 +47,34 @@ if (lit.doi && lit.doi.trim() !== '') {
|
||||
|
||||
---
|
||||
|
||||
### 2. 完善çš?设置与å<C5BD>¯åŠ?页é<C2B5>¢ â<C3A2>â<C3A2>â<C3A2>â<C3A2>â?
|
||||
### 2. 完善的"设置与启动"页面 ⭐⭐⭐⭐⭐
|
||||
|
||||
**文件**: `frontend-v2/src/modules/asl/pages/TitleScreeningSettings.tsx`
|
||||
|
||||
**完整功能流程**:
|
||||
```
|
||||
用户填写PICOS标准
|
||||
�
|
||||
↓
|
||||
上传Excel文件
|
||||
�
|
||||
↓
|
||||
前端内存解析 + 验证 + 去重
|
||||
�
|
||||
↓
|
||||
显示预览表格 + 统计信息
|
||||
�
|
||||
↓
|
||||
点击"开始AI初筛"
|
||||
�
|
||||
创建项目 â†?导入文献 â†?跳转工作å<C593>?
|
||||
↓
|
||||
创建项目 → 导入文献 → 跳转工作台
|
||||
```
|
||||
|
||||
**UI组件**:
|
||||
- âœ?Excel Draggerä¸Šä¼ ç»„ä»¶
|
||||
- âœ?Excel模æ<EFBFBD>¿ä¸‹è½½æŒ‰é’®
|
||||
- âœ?è§£æž<C3A6>统计信æ<C2A1>¯å<C2AF>¡ç‰‡ï¼?个Statistic组件ï¼?
|
||||
- âœ?æ–‡çŒ®é¢„è§ˆè¡¨æ ¼ï¼ˆåˆ†é¡µã€<C3A3>Tooltipã€<C3A3>çœ<C3A7>略)
|
||||
- âœ?错误信æ<C2A1>¯Alert
|
||||
- âœ?å<>¯åŠ¨æŒ‰é’®ï¼ˆå¸¦loading状æ€<C3A6>)
|
||||
- ✅ Excel Dragger上传组件
|
||||
- ✅ Excel模板下载按钮
|
||||
- ✅ 解析统计信息卡片(4个Statistic组件)
|
||||
- ✅ 文献预览表格(分页、Tooltip、省略)
|
||||
- ✅ 错误信息Alert
|
||||
- ✅ 启动按钮(带loading状态)
|
||||
|
||||
**状æ€<EFBFBD>管ç<EFBFBD>?*:
|
||||
**状态管理**:
|
||||
```typescript
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
const [literatures, setLiteratures] = useState<LiteratureData[]>([]);
|
||||
@@ -86,13 +86,13 @@ const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
---
|
||||
|
||||
### 3. API接å<EFBFBD>£ä¼˜åŒ– â<C3A2>â<C3A2>â?
|
||||
### 3. API接口优化 ⭐⭐⭐
|
||||
|
||||
**文件**: `frontend-v2/src/modules/asl/api/index.ts`
|
||||
|
||||
**修改内容**:
|
||||
- âœ?修改`importLiteratures`ç¾å<EFBFBD><EFBFBD>,接å<EFBFBD>—`{projectId, literatures}`对象
|
||||
- �导出统一的`aslApi`对象,便于组件引�
|
||||
- ✅ 修改`importLiteratures`签名,接受`{projectId, literatures}`对象
|
||||
- ✅ 导出统一的`aslApi`对象,便于组件引用
|
||||
|
||||
**使用示例**:
|
||||
```typescript
|
||||
@@ -110,19 +110,19 @@ await aslApi.importLiteratures({
|
||||
|
||||
---
|
||||
|
||||
## 🔧 技术实现细�
|
||||
## 🔧 技术实现细节
|
||||
|
||||
### 1. Excel模板生成
|
||||
|
||||
**包å<EFBFBD>«ä¸¤ä¸ªå·¥ä½œè¡?*:
|
||||
**包含两个工作表**:
|
||||
1. **文献列表**:
|
||||
- 3行示例数æ<EFBFBD>?
|
||||
- 7列(Title, Abstract, PMID, Authors, Journal, Year, DOI�
|
||||
- 3行示例数据
|
||||
- 7列(Title, Abstract, PMID, Authors, Journal, Year, DOI)
|
||||
- 自动设置列宽
|
||||
|
||||
2. **字段说明**:
|
||||
- æ¯<EFBFBD>ä¸ªå—æ®µçš„说æ˜?
|
||||
- å¿…å¡«/å<>¯é€‰æ ‡è®?
|
||||
- 每个字段的说明
|
||||
- 必填/可选标记
|
||||
- 使用建议
|
||||
|
||||
**代码片段**:
|
||||
@@ -140,14 +140,14 @@ XLSX.writeFile(wb, '文献导入模板.xlsx');
|
||||
|
||||
---
|
||||
|
||||
### 2. 内å˜è§£æž<EFBFBD>(云原生ï¼?
|
||||
### 2. 内存解析(云原生)
|
||||
|
||||
**é<EFBFBD>µå¾ªäº‘原生开å<EFBFBD>‘è§„èŒ?*:
|
||||
- âœ?使用`FileReader.readAsArrayBuffer()`读å<EFBFBD>–文件
|
||||
- âœ?使用`XLSX.read(buffer, { type: 'array' })`内å˜è§£æž<EFBFBD>
|
||||
- âœ?**ä¸<C3A4>è<EFBFBD>½ç›?*,直接在内å˜ä¸å¤„ç<E2809E>?
|
||||
**遵循云原生开发规范**:
|
||||
- ✅ 使用`FileReader.readAsArrayBuffer()`读取文件
|
||||
- ✅ 使用`XLSX.read(buffer, { type: 'array' })`内存解析
|
||||
- ✅ **不落盘**,直接在内存中处理
|
||||
|
||||
**å—æ®µæ˜ 射(支æŒ<EFBFBD>ä¸è‹±æ–‡ï¼?*:
|
||||
**字段映射(支持中英文)**:
|
||||
```typescript
|
||||
title: row.Title || row.title || row['标题'] || ''
|
||||
abstract: row.Abstract || row.abstract || row['摘要'] || ''
|
||||
@@ -160,14 +160,14 @@ pmid: row.PMID || row.pmid || row['PMID编号'] || ''
|
||||
### 3. 数据验证
|
||||
|
||||
**验证规则**:
|
||||
- `title`: 必填,至å°?0个å—ç¬?
|
||||
- `abstract`: 必填,至å°?0个å—ç¬?
|
||||
- å…¶ä»–å—æ®µ: å<>¯é€?
|
||||
- `title`: 必填,至少10个字符
|
||||
- `abstract`: 必填,至少50个字符
|
||||
- 其他字段: 可选
|
||||
|
||||
**错误提示**:
|
||||
```typescript
|
||||
if (!lit.title || lit.title.length < 10) {
|
||||
errors.push('æ ‡é¢˜å¤ªçŸï¼ˆè‡³å°?0个å—符)');
|
||||
errors.push('标题太短(至少10个字符)');
|
||||
}
|
||||
```
|
||||
|
||||
@@ -176,10 +176,10 @@ if (!lit.title || lit.title.length < 10) {
|
||||
### 4. 智能去重
|
||||
|
||||
**去重策略**:
|
||||
1. **优先çº?**: DOI(如果å˜åœ¨ï¼‰
|
||||
1. **优先级1**: DOI(如果存在)
|
||||
- 标准化:转小写、去空格
|
||||
2. **优先�**: Title
|
||||
- æ ‡å‡†åŒ–ï¼šè½¬å°<EFBFBD>写ã€<EFBFBD>去除所有空白å—ç¬?
|
||||
2. **优先级2**: Title
|
||||
- 标准化:转小写、去除所有空白字符
|
||||
|
||||
**代码逻辑**:
|
||||
```typescript
|
||||
@@ -207,13 +207,13 @@ for (const lit of literatures) {
|
||||
|
||||
### 5. 文献预览表格
|
||||
|
||||
**功能特�*:
|
||||
- âœ?分页显示ï¼?0æ<30>?页)
|
||||
- âœ?æ ‡é¢˜å’Œæ‘˜è¦<C3A8>è¶…é•¿çœ<C3A7>略(Tooltip显示全文ï¼?
|
||||
- âœ?å“<C3A5>应å¼<C3A5>布局(scroll xï¼?
|
||||
- âœ?åº<C3A5>å<EFBFBD>·è‡ªåŠ¨è®¡ç®—
|
||||
**功能特性**:
|
||||
- ✅ 分页显示(50条/页)
|
||||
- ✅ 标题和摘要超长省略(Tooltip显示全文)
|
||||
- ✅ 响应式布局(scroll x)
|
||||
- ✅ 序号自动计算
|
||||
|
||||
**列定�*:
|
||||
**列定义**:
|
||||
```typescript
|
||||
const columns = [
|
||||
{ title: '#', width: 60, render: (_, __, index) => index + 1 },
|
||||
@@ -221,7 +221,7 @@ const columns = [
|
||||
{ title: '摘要', width: '30%', ellipsis: true, render: truncate },
|
||||
{ title: 'PMID', width: 100 },
|
||||
{ title: '年份', width: 80 },
|
||||
{ title: '作�, ellipsis: true },
|
||||
{ title: '作者', ellipsis: true },
|
||||
];
|
||||
```
|
||||
|
||||
@@ -229,7 +229,7 @@ const columns = [
|
||||
|
||||
### 6. 统计信息展示
|
||||
|
||||
**4个统计指æ ?*:
|
||||
**4个统计指标**:
|
||||
```tsx
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
@@ -253,63 +253,63 @@ const columns = [
|
||||
|
||||
```
|
||||
[用户进入页面]
|
||||
�
|
||||
[填写PICOS表å<EFBFBD>•] â†?必填(P, I, C, S, 纳入, 排除ï¼?
|
||||
�
|
||||
[选择ç›é€‰é£Žæ ¼] â†?Radio(lenient/standard/strictï¼?
|
||||
�
|
||||
[点击"下载Excel模æ<C2A1>¿"] â†?å<>¯é€?
|
||||
â†?下载包å<E280A6>«ç¤ºä¾‹çš„Excel模æ<C2A1>¿
|
||||
�
|
||||
[ä¸Šä¼ Excel文件] â†?Dragger组件
|
||||
�
|
||||
[å‰<EFBFBD>端自动解æž<EFBFBD>] â†?xlsx.read()
|
||||
�
|
||||
├─ å—æ®µæ˜ 射(ä¸è‹±æ–‡å…¼å®¹ï¼?
|
||||
├─ æ•°æ<C2B0>®éªŒè¯<C3A8>(title + abstractå¿…å¡«ï¼?
|
||||
└─ 去é‡<C3A9>逻辑(DOI â†?Titleï¼?
|
||||
�
|
||||
[显示统计信æ<EFBFBD>¯] â†?4个Statisticå<EFBFBD>¡ç‰‡
|
||||
├─ 总数: 100�
|
||||
├─ 有效: 95篇(绿色�
|
||||
├─ é‡<C3A9>å¤<C3A5>: 3篇(橙色ï¼?
|
||||
└─ æ— æ•ˆ: 2篇(红色ï¼?
|
||||
�
|
||||
[æ˜¾ç¤ºæ–‡çŒ®é¢„è§ˆè¡¨æ ¼] â†?Table + Pagination
|
||||
�
|
||||
↓
|
||||
[填写PICOS表单] ← 必填(P, I, C, S, 纳入, 排除)
|
||||
↓
|
||||
[选择筛选风格] ← Radio(lenient/standard/strict)
|
||||
↓
|
||||
[点击"下载Excel模板"] ← 可选
|
||||
↓ 下载包含示例的Excel模板
|
||||
↓
|
||||
[上传Excel文件] ← Dragger组件
|
||||
↓
|
||||
[前端自动解析] ← xlsx.read()
|
||||
↓
|
||||
├─ 字段映射(中英文兼容)
|
||||
├─ 数据验证(title + abstract必填)
|
||||
└─ 去重逻辑(DOI → Title)
|
||||
↓
|
||||
[显示统计信息] ← 4个Statistic卡片
|
||||
├─ 总数: 100篇
|
||||
├─ 有效: 95篇(绿色)
|
||||
├─ 重复: 3篇(橙色)
|
||||
└─ 无效: 2篇(红色)
|
||||
↓
|
||||
[显示文献预览表格] ← Table + Pagination
|
||||
↓
|
||||
[用户确认无误]
|
||||
�
|
||||
[点击"开始AIåˆ<C3A5>ç›"] â†?Button(disabled如果未完æˆ<EFBFBD>)
|
||||
�
|
||||
↓
|
||||
[点击"开始AI初筛"] ← Button(disabled如果未完成)
|
||||
↓
|
||||
[Loading: "正在创建项目..."]
|
||||
�
|
||||
[API: createProject()] �获得projectId
|
||||
�
|
||||
↓
|
||||
[API: createProject()] ← 获得projectId
|
||||
↓
|
||||
[Loading: "正在导入文献..."]
|
||||
�
|
||||
↓
|
||||
[API: importLiteratures({ projectId, literatures })]
|
||||
�
|
||||
[Success: "项目创建æˆ<EFBFBD>功ï¼?]
|
||||
�
|
||||
[自动跳转] �/literature/screening/title/workbench
|
||||
↓
|
||||
[Success: "项目创建成功!"]
|
||||
↓
|
||||
[自动跳转] → /literature/screening/title/workbench
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI/UX亮点
|
||||
|
||||
### 1. å<EFBFBD>‹å¥½çš„错误æ<EFBFBD><EFBFBD>ç¤?
|
||||
### 1. 友好的错误提示
|
||||
|
||||
**分层提示**:
|
||||
- âœ?文件解æž<C3A6>错误 â†?红色Message
|
||||
- âœ?æ•°æ<C2B0>®éªŒè¯<C3A8>失败 â†?橙色Alert(显示å‰<C3A5>5æ<35>¡é”™è¯¯ï¼‰
|
||||
- âœ?é‡<C3A9>å¤<C3A5>æ•°æ<C2B0>® â†?è“<C3A8>色Info Message
|
||||
- âœ?æ— æ•ˆæ•°æ<C2B0>® â†?橙色Warning Message
|
||||
- ✅ 文件解析错误 → 红色Message
|
||||
- ✅ 数据验证失败 → 橙色Alert(显示前5条错误)
|
||||
- ✅ 重复数据 → 蓝色Info Message
|
||||
- ✅ 无效数据 → 橙色Warning Message
|
||||
|
||||
**示例**:
|
||||
```typescript
|
||||
if (statistics.invalid > 0) {
|
||||
message.warning(`æœ?${statistics.invalid} æ<EFBFBD>¡æ•°æ<EFBFBD>®éªŒè¯<EFBFBD>失败,已自动过滤`, 3);
|
||||
message.warning(`有 ${statistics.invalid} 条数据验证失败,已自动过滤`, 3);
|
||||
}
|
||||
if (statistics.duplicates > 0) {
|
||||
message.info(`检测到 ${statistics.duplicates} 条重复数据,已自动去重`, 3);
|
||||
@@ -318,14 +318,14 @@ if (statistics.duplicates > 0) {
|
||||
|
||||
---
|
||||
|
||||
### 2. 优雅的Loading状�
|
||||
### 2. 优雅的Loading状态
|
||||
|
||||
**三种Loading**:
|
||||
1. **è§£æž<EFBFBD>ä¸?*: `message.loading('æ£åœ¨è§£æž<EFBFBD>Excel文件...')`
|
||||
1. **解析中**: `message.loading('正在解析Excel文件...')`
|
||||
2. **创建项目**: `message.loading('正在创建项目...')`
|
||||
3. **导入文献**: `message.loading('正在导入文献...')`
|
||||
|
||||
**Button状�*:
|
||||
**Button状态**:
|
||||
```tsx
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -333,29 +333,29 @@ if (statistics.duplicates > 0) {
|
||||
loading={isSubmitting}
|
||||
disabled={!canStart}
|
||||
>
|
||||
{isSubmitting ? 'æ£åœ¨åˆ›å»ºé¡¹ç›®å¹¶å¯¼å…¥æ–‡çŒ?..' : '开始AIæ ‡é¢˜æ‘˜è¦<C3A8>åˆ<C3A5>ç›'}
|
||||
{isSubmitting ? '正在创建项目并导入文献...' : '开始AI标题摘要初筛'}
|
||||
</Button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. æ¸<EFBFBD>è¿›å¼<EFBFBD>å<EFBFBD>¯ç”?
|
||||
### 3. 渐进式启用
|
||||
|
||||
**å<EFBFBD>¯åŠ¨æŒ‰é’®æ¿€æ´»æ<EFBFBD>¡ä»?*:
|
||||
**启动按钮激活条件**:
|
||||
```typescript
|
||||
setCanStart(formValid && valid.length > 0);
|
||||
```
|
||||
|
||||
- â<EFBFBD>?表å<C2A8>•未填å†?â†?按钮ç¦<C3A7>用
|
||||
- â<EFBFBD>?文献未导å…?â†?按钮ç¦<C3A7>用
|
||||
- âœ?表å<C2A8>•+文献都完æˆ?â†?按钮å<C2AE>¯ç”¨
|
||||
- ❌ 表单未填写 → 按钮禁用
|
||||
- ❌ 文献未导入 → 按钮禁用
|
||||
- ✅ 表单+文献都完成 → 按钮启用
|
||||
|
||||
**提示信息**:
|
||||
```tsx
|
||||
{!canStart && literatures.length === 0 && (
|
||||
<Alert
|
||||
message="请先完成以上步骤"
|
||||
description="填写PICOSæ ‡å‡†ã€<EFBFBD>纳å…?æŽ’é™¤æ ‡å‡†ï¼Œå¹¶å¯¼å…¥æ–‡çŒ®å<C2AE>Žï¼Œå<C592>³å<C2B3>¯å¼€å§‹ç›é€?
|
||||
description="填写PICOS标准、纳入/排除标准,并导入文献后,即可开始筛选"
|
||||
type="warning"
|
||||
/>
|
||||
)}
|
||||
@@ -363,25 +363,25 @@ setCanStart(formValid && valid.length > 0);
|
||||
|
||||
---
|
||||
|
||||
## 📦 新增/修改的文�
|
||||
## 📦 新增/修改的文件
|
||||
|
||||
### 新增文件 �
|
||||
### 新增文件 ✅
|
||||
|
||||
1. **`frontend-v2/src/modules/asl/utils/excelUtils.ts`**
|
||||
- 366行代ç ?
|
||||
- 完整的Excel处ç<EFBFBD>†å·¥å…·åº?
|
||||
- 366行代码
|
||||
- 完整的Excel处理工具库
|
||||
|
||||
### 修改文件 �
|
||||
### 修改文件 ✅
|
||||
|
||||
1. **`frontend-v2/src/modules/asl/pages/TitleScreeningSettings.tsx`**
|
||||
- 从å<EFBFBD> ä½<EFBFBD>页é<EFBFBD>?â†?完整功能页é<C2B5>¢
|
||||
- 新增597行代ç ?
|
||||
- 从占位页面 → 完整功能页面
|
||||
- 新增597行代码
|
||||
|
||||
2. **`frontend-v2/src/modules/asl/api/index.ts`**
|
||||
- 修改`importLiteratures`函数签名
|
||||
- 新增`aslApi`统一导出对象
|
||||
|
||||
### ä¾<EFBFBD>赖安装 âœ?
|
||||
### 依赖安装 ✅
|
||||
|
||||
```bash
|
||||
npm install xlsx
|
||||
@@ -390,33 +390,33 @@ npm install xlsx
|
||||
|
||||
---
|
||||
|
||||
## âœ?完æˆ<C3A6>æ ‡å‡†éªŒè¯<C3A8>
|
||||
## ✅ 完成标准验证
|
||||
|
||||
### 功能完整��
|
||||
### 功能完整性 ✅
|
||||
|
||||
- [x] Excel模板下载功能
|
||||
- [x] Excelä¸Šä¼ ä¸Žè§£æž<EFBFBD>(内å˜ï¼Œä¸<EFBFBD>è<EFBFBD>½ç›˜ï¼?
|
||||
- [x] å—æ®µéªŒè¯<EFBFBD>(title + abstractå¿…å¡«ï¼?
|
||||
- [x] 去é‡<EFBFBD>逻辑(DOI + Titleï¼?
|
||||
- [x] Excel上传与解析(内存,不落盘)
|
||||
- [x] 字段验证(title + abstract必填)
|
||||
- [x] 去重逻辑(DOI + Title)
|
||||
- [x] 文献预览表格
|
||||
- [x] 统计信息展示
|
||||
- [x] "开始AI初筛"按钮可用
|
||||
- [x] 一次性创建项�导入文献
|
||||
- [x] 一次性创建项目+导入文献
|
||||
|
||||
### 代ç <EFBFBD>è´¨é‡<EFBFBD> âœ?
|
||||
### 代码质量 ✅
|
||||
|
||||
- [x] 无TypeScript类型错误
|
||||
- [x] 无ESLint警告
|
||||
- [x] 符å<EFBFBD>ˆReact最佳实è·?
|
||||
- [x] 完整的错误处ç<EFBFBD>?
|
||||
- [x] å<EFBFBD>‹å¥½çš„用户æ<EFBFBD><EFBFBD>ç¤?
|
||||
- [x] 符合React最佳实践
|
||||
- [x] 完整的错误处理
|
||||
- [x] 友好的用户提示
|
||||
|
||||
### 云原生è¦<EFBFBD>æ±?âœ?
|
||||
### 云原生要求 ✅
|
||||
|
||||
- [x] 内å˜è§£æž<EFBFBD>Excel(ä¸<EFBFBD>è<EFBFBD>½ç›˜ï¼?
|
||||
- [x] 内存解析Excel(不落盘)
|
||||
- [x] 使用环境变量配置
|
||||
- [x] æ— å<EFBFBD>Œæ¥é˜»å¡žæ“<EFBFBD>ä½?
|
||||
- [x] 完整的异æ¥å¤„ç<EFBFBD>?
|
||||
- [x] 无同步阻塞操作
|
||||
- [x] 完整的异步处理
|
||||
|
||||
---
|
||||
|
||||
@@ -425,18 +425,18 @@ npm install xlsx
|
||||
### 测试场景
|
||||
|
||||
1. **正常流程**:
|
||||
- 下载模æ<EFBFBD>¿ â†?填写数æ<C2B0>® â†?ä¸Šä¼ â†?预览 â†?å<>¯åЍ
|
||||
- 下载模板 → 填写数据 → 上传 → 预览 → 启动
|
||||
|
||||
2. **异常场景**:
|
||||
- ä¸Šä¼ ç©ºæ–‡ä»?
|
||||
- 上传空文件
|
||||
- 上传非Excel文件
|
||||
- 必填字段缺失
|
||||
- 数据格式错误
|
||||
- 重复数据处理
|
||||
|
||||
3. **边界场景**:
|
||||
- 1篇文�
|
||||
- 500+篇文�
|
||||
- 1篇文献
|
||||
- 500+篇文献
|
||||
- 中文列名
|
||||
- 英文列名
|
||||
- 混合列名
|
||||
@@ -449,21 +449,21 @@ npm install xlsx
|
||||
|
||||
```
|
||||
点击"下载Excel模板"按钮
|
||||
â†?自动下载"文献导入模æ<C2A1>¿.xlsx"
|
||||
â†?包å<E280A6>«2个工作表ï¼?
|
||||
├─ 文献列表(带示例�
|
||||
→ 自动下载"文献导入模板.xlsx"
|
||||
→ 包含2个工作表:
|
||||
├─ 文献列表(带示例)
|
||||
└─ 字段说明
|
||||
```
|
||||
|
||||
### 2. 填写数据
|
||||
|
||||
**必填字段**:
|
||||
- `Title`: æ–‡çŒ®æ ‡é¢˜ï¼ˆè‡³å°?0å—符ï¼?
|
||||
- `Abstract`: 文献摘è¦<EFBFBD>(至å°?0å—符ï¼?
|
||||
- `Title`: 文献标题(至少10字符)
|
||||
- `Abstract`: 文献摘要(至少50字符)
|
||||
|
||||
**å<EFBFBD>¯é€‰å—æ®?*:
|
||||
**可选字段**:
|
||||
- `PMID`: PubMed ID
|
||||
- `Authors`: 作者列�
|
||||
- `Authors`: 作者列表
|
||||
- `Journal`: 期刊名称
|
||||
- `Year`: 发表年份
|
||||
- `DOI`: DOI编号(用于去重)
|
||||
@@ -471,83 +471,83 @@ npm install xlsx
|
||||
### 3. 上传解析
|
||||
|
||||
```
|
||||
点击或拖拽Excelæ–‡ä»¶åˆ°ä¸Šä¼ åŒºåŸ?
|
||||
â†?自动解æž<C3A6>ï¼?-5秒)
|
||||
â†?显示统计信æ<C2A1>¯å’Œé¢„览表æ ?
|
||||
â†?如有错误,显示详细æ<E280A0><C3A6>ç¤?
|
||||
点击或拖拽Excel文件到上传区域
|
||||
→ 自动解析(2-5秒)
|
||||
→ 显示统计信息和预览表格
|
||||
→ 如有错误,显示详细提示
|
||||
```
|
||||
|
||||
### 4. å<EFBFBD>¯åЍç›é€?
|
||||
### 4. 启动筛选
|
||||
|
||||
```
|
||||
确认数æ<EFBFBD>®æ— 误å<EFBFBD>?
|
||||
â†?点击"开始AIæ ‡é¢˜æ‘˜è¦<C3A8>åˆ<C3A5>ç›"
|
||||
�自动创建项目
|
||||
�导入所有文�
|
||||
â†?è·³è½¬åˆ°å®¡æ ¸å·¥ä½œå<C593>°
|
||||
确认数据无误后
|
||||
→ 点击"开始AI标题摘要初筛"
|
||||
→ 自动创建项目
|
||||
→ 导入所有文献
|
||||
→ 跳转到审核工作台
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一æ¥è®¡åˆ?
|
||||
## 🚀 下一步计划
|
||||
|
||||
### Week 2 Day 3-4(明天开始)
|
||||
|
||||
**主è¦<EFBFBD>任务**: å®¡æ ¸å·¥ä½œå<C593>°ï¼ˆå<CB86>Œè¡Œè¡¨æ ¼ï¼?
|
||||
**主要任务**: 审核工作台(双行表格)
|
||||
|
||||
**预计实现**:
|
||||
1. å<EFBFBD>Œè¡Œè¡¨æ ¼UI(主è¡?+ 展开行)
|
||||
2. 两个模型的判æ–结果对æ¯?
|
||||
1. 双行表格UI(主行 + 展开行)
|
||||
2. 两个模型的判断结果对比
|
||||
3. 冲突高亮显示
|
||||
4. PICO判断详情
|
||||
5. 双视图原文审查Modal
|
||||
6. 人工复核功能
|
||||
|
||||
**å<EFBFBD>‚考原åž?*: `docs/03-业务模å<C2A1>—/ASL-AI智能文献/03-UI设计/AI智能文献-æ ‡é¢˜æ‘˜è¦<C3A8>åˆ<C3A5>ç›åŽŸåž‹.html`
|
||||
**参考原型**: `docs/03-业务模块/ASL-AI智能文献/03-UI设计/AI智能文献-标题摘要初筛原型.html`
|
||||
|
||||
---
|
||||
|
||||
## 💡 经验总结
|
||||
|
||||
### 技术亮ç‚?â?
|
||||
### 技术亮点 ⭐
|
||||
|
||||
1. **内存解析**:完全符合云原生要求,无文件落盘
|
||||
2. **智能去é‡<EFBFBD>**:DOI优先çº?+ Title兜底,实用性强
|
||||
3. **æ¸<EFBFBD>è¿›å¼<EFBFBD>交äº?*:表å<C2A8>•验è¯?+ 文献导入 â†?å<>¯ç”¨æŒ‰é’®
|
||||
4. **完整错误处ç<EFBFBD>†**:分层æ<E2809A><C3A6>示,用户体验å¥?
|
||||
2. **智能去重**:DOI优先级 + Title兜底,实用性强
|
||||
3. **渐进式交互**:表单验证 + 文献导入 → 启用按钮
|
||||
4. **完整错误处理**:分层提示,用户体验好
|
||||
|
||||
### 改进空间
|
||||
|
||||
1. **大文件优åŒ?*:目å‰<C3A5>未é™<C3A9>制文件大å°<C3A5>,å<C592>¯è€ƒè™‘æ·»åŠ
|
||||
2. **è§£æž<EFBFBD>进度æ<EFBFBD>?*:对于超大文件,å<C592>¯æ˜¾ç¤ºè§£æž<C3A6>è¿›åº?
|
||||
3. **Excelæ ¼å¼<EFBFBD>检æŸ?*:å<C5A1>¯æ<C2AF><C3A6>å‰<C3A5>检查列å<E28094><C3A5>是å<C2AF>¦åŒ¹é…?
|
||||
4. **批é‡<EFBFBD>æ“<EFBFBD>作**ï¼šè¡¨æ ¼å<C2BC>¯æ”¯æŒ<C3A6>批é‡<C3A9>åˆ é™¤æ— æ•ˆè¡?
|
||||
1. **大文件优化**:目前未限制文件大小,可考虑添加
|
||||
2. **解析进度条**:对于超大文件,可显示解析进度
|
||||
3. **Excel格式检查**:可提前检查列名是否匹配
|
||||
4. **批量操作**:表格可支持批量删除无效行
|
||||
|
||||
---
|
||||
|
||||
## 📊 å¼€å<E282AC>‘统è®?
|
||||
## 📊 开发统计
|
||||
|
||||
| æŒ‡æ ‡ | æ•°å€?|
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| **新增代ç <EFBFBD>** | ~1,000è¡?|
|
||||
| **新增文件** | 1�|
|
||||
| **修改文件** | 2�|
|
||||
| **新增ä¾<EFBFBD>èµ–** | 1个(xlsxï¼?|
|
||||
| **功能�* | 6�|
|
||||
| **å¼€å<EFBFBD>‘æ—¶é—?* | çº?å°<C3A5>æ—¶ |
|
||||
| **完æˆ<EFBFBD>åº?* | 100% âœ?|
|
||||
| **新增代码** | ~1,000行 |
|
||||
| **新增文件** | 1个 |
|
||||
| **修改文件** | 2个 |
|
||||
| **新增依赖** | 1个(xlsx) |
|
||||
| **功能点** | 6个 |
|
||||
| **开发时间** | 约2小时 |
|
||||
| **完成度** | 100% ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Day 2 完成总结
|
||||
|
||||
âœ?**Excel模æ<EFBFBD>¿ç”Ÿæˆ<EFBFBD>与下è½?* - 完美实现
|
||||
âœ?**Excelä¸Šä¼ ä¸Žè§£æž?* - 内å˜å¤„ç<E2809E>†ï¼Œäº‘原生
|
||||
âœ?**æ•°æ<C2B0>®éªŒè¯<C3A8>与去é‡?* - 智能去é‡<C3A9>,完整验è¯?
|
||||
âœ?**æ–‡çŒ®é¢„è§ˆè¡¨æ ¼** - å<EFBFBD>‹å¥½å±•示,分页支æŒ?
|
||||
âœ?**完整æ<C2B4><C3A6>交æµ<C3A6>程** - 一键å<EFBFBD>¯åŠ¨ï¼Œè‡ªåŠ¨è·³è½¬
|
||||
✅ **Excel模板生成与下载** - 完美实现
|
||||
✅ **Excel上传与解析** - 内存处理,云原生
|
||||
✅ **数据验证与去重** - 智能去重,完整验证
|
||||
✅ **文献预览表格** - 友好展示,分页支持
|
||||
✅ **完整提交流程** - 一键启动,自动跳转
|
||||
|
||||
**Day 2任务 100% 完æˆ<C3A6>ï¼?* 🎊
|
||||
**Day 2任务 100% 完成!** 🎊
|
||||
|
||||
**明天继续Week 2 Day 3-4开发!** 💪
|
||||
|
||||
|
||||
Reference in New Issue
Block a user