ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecompletioninfoController.java
@@ -179,6 +179,11 @@ @Log(title = "捐献完成", businessType = BusinessType.UPDATE) @PostMapping("/edit") public AjaxResult edit(@RequestBody ServiceDonatecompletioninfo serviceDonatecompletioninfo) { // 优先按主键更新(前端已回填 id 的常规路径) if (serviceDonatecompletioninfo.getId() != null) { return toAjax(serviceDonatecompletioninfoService.updateById(serviceDonatecompletioninfo)); } // 兼容未传 id 的旧调用:按 infoid 定位未删除记录 ServiceDonatecompletioninfo serviceDonatecompletioninfo1 = new ServiceDonatecompletioninfo(); serviceDonatecompletioninfo1.setInfoid(serviceDonatecompletioninfo.getInfoid()); List<ServiceDonatecompletioninfo> list = serviceDonatecompletioninfoService.queryList(serviceDonatecompletioninfo1); ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonatecomporganController.java
@@ -178,6 +178,7 @@ } } } return toAjax(i); // 回传带主键的列表,便于前端回填 id return AjaxResult.success(serviceDonatecomporganList); } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonateorganController.java
@@ -297,13 +297,23 @@ Boolean i = null; for (ServiceDonateorgan serviceDonateorgan : serviceDonateorganList) { log.info("捐献器官移植id是否为空 : {},基础表的id为 : {}", serviceDonateorgan.getId(), serviceDonateorgan.getInfoid()); // 2026-10-22:同一案例、同一器官只保留一条未删除记录——已存在则更新,避免重复插入 ServiceDonateorgan query = new ServiceDonateorgan(); query.setInfoid(serviceDonateorgan.getInfoid()); query.setOrganno(serviceDonateorgan.getOrganno()); query.setDel_flag(0); List<ServiceDonateorgan> exist = serviceDonateorganService.queryList(query); if (!CollectionUtils.isEmpty(exist)) { serviceDonateorgan.setId(exist.get(0).getId()); } if (serviceDonateorgan.getId() == null) { i = serviceDonateorganService.save(serviceDonateorgan); } else { i = serviceDonateorganService.updateById(serviceDonateorgan); } } return toAjax(i); // 回传带主键的列表,便于前端回填 id return AjaxResult.success(serviceDonateorganList); } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceDonationwitnessorganController.java
@@ -134,6 +134,7 @@ i = serviceDonationwitnessorganService.updateById(serviceDonationwitnessorgan); } } return toAjax(i); // 回传带主键的列表,便于前端回填 id return AjaxResult.success(serviceDonationwitnessorganList); } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceEthicalreviewopinionsController.java
@@ -74,10 +74,21 @@ */ //// @PreAuthorize("@ss.hasPermi('project:ethicalreviewopinions:add')") @Log(title = "伦理审查专家意见", businessType = BusinessType.INSERT) @RepeatSubmit @PostMapping("/add") // @NotRepeatCommit(key = "param:arg[1]", value = 30000) public AjaxResult add(@RequestBody ServiceEthicalreviewopinions serviceEthicalreviewopinions) { boolean save = serviceEthicalreviewopinionsService.save(serviceEthicalreviewopinions); // 2026-10-22:同一案例只允许一条未删除记录——已存在则更新,避免反复保存产生重复行 if (serviceEthicalreviewopinions.getInfoid() != null) { ServiceEthicalreviewopinions query = new ServiceEthicalreviewopinions(); query.setInfoid(serviceEthicalreviewopinions.getInfoid()); List<ServiceEthicalreviewopinions> exist = serviceEthicalreviewopinionsService.queryList(query); if (exist != null && !exist.isEmpty()) { serviceEthicalreviewopinions.setId(exist.get(0).getId()); serviceEthicalreviewopinionsService.updateById(serviceEthicalreviewopinions); return AjaxResult.success(serviceEthicalreviewopinions); } } serviceEthicalreviewopinionsService.save(serviceEthicalreviewopinions); return AjaxResult.success(serviceEthicalreviewopinions); } @@ -87,7 +98,7 @@ //// @PreAuthorize("@ss.hasPermi('project:ethicalreviewopinions:edit')") @Log(title = "伦理审查专家意见", businessType = BusinessType.UPDATE) @PostMapping("/edit") // @RepeatSubmit @RepeatSubmit public AjaxResult edit(@RequestBody ServiceEthicalreviewopinions serviceEthicalreviewopinions) { return toAjax(serviceEthicalreviewopinionsService.updateById(serviceEthicalreviewopinions)); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceFunddetailController.java
@@ -87,6 +87,13 @@ @PostMapping("/add") @NotRepeatCommit(key = "param:arg[1]", value = 30000) public AjaxResult add(@RequestBody ServiceFunddetail serviceFunddetail) { // 2026-10-15:附件文件名规范二次校验(与前端 opo-web/src/utils/fileNameCheck.js 同口径, // 目的是防止绕过前端直接调接口保存不合规附件名)。新增场景没有历史附件,用严格模式。 String nameError = com.ruoyi.project.common.AttachmentNameValidator .checkJsonList(serviceFunddetail.getInvoicefiles(), serviceFunddetail.getAnnexfiles()); if (nameError != null) { return AjaxResult.error("附件文件名不符合要求,无法保存:" + nameError); } boolean save = serviceFunddetailService.save(serviceFunddetail); return AjaxResult.success(serviceFunddetail); } @@ -101,6 +108,24 @@ @NotRepeatCommit(key = "param:arg[1]", value = 30000) public AjaxResult edit(@RequestBody ServiceFunddetail serviceFunddetail) { log.info("修改的数据信息:{}", serviceFunddetail); // 2026-10-15:附件文件名规范二次校验。修改场景按业务口径"只校验本次变更的附件": // 保存前该明细已存在的历史附件名不参与校验,否则老单据(历史不合规名占比很高)改个金额都存不进去。 java.util.Set<String> existingNames = new java.util.HashSet<>(); if (serviceFunddetail.getId() != null) { ServiceFunddetail oldDetail = serviceFunddetailService.getById(serviceFunddetail.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, serviceFunddetail.getInvoicefiles(), serviceFunddetail.getAnnexfiles()); if (nameError != null) { return AjaxResult.error("附件文件名不符合要求,无法保存:" + nameError); } return toAjax(serviceFunddetailService.updateById(serviceFunddetail)); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceMedicalevaluationController.java
@@ -128,10 +128,21 @@ @ApiOperation("新增医学评估") //// @PreAuthorize("@ss.hasPermi('project:medicalevaluation:add')") @Log(title = "医学评估", businessType = BusinessType.INSERT) @RepeatSubmit @PostMapping("/add") // @NotRepeatCommit(key = "param:arg[1]", value = 30000) public AjaxResult add(@RequestBody ServiceMedicalevaluation serviceMedicalevaluation) { boolean save = serviceMedicalevaluationService.save(serviceMedicalevaluation); // 2026-10-22:同一案例只允许一条未删除记录——已存在则更新,避免反复保存产生重复行 if (serviceMedicalevaluation.getInfoid() != null) { ServiceMedicalevaluation query = new ServiceMedicalevaluation(); query.setInfoid(serviceMedicalevaluation.getInfoid()); List<ServiceMedicalevaluation> exist = serviceMedicalevaluationService.queryList(query); if (exist != null && !exist.isEmpty()) { serviceMedicalevaluation.setId(exist.get(0).getId()); serviceMedicalevaluationService.updateById(serviceMedicalevaluation); return AjaxResult.success(serviceMedicalevaluation); } } serviceMedicalevaluationService.save(serviceMedicalevaluation); return AjaxResult.success(serviceMedicalevaluation); } @@ -141,9 +152,14 @@ @ApiOperation("修改医学评估") //// @PreAuthorize("@ss.hasPermi('project:medicalevaluation:edit')") @Log(title = "医学评估", businessType = BusinessType.UPDATE) @RepeatSubmit @PostMapping("/edit") // @NotRepeatCommit(key = "param:arg[1]", value = 30000) public AjaxResult edit(@RequestBody ServiceMedicalevaluation serviceMedicalevaluation) { // 优先按主键更新(前端已回填 id 的常规路径) if (serviceMedicalevaluation.getId() != null) { return toAjax(serviceMedicalevaluationService.updateById(serviceMedicalevaluation)); } // 兼容未传 id 的旧调用:按 infoid 定位未删除记录 List<ServiceMedicalevaluation> list = serviceMedicalevaluationService.queryList(serviceMedicalevaluation); if (CollectionUtils.isEmpty(list)) { return error("医学评估数据不存在,请检查后再次修改"); 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)); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/project/ServiceRelativesconfirmationController.java
@@ -122,7 +122,18 @@ @RepeatSubmit public AjaxResult add(@RequestBody ServiceRelativesconfirmation serviceRelativesconfirmation) { log.info("新增捐献亲属确认:{}", serviceRelativesconfirmation); boolean save = serviceRelativesconfirmationService.save(serviceRelativesconfirmation); // 2026-10-22:同一案例只允许一条未删除记录——已存在则更新,避免反复保存产生重复行 if (serviceRelativesconfirmation.getInfoid() != null) { ServiceRelativesconfirmation query = new ServiceRelativesconfirmation(); query.setInfoid(serviceRelativesconfirmation.getInfoid()); List<ServiceRelativesconfirmation> exist = serviceRelativesconfirmationService.queryList(query); if (exist != null && !exist.isEmpty()) { serviceRelativesconfirmation.setId(exist.get(0).getId()); serviceRelativesconfirmationService.updateById(serviceRelativesconfirmation); return AjaxResult.success(serviceRelativesconfirmation); } } serviceRelativesconfirmationService.save(serviceRelativesconfirmation); return AjaxResult.success(serviceRelativesconfirmation); } ruoyi-project/src/main/java/com/ruoyi/project/domain/BaseItemexpense.java
@@ -47,5 +47,13 @@ @Excel(name = "启用状态") private String usestate; /** * 专家费校验模式:1=强制校验(金额类问题不通过则不能保存);2=校验提醒(金额类问题仅提醒,允许保存);3=不校验(跳过金额类规则)。 * 数据质量类规则(金额为 0、未填写费用说明)在三种模式下都强制。 */ @ApiModelProperty("专家费校验模式:1=强制校验 2=校验提醒 3=不校验") @Excel(name = "校验模式") private Integer validateMode; } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ExpertFeeValidateService.java
@@ -305,6 +305,65 @@ } log.info("[专家费校验] 参与校验明细 {} 条:{}", rows.size(), describeRows(rows)); // 2026-10-15:按"费用项目"的校验模式(base_itemexpense.validate_mode)拆分明细后分别校验 // 1=强制校验:金额类问题 → 阻断(error) // 2=校验提醒:金额类问题 → 仅提醒(warning),允许保存 // 3=不校验 :跳过该项目全部金额类规则 // 说明:金额类规则全部按项目 id 判定,同一项目的明细才会互相产生合计类问题, // 因此按项目拆分不会影响各规则内部逻辑;含跨项目比较的规则(如评估冲突) // 在双方都是强制模式时仍然一起参与,行为不变。 List<DetailRow> forcedRows = new ArrayList<>(); List<DetailRow> remindRows = new ArrayList<>(); List<DetailRow> skippedRows = new ArrayList<>(); for (DetailRow row : rows) { int mode = loadItemMode(row.getItemid()); if (mode == MODE_SKIP) { skippedRows.add(row); } else if (mode == MODE_REMIND) { remindRows.add(row); } else { forcedRows.add(row); } } log.info("[专家费校验] 校验模式统计:强制={} 提醒={} 不校验={}", forcedRows.size(), remindRows.size(), skippedRows.size()); // 1) 强制校验:正常阻断 runAmountRules(forcedRows, result); // 2) 校验提醒:同样跑一遍,但把结果降级为提醒(不阻断) if (!remindRows.isEmpty()) { ExpertFeeCheckResult remindResult = new ExpertFeeCheckResult(); runAmountRules(remindRows, remindResult); for (String error : remindResult.getErrors()) { // 业务方确认的提醒文案:金额类问题在「校验提醒」模式下不阻断,仅提示后可继续保存 result.addWarning("该费用项存在超标准情况,仅作提醒,是否继续保存?【" + error + "】"); } if (!remindResult.getErrors().isEmpty()) { log.info("[专家费校验] 以下明细所属项目为「校验提醒」模式,仅提醒不阻断:{}", describeRows(remindRows)); } } // 3) 不校验:跳过金额类规则,仅记录日志,便于事后回溯 if (!skippedRows.isEmpty()) { log.info("[专家费校验] 以下明细所属项目为「不校验」模式,已跳过金额类规则:{}", describeRows(skippedRows)); } // 4) 数据质量类规则(金额为 0、未填写费用说明)在三种模式下都强制: // 对未参与强制校验的明细单独跑一次"只查数据质量"的检查,避免出现金额为空的脏数据 checkItemStandard(remindRows, result, false); checkItemStandard(skippedRows, result, false); log.info("[专家费校验] 校验完成 阻断={} 提示={} 阻断信息={} 提示信息={}", result.getErrors().size(), result.getWarnings().size(), result.getErrors(), result.getWarnings()); return result; } /** * 金额类规则(受"校验模式"影响):合计限额、ECOM、助手、手术室、评估冲突、费用标准、器官获取加成。 */ private void runAmountRules(List<DetailRow> rows, ExpertFeeCheckResult result) { // 规则 1~4、7~9:合计限额类(阻断),全部按项目 id 判定 checkSingleItemLimit(rows, resolveItemIds(CFG_ITEM_ORGAN_MAINTAIN, "捐献医院器官功能维护费", FALLBACK_ORGAN_MAINTAIN), false, @@ -321,13 +380,8 @@ // 规则 5:仅提示;基本规则与器官获取加成:硬拦截 checkAssessConflict(rows, result); checkItemStandard(rows, result); checkItemStandard(rows, result, true); checkDoctorOrganSecond(rows, result); log.info("[专家费校验] 校验完成 阻断={} 提示={} 阻断信息={} 提示信息={}", result.getErrors().size(), result.getWarnings().size(), result.getErrors(), result.getWarnings()); return result; } /** 把参与校验的明细拼成一行,便于排查「为什么没拦住」(金额、项目、场景一目了然) */ @@ -626,6 +680,18 @@ * 若拿税前金额(含税加价后的值)去比,会把大量正常单据误判为超标准(实测 3168 组 vs 162 组)。 */ private void checkItemStandard(List<DetailRow> rows, ExpertFeeCheckResult result) { checkItemStandard(rows, result, true); } /** * 费用标准校验。 * * @param amountCheck {@code true}=完整校验(含金额类规则,受项目校验模式影响); * {@code false}=只查数据质量(金额为 0、未填写费用说明), * 用于「校验提醒 / 不校验」模式下对未参与强制校验的明细做兜底强制, * 避免出现金额为空的脏数据。 */ private void checkItemStandard(List<DetailRow> rows, ExpertFeeCheckResult result, boolean amountCheck) { Map<String, List<DetailRow>> groups = new LinkedHashMap<>(); Map<String, BigDecimal> groupStandards = new LinkedHashMap<>(); Map<String, String> groupLabels = new LinkedHashMap<>(); @@ -644,9 +710,17 @@ } BigDecimal standard = loadItemStandard(row.getItemid(), scope); if (standard == null) { if (!amountCheck) { // 「未找到费用标准」属金额类问题,按项目校验模式处理 continue; } result.addError(String.format( "%s未找到对应的费用标准(项目id=%s,费用说明=%s),不允许报销,请联系管理员维护费用标准", itemLabel(row), row.getItemid(), scope)); continue; } if (!amountCheck) { // 只查数据质量:不再做费用标准比较与重复录入提醒 continue; } String key = groupKey(row, scope); @@ -765,6 +839,64 @@ * * @return 找不到时返回 {@code null},调用方按「匹配不到标准」阻断 */ /** 校验模式:强制校验(金额类问题不通过则不能保存) */ private static final int MODE_FORCE = 1; /** 校验模式:校验提醒(金额类问题仅提醒,允许保存) */ private static final int MODE_REMIND = 2; /** 校验模式:不校验(跳过该项目的金额类规则) */ private static final int MODE_SKIP = 3; /** 项目校验模式缓存(60 秒),key = itemid */ private final Map<Long, Integer> itemModeCache = new java.util.concurrent.ConcurrentHashMap<>(); private final Map<Long, Long> itemModeExpireCache = new java.util.concurrent.ConcurrentHashMap<>(); /** * 读取费用项目的校验模式({@code base_itemexpense.validate_mode}),缓存 60 秒。 * * <p>读不到、取值非法或查询异常时**一律按「强制校验」处理**, * 保证不会因为开关读不到而放松校验(宁可多拦,不可漏拦)。 */ private int loadItemMode(Long itemid) { if (itemid == null) { return MODE_FORCE; } long now = System.currentTimeMillis(); Integer cached = itemModeCache.get(itemid); Long expireAt = itemModeExpireCache.get(itemid); if (cached != null && expireAt != null && expireAt > now) { return cached; } int mode = MODE_FORCE; try { // 2026-10-15(修复):不能用 wrapper.select("ValidateMode") + selectMaps 取这一列,两处都会让模式取不到: // ① 字符串列名会被 MyBatis-Plus 原样拼进 SELECT,而真实列名是 validate_mode, // MySQL 直接报 Unknown column 'ValidateMode',异常被下面的 catch 吞掉后永远回落「强制校验」; // ② 即使把列名改成 validate_mode,selectMaps 返回的 Map key 也是原始列标签(validate_mode, // 不会转成驼峰),与 "validatemode" 匹配不上,模式依然取不到。 // 改为与同类 loadItemStandards 一致的实体映射写法(经实体字段 validateMode 映射到列 validate_mode)。 QueryWrapper<BaseItemexpense> wrapper = new QueryWrapper<>(); wrapper.eq("ItemId", itemid); wrapper.eq("UseState", "1"); wrapper.apply("del_flag = 0"); wrapper.orderByAsc("Id"); List<BaseItemexpense> list = baseItemexpenseMapper.selectList(wrapper); if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getValidateMode() != null) { mode = list.get(0).getValidateMode(); } if (mode != MODE_FORCE && mode != MODE_REMIND && mode != MODE_SKIP) { log.warn("[专家费校验] 项目校验模式取值非法,按强制校验处理,itemid={},validate_mode={}", itemid, mode); mode = MODE_FORCE; } } catch (Exception e) { log.error("[专家费校验] 读取项目校验模式失败,按强制校验处理,itemid={}", itemid, e); mode = MODE_FORCE; } itemModeCache.put(itemid, mode); itemModeExpireCache.put(itemid, now + ITEM_EXPENSE_CACHE_MILLIS); return mode; } private BigDecimal loadItemStandard(Long itemid, String scope) { return loadItemStandards(itemid).get(scope); } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatebaseinfoServiceImpl.java
@@ -216,6 +216,8 @@ public List<ServiceDonatebaseinfo> selectServiceDonatebaseinfoList(ServiceDonatebaseinfo serviceDonatebaseinfo) { SysUser user = SecurityUtils.getLoginUser().getUser(); // 超级管理员不受"只看本人报送 / 只看本部门"的数据范围限制,可查看全部数据 if (!isSuperAdmin(user)) { List<SysRole> l = user.getRoles(); int b = 0; @@ -234,6 +236,7 @@ } if (b == 2) { serviceDonatebaseinfo.setDeptid(user.getDeptId()); } } List<ServiceDonatebaseinfo> serviceDonatebaseinfos = serviceDonatebaseinfoMapper.selectServiceDonatebaseinfoList(serviceDonatebaseinfo); @@ -282,6 +285,8 @@ public List<ServiceDonatebaseinfo> getPatName(ServiceDonatebaseinfo serviceDonatebaseinfo) { SysUser user = SecurityUtils.getLoginUser().getUser(); // 超级管理员不受数据范围限制,可查看全部数据 if (!isSuperAdmin(user)) { List<SysRole> l = user.getRoles(); int b = 0; @@ -300,6 +305,7 @@ if (b == 2) { serviceDonatebaseinfo.setDeptid(user.getDeptId()); } } List<ServiceDonatebaseinfo> serviceDonatebaseinfos = serviceDonatebaseinfoMapper.getPatName(serviceDonatebaseinfo); return serviceDonatebaseinfos; @@ -308,6 +314,8 @@ @Override public List<ServiceDonatebaseinfo> listForSearch(ServiceDonatebaseinfo serviceDonatebaseinfo) { SysUser user = SecurityUtils.getLoginUser().getUser(); // 超级管理员不受数据范围限制,可查看全部数据 if (!isSuperAdmin(user)) { List<SysRole> l = user.getRoles(); Boolean b = false; for (SysRole r : l) { @@ -317,6 +325,7 @@ } if (b) { serviceDonatebaseinfo.setCreateBy(user.getUserName()); } } return serviceDonatebaseinfoMapper.listForSearch(serviceDonatebaseinfo); @@ -581,4 +590,33 @@ //将数据封闭,并返回 return map; } /** * 是否超级管理员。 * * <p>判定为超级管理员的情形: * <ul> * <li>内置管理员账号(userId = 1);</li> * <li>账号被授予"超级管理员"角色(roleId = 1)。</li> * </ul> * 超级管理员不受"只看本人报送(角色3 专职人员)/ 只看本部门(角色13 业务组长)"的数据范围限制, * 可查看全部数据。 */ private boolean isSuperAdmin(SysUser user) { if (user == null) { return false; } if (SysUser.isAdmin(user.getUserId())) { return true; } List<SysRole> roles = user.getRoles(); if (roles != null) { for (SysRole role : roles) { if (role.getRoleId() != null && role.getRoleId().longValue() == 1L) { return true; } } } return false; } } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonatecompletioninfoServiceImpl.java
@@ -74,6 +74,12 @@ if (StringUtils.isNotNull(serviceDonatecompletioninfo.getInfoid())) { wrappers.eq(ServiceDonatecompletioninfo::getInfoid, serviceDonatecompletioninfo.getInfoid()); } // 2026-10-22:默认只查询未删除记录 if (StringUtils.isNotNull(serviceDonatecompletioninfo.getDel_flag())) { wrappers.eq(ServiceDonatecompletioninfo::getDel_flag, serviceDonatecompletioninfo.getDel_flag()); } else { wrappers.eq(ServiceDonatecompletioninfo::getDel_flag, 0); } return this.list(wrappers); } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceDonationwitnessServiceImpl.java
@@ -73,6 +73,12 @@ if (StringUtils.isNotBlank(serviceDonationwitness.getOperationdoctor())) { wrappers.eq(ServiceDonationwitness::getOperationdoctor, serviceDonationwitness.getOperationdoctor()); } // 2026-10-22:默认只查询未删除记录 if (StringUtils.isNotNull(serviceDonationwitness.getDel_flag())) { wrappers.eq(ServiceDonationwitness::getDel_flag, serviceDonationwitness.getDel_flag()); } else { wrappers.eq(ServiceDonationwitness::getDel_flag, 0); } return this.list(wrappers); } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceEthicalreviewopinionsServiceImpl.java
@@ -81,6 +81,12 @@ if (serviceEthicalreviewopinions.getConclusionorder() != null) { wrappers.eq(ServiceEthicalreviewopinions::getConclusionorder, serviceEthicalreviewopinions.getConclusionorder()); } // 2026-10-22:默认只查询未删除记录 if (StringUtils.isNotNull(serviceEthicalreviewopinions.getDel_flag())) { wrappers.eq(ServiceEthicalreviewopinions::getDel_flag, serviceEthicalreviewopinions.getDel_flag()); } else { wrappers.eq(ServiceEthicalreviewopinions::getDel_flag, 0); } return this.list(wrappers); } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceFundServiceImpl.java
@@ -1583,6 +1583,28 @@ // 保存详情数据 for (ServiceFunddetailVO serviceFunddetailVO : serviceFunddetails) { // 2026-10-15:附件文件名规范二次校验(与前端 fileNameCheck 同口径;只校验本次变更的附件,历史附件放行) java.util.Set<String> existingNames = new java.util.HashSet<>(); if (serviceFunddetailVO.getId() != null) { ServiceFunddetail oldDetail = serviceFunddetailMapper.selectById(serviceFunddetailVO.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 invoiceJson = CollectionUtils.isEmpty(serviceFunddetailVO.getInvoicefilesList()) ? serviceFunddetailVO.getInvoicefiles() : JSON.toJSONString(serviceFunddetailVO.getInvoicefilesList()); String annexJson = CollectionUtils.isEmpty(serviceFunddetailVO.getAnnexfilesList()) ? serviceFunddetailVO.getAnnexfiles() : JSON.toJSONString(serviceFunddetailVO.getAnnexfilesList()); String nameError = com.ruoyi.project.common.AttachmentNameValidator .checkJsonListForUpdate(existingNames, invoiceJson, annexJson); if (nameError != null) { throw new BaseException("附件文件名不符合要求,无法保存:" + nameError); } //去掉身份证的首尾空格 if (StringUtils.isNotEmpty(serviceFunddetailVO.getIdcardno())) { serviceFunddetailVO.setIdcardno(serviceFunddetailVO.getIdcardno().trim()); ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceMedicalevaluationServiceImpl.java
@@ -54,6 +54,12 @@ if (StringUtils.isNotBlank(serviceMedicalevaluation.getDonorno())) { wrappers.eq(ServiceMedicalevaluation::getDonorno, serviceMedicalevaluation.getDonorno()); } // 2026-10-22:默认只查询未删除记录 if (StringUtils.isNotNull(serviceMedicalevaluation.getDel_flag())) { wrappers.eq(ServiceMedicalevaluation::getDel_flag, serviceMedicalevaluation.getDel_flag()); } else { wrappers.eq(ServiceMedicalevaluation::getDel_flag, 0); } return this.list(wrappers); } ruoyi-project/src/main/java/com/ruoyi/project/service/impl/ServiceRelativesconfirmationServiceImpl.java
@@ -185,6 +185,12 @@ if (serviceRelativesconfirmation.getUpdateTime() != null) { wrappers.eq(ServiceRelativesconfirmation::getUpdateTime, serviceRelativesconfirmation.getUpdateTime()); } // 2026-10-22:默认只查询未删除记录 if (StringUtils.isNotNull(serviceRelativesconfirmation.getDel_flag())) { wrappers.eq(ServiceRelativesconfirmation::getDel_flag, serviceRelativesconfirmation.getDel_flag()); } else { wrappers.eq(ServiceRelativesconfirmation::getDel_flag, 0); } return this.list(wrappers); } ruoyi-project/src/main/resources/mapper/project/ServiceFundMapper.xml
@@ -142,6 +142,8 @@ where del_flag = '0' <if test="donorno != null and donorno != ''">and DonorNo = #{donorno}</if> <!-- 2026-10-22:报销单列表支持按"捐献者姓名"模糊筛选(仅在传值时生效,不影响其它调用方) --> <if test="donorname != null and donorname != ''">and DonorName like concat('%', #{donorname}, '%')</if> <if test="fundTaxId != null ">and fund_tax_id = #{fundTaxId}</if> <if test="userno != null and userno != ''">and UserNo = #{userno}</if> <if test="username != null and username != ''">and UserName like concat('%', #{username}, '%')</if>