Kaynağa Gözat

1.报告文书排序

赵越越 1 hafta önce
ebeveyn
işleme
cd2546010f

+ 16 - 13
assistMg/src/main/java/com/hotent/project/manager/impl/CostProjectDocumentManagerImpl.java

@@ -41,6 +41,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import shade.com.alibaba.fastjson2.JSON;
 
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -342,18 +343,7 @@ public class CostProjectDocumentManagerImpl extends BaseManagerImpl<CostProjectD
             projectDocument.setDocumentType(costProjectDocument.getDocumentType()+"-"+templateManagerById.getDocumentType());
             projectDocument.setDocumentTypeName(templateManagerById.getDocumentTypeName());
             projectDocument.setDocumentAlias(templateManagerById.getAlias());
-            // 异步执行耗时任务
-            asyncExecutor.execute(() -> {
-                // 这里是你的业务逻辑
-                try {
-                    System.out.println("开始处理数据...");
-                    this.createDocument(projectDocument.getId());
-                    Thread.sleep(5000);  // 模拟耗时操作
-                    System.out.println("数据处理完成");
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                }
-            });
+
             //super.create(projectDocument);
             this.save(projectDocument);
 
@@ -402,6 +392,19 @@ public class CostProjectDocumentManagerImpl extends BaseManagerImpl<CostProjectD
             });
             //asyncService.executeAsync(projectDocument.getId());
 
+            // 异步执行耗时任务
+            asyncExecutor.execute(() -> {
+                // 这里是你的业务逻辑
+                try {
+                    System.out.println("开始处理数据...");
+                    this.createDocument(projectDocument.getId());
+                    Thread.sleep(5000);  // 模拟耗时操作
+                    System.out.println("数据处理完成");
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+            });
+
             costProjectDocumentFileManager.saveBatch(arrayList);
         }
 
@@ -632,7 +635,7 @@ public class CostProjectDocumentManagerImpl extends BaseManagerImpl<CostProjectD
                     List<String> years = (List<String>)map1.get("years");
                     @SuppressWarnings("unchecked")
                     List<Map<String, Object>> costItems = (List<Map<String, Object>>) map1.get("costItems");
