Files
hzdyjs/出国申请附件下载问题分析与修复方案.md
T
2025-10-14 16:41:19 +08:00

10 KiB
Raw Blame History

出国申请附件下载问题分析与修复方案

🔍 问题描述

现象:

  • ✅ ID 37 的申请可以正常下载盖章附件
  • ❌ ID 39 的申请点击下载提示"文件OSS ID不存在"
  • 新增申请上传的附件都无法下载

📊 问题根因分析

1. 数据库对比

请在数据库中执行以下SQL查询:

-- 查询ID 37和ID 39的关键字段对比
SELECT 
    application_id AS '申请ID',
    applicant_name AS '申请人',
    stamped_registration_file_name AS '盖章文件名',
    stamped_file_oss_id AS '盖章OSS_ID',
    DATE_FORMAT(stamped_file_upload_time, '%Y-%m-%d %H:%i:%s') AS '上传时间',
    CASE 
        WHEN stamped_file_oss_id IS NOT NULL THEN '✅ 正常'
        ELSE '❌ 缺失OSS_ID'
    END AS '状态'
FROM rs_overseas_application
WHERE application_id IN (37, 38, 39) AND deleted = 0
ORDER BY application_id;

预期结果:

申请ID 盖章文件名 盖章OSS_ID 状态
37 xxx.pdf 197xxxxxxxxx ✅ 正常
38 xxx.pdf NULL ❌ 缺失OSS_ID
39 xxx.pdf NULL ❌ 缺失OSS_ID

2. 根本原因

问题代码位置:web/src/views/rs/overseas/index.vue 第727行

<el-upload
  :action="uploadStampedFileAction"
  :data="{ applicationId: applicationForm.applicationId || 0 }"
  ...
>

问题分析:

  1. 用户点击"新增申请"→ applicationForm是空对象,applicationId为undefined
  2. 用户上传盖章文件 → 传递applicationId=0给后端
  3. 后端updateStampedFileInfo方法无法找到applicationId=0的记录
  4. OSS文件虽然上传成功,但stamped_file_oss_id字段未更新
  5. 点击下载时检查OSS_ID为NULL,提示"文件OSS ID不存在"

为什么ID 37可以下载?

ID 37可能是通过以下方式创建的:

  • 先点击"新增"并填写表单
  • 点击"确定"保存申请(此时获得了applicationId)
  • 再次点击"编辑"
  • 上传盖章文件(此时applicationId已经存在)

✅ 修复方案

方案1:修改前端上传逻辑(推荐)

思路

在用户上传文件前,先自动保存申请记录(草稿状态),获得applicationId,然后再上传文件。

具体步骤

步骤1:修改后端add接口,返回新创建的ID

文件:backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasApplicationController.java

找到第184行的add方法,修改返回类型:

// 修改前
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody RsOverseasApplicationBo bo) {
    // ... 现有逻辑 ...
    return toAjax(applicationService.insertByBo(bo));
}

// 修改后
@PostMapping
public R<Map<String, Object>> add(@Validated(AddGroup.class) @RequestBody RsOverseasApplicationBo bo) {
    // ... 现有逻辑 ...
    boolean result = applicationService.insertByBo(bo);
    if (result) {
        // 返回新创建的applicationId
        Map<String, Object> data = new HashMap<>();
        data.put("applicationId", bo.getApplicationId());
        return R.ok("操作成功", data);
    } else {
        return R.fail("新增失败");
    }
}
步骤2:修改前端上传前的钩子函数

文件:web/src/views/rs/overseas/index.vue

找到beforeStampedFileUpload方法(约2220行),修改如下:

// 上传前的验证
const beforeStampedFileUpload = async (file: File) => {
  // 检查文件格式
  const validTypes = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png'];
  if (!validTypes.includes(file.type)) {
    ElMessage.error('只支持PDF、JPG、PNG格式的文件');
    return false;
  }
  
  // 检查文件大小(10MB)
  const maxSize = 10 * 1024 * 1024;
  if (file.size > maxSize) {
    ElMessage.error('文件大小不能超过10MB');
    return false;
  }
  
  // 🔴 关键修复:如果是新增模式(没有applicationId),先保存申请记录
  if (!state.applicationForm.applicationId) {
    try {
      ElMessage.info('正在保存申请记录...');
      
      // 执行必要的字段映射
      if (state.applicationForm.startDate) {
        state.applicationForm.startDate = dayjs(state.applicationForm.startDate).format('YYYY-MM-DD');
      }
      if (state.applicationForm.endDate) {
        state.applicationForm.endDate = dayjs(state.applicationForm.endDate).format('YYYY-MM-DD');
      }
      if (state.applicationForm.birthDate) {
        state.applicationForm.birthDate = dayjs(state.applicationForm.birthDate).format('YYYY-MM-DD');
      }
      
      // 保存申请记录(草稿状态)
      const response = await addOverseasApplication(state.applicationForm);
      
      // 🔴 重要:从响应中获取新创建的applicationId
      if (response.data && response.data.applicationId) {
        state.applicationForm.applicationId = response.data.applicationId;
        ElMessage.success('申请记录已保存,现在可以上传盖章文件了');
      } else {
        ElMessage.error('保存申请记录失败,无法获取申请ID');
        return false;
      }
      
      return true;
    } catch (error) {
      console.error('保存申请记录失败:', error);
      ElMessage.error('保存申请记录失败,请先手动保存');
      return false;
    }
  }
  
  return true;
};
步骤3:(可选)使用computed动态获取applicationId

