文件夹整理
This commit is contained in:
@@ -1,922 +0,0 @@
|
||||
# 员工导入结果跨页面持久化实施计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**目标:** 实现员工导入结果的跨页面持久化,使用户在切换菜单后仍能查看上一次的导入失败记录
|
||||
|
||||
**架构:** 使用浏览器localStorage存储最近一次导入的任务信息,在页面加载时恢复状态,实现导入状态的持久化保存
|
||||
|
||||
**技术栈:**
|
||||
- Vue 2.6.12
|
||||
- localStorage API
|
||||
- Element UI 2.15.14
|
||||
|
||||
---
|
||||
|
||||
## 前置准备
|
||||
|
||||
### Task 0: 验证环境
|
||||
|
||||
**Files:**
|
||||
- 检查: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 阅读现有代码**
|
||||
|
||||
读取 `ruoyi-ui/src/views/ccdiEmployee/index.vue` 文件,特别关注:
|
||||
- `data()` 中的 `showFailureButton`、`currentTaskId`、`pollingTimer` 等状态变量
|
||||
- `handleFileSuccess()` 方法 - 导入上传成功处理
|
||||
- `handleImportComplete()` 方法 - 导入完成处理
|
||||
- `getFailureList()` 方法 - 查询失败记录
|
||||
- `created()` 和 `beforeDestroy()` 生命周期钩子
|
||||
|
||||
确认当前实现确实存在状态丢失问题。
|
||||
|
||||
**Step 2: 理解localStorage使用场景**
|
||||
|
||||
理解需要持久化的数据:
|
||||
```javascript
|
||||
{
|
||||
taskId: 'uuid',
|
||||
status: 'SUCCESS' | 'PARTIAL_SUCCESS' | 'FAILED',
|
||||
timestamp: 1707225900000,
|
||||
saveTime: 1707225900000,
|
||||
hasFailures: true,
|
||||
totalCount: 100,
|
||||
successCount: 95,
|
||||
failureCount: 5
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 无需提交**
|
||||
|
||||
这只是验证步骤,无需提交代码。
|
||||
|
||||
---
|
||||
|
||||
## 核心功能实现
|
||||
|
||||
### Task 1: 新增localStorage工具方法
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiEmployee/index.vue` (在 methods 对象中添加)
|
||||
|
||||
**Step 1: 添加 saveImportTaskToStorage 方法**
|
||||
|
||||
在 `methods` 对象中添加以下方法(放在 `methods` 的开头部分):
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 保存导入任务到localStorage
|
||||
* @param {Object} taskData - 任务数据
|
||||
*/
|
||||
saveImportTaskToStorage(taskData) {
|
||||
try {
|
||||
const data = {
|
||||
...taskData,
|
||||
saveTime: Date.now()
|
||||
};
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify(data));
|
||||
} catch (error) {
|
||||
console.error('保存导入任务状态失败:', error);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
**Step 2: 添加 getImportTaskFromStorage 方法**
|
||||
|
||||
在 `saveImportTaskToStorage` 方法后添加:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 从localStorage读取导入任务
|
||||
* @returns {Object|null} 任务数据或null
|
||||
*/
|
||||
getImportTaskFromStorage() {
|
||||
try {
|
||||
const data = localStorage.getItem('employee_import_last_task');
|
||||
if (!data) return null;
|
||||
|
||||
const task = JSON.parse(data);
|
||||
|
||||
// 数据格式校验
|
||||
if (!task || !task.taskId) {
|
||||
this.clearImportTaskFromStorage();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 时间戳校验
|
||||
if (task.saveTime && typeof task.saveTime !== 'number') {
|
||||
this.clearImportTaskFromStorage();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 过期检查(7天)
|
||||
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
||||
if (Date.now() - task.saveTime > sevenDays) {
|
||||
this.clearImportTaskFromStorage();
|
||||
return null;
|
||||
}
|
||||
|
||||
return task;
|
||||
} catch (error) {
|
||||
console.error('读取导入任务状态失败:', error);
|
||||
this.clearImportTaskFromStorage();
|
||||
return null;
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
**Step 3: 添加 clearImportTaskFromStorage 方法**
|
||||
|
||||
在 `getImportTaskFromStorage` 方法后添加:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 清除localStorage中的导入任务
|
||||
*/
|
||||
clearImportTaskFromStorage() {
|
||||
try {
|
||||
localStorage.removeItem('employee_import_last_task');
|
||||
} catch (error) {
|
||||
console.error('清除导入任务状态失败:', error);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
**Step 4: 手动测试 - 打开浏览器控制台验证**
|
||||
|
||||
1. 启动前端开发服务器: `npm run dev` (在 ruoyi-ui 目录)
|
||||
2. 打开浏览器,访问员工管理页面
|
||||
3. 打开浏览器开发者工具(F12),切换到 Console 标签
|
||||
4. 在控制台输入:
|
||||
```javascript
|
||||
// 测试保存
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify({
|
||||
taskId: 'test-123',
|
||||
status: 'SUCCESS',
|
||||
timestamp: Date.now(),
|
||||
saveTime: Date.now(),
|
||||
hasFailures: true,
|
||||
totalCount: 100,
|
||||
successCount: 95,
|
||||
failureCount: 5
|
||||
}))
|
||||
|
||||
// 测试读取
|
||||
JSON.parse(localStorage.getItem('employee_import_last_task'))
|
||||
|
||||
// 测试清除
|
||||
localStorage.removeItem('employee_import_last_task')
|
||||
```
|
||||
5. 确认每个操作都正常工作
|
||||
|
||||
**Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiEmployee/index.vue
|
||||
git commit -m "feat: 添加localStorage工具方法用于导入状态持久化
|
||||
|
||||
- saveImportTaskToStorage: 保存导入任务到localStorage
|
||||
- getImportTaskFromStorage: 读取并校验导入任务数据
|
||||
- clearImportTaskFromStorage: 清除localStorage数据
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 添加状态恢复和用户交互方法
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 添加 restoreImportState 方法**
|
||||
|
||||
在 `clearImportTaskFromStorage` 方法后添加:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 恢复导入状态
|
||||
* 在created()钩子中调用
|
||||
*/
|
||||
async restoreImportState() {
|
||||
const savedTask = this.getImportTaskFromStorage();
|
||||
|
||||
if (!savedTask) {
|
||||
this.showFailureButton = false;
|
||||
this.currentTaskId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果有失败记录,恢复按钮显示
|
||||
if (savedTask.hasFailures && savedTask.taskId) {
|
||||
this.currentTaskId = savedTask.taskId;
|
||||
this.showFailureButton = true;
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
**Step 2: 添加 getLastImportTooltip 方法**
|
||||
|
||||
在 `restoreImportState` 方法后添加:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 获取上次导入的提示信息
|
||||
* @returns {String} 提示文本
|
||||
*/
|
||||
getLastImportTooltip() {
|
||||
const savedTask = this.getImportTaskFromStorage();
|
||||
if (savedTask && savedTask.timestamp) {
|
||||
const date = new Date(savedTask.timestamp);
|
||||
const timeStr = this.parseTime(date, '{y}-{m}-{d} {h}:{i}');
|
||||
return `上次导入: ${timeStr}`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
```
|
||||
|
||||
**Step 3: 添加 clearImportHistory 方法**
|
||||
|
||||
在 `getLastImportTooltip` 方法后添加:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 清除导入历史记录
|
||||
* 用户手动触发
|
||||
*/
|
||||
clearImportHistory() {
|
||||
this.$confirm('确认清除上次导入记录?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.clearImportTaskFromStorage();
|
||||
this.showFailureButton = false;
|
||||
this.currentTaskId = null;
|
||||
this.failureDialogVisible = false;
|
||||
this.$message.success('已清除');
|
||||
}).catch(() => {});
|
||||
},
|
||||
```
|
||||
|
||||
**Step 4: 修改 created() 生命周期钩子**
|
||||
|
||||
找到 `created()` 方法,在 `this.getList();` 后添加:
|
||||
|
||||
```javascript
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDeptTree();
|
||||
this.restoreImportState(); // 新增:恢复导入状态
|
||||
},
|
||||
```
|
||||
|
||||
**Step 5: 手动测试 - 状态恢复功能**
|
||||
|
||||
1. 在浏览器控制台手动设置测试数据:
|
||||
```javascript
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify({
|
||||
taskId: 'test-restore-123',
|
||||
status: 'PARTIAL_SUCCESS',
|
||||
timestamp: Date.now(),
|
||||
saveTime: Date.now(),
|
||||
hasFailures: true,
|
||||
totalCount: 100,
|
||||
successCount: 95,
|
||||
failureCount: 5
|
||||
}))
|
||||
```
|
||||
2. 刷新员工管理页面
|
||||
3. 确认"查看上次导入失败记录"按钮显示出来
|
||||
4. 打开Vue DevTools(如果有的话),检查 `showFailureButton` 为 `true`, `currentTaskId` 为 `'test-restore-123'`
|
||||
|
||||
**Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiEmployee/index.vue
|
||||
git commit -m "feat: 添加导入状态恢复和用户交互方法
|
||||
|
||||
- restoreImportState: 从localStorage恢复导入状态
|
||||
- getLastImportTooltip: 获取导入时间提示信息
|
||||
- clearImportHistory: 用户手动清除历史记录
|
||||
- created(): 添加状态恢复调用
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 修改导入成功处理逻辑
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 修改 handleFileSuccess 方法**
|
||||
|
||||
找到 `handleFileSuccess` 方法,替换为:
|
||||
|
||||
```javascript
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
this.upload.isUploading = false;
|
||||
this.upload.open = false;
|
||||
|
||||
if (response.code === 200) {
|
||||
const taskId = response.data.taskId;
|
||||
|
||||
// 清除旧的导入记录(防止并发)
|
||||
if (this.pollingTimer) {
|
||||
clearInterval(this.pollingTimer);
|
||||
this.pollingTimer = null;
|
||||
}
|
||||
|
||||
this.clearImportTaskFromStorage();
|
||||
|
||||
// 保存新任务的初始状态
|
||||
this.saveImportTaskToStorage({
|
||||
taskId: taskId,
|
||||
status: 'PROCESSING',
|
||||
timestamp: Date.now(),
|
||||
hasFailures: false
|
||||
});
|
||||
|
||||
// 重置状态
|
||||
this.showFailureButton = false;
|
||||
this.currentTaskId = taskId;
|
||||
|
||||
// 显示后台处理提示
|
||||
this.$notify({
|
||||
title: '导入任务已提交',
|
||||
message: '正在后台处理中,处理完成后将通知您',
|
||||
type: 'info',
|
||||
duration: 3000
|
||||
});
|
||||
|
||||
// 开始轮询检查状态
|
||||
this.startImportStatusPolling(taskId);
|
||||
} else {
|
||||
this.$modal.msgError(response.msg);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
关键改动:
|
||||
- 添加清除旧轮询定时器的逻辑
|
||||
- 调用 `clearImportTaskFromStorage()` 清除旧数据
|
||||
- 调用 `saveImportTaskToStorage()` 保存新任务初始状态
|
||||
- 重置 `showFailureButton` 和 `currentTaskId`
|
||||
|
||||
**Step 2: 修改 handleImportComplete 方法**
|
||||
|
||||
找到 `handleImportComplete` 方法,替换为:
|
||||
|
||||
```javascript
|
||||
/** 处理导入完成 */
|
||||
handleImportComplete(statusResult) {
|
||||
const hasFailures = statusResult.failureCount > 0;
|
||||
|
||||
// 更新localStorage中的任务状态
|
||||
this.saveImportTaskToStorage({
|
||||
taskId: statusResult.taskId,
|
||||
status: statusResult.status,
|
||||
timestamp: Date.now(),
|
||||
hasFailures: hasFailures,
|
||||
totalCount: statusResult.totalCount,
|
||||
successCount: statusResult.successCount,
|
||||
failureCount: statusResult.failureCount
|
||||
});
|
||||
|
||||
if (statusResult.status === 'SUCCESS') {
|
||||
this.$notify({
|
||||
title: '导入完成',
|
||||
message: `全部成功!共导入${statusResult.totalCount}条数据`,
|
||||
type: 'success',
|
||||
duration: 5000
|
||||
});
|
||||
this.getList();
|
||||
} else if (hasFailures) {
|
||||
this.$notify({
|
||||
title: '导入完成',
|
||||
message: `成功${statusResult.successCount}条,失败${statusResult.failureCount}条`,
|
||||
type: 'warning',
|
||||
duration: 5000
|
||||
});
|
||||
|
||||
// 显示查看失败记录按钮
|
||||
this.showFailureButton = true;
|
||||
this.currentTaskId = statusResult.taskId;
|
||||
|
||||
// 刷新列表
|
||||
this.getList();
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
关键改动:
|
||||
- 在方法开头调用 `saveImportTaskToStorage()` 更新完整状态
|
||||
|
||||
**Step 3: 手动测试 - 导入流程**
|
||||
|
||||
1. 准备一个包含错误数据的Excel文件
|
||||
2. 打开浏览器开发者工具 > Application > Local Storage
|
||||
3. 上传Excel文件,开始导入
|
||||
4. 观察 Local Storage 中是否有 `employee_import_last_task` 键
|
||||
5. 等待导入完成
|
||||
6. 检查 localStorage 中的数据是否包含完整的统计信息(totalCount, successCount, failureCount)
|
||||
7. 刷新页面,确认按钮仍然显示
|
||||
|
||||
**Step 4: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiEmployee/index.vue
|
||||
git commit -m "feat: 修改导入处理逻辑以支持状态持久化
|
||||
|
||||
- handleFileSuccess: 清除旧数据,保存新任务初始状态
|
||||
- handleImportComplete: 更新localStorage中的完整任务状态
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 增强失败记录查询的错误处理
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 修改 getFailureList 方法**
|
||||
|
||||
找到 `getFailureList` 方法,替换为:
|
||||
|
||||
```javascript
|
||||
/** 查询失败记录列表 */
|
||||
getFailureList() {
|
||||
this.failureLoading = true;
|
||||
getImportFailures(
|
||||
this.currentTaskId,
|
||||
this.failureQueryParams.pageNum,
|
||||
this.failureQueryParams.pageSize
|
||||
).then(response => {
|
||||
this.failureList = response.rows;
|
||||
this.failureTotal = response.total;
|
||||
this.failureLoading = false;
|
||||
}).catch(error => {
|
||||
this.failureLoading = false;
|
||||
|
||||
// 处理不同类型的错误
|
||||
if (error.response) {
|
||||
const status = error.response.status;
|
||||
|
||||
if (status === 404) {
|
||||
// 记录不存在或已过期
|
||||
this.$modal.msgWarning('导入记录已过期,无法查看失败记录');
|
||||
this.clearImportTaskFromStorage();
|
||||
this.showFailureButton = false;
|
||||
this.currentTaskId = null;
|
||||
this.failureDialogVisible = false;
|
||||
} else if (status === 500) {
|
||||
this.$modal.msgError('服务器错误,请稍后重试');
|
||||
} else {
|
||||
this.$modal.msgError(`查询失败: ${error.response.data.msg || '未知错误'}`);
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 请求发送了但没有收到响应
|
||||
this.$modal.msgError('网络连接失败,请检查网络');
|
||||
} else {
|
||||
this.$modal.msgError('查询失败记录失败: ' + error.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
```
|
||||
|
||||
关键改动:
|
||||
- 添加详细的错误分类处理
|
||||
- 404错误时清除localStorage并隐藏按钮
|
||||
- 添加网络错误和服务器错误的友好提示
|
||||
|
||||
**Step 2: 手动测试 - 错误处理**
|
||||
|
||||
由于需要模拟后端404错误,这里提供两种测试方式:
|
||||
|
||||
**方式1: 修改localStorage时间戳模拟过期**
|
||||
```javascript
|
||||
// 在控制台执行
|
||||
const data = JSON.parse(localStorage.getItem('employee_import_last_task'));
|
||||
data.saveTime = Date.now() - (8 * 24 * 60 * 60 * 1000); // 8天前
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify(data));
|
||||
```
|
||||
然后刷新页面,虽然不会触发API 404,但可以验证localStorage的过期清除逻辑。
|
||||
|
||||
**方式2: 使用无效的taskId测试**
|
||||
```javascript
|
||||
// 在控制台执行
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify({
|
||||
taskId: 'invalid-task-id-12345',
|
||||
status: 'PARTIAL_SUCCESS',
|
||||
timestamp: Date.now(),
|
||||
saveTime: Date.now(),
|
||||
hasFailures: true,
|
||||
totalCount: 100,
|
||||
successCount: 95,
|
||||
failureCount: 5
|
||||
}));
|
||||
```
|
||||
刷新页面,点击"查看上次导入失败记录"按钮,应该会显示错误提示。
|
||||
|
||||
**Step 3: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiEmployee/index.vue
|
||||
git commit -m "feat: 增强失败记录查询的错误处理
|
||||
|
||||
- 添加404错误处理(记录过期)
|
||||
- 添加500错误和500错误的友好提示
|
||||
- 错误时自动清除localStorage并隐藏按钮
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 添加计算属性和模板优化
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 添加 computed 计算属性**
|
||||
|
||||
找到 `export default {` 中的 `data()` 方法,在 `data()` 后添加 `computed`:
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
/**
|
||||
* 上次导入信息摘要
|
||||
*/
|
||||
lastImportInfo() {
|
||||
const savedTask = this.getImportTaskFromStorage();
|
||||
if (savedTask && savedTask.totalCount) {
|
||||
return `导入时间: ${this.parseTime(savedTask.timestamp)} | 总数: ${savedTask.totalCount}条 | 成功: ${savedTask.successCount}条 | 失败: ${savedTask.failureCount}条`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
**Step 2: 修改失败记录按钮 - 添加tooltip**
|
||||
|
||||
找到"查看导入失败记录"按钮的代码(大约在第70-78行),替换为:
|
||||
|
||||
```vue
|
||||
<el-col :span="1.5" v-if="showFailureButton">
|
||||
<el-tooltip
|
||||
:content="getLastImportTooltip()"
|
||||
placement="top"
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-warning"
|
||||
size="mini"
|
||||
@click="viewImportFailures"
|
||||
>
|
||||
查看上次导入失败记录
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
```
|
||||
|
||||
**Step 3: 修改失败记录对话框 - 添加信息提示和清除按钮**
|
||||
|
||||
找到导入失败记录对话框(大约在第269-294行),在 `<el-table>` 上方添加信息提示,在footer添加清除按钮:
|
||||
|
||||
```vue
|
||||
<!-- 导入失败记录对话框 -->
|
||||
<el-dialog
|
||||
title="导入失败记录"
|
||||
:visible.sync="failureDialogVisible"
|
||||
width="1200px"
|
||||
append-to-body
|
||||
>
|
||||
<el-alert
|
||||
v-if="lastImportInfo"
|
||||
:title="lastImportInfo"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 15px"
|
||||
/>
|
||||
|
||||
<el-table :data="failureList" v-loading="failureLoading">
|
||||
<el-table-column label="姓名" prop="name" align="center" />
|
||||
<el-table-column label="柜员号" prop="employeeId" align="center" />
|
||||
<el-table-column label="身份证号" prop="idCard" align="center" />
|
||||
<el-table-column label="电话" prop="phone" align="center" />
|
||||
<el-table-column label="失败原因" prop="errorMessage" align="center" min-width="200" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="failureTotal > 0"
|
||||
:total="failureTotal"
|
||||
:page.sync="failureQueryParams.pageNum"
|
||||
:limit.sync="failureQueryParams.pageSize"
|
||||
@pagination="getFailureList"
|
||||
/>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="failureDialogVisible = false">关闭</el-button>
|
||||
<el-button type="danger" plain @click="clearImportHistory">清除历史记录</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
```
|
||||
|
||||
**Step 4: 手动测试 - UI优化验证**
|
||||
|
||||
1. 完成一次有失败记录的导入
|
||||
2. 鼠标悬停在"查看上次导入失败记录"按钮上
|
||||
3. 确认显示tooltip提示上次导入时间
|
||||
4. 点击按钮打开对话框
|
||||
5. 确认对话框顶部显示导入统计信息
|
||||
6. 点击"清除历史记录"按钮
|
||||
7. 确认弹出确认对话框
|
||||
8. 确认后对话框关闭,按钮消失
|
||||
|
||||
**Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiEmployee/index.vue
|
||||
git commit -m "feat: 添加UI优化和用户体验增强
|
||||
|
||||
- 新增lastImportInfo计算属性显示导入统计
|
||||
- 失败记录按钮添加tooltip显示导入时间
|
||||
- 失败记录对话框添加统计信息展示
|
||||
- 对话框添加清除历史记录按钮
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整功能测试
|
||||
|
||||
### Task 6: 端到端功能测试
|
||||
|
||||
**Files:**
|
||||
- 无修改,仅测试
|
||||
|
||||
**Step 1: 测试场景1 - 导入成功无失败后刷新**
|
||||
|
||||
1. 准备一个正确的Excel文件(所有数据都有效)
|
||||
2. 上传文件并等待导入完成
|
||||
3. 确认不显示"查看上次导入失败记录"按钮
|
||||
4. 刷新页面(F5)
|
||||
5. **预期**: 仍然不显示失败记录按钮
|
||||
6. **实际**: 验证符合预期
|
||||
|
||||
**Step 2: 测试场景2 - 导入有失败后刷新**
|
||||
|
||||
1. 准备一个包含错误数据的Excel文件
|
||||
2. 上传文件并等待导入完成
|
||||
3. 确认显示"查看上次导入失败记录"按钮
|
||||
4. 刷新页面(F5)
|
||||
5. **预期**: 按钮仍然显示
|
||||
6. **实际**: 验证符合预期
|
||||
7. 点击按钮,确认能正常查看失败记录
|
||||
|
||||
**Step 3: 测试场景3 - 导入有失败后切换菜单**
|
||||
|
||||
1. 准备一个包含错误数据的Excel文件
|
||||
2. 上传文件并等待导入完成
|
||||
3. 确认显示"查看上次导入失败记录"按钮
|
||||
4. 点击左侧菜单,切换到其他页面(如"部门管理")
|
||||
5. 再点击菜单返回"员工管理"
|
||||
6. **预期**: 按钮仍然显示
|
||||
7. **实际**: 验证符合预期
|
||||
|
||||
**Step 4: 测试场景4 - 新导入覆盖旧记录**
|
||||
|
||||
1. 完成一次有失败记录的导入
|
||||
2. 确认显示按钮
|
||||
3. 上传新的Excel文件(正确或错误都可以)
|
||||
4. **预期**: 新导入开始时,旧记录被清除
|
||||
5. **实际**: 验证localStorage中的数据被新的taskId覆盖
|
||||
|
||||
**Step 5: 测试场景5 - 手动清除历史记录**
|
||||
|
||||
1. 完成一次有失败记录的导入
|
||||
2. 点击"查看上次导入失败记录"按钮
|
||||
3. 在对话框中点击"清除历史记录"按钮
|
||||
4. **预期**: 弹出确认对话框,确认后对话框关闭,按钮消失
|
||||
5. **实际**: 验证符合预期
|
||||
6. 刷新页面
|
||||
7. **预期**: 按钮仍然不显示
|
||||
8. **实际**: 验证符合预期
|
||||
|
||||
**Step 6: 测试场景6 - localStorage过期处理**
|
||||
|
||||
这个场景由于Redis TTL是7天,手动测试比较困难,可以通过修改localStorage数据模拟:
|
||||
|
||||
```javascript
|
||||
// 在浏览器控制台执行
|
||||
const data = JSON.parse(localStorage.getItem('employee_import_last_task'));
|
||||
if (data) {
|
||||
// 将saveTime改为8天前
|
||||
data.saveTime = Date.now() - (8 * 24 * 60 * 60 * 1000);
|
||||
localStorage.setItem('employee_import_last_task', JSON.stringify(data));
|
||||
}
|
||||
```
|
||||
然后刷新页面,确认数据被自动清除,按钮不显示。
|
||||
|
||||
**Step 7: 浏览器兼容性快速测试**
|
||||
|
||||
在不同浏览器中重复上述测试场景:
|
||||
- Chrome (主要浏览器)
|
||||
- Edge (如果可用)
|
||||
- Firefox (如果可用)
|
||||
|
||||
确认功能在各个浏览器中正常工作。
|
||||
|
||||
**Step 8: 无需提交**
|
||||
|
||||
这是纯测试步骤,无需提交代码。
|
||||
|
||||
---
|
||||
|
||||
## 文档更新
|
||||
|
||||
### Task 7: 更新API文档(可选)
|
||||
|
||||
**Files:**
|
||||
- Check: `doc/api/ccdi-employee-import-api.md`
|
||||
|
||||
**Step 1: 检查API文档是否需要更新**
|
||||
|
||||
由于这个改动是纯前端实现,不涉及后端API的变化,因此API文档理论上不需要更新。
|
||||
|
||||
检查 `doc/api/ccdi-employee-import-api.md` 文档中是否有关于前端行为或状态的说明,如果有的话,补充说明现在支持跨页面状态持久化。
|
||||
|
||||
**Step 2: 如需要,在文档末尾添加说明**
|
||||
|
||||
```markdown
|
||||
### 前端行为说明
|
||||
|
||||
#### 导入结果持久化
|
||||
|
||||
- 前端使用localStorage存储最近一次导入的任务信息
|
||||
- 支持在切换菜单或刷新页面后继续查看上一次的导入失败记录
|
||||
- 存储期限: 7天(与后端Redis TTL一致)
|
||||
- 下次导入开始时,自动清除上一次的导入记录
|
||||
- 用户可以手动清除导入历史记录
|
||||
```
|
||||
|
||||
**Step 3: 提交(如果进行了修改)**
|
||||
|
||||
```bash
|
||||
git add doc/api/ccdi-employee-import-api.md
|
||||
git commit -m "docs: 补充导入结果持久化说明
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最终验证
|
||||
|
||||
### Task 8: 代码审查和最终验证
|
||||
|
||||
**Files:**
|
||||
- Review: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
|
||||
|
||||
**Step 1: 代码审查清单**
|
||||
|
||||
- [ ] 所有新增方法都有适当的注释
|
||||
- [ ] localStorage操作都有try-catch保护
|
||||
- [ ] 错误处理覆盖了主要场景(404, 500, 网络错误)
|
||||
- [ ] 代码格式符合项目规范
|
||||
- [ ] 没有console.log等调试代码残留
|
||||
- [ ] 没有硬编码的测试数据
|
||||
|
||||
**Step 2: 最终功能回归测试**
|
||||
|
||||
按照 Task 6 的所有测试场景再执行一遍,确保所有功能正常。
|
||||
|
||||
**Step 3: 浏览器控制台检查**
|
||||
|
||||
打开浏览器控制台,执行以下操作,确认没有错误或警告:
|
||||
1. 刷新页面
|
||||
2. 完成一次导入
|
||||
3. 切换菜单
|
||||
4. 查看失败记录
|
||||
|
||||
**Step 4: 性能检查**
|
||||
|
||||
打开浏览器开发者工具 > Performance 或 Lighthouse(如果可用):
|
||||
1. 录制页面加载过程
|
||||
2. 确认localStorage读写操作不会明显影响页面加载性能
|
||||
3. 预期: 增加的开销 < 10ms
|
||||
|
||||
**Step 5: 最终提交**
|
||||
|
||||
所有代码已经在前面的任务中提交,这里只需确认所有提交都已完成:
|
||||
|
||||
```bash
|
||||
# 查看最近的提交历史
|
||||
git log --oneline -10
|
||||
```
|
||||
|
||||
应该看到以下提交:
|
||||
1. `feat: 添加localStorage工具方法用于导入状态持久化`
|
||||
2. `feat: 添加导入状态恢复和用户交互方法`
|
||||
3. `feat: 修改导入处理逻辑以支持状态持久化`
|
||||
4. `feat: 增强失败记录查询的错误处理`
|
||||
5. `feat: 添加UI优化和用户体验增强`
|
||||
6. (可选) `docs: 补充导入结果持久化说明`
|
||||
|
||||
**Step 6: 创建功能总结提交**
|
||||
|
||||
```bash
|
||||
git commit --allow-empty -m "feat: 完成员工导入结果跨页面持久化功能
|
||||
|
||||
功能概述:
|
||||
- 使用localStorage存储最近一次导入任务信息
|
||||
- 支持切换菜单后查看上一次的导入失败记录
|
||||
- 自动过期处理(7天)
|
||||
- 完整的错误处理和用户友好的提示信息
|
||||
- 新增清除历史记录功能
|
||||
|
||||
测试场景:
|
||||
- 导入成功无失败后刷新页面
|
||||
- 导入有失败后刷新页面
|
||||
- 导入有失败后切换菜单
|
||||
- 新导入覆盖旧记录
|
||||
- 手动清除历史记录
|
||||
- localStorage过期处理
|
||||
|
||||
相关提交:
|
||||
- b932a7d docs: 添加员工导入结果跨页面持久化设计文档
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### A. 相关设计文档
|
||||
|
||||
- `doc/plans/2026-02-06-employee-import-result-persistence-design.md` - 详细设计文档
|
||||
- `doc/plans/2026-02-06-employee-async-import-design.md` - 异步导入功能设计文档
|
||||
|
||||
### B. 测试数据准备
|
||||
|
||||
**正确的Excel文件**:
|
||||
- 柜员号: 7位数字,唯一
|
||||
- 姓名: 非空
|
||||
- 身份证号: 18位有效身份证号
|
||||
- 部门: 系统中存在的部门ID
|
||||
- 电话: 11位手机号
|
||||
- 状态: 0(在职)或1(离职)
|
||||
|
||||
**包含错误数据的Excel文件**:
|
||||
- 至少包含以下几种错误:
|
||||
- 重复的柜员号
|
||||
- 无效的身份证号(位数不对或校验位错误)
|
||||
- 不存在的部门ID
|
||||
- 无效的手机号格式
|
||||
|
||||
### C. 常见问题排查
|
||||
|
||||
**问题1: 按钮不显示**
|
||||
- 检查localStorage是否有数据
|
||||
- 检查hasFailures是否为true
|
||||
- 检查taskId是否存在
|
||||
|
||||
**问题2: 点击查询报错**
|
||||
- 检查后端API是否正常
|
||||
- 检查taskId是否有效
|
||||
- 查看浏览器控制台的错误信息
|
||||
|
||||
**问题3: 数据没有持久化**
|
||||
- 检查浏览器是否支持localStorage
|
||||
- 检查是否在隐私模式/无痕模式
|
||||
- 查看控制台是否有异常
|
||||
|
||||
### D. 回滚方案
|
||||
|
||||
如果需要回滚此功能:
|
||||
|
||||
```bash
|
||||
# 查看提交历史
|
||||
git log --oneline
|
||||
|
||||
# 回滚到功能之前的提交(假设功能前的提交是 abc1234)
|
||||
git revert abc1234..HEAD
|
||||
|
||||
# 或者硬重置(慎用)
|
||||
git reset --hard abc1234
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**计划版本**: 1.0
|
||||
**创建日期**: 2026-02-06
|
||||
**预计工时**: 2-3小时
|
||||
Reference in New Issue
Block a user