-
+                    //System.err.println(JSON.parse(costItems.toString()));
                     // 处理文档
                     RobustComplexDocumentProcessor.processDocumentWithMaps(
                             document,

+ 132 - 140
assistMg/src/main/java/com/hotent/util/CostDataUtil.java

@@ -10,14 +10,12 @@ import java.time.format.DateTimeParseException;
 import java.util.*;
 import java.util.stream.Collectors;
 
-
 /**
  *@author: zhao yue yue
  *@create: 2025-12-08 10:05
  */
 public class CostDataUtil {
 
-
     private static final List<DateTimeFormatter> FORMATTERS = Arrays.asList(
             DateTimeFormatter.ofPattern("yyyy-MM-dd"),
             DateTimeFormatter.ofPattern("yyyy/MM/dd"),
@@ -28,27 +26,24 @@ public class CostDataUtil {
             DateTimeFormatter.ofPattern("yyyy年MM月dd日")
     );
 
-
     /**
      * 将查询结果转换为目标格式
-     * @param maps 查询结果:包含序号(xuhao)、项目名称(xiangmu)、年份(nianfen)、数值(shuzhi)和rowid
-     * @return 转换后的数据结构
      */
     public Map<String, Object> convertToCostFormat(List<Map<String, Object>> maps) {
         if (maps == null || maps.isEmpty()) {
             return createEmptyResult();
         }
 
-        // 1. 提取所有年份(从nianfen字段中提取年份数字)
+        // 1. 提取所有年份
         Set<String> years = extractYearsFromData(maps);
 
         // 2. 按序号和项目名称分组
-        Map<String, Map<String, String>> groupedData = groupBySerialAndProject(maps, years);
+        Map<String, Map<String, Object>> groupedData = groupBySerialAndProject(maps, years);
 
-        // 3. 构建costItems列表(按序号排序)
+        // 3. 构建costItems列表(完全按照orderNum数值排序)
         List<Map<String, Object>> costItems = buildCostItems(groupedData, years);
 
-        // 4. 添加合计行(可选)
+        // 4. 添加合计行
         addTotalItem(costItems, groupedData, years);
 
         // 5. 返回最终结果
@@ -60,28 +55,20 @@ public class CostDataUtil {
      */
     private Set<String> extractYearsFromData(List<Map<String, Object>> maps) {
         return maps.stream()
-                .map(row -> {
-                    String nianfen = (String) row.get("nianfen");
-                    if (nianfen != null) {
-                        // 提取年份数字,如从"2024年核定值"中提取"2024"
-                        return extractYearNumber(nianfen);
-                    }
-                    return null;
-                })
+                .map(row -> extractYearNumber((String) row.get("nianfen")))
                 .filter(Objects::nonNull)
                 .filter(year -> !year.isEmpty())
-                .collect(Collectors.toCollection(TreeSet::new)); // 自动排序
+                .collect(Collectors.toCollection(TreeSet::new));
     }
 
     /**
-     * 按序号和项目名称分组
+     * 按序号和项目名称分组,同时保存orderNum
      */
-    private Map<String, Map<String, String>> groupBySerialAndProject(
+    private Map<String, Map<String, Object>> groupBySerialAndProject(
             List<Map<String, Object>> maps,
             Set<String> years) {
 
-        // 使用LinkedHashMap保持插入顺序
-        Map<String, Map<String, String>> result = new LinkedHashMap<>();
+        Map<String, Map<String, Object>> result = new HashMap<>();
 
         for (Map<String, Object> row : maps) {
             try {
@@ -89,23 +76,42 @@ public class CostDataUtil {
                 String xiangmu = (String) row.get("xiangmu");
                 String nianfen = (String) row.get("nianfen");
                 Object shuzhiObj = row.get("shuzhi");
+                Object orderNumObj = row.get("orderNum");
 
                 if (xuhao == null || xiangmu == null || nianfen == null) {
                     continue;
                 }
 
-                // 生成唯一键:序号 + "|" + 项目名称
                 String key = xuhao + "|" + xiangmu;
 
-                // 初始化项目数据
                 if (!result.containsKey(key)) {
                     result.put(key, new HashMap<>());
+
+                    // 保存orderNum(字符串)
+                    String orderNumStr = null;
+                    Long orderNumValue = null;
+
+                    if (orderNumObj != null) {
+                        orderNumStr = orderNumObj.toString().trim();
+                        if (!orderNumStr.isEmpty()) {
+                            // 将orderNum转换为数值用于排序
+                            try {
+                                orderNumValue = Long.parseLong(orderNumStr);
+                            } catch (NumberFormatException e) {
+                                // 如果不是纯数字,按字符串处理
+                                orderNumValue = Long.MAX_VALUE;
+                            }
+                        }
+                    }
+
+                    result.get(key).put("orderNumStr", orderNumStr);
+                    result.get(key).put("orderNumValue", orderNumValue);
+                    result.get(key).put("yearData", new HashMap<String, String>());
                 }
 
                 // 提取年份
                 String year = extractYearNumber(nianfen);
                 if (year != null && years.contains(year)) {
-                    // 转换值为字符串
                     String value = "";
                     if (shuzhiObj != null) {
                         String strValue = shuzhiObj.toString().trim();
@@ -113,11 +119,13 @@ public class CostDataUtil {
                             value = strValue;
                         }
                     }
-                    result.get(key).put(year, value);
+
+                    @SuppressWarnings("unchecked")
+                    Map<String, String> yearData = (Map<String, String>) result.get(key).get("yearData");
+                    yearData.put(year, value);
                 }
 
             } catch (Exception e) {
-                // 跳过错误数据
                 continue;
             }
         }
@@ -126,25 +134,34 @@ public class CostDataUtil {
     }
 
     /**
-     * 构建costItems列表,按序号排序
+     * 构建costItems列表,完全按照orderNum数值排序
      */
     private List<Map<String, Object>> buildCostItems(
-            Map<String, Map<String, String>> groupedData,
+            Map<String, Map<String, Object>> groupedData,
             Set<String> years) {
 
         List<Map<String, Object>> costItems = new ArrayList<>();
 
-        // 按序号排序(先按中文序号,再按数字序号
+        // 按照orderNumValue排序(从小到大
         List<String> sortedKeys = groupedData.keySet().stream()
                 .sorted((key1, key2) -> {
-                    // 分割键:序号|项目名称
-                    String[] parts1 = key1.split("\\|");
-                    String[] parts2 = key2.split("\\|");
-                    String xuhao1 = parts1[0];
-                    String xuhao2 = parts2[0];
-
-                    // 自定义排序:先中文序号,后数字序号
-                    return compareChineseAndNumber(xuhao1, xuhao2);
+                    Map<String, Object> data1 = groupedData.get(key1);
+                    Map<String, Object> data2 = groupedData.get(key2);
+
+                    Long orderNum1 = (Long) data1.get("orderNumValue");
+                    Long orderNum2 = (Long) data2.get("orderNumValue");
+
+                    // 处理null值:null值排到最后
+                    if (orderNum1 == null && orderNum2 == null) {
+                        return key1.compareTo(key2);
+                    } else if (orderNum1 == null) {
+                        return 1; // orderNum1为null,排到后面
+                    } else if (orderNum2 == null) {
+                        return -1; // orderNum2为null,排到后面
+                    } else {
+                        // 按照数值大小排序
+                        return Long.compare(orderNum1, orderNum2);
+                    }
                 })
                 .collect(Collectors.toList());
 
@@ -153,20 +170,26 @@ public class CostDataUtil {
             String xuhao = parts[0];
             String xiangmu = parts[1];
 
+            Map<String, Object> itemData = groupedData.get(key);
+
             Map<String, Object> item = new HashMap<>();
 
-            // 使用项目名称作为costItemName
             item.put("costItemName", xiangmu);
-            // 如果需要,也可以添加序号字段
             item.put("serialNumber", xuhao);
 
+            String orderNumStr = (String) itemData.get("orderNumStr");
+            if (orderNumStr != null) {
+                item.put("orderNum", orderNumStr);
+            }
+
             // 添加年份数据
+            @SuppressWarnings("unchecked")
+            Map<String, String> yearData = (Map<String, String>) itemData.get("yearData");
             Map<String, String> yearValues = new HashMap<>();
-            Map<String, String> projectYearData = groupedData.get(key);
 
             for (String year : years) {
-                String value = projectYearData != null ?
-                        projectYearData.getOrDefault(year, "") : "";
+                String value = yearData != null ?
+                        yearData.getOrDefault(year, "") : "";
                 yearValues.put(year, value);
             }
             item.put("yearValues", yearValues);
@@ -178,26 +201,28 @@ public class CostDataUtil {
     }
 
     /**
-     * 添加合计行
+     * 添加合计行(合计行不参与排序,总是放在最后)
      */
     private void addTotalItem(
             List<Map<String, Object>> costItems,
-            Map<String, Map<String, String>> groupedData,
+            Map<String, Map<String, Object>> groupedData,
             Set<String> years) {
 
         Map<String, Object> totalItem = new HashMap<>();
         totalItem.put("costItemName", "合计");
+        totalItem.put("serialNumber", ""); // 合计行没有序号
 
         Map<String, String> totalValues = new HashMap<>();
 
         for (String year : years) {
             BigDecimal total = BigDecimal.ZERO;
 
-            for (Map<String, String> projectYearData : groupedData.values()) {
-                String valueStr = projectYearData.get(year);
+            for (Map<String, Object> itemData : groupedData.values()) {
+                @SuppressWarnings("unchecked")
+                Map<String, String> yearData = (Map<String, String>) itemData.get("yearData");
+                String valueStr = yearData != null ? yearData.get(year) : null;
                 if (valueStr != null && !valueStr.trim().isEmpty()) {
                     try {
-                        // 移除逗号等分隔符
                         String cleanValue = valueStr.replaceAll("[^\\d.-]", "");
                         if (!cleanValue.isEmpty()) {
                             BigDecimal value = new BigDecimal(cleanValue);
@@ -209,7 +234,7 @@ public class CostDataUtil {
                 }
             }
 
-            // 格式化合计值(添加千分位)
+            // 格式化合计值
             String totalStr = total.compareTo(BigDecimal.ZERO) > 0 ?
                     formatNumberWithCommas(total) : "";
             totalValues.put(year, totalStr);
@@ -235,7 +260,6 @@ public class CostDataUtil {
     private String extractYearNumber(String nianfen) {
         if (nianfen == null) return null;
 
-        // 匹配4位数字年份
         java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\d{4}");
         java.util.regex.Matcher matcher = pattern.matcher(nianfen);
         if (matcher.find()) {
@@ -245,46 +269,6 @@ public class CostDataUtil {
     }
 
     /**
-     * 比较中文序号和数字序号
-     */
-    private int compareChineseAndNumber(String xuhao1, String xuhao2) {
-        // 中文序号映射
-        Map<String, Integer> chineseMap = new HashMap<>();
-        chineseMap.put("一", 1);
-        chineseMap.put("二", 2);
-        chineseMap.put("三", 3);
-        chineseMap.put("四", 4);
-        chineseMap.put("五", 5);
-        chineseMap.put("六", 6);
-        chineseMap.put("七", 7);
-        chineseMap.put("八", 8);
-        chineseMap.put("九", 9);
-        chineseMap.put("十", 10);
-
-        // 尝试将字符串转换为数字
-        Integer num1 = chineseMap.get(xuhao1);
-        Integer num2 = chineseMap.get(xuhao2);
-
-        if (num1 == null) {
-            try {
-                num1 = Integer.parseInt(xuhao1);
-            } catch (NumberFormatException e) {
-                num1 = Integer.MAX_VALUE; // 无法转换的排到最后
-            }
-        }
-
-        if (num2 == null) {
-            try {
-                num2 = Integer.parseInt(xuhao2);
-            } catch (NumberFormatException e) {
-                num2 = Integer.MAX_VALUE; // 无法转换的排到最后
-            }
-        }
-
-        return Integer.compare(num1, num2);
-    }
-
-    /**
      * 格式化数字(添加千分位)
      */
     private String formatNumberWithCommas(BigDecimal number) {
@@ -303,76 +287,100 @@ public class CostDataUtil {
     }
 
     /**
-     * 使用示例
+     * 测试方法 - 模拟您的数据
      */
     public static void main(String[] args) {
-        // 模拟你的查询数据
+        // 模拟您的查询数据(orderNum不是按顺序查询出来的)
         List<Map<String, Object>> maps = new ArrayList<>();
 
-        // 添加测试数据(根据你提供的数据)
-        addRow(maps, "一", "人数", "2024年核定值", "");
-        addRow(maps, "一", "人数", "2025年核定值", "");
-        addRow(maps, "1", "1班", "2024年核定值", "");
-        addRow(maps, "1", "1班", "2025年核定值", "");
-        addRow(maps, "2", "2班", "2024年核定值", "");
-        addRow(maps, "2", "2班", "2025年核定值", "");
-        addRow(maps, "二", "1班费用", "2024年核定值", "");
-        addRow(maps, "二", "1班费用", "2025年核定值", "");
-        addRow(maps, "1", "押金", "2024年核定值", "");
-        addRow(maps, "1", "押金", "2025年核定值", "");
-        addRow(maps, "2", "缴纳", "2024年核定值", "");
-        addRow(maps, "2", "缴纳", "2025年核定值", "");
-        addRow(maps, "三", "班级乘法", "2024年核定值", "556");
-        addRow(maps, "三", "班级乘法", "2025年核定值", "85");
-        addRow(maps, "四", "人均费用", "2024年核定值", "223");
-        addRow(maps, "四", "人均费用", "2025年核定值", "225");
+        // 注意:这里故意不按orderNum顺序添加数据
+        addRow(maps, "一", "人数", "2025年核定值", "2", "1");
+        addRow(maps, "一", "人数", "2026年核定值", "2", "1");
+        addRow(maps, "2", "2班", "2025年核定值", "2", "3");
+        addRow(maps, "2", "2班", "2026年核定值", "6", "3");
+        addRow(maps, "二", "电费", "2025年核定值", "2", "4");
+        addRow(maps, "二", "电费", "2026年核定值", "8", "4");
+        addRow(maps, "1", "1班", "2025年核定值", "2", "2");
+        addRow(maps, "1", "1班", "2026年核定值", "4", "2");
+        addRow(maps, "四", "班费率", "2025年核定值", "2", "9");
+        addRow(maps, "四", "班费率", "2026年核定值", "18", "9");
+        addRow(maps, "2", "押金", "2025年核定值", "2", "6");
+        addRow(maps, "2", "押金", "2026年核定值", "12", "6");
+        addRow(maps, "三", "总班费", "2025年核定值", "2", "7");
+        addRow(maps, "三", "总班费", "2026年核定值", "14", "7");
+        addRow(maps, "1", "总支出", "2025年核定值", "2", "5");
+        addRow(maps, "1", "总支出", "2026年核定值", "10", "5");
+        addRow(maps, "1", "个人班费", "2025年核定值", "2", "8");
+        addRow(maps, "1", "个人班费", "2026年核定值", "16", "8");
+
+        System.out.println("原始查询数据(不按orderNum顺序):");
+        System.out.println("=================================");
+        for (int i = 0; i < maps.size(); i += 2) {
+            Map<String, Object> row = maps.get(i);
+            System.out.printf("序号:%s 项目:%s orderNum:%s\n",
+                    row.get("xuhao"),
+                    row.get("xiangmu"),
+                    row.get("orderNum"));
+        }
 
         CostDataUtil converter = new CostDataUtil();
         Map<String, Object> result = converter.convertToCostFormat(maps);
 
         // 输出结果
-        System.out.println("Years: " + result.get("years"));
+        System.out.println("\n\n转换后结果(按orderNum排序):");
+        System.out.println("================================");
+        System.out.println("成本项目\t行次\t2025年度\t2026年度");
 
         @SuppressWarnings("unchecked")
         List<Map<String, Object>> costItems = (List<Map<String, Object>>) result.get("costItems");
 
-        System.out.println("\nCost Items:");
         for (Map<String, Object> item : costItems) {
             String costItemName = (String) item.get("costItemName");
-            System.out.println("\n项目: " + costItemName);
+            String serialNumber = (String) item.get("serialNumber");
+            String orderNum = (String) item.get("orderNum");
 
             @SuppressWarnings("unchecked")
             Map<String, String> yearValues = (Map<String, String>) item.get("yearValues");
 
-            @SuppressWarnings("unchecked")
-            List<String> years = (List<String>) result.get("years");
-
-            for (String year : years) {
-                String value = yearValues.get(year);
-                System.out.println("  " + year + "年: " + (value != null && !value.isEmpty() ? value : ""));
+            String year2025 = yearValues.get("2025");
+            String year2026 = yearValues.get("2026");
+
+            if ("合计".equals(costItemName)) {
+                System.out.printf("%s\t%s\t%s\t%s\n",
+                        costItemName,
+                        serialNumber,
+                        year2025 != null ? year2025 : "",
+                        year2026 != null ? year2026 : "");
+            } else {
+                System.out.printf("%s\t%s\t%s\t%s\t(orderNum=%s)\n",
+                        costItemName,
+                        serialNumber,
+                        year2025 != null ? year2025 : "",
+                        year2026 != null ? year2026 : "",
+                        orderNum);
             }
         }
+
+        System.out.println("\n排序说明:完全按照orderNum数值大小排序,与查询顺序无关");
     }
 
     private static void addRow(List<Map<String, Object>> list,
                                String xuhao, String xiangmu,
-                               String nianfen, String shuzhi) {
+                               String nianfen, String shuzhi, String orderNum) {
         Map<String, Object> row = new HashMap<>();
         row.put("xuhao", xuhao);
         row.put("xiangmu", xiangmu);
         row.put("nianfen", nianfen);
         row.put("shuzhi", shuzhi);
+        row.put("orderNum", orderNum);
         list.add(row);
     }
 
-
-
-
+    // 原有的日期转换方法保持不变...
     public static String convertToChineseDate(String dateStr) {
         if(StringUtil.isEmpty(dateStr)){
             return dateStr;
         }
-        // 定义多种可能的日期格式
         List<String> patterns = Arrays.asList(
                 "yyyy-MM-dd",
                 "yyyy/MM/dd",
@@ -387,33 +395,25 @@ public class CostDataUtil {
             try {
                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                 LocalDate date = LocalDate.parse(dateStr, formatter);
-
-                // 转换为中文格式
                 DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
                 return date.format(chineseFormatter);
             } catch (DateTimeParseException e) {
-                // 继续尝试其他格式
                 continue;
             }
         }
 
-        // 如果不是日期,返回原字符串
         return dateStr;
     }
 
-
     public static String convert(String input) {
-        // 先尝试精确匹配日期格式
         for (DateTimeFormatter formatter : FORMATTERS) {
             try {
                 LocalDate date = LocalDate.parse(input, formatter);
                 return date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
             } catch (DateTimeParseException e) {
-                // 继续尝试下一个格式
             }
         }
 
-        // 如果不是标准格式,可以添加正则表达式检测
         if (isLikelyDate(input)) {
             return tryParseUnusualDate(input);
         }
@@ -422,29 +422,21 @@ public class CostDataUtil {
     }
 
     private static boolean isLikelyDate(String str) {
-        // 简单的日期特征检测
         return str.matches(".*\\d{4}.*\\d{1,2}.*\\d{1,2}.*") ||
                 str.matches("\\d{1,2}[-/.]\\d{1,2}[-/.]\\d{4}");
     }
 
     private static String tryParseUnusualDate(String str) {
-        // 尝试清理和转换非标准日期
         try {
-            // 移除非数字字符,保留数字
             String numbers = str.replaceAll("[^0-9]", "");
-
             if (numbers.length() == 8) {
-                // 假设是 yyyyMMdd 格式
                 String year = numbers.substring(0, 4);
                 String month = numbers.substring(4, 6);
                 String day = numbers.substring(6, 8);
                 return year + "年" + month + "月" + day + "日";
             }
         } catch (Exception e) {
-            // 转换失败
         }
         return str;
     }
-}
-
-
+}

+ 1 - 1
assistMg/src/main/resources/mapper/CostDocumentTemplateFileMapper.xml

@@ -87,7 +87,7 @@
 				r.rkey as nianfen,
 				r.rvalue as shuzhi,
 				r.rowid,
-				r.order_num
+				r.order_num as orderNum
 		FROM ranked_data r
 		WHERE r.rkey LIKE CONCAT('%', '核定值', '%') and r.type=3
 		ORDER BY r.order_num,