9.4 KiB
9.4 KiB
✅ 党籍保留附件查看功能实现说明
实现时间: 2025-10-13
功能描述: 在出国申请详情弹窗中,为党籍保留附件增加"查看"按钮,支持在线预览
🎯 功能概述
在出国申请管理的详情弹窗中,党籍保留附件区域新增了"查看"按钮,用户可以:
- 📄 PDF文件: 在新窗口中直接预览
- 🖼️ 图片文件: 在新窗口中查看(支持JPG、PNG、GIF、BMP、WEBP)
- 📦 其他文件: 自动触发下载
📝 实现细节
1. 界面修改
文件位置: web/src/views/rs/overseas/index.vue
修改内容 (第1024-1060行):
<!-- 党籍保留附件 -->
<div v-if="(state.viewData as OverseasApplicationVO).partyRetentionUploadStatus === '1'"
style="margin-bottom: 15px; padding: 12px; border: 1px solid #e4e7ed; border-radius: 4px; background: #fff5f5;">
<div style="font-size: 14px; color: #ff4757; margin-bottom: 8px;">
<el-icon><Warning /></el-icon>
<span style="margin-left: 5px; font-weight: 500;">党籍保留附件</span>
</div>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tag type="danger" size="small">
<el-icon><Document /></el-icon>
{{ (state.viewData as OverseasApplicationVO).partyRetentionFileName }}
</el-tag>
<span style="margin-left: 10px; font-size: 12px; color: #909399;">
上传时间: {{ (state.viewData as OverseasApplicationVO).partyRetentionUploadTime }}
</span>
</div>
<!-- 操作按钮组 -->
<div style="display: flex; gap: 8px;">
<!-- 新增:查看按钮 -->
<el-button
link
type="primary"
size="small"
@click="handlePreviewPartyRetentionFile((state.viewData as OverseasApplicationVO))"
>
<el-icon><View /></el-icon> 查看
</el-button>
<!-- 原有:下载按钮 -->
<el-button
link
type="primary"
size="small"
@click="handleDownloadPartyRetentionFile((state.viewData as OverseasApplicationVO))"
>
<el-icon><Download /></el-icon> 下载
</el-button>
</div>
</div>
</div>
界面变化:
- ✅ 新增"查看"按钮,位于"下载"按钮左侧
- ✅ 使用
flex布局,两个按钮间距8px - ✅ 按钮样式与下载按钮保持一致
- ✅ 使用Element Plus的
View图标
2. 图标导入
修改位置: 第1260行
// 原代码
import { UploadFilled, Document, Loading, Download, Delete } from '@element-plus/icons-vue';
// 修改后
import { UploadFilled, Document, Loading, Download, Delete, View } from '@element-plus/icons-vue';
3. 预览方法实现
方法位置: 第3437-3515行
// 预览党籍保留附件
const handlePreviewPartyRetentionFile = async (data: OverseasApplicationVO) => {
console.log('👁️ 预览党籍保留附件:', data.partyRetentionFileName);
if (!data.partyRetentionFileOssId) {
ElMessage.warning('文件OSS ID不存在,无法预览');
return;
}
try {
// 判断文件类型
const fileName = data.partyRetentionFileName || '';
const fileExt = fileName.split('.').pop()?.toLowerCase();
// 图片类型直接在新窗口预览
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExt || '')) {
// 使用OSS下载接口获取图片
const imageUrl = `/resource/oss/download/${data.partyRetentionFileOssId}`;
// 获取blob URL用于预览
const response = await request({
url: imageUrl,
method: 'get',
responseType: 'blob'
});
const blob = response instanceof Blob ? response : new Blob([response.data]);
const blobUrl = window.URL.createObjectURL(blob);
// 在新窗口打开图片
const previewWindow = window.open('', '_blank');
if (previewWindow) {
previewWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>${fileName}</title>
<style>
body { margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #f5f5f5; }
img { max-width: 100%; max-height: 100vh; object-fit: contain; }
</style>
</head>
<body>
<img src="${blobUrl}" alt="${fileName}" />
</body>
</html>
`);
previewWindow.document.close();
}
}
// PDF类型在新窗口预览
else if (fileExt === 'pdf') {
// 获取PDF文件
const response = await request({
url: `/resource/oss/download/${data.partyRetentionFileOssId}`,
method: 'get',
responseType: 'blob'
});
const blob = response instanceof Blob ? response : new Blob([response.data], { type: 'application/pdf' });
const blobUrl = window.URL.createObjectURL(blob);
// 在新窗口打开PDF
window.open(blobUrl, '_blank');
// 延迟清理,确保新窗口已加载
setTimeout(() => {
window.URL.revokeObjectURL(blobUrl);
}, 60000); // 60秒后清理
}
// 其他文件类型提示下载
else {
ElMessage.info('该文件类型不支持在线预览,请下载后查看');
await handleDownloadPartyRetentionFile(data);
}
} catch (error) {
console.error('预览党籍保留附件失败:', error);
ElMessage.error('预览文件失败,请检查文件权限或稍后重试');
}
};
🎨 功能特性
✅ 支持的文件类型
-
PDF文件 (
.pdf)- 在新浏览器标签页中打开
- 浏览器原生PDF预览器
- 支持缩放、打印等操作
-
图片文件 (
.jpg,.jpeg,.png,.gif,.bmp,.webp)- 在新窗口中居中显示
- 自适应屏幕大小
- 灰色背景,美观舒适
-
其他文件类型
- 自动提示用户
- 触发下载功能
- 无缝切换到下载流程
✅ 安全性保障
-
认证请求
- 使用
request工具发送请求 - 自动携带Token认证头
- 自动携带clientId等必需Header
- 使用
-
权限检查
- 检查OSS ID是否存在
- 后端权限验证
- 错误提示友好
-
资源管理
- Blob URL自动清理
- 防止内存泄漏
- PDF预览60秒后清理
✅ 用户体验
-
操作便捷
- 一键预览
- 新窗口打开,不影响当前页面
- 支持浏览器返回键
-
提示友好
- 加载中提示
- 成功/失败消息
- 不支持预览时自动下载
-
界面美观
- 按钮对齐整齐
- 图标语义清晰
- 样式统一协调
🧪 测试场景
测试用例1: PDF文件预览
- 上传PDF格式的党籍保留附件
- 在详情弹窗中点击"查看"按钮
- 预期结果: 在新标签页中打开PDF,可以正常查看
测试用例2: 图片文件预览
- 上传JPG/PNG格式的党籍保留附件
- 在详情弹窗中点击"查看"按钮
- 预期结果: 在新窗口中居中显示图片
测试用例3: 不支持的文件类型
- 上传DOC/DOCX等其他格式的文件
- 在详情弹窗中点击"查看"按钮
- 预期结果: 提示"该文件类型不支持在线预览,请下载后查看",并自动触发下载
测试用例4: 权限验证
- 使用没有权限的用户
- 尝试预览党籍保留附件
- 预期结果: 后端返回权限错误,前端显示错误提示
测试用例5: 文件不存在
- 删除OSS中的文件
- 尝试预览党籍保留附件
- 预期结果: 显示"预览文件失败"错误提示
📊 技术实现对比
与盖章文件的对比
| 特性 | 盖章文件 | 党籍保留附件 |
|---|---|---|
| 上传组件 | el-upload | el-upload |
| 显示方式 | 上传列表 | 单个附件卡片 |
| 预览方式 | 组件内预览 | 新窗口预览 |
| 下载方式 | OSS下载接口 | OSS下载接口 |
| 权限控制 | Token认证 | Token认证 |
技术选型原因
-
新窗口预览 vs 弹窗预览
- ✅ 不影响当前页面状态
- ✅ 用户可以同时查看多个文件
- ✅ 浏览器原生支持,兼容性好
- ✅ 可以使用浏览器的打印、缩放等功能
-
Blob URL vs 直接URL
- ✅ 支持认证请求
- ✅ 安全性更高
- ✅ 可以自定义预览样式
- ✅ 避免CORS问题
🔄 后续优化建议
1. 增强预览功能
- 支持Word、Excel在线预览(需要引入第三方库)
- 支持视频、音频预览
- 支持压缩包内容预览
2. 用户体验优化
- 添加预览加载进度条
- 支持图片放大缩小
- 支持PDF页面跳转
3. 性能优化
- 添加文件预览缓存
- 优化大文件预览加载速度
- 支持分页预览大型PDF
📞 相关文档
- 前端开发规范:
.cursor/cursorrules-frontend.md - API文档:
docs/开发文档/API/出国申请管理API.md - 组件文档:
web/src/components/ImagePreview/index.vue
✅ 验收标准
- 界面上显示"查看"按钮
- 按钮位置在"下载"按钮左侧
- 点击按钮可以预览PDF文件
- 点击按钮可以预览图片文件
- 不支持的文件类型自动下载
- 错误提示友好
- 无TypeScript编译错误
- 无ESLint错误
实现人: Cursor AI
审核人: 待审核
状态: ✅ 已完成
最后更新: 2025-10-13