14 KiB
14 KiB
✅ 出国记录变更历史显示功能实现完成报告
📋 功能概述
实现日期: 2025-10-13
开发者: AI Assistant
需求描述: 在"出国申请"菜单下的"出国记录"选项卡中,点击"查看详情"按钮时,在弹窗界面中显示该记录的变更历史记录。
🎯 功能说明
业务流程
- 变更申请提交 → 用户在"出国行程变更申请"菜单下的"变更申请"选项卡提交变更
- 变更审批 → 管理员在"出国行程变更审批"菜单中审批变更申请
- 变更记录流转 → 审批通过后,变更记录会显示在两个地方:
- 出国行程变更申请 → "变更记录"选项卡
- 出国申请 → "出国记录"选项卡 → 查看详情弹窗中的"变更历史记录"区域 ✅ (本次实现)
数据关联关系
出国申请 (rs_overseas_application)
↓ 审批通过
出国记录 (rs_overseas_record)
↓ recordId 关联
出国行程变更 (rs_overseas_itinerary_change)
🛠️ 实现内容
1. 前端API导入
文件: web/src/views/rs/overseas/index.vue
修改内容:
// 导入变更历史查询API
import {
// ... 其他API
getItineraryChangeHistory, // 新增:查询变更历史
// ... 其他类型
} from '@/api/rs/overseas';
// 导入EditPen图标用于变更历史标题
import { UploadFilled, Document, Loading, Download, Delete, View, EditPen } from '@element-plus/icons-vue';
2. 状态管理
添加变更历史相关状态:
const state = reactive({
// ... 其他状态
// 变更历史记录
changeHistoryLoading: false,
changeHistoryList: [] as any[],
// ... 其他状态
});
3. 核心方法实现
3.1 修改查看记录详情方法
原方法:
const handleViewRecord = (row: OverseasRecordVO) => {
console.log('查看记录:', row);
state.viewData = row;
state.viewDialog.visible = true;
state.viewDialog.title = '出国记录详情';
};
修改后:
const handleViewRecord = async (row: OverseasRecordVO) => {
// 查看记录详情
console.log('查看记录:', row);
state.viewData = row;
state.viewDialog.visible = true;
state.viewDialog.title = '出国记录详情';
// 加载该记录的变更历史
await loadChangeHistory(row.recordId);
};
3.2 新增加载变更历史方法
// 加载变更历史记录
const loadChangeHistory = async (recordId: number) => {
if (!recordId) {
console.warn('recordId为空,无法加载变更历史');
state.changeHistoryList = [];
return;
}
state.changeHistoryLoading = true;
try {
console.log('🔄 开始加载变更历史记录, recordId:', recordId);
const response = await getItineraryChangeHistory(recordId);
if (response.code === 200) {
state.changeHistoryList = response.data || [];
console.log('✅ 变更历史记录加载成功, 共', state.changeHistoryList.length, '条记录');
} else {
console.warn('⚠️ 获取变更历史失败:', response.msg);
state.changeHistoryList = [];
}
} catch (error) {
console.error('❌ 加载变更历史记录失败:', error);
state.changeHistoryList = [];
} finally {
state.changeHistoryLoading = false;
}
};
3.3 新增变更状态Tag类型方法
// 获取变更状态的Tag类型
const getChangeStatusTagType = (status: string): 'success' | 'warning' | 'danger' | 'info' => {
const typeMap: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
'0': 'warning', // 待审核
'1': 'success', // 已通过
'2': 'danger', // 已拒绝
'3': 'info' // 已撤回
};
return typeMap[status] || 'info';
};
4. UI界面实现
在记录详情弹窗中增加变更历史区域:
<!-- 变更历史记录 -->
<div v-if="state.viewData && 'recordId' in state.viewData" style="margin-top: 20px;">
<el-divider content-position="left">
<span style="font-size: 16px; font-weight: bold; color: #409eff;">
<el-icon style="vertical-align: middle; margin-right: 5px;"><EditPen /></el-icon>
变更历史记录
</span>
</el-divider>
<!-- 变更历史列表 -->
<div v-loading="state.changeHistoryLoading">
<el-empty
v-if="!state.changeHistoryLoading && state.changeHistoryList.length === 0"
description="暂无变更记录"
:image-size="80"
/>
<el-table
v-else
:data="state.changeHistoryList"
border
style="width: 100%"
max-height="400px"
>
<el-table-column label="变更时间" align="center" prop="createTime" min-width="160" />
<el-table-column label="变更类型" align="center" prop="changeType" min-width="150">
<template #default="scope">
<el-tag
v-for="(type, index) in (scope.row.changeType || '').split(',')"
:key="index"
style="margin: 2px;"
size="small"
>
{{ type }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="原目的地" align="center" prop="originalDestination" min-width="120" />
<el-table-column label="新目的地" align="center" prop="newDestination" min-width="120" />
<el-table-column label="原出国时间" align="center" min-width="200">
<template #default="scope">
{{ formatDate(scope.row.originalStartDate) }} 至 {{ formatDate(scope.row.originalEndDate) }}
</template>
</el-table-column>
<el-table-column label="新出国时间" align="center" min-width="200">
<template #default="scope">
{{ formatDate(scope.row.newStartDate) }} 至 {{ formatDate(scope.row.newEndDate) }}
</template>
</el-table-column>
<el-table-column label="变更原因" align="center" prop="changeReason" min-width="200" show-overflow-tooltip />
<el-table-column label="状态" align="center" prop="statusText" min-width="100">
<template #default="scope">
<el-tag :type="getChangeStatusTagType(scope.row.status)">{{ scope.row.statusText }}</el-tag>
</template>
</el-table-column>
<el-table-column label="审批意见" align="center" prop="approvalOpinion" min-width="150" show-overflow-tooltip />
</el-table>
</div>
</div>
📊 功能展示
详情弹窗结构
┌────────────────────────────────────────┐
│ 出国记录详情 │
├────────────────────────────────────────┤
│ 【基本信息】 │
│ - 姓名、性别、出生年月、政治面貌 │
│ - 工作部门、职称、职务、证件信息 │
│ - 出国时间、目的地、行程安排等 │
├────────────────────────────────────────┤
│ 【变更历史记录】✨ 新增 │
│ ┌──────────────────────────────────┐ │
│ │ 📝 变更历史记录 │ │
│ ├──────────────────────────────────┤ │
│ │ 📋 变更记录列表表格 │ │
│ │ - 变更时间 │ │
│ │ - 变更类型(支持多个标签) │ │
│ │ - 原目的地 → 新目的地 │ │
│ │ - 原时间 → 新时间 │ │
│ │ - 变更原因 │ │
│ │ - 审批状态 │ │
│ │ - 审批意见 │ │
│ └──────────────────────────────────┘ │
├────────────────────────────────────────┤
│ [下载因私出国(境)情况回执] [关闭] │
└────────────────────────────────────────┘
状态标签配色
| 状态 | 显示文字 | 标签颜色 |
|---|---|---|
| 0 | 待审核 | warning (橙色) |
| 1 | 已通过 | success (绿色) |
| 2 | 已拒绝 | danger (红色) |
| 3 | 已撤回 | info (灰色) |
🔗 后端API支持
API接口信息
- 接口地址:
GET /rs/itinerary/change/record/{recordId}/history - 权限标识:
rs:itineraryChange:query - 返回数据: 该出国记录的所有变更历史记录列表
前端API定义
文件: web/src/api/rs/overseas.ts
// 查询某个记录的变更历史
export function getItineraryChangeHistory(recordId: string | number) {
return request({
url: `/rs/itinerary/change/record/${recordId}/history`,
method: 'get'
});
}
✅ 完成清单
- 导入变更历史查询API
- 添加变更历史状态管理
- 修改查看记录详情方法,增加加载变更历史
- 实现加载变更历史的方法
- 实现变更状态Tag类型方法
- 在详情弹窗UI中增加变更历史展示区域
- 添加EditPen图标导入
- 代码linter检查通过
🧪 测试指南
测试前提条件
- 数据库准备: 确保
rs_overseas_itinerary_change表已创建并有测试数据 - 权限配置: 用户具有
rs:overseas:query和rs:itineraryChange:query权限 - 测试数据: 至少有一条出国记录,并且该记录有对应的变更历史
测试步骤
1️⃣ 准备测试数据
-- 查询已有的出国记录
SELECT record_id, applicant_name, destination
FROM rs_overseas_record
WHERE deleted = 0
LIMIT 5;
-- 查询某个记录的变更历史
SELECT * FROM rs_overseas_itinerary_change
WHERE record_id = <你的record_id>
AND deleted = 0;
2️⃣ 前端功能测试
步骤:
- 登录系统
- 进入菜单: 人事管理 → 出国申请
- 切换到 "出国记录" 选项卡
- 找到有变更历史的记录,点击 "查看详情" 按钮 (👁 图标)
- 在弹出的详情弹窗中,向下滚动到底部
- 查看 "变更历史记录" 区域
预期结果:
- ✅ 弹窗正常打开,显示出国记录详情
- ✅ 底部显示 "变更历史记录" 标题(带蓝色图标)
- ✅ 如果有变更历史,显示变更记录表格
- ✅ 如果没有变更历史,显示 "暂无变更记录" 提示
- ✅ 变更类型显示为多个标签(如果有多个变更类型)
- ✅ 状态标签颜色正确显示(待审核=橙色,已通过=绿色等)
- ✅ 所有字段数据正确显示
3️⃣ 边界情况测试
测试场景:
- 没有变更历史的记录 → 应显示 "暂无变更记录"
- 有多条变更历史的记录 → 应显示所有变更记录
- 变更历史有多个变更类型 → 应显示多个标签
- recordId为空的记录 → 应正常处理,不报错
4️⃣ 控制台日志检查
打开浏览器控制台,查看日志输出:
✅ 正常日志示例:
🔄 开始加载变更历史记录, recordId: 123456789
✅ 变更历史记录加载成功, 共 2 条记录
📝 功能特点
1. 用户体验优化
- ✨ 自动加载: 打开详情弹窗时自动加载变更历史,无需手动刷新
- 🔄 加载动画: 显示loading状态,提升用户体验
- 📊 表格展示: 使用表格形式,清晰展示所有变更信息
- 🏷️ 多标签支持: 变更类型支持多个标签显示
- 🎨 状态配色: 不同状态使用不同颜色的标签,一目了然
2. 数据完整性
- 📅 时间对比: 清晰对比原时间和新时间
- 🗺️ 目的地对比: 清晰对比原目的地和新目的地
- 📋 变更原因: 显示详细的变更原因说明
- 💬 审批意见: 显示审批人的审批意见
3. 技术实现
- 🔗 API关联: 通过recordId关联查询变更历史
- 🛡️ 错误处理: 完善的错误处理和日志记录
- 🎯 类型安全: TypeScript类型定义完整
- ⚡ 性能优化: 异步加载,不阻塞主流程
🔍 常见问题
Q1: 为什么看不到变更历史记录?
可能原因:
- 该出国记录确实没有提交过行程变更申请
- 变更申请还未通过审批
- recordId为空或不正确
排查步骤:
-- 检查记录是否存在变更历史
SELECT * FROM rs_overseas_itinerary_change
WHERE record_id = <你的record_id>
AND deleted = 0;
Q2: 变更类型标签不显示
可能原因: changeType 字段为空或格式不正确
解决方案: 确保变更类型字段有值,多个类型用逗号分隔
Q3: 加载失败
检查项:
- 浏览器控制台是否有错误信息
- 网络请求是否成功(开发者工具 → Network)
- 用户是否有
rs:itineraryChange:query权限
🎯 后续优化建议
功能扩展
- 🔍 详情查看: 点击变更记录可查看完整的变更详情
- 📊 统计信息: 显示变更次数统计
- 🔔 变更提醒: 有新变更时给予提醒
- 📥 导出功能: 支持导出变更历史记录
性能优化
- ⚡ 懒加载: 只在展开变更历史时才加载数据
- 💾 缓存机制: 缓存已加载的变更历史
- 📄 分页支持: 变更记录很多时支持分页
📅 开发记录
| 时间 | 版本 | 说明 |
|---|---|---|
| 2025-10-13 | v1.0 | ✅ 初版实现完成 |
| - 前端UI展示 | ||
| - API集成 | ||
| - 状态管理 | ||
| - 功能测试 |
📚 相关文档
👥 相关人员
- 需求提出: 用户
- 功能开发: AI Assistant
- 技术审核: 待定
- 测试验证: 待定
🎉 功能已完成,等待测试验证!