Files
hzdyjs/✅党籍保留附件查看功能实现说明.md
T
2025-10-14 16:41:19 +08:00

9.4 KiB
Raw Blame History

✅ 党籍保留附件查看功能实现说明

实现时间: 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('预览文件失败,请检查文件权限或稍后重试');
  }
};

🎨 功能特性

✅ 支持的文件类型

  1. PDF文件 (.pdf)

    • 在新浏览器标签页中打开
    • 浏览器原生PDF预览器
    • 支持缩放、打印等操作
  2. 图片文件 (.jpg, .jpeg, .png, .gif, .bmp, .webp)

    • 在新窗口中居中显示
    • 自适应屏幕大小
    • 灰色背景,美观舒适
  3. 其他文件类型

    • 自动提示用户
    • 触发下载功能
    • 无缝切换到下载流程

✅ 安全性保障

  1. 认证请求

    • 使用request工具发送请求
    • 自动携带Token认证头
    • 自动携带clientId等必需Header
  2. 权限检查

    • 检查OSS ID是否存在
    • 后端权限验证
    • 错误提示友好
  3. 资源管理

    • Blob URL自动清理
    • 防止内存泄漏
    • PDF预览60秒后清理

✅ 用户体验

  1. 操作便捷

    • 一键预览
    • 新窗口打开,不影响当前页面
    • 支持浏览器返回键
  2. 提示友好

    • 加载中提示
    • 成功/失败消息
    • 不支持预览时自动下载
  3. 界面美观

    • 按钮对齐整齐
    • 图标语义清晰
    • 样式统一协调

🧪 测试场景

测试用例1: PDF文件预览

  1. 上传PDF格式的党籍保留附件
  2. 在详情弹窗中点击"查看"按钮
  3. 预期结果: 在新标签页中打开PDF,可以正常查看

测试用例2: 图片文件预览

  1. 上传JPG/PNG格式的党籍保留附件
  2. 在详情弹窗中点击"查看"按钮
  3. 预期结果: 在新窗口中居中显示图片

测试用例3: 不支持的文件类型

  1. 上传DOC/DOCX等其他格式的文件
  2. 在详情弹窗中点击"查看"按钮
  3. 预期结果: 提示"该文件类型不支持在线预览,请下载后查看",并自动触发下载

测试用例4: 权限验证

  1. 使用没有权限的用户
  2. 尝试预览党籍保留附件
  3. 预期结果: 后端返回权限错误,前端显示错误提示

测试用例5: 文件不存在

  1. 删除OSS中的文件
  2. 尝试预览党籍保留附件
  3. 预期结果: 显示"预览文件失败"错误提示

📊 技术实现对比

与盖章文件的对比

特性 盖章文件 党籍保留附件
上传组件 el-upload el-upload
显示方式 上传列表 单个附件卡片
预览方式 组件内预览 新窗口预览
下载方式 OSS下载接口 OSS下载接口
权限控制 Token认证 Token认证

技术选型原因

  1. 新窗口预览 vs 弹窗预览

    • ✅ 不影响当前页面状态
    • ✅ 用户可以同时查看多个文件
    • ✅ 浏览器原生支持,兼容性好
    • ✅ 可以使用浏览器的打印、缩放等功能
  2. 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