diff --git a/doc/plans/2026-02-06-employee-import-result-persistence-design.md b/doc/plans/2026-02-06-employee-import-result-persistence-design.md
new file mode 100644
index 0000000..832c53c
--- /dev/null
+++ b/doc/plans/2026-02-06-employee-import-result-persistence-design.md
@@ -0,0 +1,678 @@
+# 员工导入结果跨页面持久化设计文档
+
+**创建日期**: 2026-02-06
+**设计者**: Claude Code
+**状态**: 已确认
+**关联文档**: [员工信息异步导入功能设计文档](./2026-02-06-employee-async-import-design.md)
+
+---
+
+## 一、需求概述
+
+### 1.1 背景
+当前员工信息异步导入功能存在问题:
+- 导入开始后,切换到其他菜单再返回,无法查看上一次的导入结果
+- `showFailureButton`、`currentTaskId` 等状态变量存储在组件内存中,页面切换后丢失
+
+### 1.2 目标
+- 实现导入结果的跨页面持久化
+- 用户可以在切换菜单后仍然查看上一次的导入失败记录
+- 仅保留最近一次导入记录,下次导入时自动清除旧数据
+- 依赖Redis的7天TTL机制自动清理过期数据
+
+### 1.3 核心决策
+- **存储方案**: localStorage(前端持久化)
+- **保留范围**: 仅最后一次导入记录
+- **过期策略**: 依赖Redis TTL(7天),前端校验时间戳
+- **清除时机**: 下次导入开始时自动清除旧数据
+
+---
+
+## 二、技术方案
+
+### 2.1 整体设计
+
+采用 **前端localStorage持久化** 方案:
+
+```
+用户上传Excel
+ ↓
+清除localStorage旧数据 → 保存新taskId
+ ↓
+开始轮询查询状态
+ ↓
+导入完成 → 更新localStorage状态
+ ↓
+用户切换菜单 → 组件销毁
+ ↓
+用户返回页面 → created()钩子
+ ↓
+从localStorage读取 → 恢复按钮显示状态
+ ↓
+用户点击查看失败记录 → 正常查询
+```
+
+**核心优势**:
+- 无需后端改动,完全前端实现
+- 简单可靠,利用浏览器原生存储
+- 用户体验流畅,状态不丢失
+
+### 2.2 数据结构设计
+
+**localStorage存储格式**:
+
+```javascript
+// key: 'employee_import_last_task'
+{
+ taskId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
+ status: 'SUCCESS' | 'PARTIAL_SUCCESS' | 'FAILED' | 'PROCESSING',
+ timestamp: 1707225900000,
+ saveTime: 1707225900000,
+ hasFailures: true,
+ totalCount: 100,
+ successCount: 95,
+ failureCount: 5
+}
+```
+
+**字段说明**:
+- `taskId`: 导入任务唯一标识
+- `status`: 导入状态
+- `timestamp`: 导入完成时间戳
+- `saveTime`: 保存到localStorage的时间戳(用于过期校验)
+- `hasFailures`: 是否有失败记录
+- `totalCount/successCount/failureCount`: 导入统计信息
+
+---
+
+## 三、前端实现设计
+
+### 3.1 新增工具方法
+
+**文件**: `ruoyi-ui/src/views/ccdiEmployee/index.vue`
+
+```javascript
+methods: {
+ /**
+ * 保存导入任务到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);
+ }
+ },
+
+ /**
+ * 从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;
+ }
+ },
+
+ /**
+ * 清除localStorage中的导入任务
+ */
+ clearImportTaskFromStorage() {
+ try {
+ localStorage.removeItem('employee_import_last_task');
+ } catch (error) {
+ console.error('清除导入任务状态失败:', error);
+ }
+ },
+
+ /**
+ * 恢复导入状态
+ * 在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;
+ }
+ },
+
+ /**
+ * 获取上次导入的提示信息
+ * @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 '';
+ },
+
+ /**
+ * 清除导入历史记录
+ * 用户手动触发
+ */
+ clearImportHistory() {
+ this.$confirm('确认清除上次导入记录?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ this.clearImportTaskFromStorage();
+ this.showFailureButton = false;
+ this.currentTaskId = null;
+ this.failureDialogVisible = false;
+ this.$message.success('已清除');
+ }).catch(() => {});
+ }
+}
+```
+
+### 3.2 生命周期钩子修改
+
+```javascript
+created() {
+ this.getList();
+ this.getDeptTree();
+ this.restoreImportState(); // 新增:恢复导入状态
+}
+```
+
+### 3.3 导入成功处理修改
+
+```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);
+ }
+}
+```
+
+### 3.4 导入完成处理修改
+
+```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();
+ }
+}
+```
+
+### 3.5 失败记录查询增强
+
+```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);
+ }
+ });
+}
+```
+
+### 3.6 新增计算属性
+
+```javascript
+computed: {
+ /**
+ * 上次导入信息摘要
+ */
+ lastImportInfo() {
+ const savedTask = this.getImportTaskFromStorage();
+ if (savedTask && savedTask.totalCount) {
+ return `导入时间: ${this.parseTime(savedTask.timestamp)} | 总数: ${savedTask.totalCount}条 | 成功: ${savedTask.successCount}条 | 失败: ${savedTask.failureCount}条`;
+ }
+ return '';
+ }
+}
+```
+
+### 3.7 模板修改
+
+**失败记录按钮**:
+```vue
+
+
+
+ 查看上次导入失败记录
+
+
+
+```
+
+**失败记录对话框**:
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+---
+
+## 四、用户体验流程
+
+### 4.1 典型场景
+
+**场景1: 导入成功无失败**
+1. 用户上传Excel文件
+2. 导入成功,显示通知"全部成功!共导入100条数据"
+3. 刷新页面或切换菜单后返回
+4. **预期**: 不显示"查看导入失败记录"按钮
+
+**场景2: 导入有失败记录**
+1. 用户上传有错误数据的Excel文件
+2. 导入完成,显示通知"成功95条,失败5条"
+3. 显示"查看导入失败记录"按钮
+4. 用户切换到其他菜单
+5. 用户返回员工管理页面
+6. **预期**: 按钮仍然存在,点击可查看失败记录
+
+**场景3: 导入中切换页面**
+1. 用户上传Excel文件
+2. 后台开始处理,用户立即切换菜单
+3. 用户返回员工管理页面
+4. **预期**: 如有失败,显示按钮并可查看
+
+**场景4: Redis数据过期**
+1. 导入完成,有失败记录
+2. 7天后用户点击"查看导入失败记录"
+3. 后端返回404错误
+4. **预期**: 前端提示"导入记录已过期,无法查看失败记录",并清除localStorage数据,隐藏按钮
+
+**场景5: 新导入覆盖旧记录**
+1. 已有上一次的导入失败记录
+2. 用户上传新的Excel文件
+3. **预期**: 旧记录被立即清除,新导入的结果覆盖localStorage
+
+---
+
+## 五、错误处理与边界情况
+
+### 5.1 localStorage异常
+
+| 异常情况 | 处理方式 |
+|---------|---------|
+| localStorage被禁用 | try-catch捕获,console.error记录,功能降级但不报错 |
+| 数据损坏(非JSON格式) | try-catch捕获,清除损坏数据,返回null |
+| 数据格式不完整 | 校验必要字段,清除无效数据 |
+| 时间戳异常 | 校验类型,清除无效数据 |
+
+### 5.2 API请求失败
+
+| 错误类型 | HTTP状态码 | 处理方式 |
+|---------|-----------|---------|
+| 记录不存在或已过期 | 404 | 提示用户"记录已过期",清除localStorage,隐藏按钮 |
+| 服务器内部错误 | 500 | 提示"服务器错误,请稍后重试" |
+| 网络连接失败 | 无响应 | 提示"网络连接失败,请检查网络" |
+| 其他错误 | 其他 | 显示具体错误信息 |
+
+### 5.3 并发导入处理
+
+- 新导入开始时,立即清除旧的localStorage数据
+- 清除旧的轮询定时器(如果有)
+- 防止状态混乱
+
+### 5.4 浏览器兼容性
+
+localStorage在所有现代浏览器中都得到支持:
+- Chrome 4+
+- Firefox 3.5+
+- Safari 4+
+- IE 8+
+- Edge(所有版本)
+
+### 5.5 存储空间限制
+
+- localStorage通常有5-10MB限制
+- 本功能仅存储一个JSON对象(约200字节),远低于限制
+- 不需要考虑存储空间问题
+
+---
+
+## 六、测试策略
+
+### 6.1 功能测试
+
+| 测试用例 | 步骤 | 预期结果 |
+|---------|------|---------|
+| 导入成功无失败-刷新 | 上传正确Excel → 等待完成 → 刷新页面 | 不显示失败记录按钮 |
+| 导入有失败-刷新 | 上传有错误Excel → 等待完成 → 刷新页面 | 显示按钮,可查看失败记录 |
+| 导入有失败-切换菜单 | 上传有错误Excel → 等待完成 → 切换菜单 → 返回 | 显示按钮,可查看失败记录 |
+| 导入中切换页面 | 上传Excel → 立即切换菜单 → 返回 | 状态正常,如有失败显示按钮 |
+| 新导入覆盖 | 有旧记录 → 上传新Excel → 等待完成 | 显示新导入的按钮,旧记录清除 |
+| 手动清除记录 | 有失败记录 → 点击"清除历史记录" | 按钮隐藏,localStorage清空 |
+| Redis过期模拟 | 修改localStorage时间戳为8天前 → 打开页面 | 自动清除数据,不显示按钮 |
+| API 404处理 | 有失败记录 → Mock后端返回404 | 提示过期,清除数据,隐藏按钮 |
+
+### 6.2 边界测试
+
+| 测试用例 | 预期结果 |
+|---------|---------|
+| localStorage被禁用 | 功能正常,不报错,仅不持久化 |
+| localStorage数据手动篡改 | 自动检测并清除,恢复正常 |
+| 连续快速多次导入 | 最后一次导入的状态为准 |
+| 浏览器关闭后重新打开 | localStorage数据保留,状态恢复 |
+
+### 6.3 浏览器兼容性测试
+
+测试目标浏览器:
+- Chrome(最新版)
+- Firefox(最新版)
+- Edge(最新版)
+- Safari(如适用)
+
+### 6.4 性能测试
+
+| 指标 | 目标 |
+|------|------|
+| localStorage读取时间 | < 10ms |
+| localStorage写入时间 | < 10ms |
+| 页面加载恢复时间 | < 50ms |
+| 内存占用增加 | 可忽略(约200字节) |
+
+---
+
+## 七、实施检查清单
+
+### 7.1 代码实现
+
+- [ ] 新增 `saveImportTaskToStorage()` 方法
+- [ ] 新增 `getImportTaskFromStorage()` 方法
+- [ ] 新增 `clearImportTaskFromStorage()` 方法
+- [ ] 新增 `restoreImportState()` 方法
+- [ ] 新增 `getLastImportTooltip()` 方法
+- [ ] 新增 `clearImportHistory()` 方法
+- [ ] 新增 `lastImportInfo` 计算属性
+- [ ] 修改 `created()` 钩子,调用 `restoreImportState()`
+- [ ] 修改 `handleFileSuccess()` 方法
+- [ ] 修改 `handleImportComplete()` 方法
+- [ ] 修改 `getFailureList()` 方法
+- [ ] 修改模板,添加tooltip和清除按钮
+
+### 7.2 测试
+
+- [ ] 导入成功无失败-刷新页面测试
+- [ ] 导入有失败-刷新页面测试
+- [ ] 导入有失败-切换菜单测试
+- [ ] 导入中切换页面测试
+- [ ] 新导入覆盖旧记录测试
+- [ ] 手动清除记录测试
+- [ ] Redis过期处理测试
+- [ ] API 404错误处理测试
+- [ ] localStorage异常处理测试
+- [ ] 浏览器兼容性测试
+
+### 7.3 文档
+
+- [ ] 更新 `doc/api/ccdi-employee-import-api.md` (如有需要)
+- [ ] 更新用户手册(如需要)
+
+---
+
+## 八、风险与限制
+
+### 8.1 风险
+
+| 风险 | 影响 | 缓解措施 |
+|------|------|---------|
+| localStorage被禁用 | 无法持久化 | 功能降级,不影响基本使用 |
+| 用户清除浏览器数据 | 记录丢失 | 符合预期,无负面影响 |
+| 多标签页并发导入 | 状态可能不一致 | 新导入会覆盖旧数据,可接受 |
+
+### 8.2 限制
+
+1. **仅保留最后一次导入记录**
+ - 设计决策,符合用户需求
+ - 需要查看历史记录可考虑后续扩展
+
+2. **依赖Redis TTL**
+ - 7天后Redis数据自动删除
+ - 前端有7天时间戳校验,但以Redis为准
+
+3. **单浏览器本地存储**
+ - 不同浏览器不共享状态
+ - 换设备后无法查看(符合预期)
+
+---
+
+## 九、未来扩展方向
+
+### 9.1 可能的增强功能
+
+1. **历史导入记录列表**
+ - 后端新增导入记录表
+ - 支持查询所有历史导入
+ - 按时间倒序展示
+
+2. **跨设备同步**
+ - 使用后端存储导入记录
+ - 用户登录后同步导入状态
+
+3. **导入结果导出**
+ - 支持导出失败记录为Excel
+ - 便于用户修正后重新导入
+
+4. **导入统计可视化**
+ - 展示导入成功率趋势
+ - 常见错误类型统计
+
+---
+
+## 十、相关文件清单
+
+### 10.1 修改文件
+
+- `ruoyi-ui/src/views/ccdiEmployee/index.vue` - 员工管理页面
+
+### 10.2 关联文档
+
+- `doc/plans/2026-02-06-employee-async-import-design.md` - 员工信息异步导入功能设计文档
+- `doc/api/ccdi-employee-import-api.md` - 员工导入API文档
+
+---
+
+## 附录
+
+### A. localStorage Key命名规范
+
+```
+employee_import_last_task // 员工导入最后一次任务
+```
+
+命名格式: `{模块}_{功能}_{用途}`
+
+### B. 相关接口
+
+| 接口 | 方法 | 说明 |
+|------|------|------|
+| /ccdi/employee/importData | POST | 提交导入任务 |
+| /ccdi/employee/importStatus/{taskId} | GET | 查询导入状态 |
+| /ccdi/employee/importFailures/{taskId} | GET | 查询失败记录 |
+
+---
+
+**文档版本**: 1.0
+**最后更新**: 2026-02-06