فهرست منبع

修改
1、优化账单导出,新增导出列不需要修改代码,只需要更新字典即可

liangwenxuan 2 هفته پیش
والد
کامیت
d11addee3a

+ 88 - 97
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java

@@ -1296,7 +1296,8 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
             for (int i = 0; i < orderItems.size(); i++) {
                 ExpenseOrderItemDO expenseOrderItemDO = orderItems.get(i);
                 orderActualAmount = orderActualAmount.add(expenseOrderItemDO.getTotalAmount());
-                setExpenseOrderType(expenseOrderItemDO);
+                // 若明细未带 type,则根据“费用标识类型”字典的关键词(label/remark)从名称中推断 type
+                setExpenseOrderType(expenseOrderItemDO, dictDataDOList);
 
                 if (identificationTypeMap.containsKey(expenseOrderItemDO.getType())) {
                     BigDecimal add = expenseOrderItemDO.getTotalAmount()
@@ -3579,105 +3580,95 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
     }
 
     /**
-     * 设置费用项目详情类型,临时使用
-     * @param expenseOrderItemDO
+     * 设置费用项目详情类型(从字典动态匹配)。
+     *
+     * <p>背景:历史数据中部分账单明细未写入 type(为 null/0),导出时需要按分类汇总;
+     * 以前通过 if/else 写死匹配规则,新增一种类型就要改代码。
+     *
+     * <p>当前策略:基于字典 {@code fee_identification_type} 的配置进行匹配:
+     * <ul>
+     *     <li>{@link DictDataDO#getValue()}:目标 type(必须是数字字符串)</li>
+     *     <li>{@link DictDataDO#getLabel()}:匹配关键词(同时也是导出表头)</li>
+     *     <li>{@link DictDataDO#getRemark()}:可选,同义词/额外关键词,支持用 ,,;;| 分隔</li>
+     * </ul>
+     *
+     * <p>匹配字段:优先在 {@code itemName} 命中,其次 {@code itemCategoryName}。
+     * 另外对包含“标准/类型”的关键词,会自动尝试去掉“标准/类型”后的匹配,减少配置成本。
      */
-    private void setExpenseOrderType(ExpenseOrderItemDO expenseOrderItemDO){
-        if(expenseOrderItemDO.getType() != null && expenseOrderItemDO.getType() != 0){
+    private void setExpenseOrderType(ExpenseOrderItemDO expenseOrderItemDO, List<DictDataDO> identificationTypeDictList) {
+        // 明细已带 type 时不处理,避免覆盖正确值
+        if (expenseOrderItemDO.getType() != null && expenseOrderItemDO.getType() != 0) {
+            return;
+        }
+        // 无字典配置时无法推断
+        if (CollectionUtil.isEmpty(identificationTypeDictList)) {
             return;
         }
-        if(expenseOrderItemDO.getItemName().contains("气垫床管理费")){
-            expenseOrderItemDO.setType(23);
-        }else if(expenseOrderItemDO.getItemName().contains("预备金")){
-            expenseOrderItemDO.setType(22);
-        }else if(expenseOrderItemDO.getItemName().contains("居家服务费")){
-            expenseOrderItemDO.setType(21);
-        }else if(expenseOrderItemDO.getItemName().contains("陪护费")){
-            expenseOrderItemDO.setType(20);
-        }else if(expenseOrderItemDO.getItemName().contains("炖汤票")){
-            expenseOrderItemDO.setType(19);
-        }else if(expenseOrderItemDO.getItemName().contains("匀浆膳")){
-            expenseOrderItemDO.setType(18);
-        }else if(expenseOrderItemDO.getItemName().contains("电器管理费")){
-            expenseOrderItemDO.setType(17);
-        }else if(expenseOrderItemDO.getItemName().contains("洗衣")){
-            expenseOrderItemDO.setType(16);
-        }else if(expenseOrderItemDO.getItemName().contains("善后处理费")){
-            expenseOrderItemDO.setType(15);
-        }else if(expenseOrderItemDO.getItemName().contains("注射费")){
-            expenseOrderItemDO.setType(14);
-        }else if(expenseOrderItemDO.getItemName().contains("西药费")){
-            expenseOrderItemDO.setType(13);
-        }else if(expenseOrderItemDO.getItemName().contains("材料费")){
-            expenseOrderItemDO.setType(12);
-        }else if(expenseOrderItemDO.getItemName().contains("药品管理费") || expenseOrderItemDO.getItemName().contains("药品保管费")){
-            expenseOrderItemDO.setType(11);
-        }else if(expenseOrderItemDO.getItemName().contains("治疗费")){
-            expenseOrderItemDO.setType(10);
-        }else if(expenseOrderItemDO.getItemName().contains("护理用品费")){
-            expenseOrderItemDO.setType(9);
-        }else if(expenseOrderItemDO.getItemName().contains("一次性费用")){
-            expenseOrderItemDO.setType(8);
-        }else if(expenseOrderItemDO.getItemName().contains("服务标准")){
-            expenseOrderItemDO.setType(7);
-        }else if(expenseOrderItemDO.getItemName().contains("水电费")){
-            expenseOrderItemDO.setType(6);
-        }else if(expenseOrderItemDO.getItemName().contains("试住费用")){
-            expenseOrderItemDO.setType(5);
-        }else if(expenseOrderItemDO.getItemName().contains("押金")){
-            expenseOrderItemDO.setType(4);
-        }else if(expenseOrderItemDO.getItemName().contains("餐饮标准")){
-            expenseOrderItemDO.setType(3);
-        }else if(expenseOrderItemDO.getItemName().contains("护理标准")){
-            expenseOrderItemDO.setType(2);
-        }else if(expenseOrderItemDO.getItemName().contains("床位类型")){
-            expenseOrderItemDO.setType(1);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("气垫床管理费")){
-            expenseOrderItemDO.setType(23);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("预备金")){
-            expenseOrderItemDO.setType(22);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("居家服务费")){
-            expenseOrderItemDO.setType(21);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("陪护费")){
-            expenseOrderItemDO.setType(20);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("炖汤票")){
-            expenseOrderItemDO.setType(19);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("匀浆膳")){
-            expenseOrderItemDO.setType(18);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("电器管理费")){
-            expenseOrderItemDO.setType(17);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("洗衣")){
-            expenseOrderItemDO.setType(16);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("善后处理费")){
-            expenseOrderItemDO.setType(15);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("注射费")){
-            expenseOrderItemDO.setType(14);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("西药费")){
-            expenseOrderItemDO.setType(13);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("材料费")){
-            expenseOrderItemDO.setType(12);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("药品管理费") || expenseOrderItemDO.getItemCategoryName().contains("药品保管费")){
-            expenseOrderItemDO.setType(11);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("治疗费")){
-            expenseOrderItemDO.setType(10);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("护理用品费")){
-            expenseOrderItemDO.setType(9);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("一次性费用")){
-            expenseOrderItemDO.setType(8);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("服务")){
-            expenseOrderItemDO.setType(7);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("水电费")){
-            expenseOrderItemDO.setType(6);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("试住费用")){
-            expenseOrderItemDO.setType(5);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("押金")){
-            expenseOrderItemDO.setType(4);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("餐饮")){
-            expenseOrderItemDO.setType(3);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("护理")){
-            expenseOrderItemDO.setType(2);
-        }else if(expenseOrderItemDO.getItemCategoryName().contains("床位")){
-            expenseOrderItemDO.setType(1);
+
+        String itemName = StringUtils.defaultString(expenseOrderItemDO.getItemName());
+        String itemCategoryName = StringUtils.defaultString(expenseOrderItemDO.getItemCategoryName());
+
+        for (DictDataDO dictDataDO : identificationTypeDictList) {
+            if (dictDataDO == null) {
+                continue;
+            }
+            if (StringUtils.isBlank(dictDataDO.getValue())) {
+                continue;
+            }
+            // 收集候选关键词:label + remark(分隔后)
+            List<String> keywords = new ArrayList<>();
+            if (StringUtils.isNotBlank(dictDataDO.getLabel())) {
+                keywords.add(dictDataDO.getLabel());
+            }
+            if (StringUtils.isNotBlank(dictDataDO.getRemark())) {
+                String[] remarkKeywords = dictDataDO.getRemark().split("[,,;;|]");
+                for (String keyword : remarkKeywords) {
+                    if (StringUtils.isNotBlank(keyword)) {
+                        keywords.add(keyword.trim());
+                    }
+                }
+            }
+
+            // 扩展关键词:自动补充去掉“标准/类型”后的版本(例如“服务标准”->“服务”)
+            List<String> expandedKeywords = new ArrayList<>(keywords.size() * 2);
+            for (String keyword : keywords) {
+                if (StringUtils.isBlank(keyword)) {
+                    continue;
+                }
+                expandedKeywords.add(keyword);
+                if (keyword.contains("标准")) {
+                    expandedKeywords.add(keyword.replace("标准", ""));
+                }
+                if (keyword.contains("类型")) {
+                    expandedKeywords.add(keyword.replace("类型", ""));
+                }
+            }
+            expandedKeywords.removeIf(StringUtils::isBlank);
+            // 先匹配更长的关键词,避免短关键词抢占(例如“护理”比“护理用品费”更容易误命中)
+            expandedKeywords.sort((a, b) -> Integer.compare(b.length(), a.length()));
+
+            boolean matched = false;
+            for (String keyword : expandedKeywords) {
+                if (StringUtils.isNotBlank(itemName) && itemName.contains(keyword)) {
+                    matched = true;
+                    break;
+                }
+                if (StringUtils.isNotBlank(itemCategoryName) && itemCategoryName.contains(keyword)) {
+                    matched = true;
+                    break;
+                }
+            }
+            if (!matched) {
+                continue;
+            }
+
+            try {
+                // 命中后写入 type,供后续汇总统计使用
+                expenseOrderItemDO.setType(Integer.valueOf(dictDataDO.getValue()));
+                return;
+            } catch (NumberFormatException ignored) {
+                // value 不是数字时忽略该字典项,继续尝试下一项
+            }
         }
     }