如果上面的修改不生效,可以将:data改为计算属性:

找到第727行,修改如下:

<!-- 修改前 -->
:data="{ applicationId: applicationForm.applicationId || 0 }"

<!-- 修改后 -->
:data="uploadStampedFileData"

然后在script中添加计算属性(约1430行附近):

// 上传盖章文件的data参数
const uploadStampedFileData = computed(() => {
  return {
    applicationId: state.applicationForm.applicationId || 0
  };
});

方案2:临时修复数据库(快速解决ID 39的问题)

步骤1:查找ID 39对应的OSS文件

-- 查询sys_oss表中ID 39上传的文件
SELECT 
    oss_id,
    file_name,
    original_name,
    url,
    DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') AS create_time
FROM sys_oss
WHERE DATE(create_time) = CURDATE()  -- 今天上传的
  AND original_name LIKE '%pdf%'  -- PDF文件
ORDER BY create_time DESC
LIMIT 10;

步骤2:手动更新rs_overseas_application表

找到ID 39对应的oss_id后,执行:

-- 假设找到的oss_id是 1976886772986052610
UPDATE rs_overseas_application 
SET stamped_file_oss_id = 1976886772986052610
WHERE application_id = 39 AND deleted = 0;

-- 验证更新
SELECT 
    application_id,
    stamped_file_oss_id,
    stamped_registration_file_name
FROM rs_overseas_application
WHERE application_id = 39 AND deleted = 0;

步骤3:刷新前端页面测试

Cmd + Shift + R (macOS)
Ctrl + F5 (Windows)

🧪 测试步骤

1. 测试新增申请流程

  1. 进入出国申请管理

  2. 点击"新增"按钮

  3. 填写必填字段:

    • 政治面貌:选择任意值
    • 出国开始日期:2025-11-01
    • 出国结束日期:2025-11-10
    • 紧急联系人:张三 13800138000
    • 目的国家:美国
  4. 上传盖章文件(不要先点击确定):

    • 选择一个PDF文件
    • 观察是否出现"正在保存申请记录..."提示
    • 观察是否上传成功
  5. 点击"确定"提交申请

  6. 进入"我的申请",找到刚才新增的记录

  7. 点击"查看详情"

  8. 点击下载盖章文件

    • ✅ 预期:文件可以正常下载
    • ❌ 如果失败:查看控制台错误信息

2. 验证数据库

-- 查询最新的申请记录
SELECT 
    application_id,
    applicant_name,
    stamped_registration_file_name,
    stamped_file_oss_id,
    CASE 
        WHEN stamped_file_oss_id IS NOT NULL THEN '✅ 正常'
        ELSE '❌ 异常'
    END AS status
FROM rs_overseas_application
WHERE deleted = 0
ORDER BY application_id DESC
LIMIT 5;

预期:新增的记录中stamped_file_oss_id字段不为NULL。


📋 修复检查清单

后端修改

  • 修改RsOverseasApplicationController.add方法返回类型
  • 返回applicationId字段
  • 重启后端服务

前端修改

  • 修改beforeStampedFileUpload方法
  • 添加自动保存申请记录的逻辑
  • (可选)添加uploadStampedFileData计算属性
  • 刷新前端页面(Cmd+Shift+R)

数据库修复

  • 查询ID 39对应的OSS文件ID
  • 更新rs_overseas_application表的stamped_file_oss_id字段
  • 验证更新结果

功能测试

  • 测试新增申请并上传附件
  • 验证可以正常下载
  • 检查数据库OSS_ID字段是否正常保存

💡 为什么这样修复?

问题本质

El-upload组件的auto-upload模式下,文件选择后立即上传,此时表单可能还未保存,applicationId不存在。

解决思路

  1. 在上传前拦截:使用before-upload钩子
  2. 自动保存表单:如果没有ID,先调用新增接口
  3. 获取真实ID:从响应中提取applicationId
  4. 继续上传:使用真实ID作为参数

技术要点

  • before-upload钩子可以返回Promise<boolean>,用于异步验证
  • 新增接口需要返回applicationId供后续使用
  • 使用computed包装:data,确保响应式更新

🔧 如果修复后仍然失败

调试步骤

  1. 检查后端日志

    IDEA控制台查看是否有错误信息
    
  2. 检查前端Console

    // 在beforeStampedFileUpload方法中添加
    console.log('当前applicationId:', state.applicationForm.applicationId);
    
  3. 检查Network请求

    F12 → Network → 找到uploadStampedFile请求
    查看Payload中的applicationId是否为0
    
  4. 检查数据库

    -- 查看最新记录
    SELECT * FROM rs_overseas_application 
    WHERE deleted = 0 
    ORDER BY application_id DESC 
    LIMIT 1;
    

📞 需要帮助?

如果按照以上步骤修复后仍然有问题,请提供:

  1. 后端控制台的完整日志
  2. 前端Console的错误信息
  3. Network面板的uploadStampedFile请求详情
  4. 数据库查询结果截图

创建时间:2025-10-11
问题优先级:🔴 高
预计修复时间:30分钟

建议修复顺序:

  1. 先执行方案2(临时修复数据库),立即解决ID 39的问题
  2. 再执行方案1(修改代码),解决根本问题
  3. 最后进行完整测试