yxh
昨天 8c215c8be0f5076e8c95daf1b2203440ca7dfcad
ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceReimbursementdetailController.java
@@ -102,6 +102,21 @@
    @PostMapping("/add")
    @RepeatSubmit
    public AjaxResult add(@RequestBody ServiceReimbursementdetailVO serviceReimbursementdetailVO) {
        // 2026-10-15:附件文件名规范二次校验(与前端 opo-web/src/utils/fileNameCheck.js 同口径,
        // 目的是防止绕过前端直接调接口保存不合规附件名)。新增场景没有历史附件,用严格模式。
        // 注意:List 为空时必须回退校验字符串字段(annexfiles / invoicefiles),
        // 否则只传字符串字段就能绕过校验(接口层面的绕过口)。
        String invoiceJson = CollectionUtils.isEmpty(serviceReimbursementdetailVO.getInvoicefilesList())
                ? serviceReimbursementdetailVO.getInvoicefiles()
                : JSON.toJSONString(serviceReimbursementdetailVO.getInvoicefilesList());
        String annexJson = CollectionUtils.isEmpty(serviceReimbursementdetailVO.getAnnexfilesList())
                ? serviceReimbursementdetailVO.getAnnexfiles()
                : JSON.toJSONString(serviceReimbursementdetailVO.getAnnexfilesList());
        String nameError = com.ruoyi.project.common.AttachmentNameValidator
                .checkJsonList(invoiceJson, annexJson);
        if (nameError != null) {
            return AjaxResult.error("附件文件名不符合要求,无法保存:" + nameError);
        }
        ServiceReimbursementdetail serviceReimbursementdetail = DtoConversionUtils.sourceToTarget(serviceReimbursementdetailVO, ServiceReimbursementdetail.class);
        //将前端传来的附件集合转成字符串
        if (!CollectionUtils.isEmpty(serviceReimbursementdetailVO.getAnnexfilesList())) {
@@ -123,6 +138,24 @@
    @PostMapping("/updateRDlList")
    public AjaxResult updateRDlList(@RequestBody List<ServiceReimbursementdetail> serviceReimbursementdetails) {
        for (ServiceReimbursementdetail serviceReimbursementdetail : serviceReimbursementdetails) {
            // 2026-10-15:附件文件名规范二次校验(只校验本次变更的附件,历史附件放行)
            java.util.Set<String> existingNames = new java.util.HashSet<>();
            if (serviceReimbursementdetail.getId() != null) {
                ServiceReimbursementdetail oldDetail = serviceReimbursementdetailService
                        .getById(serviceReimbursementdetail.getId());
                if (oldDetail != null) {
                    existingNames.addAll(com.ruoyi.project.common.AttachmentNameValidator
                            .collectNames(oldDetail.getInvoicefiles()));
                    existingNames.addAll(com.ruoyi.project.common.AttachmentNameValidator
                            .collectNames(oldDetail.getAnnexfiles()));
                }
            }
            String nameError = com.ruoyi.project.common.AttachmentNameValidator.checkJsonListForUpdate(
                    existingNames, serviceReimbursementdetail.getInvoicefiles(),
                    serviceReimbursementdetail.getAnnexfiles());
            if (nameError != null) {
                return AjaxResult.error("附件文件名不符合要求,无法保存:" + nameError);
            }
            serviceReimbursementdetailService.saveOrUpdate(serviceReimbursementdetail);
        }
@@ -138,6 +171,31 @@
    @PostMapping("/reimbursementdetailEdit")
    //@RepeatSubmit
    public AjaxResult edit(@RequestBody ServiceReimbursementdetailVO serviceReimbursementdetailVO) {
        // 2026-10-15:附件文件名规范二次校验(与前端 fileNameCheck 同口径,防止绕过前端)。
        // 修改场景按业务口径"只校验本次变更的附件":保存前已存在的历史附件名不参与校验,避免卡住老单据。
        java.util.Set<String> existingNames = new java.util.HashSet<>();
        if (serviceReimbursementdetailVO.getId() != null) {
            ServiceReimbursementdetail oldDetail = serviceReimbursementdetailService
                    .getById(serviceReimbursementdetailVO.getId());
            if (oldDetail != null) {
                existingNames.addAll(com.ruoyi.project.common.AttachmentNameValidator
                        .collectNames(oldDetail.getInvoicefiles()));
                existingNames.addAll(com.ruoyi.project.common.AttachmentNameValidator
                        .collectNames(oldDetail.getAnnexfiles()));
            }
        }
        // List 为空时回退校验字符串字段(annexfiles / invoicefiles),堵住"只传字符串字段"的绕过口
        String invoiceJson = CollectionUtils.isEmpty(serviceReimbursementdetailVO.getInvoicefilesList())
                ? serviceReimbursementdetailVO.getInvoicefiles()
                : JSON.toJSONString(serviceReimbursementdetailVO.getInvoicefilesList());
        String annexJson = CollectionUtils.isEmpty(serviceReimbursementdetailVO.getAnnexfilesList())
                ? serviceReimbursementdetailVO.getAnnexfiles()
                : JSON.toJSONString(serviceReimbursementdetailVO.getAnnexfilesList());
        String nameError = com.ruoyi.project.common.AttachmentNameValidator
                .checkJsonListForUpdate(existingNames, invoiceJson, annexJson);
        if (nameError != null) {
            return AjaxResult.error("附件文件名不符合要求,无法保存:" + nameError);
        }
        if (serviceReimbursementdetailVO.getTrafficexpense() == null) {
            serviceReimbursementdetailVO.setTrafficexpense(new BigDecimal(0));
        }