yxh
2 天以前 596834ce4e233130d61888128fe66a0c008543dd
修改了报销校验
已修改3个文件
147 ■■■■■ 文件已修改
ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDocumentfilesController.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDocumentfilesController.java
@@ -1,5 +1,6 @@
package com.ruoyi.web.controller.project;
import java.io.File;
import java.util.Arrays;
import java.util.List;
@@ -23,8 +24,13 @@
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.project.domain.ServiceDocumentfiles;
import com.ruoyi.project.service.IServiceDocumentfilesService;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.framework.config.ServerConfig;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
/**
 * 捐献附件Controller
@@ -40,6 +46,72 @@
    @Autowired
    private IServiceDocumentfilesService serviceDocumentfilesService;
    @Autowired
    private ServerConfig serverConfig;
    /**
     * 政策文件上传(**不限文件类型**)。
     *
     * <p>2026-10-09 业务要求:政策文件模块允许上传/下载任意文件类型。
     *
     * <p>为什么不直接用 {@code /common/upload}:通用上传走
     * {@code FileUploadUtils.upload(baseDir, file)},会按 {@code MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION}
     * 白名单校验扩展名,非白名单类型(如 dwg、7z、ofd、eml 等)会被拒绝。
     * 这里把 allowedExtension 显式传 {@code null} —— {@code assertAllowed} 的判断是
     * {@code allowedExtension != null && !isAllowedExtension(...)},传 null 即跳过扩展名校验,
     * 同时**仍保留** 500MB 大小限制、文件名长度限制与存储路径安全处理。
     *
     * <p>仅政策文件模块使用本接口;{@code /common/upload} 与其他模块的白名单保持不变。
     *
     * @param file 上传文件
     * @return 与 {@code /common/upload} 一致的返回体(code/msg/fileName/url)
     */
    @ApiOperation("政策文件上传(不限文件类型)")
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file) {
        String originalFilename = file == null ? null : file.getOriginalFilename();
        try {
            if (file == null || file.isEmpty()) {
                return AjaxResult.error("上传文件为空,请重新选择文件");
            }
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 同名文件处理:加时间戳重命名,避免覆盖已上传文件(与通用上传保持一致)
            String filename = originalFilename == null ? "" : originalFilename.trim();
            String pathFileName = FileUploadUtils.extractFilename(file);
            File target = new File(filePath + "/" + pathFileName);
            if (target.exists()) {
                int i = filename.lastIndexOf(".");
                if (i > -1) {
                    String startStr = filename.substring(0, i);
                    String endStr = filename.substring(i);
                    String newFilename = startStr + System.currentTimeMillis() + endStr;
                    file = new MockMultipartFile(newFilename, newFilename, file.getContentType(), file.getBytes());
                }
            }
            // allowedExtension 传 null:不做扩展名校验,允许任意文件类型
            String relativePath = FileUploadUtils.upload(filePath, file, null);
            // 与通用上传一致的 url 处理(部分部署下 8032 需要带 /prod-api 前缀)
            String url = serverConfig.getUrl();
            if (url != null && url.contains("8032")) {
                url = url.replace("8032", "8032/prod-api");
            }
            log.info("政策文件上传成功:原始文件名={},存储路径={}", filename, relativePath);
            AjaxResult ajax = AjaxResult.success();
            ajax.put("fileName", relativePath);
            ajax.put("url", url + relativePath);
            return ajax;
        } catch (Exception e) {
            // 返回 AjaxResult(HTTP 200 + code=500),前端 uploadSccess 的 else 分支会把原因弹出来
            log.error("政策文件上传失败:原始文件名={}", originalFilename, e);
            return AjaxResult.error("上传失败:" + e.getMessage());
        }
    }
    /**
     * 查询捐献附件列表
     */
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java
@@ -609,8 +609,16 @@
            sysUsers = sysUserMapper.selectUserByUserName(user.getUserName());
            log.info("费用sysUsers返回的值为:{}", sysUsers);
        }
        if (checkFundVO.getFlowconclusion() == 1 && sysUsers != null && sysUsers.getRoles() != null && sysUsers.getRoles().stream().anyMatch(role -> "officedirector".equals(role.getRoleKey()))) {
            serviceFund.setOfficedirector(user.getNickName());
        // 2026-10-09:推送条件由"当前审核人有 officedirector 角色"改为"本次审批后到达最后一级"。
        // 原写法在"最后一级审核人没有该角色"时永远不会推送,而"非最后一级的 officedirector"会提前推送。
        boolean uploadAtLastLevel = checkFundVO.getFlowconclusion() == 1
                && TotalLevel != null && TotalLevel != 0 && TotalLevel == OriginalFlowLevel + 1;
        if (uploadAtLastLevel) {
            // 仍只在该角色审批时记录办公室主任,保持字段语义不变
            if (sysUsers != null && sysUsers.getRoles() != null
                    && sysUsers.getRoles().stream().anyMatch(role -> "officedirector".equals(role.getRoleKey()))) {
                serviceFund.setOfficedirector(user.getNickName());
            }
            serviceFund.setUploadStates(1);
            //数据发送
            Boolean aBoolean1 = null;
@@ -709,8 +717,12 @@
    }
    private Boolean doSendData(ServiceFund serviceFund) {
        // fund和funddetail的数据获取
        addFundSharedInfo(serviceFund.getId());
        // 2026-10-09:接住 addFundSharedInfo 的失败信号(附件上传失败时它会回滚分享表并返回 false)
        Boolean sharedOk = addFundSharedInfo(serviceFund.getId());
        if (sharedOk == null || !sharedOk) {
            log.error("费用报销单上传失败:分享表/附件环节失败,审批不生效,fundId={}", serviceFund.getId());
            return false;
        }
        List<ServiceFundShared> fundShareInfos = serviceFundSharedMapper.getFundShareInfoById(serviceFund.getId());
        if (CollectionUtils.isEmpty(fundShareInfos)) return false;
@@ -1011,11 +1023,10 @@
            try {
                if (isUploadOaEnabled()) uploadOAFileAndUpdateDb(serviceFunddetailShareds.get(i));
            } catch (Exception e) {
                e.printStackTrace();
                log.error("Exception中入参的ID为:{},异常信息为 : {}", id, e.getMessage());
                log.error("费用附件上传医院协友系统失败:单据id={}(本次报销单上传整体失败,审批不生效)", id, e);
                if (id != null) {
                    Boolean aBoolean = sharedService.delfundsharedInfoById(null, id);
                    log.error("fund2分享表里的数据是否删除成功:{}", aBoolean);
                    log.error("已回滚分享表数据:{}", aBoolean);
                }
                return false;
            }
@@ -1860,10 +1871,18 @@
                log.info("filePath的修改:{}", filePath);
                String url = rbDetailFile.getUrl();
                //file用的是绝对位置
                String substring = url.substring(url.indexOf("/profile/upload") + "/profile/upload".length());
                // 2026-10-09:附件地址解析加固,避免 url 异常/文件缺失时抛 NPE 导致看不到失败原因
                int profileIdx = url == null ? -1 : url.indexOf("/profile/upload");
                if (profileIdx < 0) {
                    throw new ServiceException("附件地址格式不正确(缺少 /profile/upload),无法上传协友:" + url);
                }
                String substring = url.substring(profileIdx + "/profile/upload".length());
//            String strFile = rbDetailFile.getUrl().replace(filePath, "/profile/upload");
                System.out.println("fund服务的filePath + substring: " + filePath + substring);
                File filetest = new File(filePath + substring);
                if (!filetest.exists()) {
                    throw new ServiceException("附件文件在服务器上不存在,无法上传协友:" + filetest.getAbsolutePath());
                }
                String struploadResult = HttpClientKit.sendPostWithFile(filetest, strFUrl);
                log.info("第三方传回的数据: {}", struploadResult);
ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceReimbursementServiceImpl.java
@@ -293,12 +293,12 @@
                //如果是本地环境,就不调这个了
                if (isUploadOaEnabled()) uploadOAFileAndUpdateDb(serviceReimbursementdetailShareds.get(i));
            } catch (Exception e) {
                log.error("Exception中reimShare的入参id为:{}", serviceReimbursementShared.getId());
                log.error("差旅附件上传医院协友系统失败:分享id={},明细={}(本次报销单上传整体失败,审批不生效)",
                        serviceReimbursementShared.getId(), serviceReimbursementdetailShareds.get(i), e);
                if (serviceReimbursementShared.getId() != null) {
                    Boolean aBoolean = sharedService.delResharedInfoById(serviceReimbursementShared.getId());
                    log.error("文件上传失败,将分享表数据回滚:{}", aBoolean);
                    log.error("已回滚分享表数据:{}", aBoolean);
                }
                e.getMessage();
                return false;
            }
@@ -543,8 +543,16 @@
                log.info("差旅sysUsers返回的值为:{}", sysUser);
            }
            if (checkFundVO.getFlowconclusion() == 1 && Objects.nonNull(sysUser) && sysUser.getRoles() != null && sysUser.getRoles().stream().anyMatch(role -> "officedirector".equals(role.getRoleKey()))) {
                serviceReimbursement.setOfficedirector(user.getNickName());
            // 2026-10-09:推送条件由"当前审核人有 officedirector 角色"改为"本次审批后到达最后一级"。
            // 原写法在"最后一级审核人没有该角色"时永远不会推送,而"非最后一级的 officedirector"会提前推送。
            boolean uploadAtLastLevel = checkFundVO.getFlowconclusion() == 1
                    && totalLevel != null && totalLevel != 0 && totalLevel == OriginalFlowLevel + 1;
            if (uploadAtLastLevel) {
                // 仍只在该角色审批时记录办公室主任,保持字段语义不变
                if (Objects.nonNull(sysUser) && sysUser.getRoles() != null
                        && sysUser.getRoles().stream().anyMatch(role -> "officedirector".equals(role.getRoleKey()))) {
                    serviceReimbursement.setOfficedirector(user.getNickName());
                }
                serviceReimbursement.setUploadStates(1);
                Boolean aBoolean1 = null;
@@ -648,9 +656,17 @@
    private Boolean doSendData(ServiceReimbursement serviceReimbursement) {
        // fund和funddetail的数据获取
        addSharedData(serviceReimbursement.getId());
        // 2026-10-09:接住 addSharedData 的失败信号(附件上传失败时它会回滚分享表并返回 false)
        Boolean sharedOk = addSharedData(serviceReimbursement.getId());
        if (sharedOk == null || !sharedOk) {
            log.error("差旅报销单上传失败:分享表/附件环节失败,审批不生效,id={}", serviceReimbursement.getId());
            return false;
        }
        List<ServiceReimbursementShared> serviceReimbursementSharedList = sharedService.getRemShareInfoByRemId(serviceReimbursement.getId());
        if (org.springframework.util.CollectionUtils.isEmpty(serviceReimbursementSharedList)) return false;
        if (org.springframework.util.CollectionUtils.isEmpty(serviceReimbursementSharedList)) {
            log.error("差旅报销单上传失败:分享表为空(附件或组装环节异常),审批不生效,id={}", serviceReimbursement.getId());
            return false;
        }
        log.info("serviceReimbursementSharedList的数据量为:{}", serviceReimbursementSharedList.size());
        //detail详情
@@ -974,9 +990,17 @@
                log.info("filePath的修改:{}", filePath);
                String url = rbDetailFile.getUrl();
                //file用的是绝对位置
                String fileName = url.substring(url.indexOf("/profile/upload") + "/profile/upload".length());
                // 2026-10-09:附件地址解析加固,避免 url 异常/文件缺失时抛 NPE 导致看不到失败原因
                int profileIdx = url == null ? -1 : url.indexOf("/profile/upload");
                if (profileIdx < 0) {
                    throw new ServiceException("附件地址格式不正确(缺少 /profile/upload),无法上传协友:" + url);
                }
                String fileName = url.substring(profileIdx + "/profile/upload".length());
                String strFile = rbDetailFile.getUrl().replace(filePath, "/profile/upload");
                File fileUpload = new File(filePath + fileName);
                if (!fileUpload.exists()) {
                    throw new ServiceException("附件文件在服务器上不存在,无法上传协友:" + fileUpload.getAbsolutePath());
                }
                log.info("请求第三方的入参strFile : {}, strFUrl : {}", strFile, filePath);
                String struploadResult = HttpClientKit.sendPostWithFile(fileUpload, strFUrl);
                log.info("第三方传回的数据: {}", struploadResult);