zzw 1 місяць тому
батько
коміт
5b2fb281bd

+ 225 - 43
assistMg/src/main/java/com/hotent/enterpriseDeclare/controller/material/CostProjectTaskSurveyGenericController.java

@@ -147,7 +147,8 @@ public class CostProjectTaskSurveyGenericController {
                 List<CostSurveyTemplateUpload> uploadList = costSurveyTemplateUploadManager.listByTaskId(taskId);
                 //创建记录
                 if (uploadList.isEmpty()) {
-                    List<CostSurveyTemplate> costSurveyTemplates = costSurveyTemplateManager.taskListByCatalogId(catalogId);
+                    CostProjectTask task = costProjectTaskManager.getById(taskId);
+                     List<CostSurveyTemplate> costSurveyTemplates = costSurveyTemplateManager.taskListByCatalogId(task.getCatalogId());
                     for (CostSurveyTemplate template : costSurveyTemplates) {
                         CostSurveyTemplateUpload upload = new CostSurveyTemplateUpload();
                         upload.setSurveyTemplateId(template.getSurveyTemplateId());
@@ -863,10 +864,19 @@ public class CostProjectTaskSurveyGenericController {
 
                 // 创建表头行
                 Row headerRow = sheet.createRow(0);
+                int colIndex = 0;
+
+                // 添加原有表头
                 for (int i = 0; i < headersList.size(); i++) {
-                    headerRow.createCell(i).setCellValue(headersList.get(i).getFieldName());
+                    headerRow.createCell(colIndex++).setCellValue(headersList.get(i).getFieldName());
                 }
 
+                // 添加行ID列和父行ID列(固定表需要)
+                int rowIdColIndex = colIndex;
+                headerRow.createCell(colIndex++).setCellValue("行ID");
+                int parentIdColIndex = colIndex;
+                headerRow.createCell(colIndex++).setCellValue("父行ID");
+
                 // 填充数据
                 if (itemsList != null && !itemsList.isEmpty()) {
 
@@ -887,7 +897,7 @@ public class CostProjectTaskSurveyGenericController {
                             System.out.println("  headersId: " + headersId + ", 数量: " + count)
                     );
 
-                    fillExcelDataVerify(sheet, itemsList, headerIndexMap);
+                    fillExcelDataVerify(sheet, itemsList, headerIndexMap, rowIdColIndex, parentIdColIndex);
                 }
 
                 // 列宽处理
@@ -896,6 +906,10 @@ public class CostProjectTaskSurveyGenericController {
                     sheet.setColumnWidth(i, Math.max(sheet.getColumnWidth(i), 3000));
                 }
 
+                // 隐藏行ID和父行ID列
+                sheet.setColumnHidden(rowIdColIndex, true);
+                sheet.setColumnHidden(parentIdColIndex, true);
+
                 // 输出
                 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                 response.setCharacterEncoding("utf-8");
@@ -1047,6 +1061,7 @@ public class CostProjectTaskSurveyGenericController {
                     }
 
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
                     int dataRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
@@ -1072,6 +1087,9 @@ public class CostProjectTaskSurveyGenericController {
                                     "row_" + System.currentTimeMillis() : "row_" + rowIndex;
                         }
 
+                        // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
+                        rowIdToExcelRowMap.put(currentRowId, rowIndex + 1);
+
                         // 读取父行ID
                         String parentRowId = null;
                         if (parentIdColumnIndex != null) {
@@ -1149,7 +1167,7 @@ public class CostProjectTaskSurveyGenericController {
                         return CommonResult.<String>error().message("Excel文件中没有有效数据");
                     }
 
-                    verifyImportData(dataList, type, surveyTemplateId);
+                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
                     costSurveyTemplateUploadDataManager.saveData(dataList);
 
                     // 更新上传状态
@@ -1213,9 +1231,11 @@ public class CostProjectTaskSurveyGenericController {
                         return CommonResult.<String>error().message("Excel文件第一行为空");
                     }
 
-                    // 检查是否有立项年限列和备注
+                    // 检查是否有立项年限列、备注列、行ID列和父行ID
                     Map<String, Integer> auditPeriodColumnMap = new HashMap<>(); // 年限->列索引
                     Integer remarkColumnIndex = null; // 备注列索引
+                    Integer rowIdColumnIndex = null; // 行ID列索引
+                    Integer parentIdColumnIndex = null; // 父行ID列索引
                     Map<Integer, CostSurveyFdTemplateHeaders> columnIndexMap = new HashMap<>();
                     for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                         Cell cell = headerRow.getCell(i);
@@ -1225,6 +1245,10 @@ public class CostProjectTaskSurveyGenericController {
                                 String trimmedValue = cellValue.trim();
                                 if ("备注".equals(trimmedValue)) {
                                     remarkColumnIndex = i;
+                                } else if ("行ID".equals(trimmedValue)) {
+                                    rowIdColumnIndex = i;
+                                } else if ("父行ID".equals(trimmedValue)) {
+                                    parentIdColumnIndex = i;
                                 } else if (trimmedValue.matches("\\d{4}")) {
                                     // 如果是4位数字,认为是年限列
                                     auditPeriodColumnMap.put(trimmedValue, i);
@@ -1243,14 +1267,44 @@ public class CostProjectTaskSurveyGenericController {
                     }
 
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
                     int dataRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                         Row dataRow = sheet.getRow(rowIndex);
                         if (dataRow == null || isEmptyRow(dataRow)) continue;
 
-                        String currentRowId = "1".equals(templateType) ?
-                                "row_" + System.currentTimeMillis() : "row_" + rowIndex;
+                        // 确定当前行的rowId
+                        String currentRowId;
+                        if (rowIdColumnIndex != null) {
+                            // 如果有行ID列,必须使用Excel中的行ID
+                            Cell rowIdCell = dataRow.getCell(rowIdColumnIndex);
+                            String excelRowId = getCellStringValue(rowIdCell);
+                            if (StringUtil.isNotEmpty(excelRowId)) {
+                                currentRowId = excelRowId.trim();
+                            } else {
+                                // 固定表和动态表都不支持新增行,行ID不能为空
+                                // 如果为空则使用行号作为兜底
+                                currentRowId = "row_" + rowIndex;
+                            }
+                        } else {
+                            // 没有行ID列,使用原有逻辑
+                            currentRowId = "1".equals(templateType) ?
+                                    "row_" + System.currentTimeMillis() : "row_" + rowIndex;
+                        }
+
+                        // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
+                        rowIdToExcelRowMap.put(currentRowId, rowIndex + 1);
+
+                        // 读取父行ID
+                        String parentRowId = null;
+                        if (parentIdColumnIndex != null) {
+                            Cell parentIdCell = dataRow.getCell(parentIdColumnIndex);
+                            parentRowId = getCellStringValue(parentIdCell);
+                            if (StringUtil.isNotEmpty(parentRowId)) {
+                                parentRowId = parentRowId.trim();
+                            }
+                        }
 
                         // 读取原有字段数据(包括空值)
                         for (Map.Entry<Integer, CostSurveyFdTemplateHeaders> entry : columnIndexMap.entrySet()) {
@@ -1317,7 +1371,7 @@ public class CostProjectTaskSurveyGenericController {
                     if (dataList.isEmpty()) {
                         return CommonResult.<String>error().message("Excel文件中没有有效数据");
                     }
-                    verifyImportData(dataList, type, surveyTemplateId);
+                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
                     costSurveyTemplateUploadDataManager.saveData(dataList);
                     CostProjectTaskMaterial material = costProjectTaskMaterialManager.getById(materialId);
                     material.setIsUpload("1");
@@ -1371,15 +1425,25 @@ public class CostProjectTaskSurveyGenericController {
                         return CommonResult.<String>error().message("Excel表头行为空");
                     }
 
+                    // 识别行ID列和父行ID列
+                    Integer rowIdColumnIndex = null;
+                    Integer parentIdColumnIndex = null;
                     Map<Integer, CostVerifyTemplateHeaders> columnIndexMap = new HashMap<>();
                     for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                         Cell cell = headerRow.getCell(i);
                         if (cell != null) {
                             String cellValue = getCellStringValue(cell);
                             if (StringUtil.isNotEmpty(cellValue)) {
-                                CostVerifyTemplateHeaders header = headerNameMap.get(cellValue.trim());
-                                if (header != null) {
-                                    columnIndexMap.put(i, header);
+                                String trimmedValue = cellValue.trim();
+                                if ("行ID".equals(trimmedValue)) {
+                                    rowIdColumnIndex = i;
+                                } else if ("父行ID".equals(trimmedValue)) {
+                                    parentIdColumnIndex = i;
+                                } else {
+                                    CostVerifyTemplateHeaders header = headerNameMap.get(trimmedValue);
+                                    if (header != null) {
+                                        columnIndexMap.put(i, header);
+                                    }
                                 }
                             }
                         }
@@ -1391,13 +1455,43 @@ public class CostProjectTaskSurveyGenericController {
 
                     // 读取数据行
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
                     int importRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                         Row dataRow = sheet.getRow(rowIndex);
                         if (dataRow == null || isEmptyRow(dataRow)) continue;
 
-                        String rowId = "row_" + rowIndex;
+                        // 确定当前行的rowId
+                        String currentRowId;
+                        if (rowIdColumnIndex != null) {
+                            // 如果有行ID列,必须使用Excel中的行ID
+                            Cell rowIdCell = dataRow.getCell(rowIdColumnIndex);
+                            String excelRowId = getCellStringValue(rowIdCell);
+                            if (StringUtil.isNotEmpty(excelRowId)) {
+                                currentRowId = excelRowId.trim();
+                            } else {
+                                // 固定表不支持新增行,行ID不能为空
+                                // 如果为空则使用行号作为兜底
+                                currentRowId = "row_" + rowIndex;
+                            }
+                        } else {
+                            // 没有行ID列,使用行号
+                            currentRowId = "row_" + rowIndex;
+                        }
+
+                        // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
+                        rowIdToExcelRowMap.put(currentRowId, rowIndex + 1);
+
+                        // 读取父行ID
+                        String parentRowId = null;
+                        if (parentIdColumnIndex != null) {
+                            Cell parentIdCell = dataRow.getCell(parentIdColumnIndex);
+                            parentRowId = getCellStringValue(parentIdCell);
+                            if (StringUtil.isNotEmpty(parentRowId)) {
+                                parentRowId = parentRowId.trim();
+                            }
+                        }
 
                         for (Map.Entry<Integer, CostVerifyTemplateHeaders> entry : columnIndexMap.entrySet()) {
                             Cell cell = dataRow.getCell(entry.getKey());
@@ -1405,7 +1499,7 @@ public class CostProjectTaskSurveyGenericController {
 
                             if (StringUtil.isNotEmpty(cellValue)) {
                                 CostSurveyTemplateUploadData uploadData = createUploadData(
-                                        surveyTemplateId, taskId, uploadId, rowId,
+                                        surveyTemplateId, taskId, uploadId, currentRowId,
                                         entry.getValue(), cellValue, periodRecordId, type
                                 );
                                 dataList.add(uploadData);
@@ -1417,7 +1511,7 @@ public class CostProjectTaskSurveyGenericController {
                     if (dataList.isEmpty()) {
                         return CommonResult.<String>error().message("Excel文件没有有效数据");
                     }
-                    verifyImportData(dataList, type, surveyTemplateId);
+                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
                     // 保存
                     costSurveyTemplateUploadDataManager.saveData(dataList);
 
@@ -1436,8 +1530,19 @@ public class CostProjectTaskSurveyGenericController {
     }
 
 
+    /**
+     * 获取友好的行号显示
+     */
+    private String getRowDisplay(String rowid, Map<String, Integer> rowIdToExcelRowMap) {
+        if (rowIdToExcelRowMap == null) {
+            return "行[" + rowid + "]";
+        }
+        Integer excelRow = rowIdToExcelRowMap.get(rowid);
+        return excelRow != null ? "第" + excelRow + "行" : "行[" + rowid + "]";
+    }
+
     // 校验逻辑
-    private void verifyImportData(List<CostSurveyTemplateUploadData> dataList, String type, String surveyTemplateId) throws Exception {
+    private void verifyImportData(List<CostSurveyTemplateUploadData> dataList, String type, String surveyTemplateId, Map<String, Integer> rowIdToExcelRowMap) throws Exception {
         if (dataList == null || dataList.isEmpty()) {
             return;
         }
@@ -1466,7 +1571,7 @@ public class CostProjectTaskSurveyGenericController {
         for (Map.Entry<String, Map<String, String>> rowEntry : rowDataMap.entrySet()) {
             String rowid = rowEntry.getKey();
             Map<String, String> rowData = rowEntry.getValue();
-            validateFieldRulesExcludingPeriods(rowid, rowData, headersList);
+            validateFieldRulesExcludingPeriods(rowid, rowData, headersList, rowIdToExcelRowMap);
         }
 
         // 2. 计算公式校验/结构校验(仅针对固定表,动态表不需要)
@@ -1547,7 +1652,7 @@ public class CostProjectTaskSurveyGenericController {
 
                     // 针对每个年限分别校验(直接抛异常,不需要检查errors)
                     for (String period : periods) {
-                        validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type);
+                        validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type,rowIdToExcelRowMap);
                     }
                 }
             }
@@ -1677,9 +1782,10 @@ public class CostProjectTaskSurveyGenericController {
      * 字段级别校验
      */
     private void validateFieldRulesExcludingPeriods(String rowid, Map<String, String> rowData,
-                                                    List<? extends Object> headersList) {
+                                                    List<? extends Object> headersList, Map<String, Integer> rowIdToExcelRowMap) {
+        String rowDisplay = getRowDisplay(rowid, rowIdToExcelRowMap);
         System.out.println("========================================");
-        System.out.println("开始校验行[" + rowid + "]的字段(排除年限列)");
+        System.out.println("开始校验" + rowDisplay + "的字段(排除年限列)");
         System.out.println("表头数量: " + headersList.size());
         System.out.println("行数据: " + rowData);
 
@@ -1702,7 +1808,7 @@ public class CostProjectTaskSurveyGenericController {
             // 1. 必填校验(支持 "1" 和 "true" 两种格式)
             if (("1".equals(isRequired) || "true".equalsIgnoreCase(isRequired)) && StringUtil.isEmpty(value)) {
                 System.out.println("  ❌ 必填校验失败!");
-                throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]为必填项,不能为空", rowid, fieldEname, fieldName));
+                throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]为必填项,不能为空", rowDisplay, fieldEname, fieldName));
             }
 
             // 如果值为空且非必填,跳过后续校验
@@ -1784,7 +1890,7 @@ public class CostProjectTaskSurveyGenericController {
     /**
      * 字段类型校验
      */
-    private void validateFieldType(String rowid, String fieldEname, String fieldName,
+    private void validateFieldType(String rowDisplay, String fieldEname, String fieldName,
                                    String value, String fieldType) {
         try {
             switch (fieldType.toLowerCase()) {
@@ -1794,7 +1900,7 @@ public class CostProjectTaskSurveyGenericController {
                     try {
                         Long.parseLong(value);
                     } catch (NumberFormatException e) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]类型错误,应为整数,实际值:%s", rowid, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型错误,应为整数,实际值:%s", rowDisplay, fieldEname, fieldName, value));
                     }
                     break;
 
@@ -1805,21 +1911,21 @@ public class CostProjectTaskSurveyGenericController {
                     try {
                         Double.parseDouble(value);
                     } catch (NumberFormatException e) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]类型错误,应为数字,实际值:%s", rowid, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型错误,应为数字,实际值:%s", rowDisplay, fieldEname, fieldName, value));
                     }
                     break;
 
                 case "date":
                     // 日期格式校验(可以根据实际需求调整)
                     if (!value.matches("\\d{4}-\\d{2}-\\d{2}")) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]日期格式错误,应为yyyy-MM-dd,实际值:%s", rowid, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]日期格式错误,应为yyyy-MM-dd,实际值:%s", rowDisplay, fieldEname, fieldName, value));
                     }
                     break;
 
                 case "datetime":
                     // 日期时间格式校验
                     if (!value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]日期时间格式错误,应为yyyy-MM-dd HH:mm:ss,实际值:%s", rowid, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]日期时间格式错误,应为yyyy-MM-dd HH:mm:ss,实际值:%s", rowDisplay, fieldEname, fieldName, value));
                     }
                     break;
 
@@ -1830,8 +1936,8 @@ public class CostProjectTaskSurveyGenericController {
                     if (!lowerValue.equals("true") && !lowerValue.equals("false") &&
                         !lowerValue.equals("1") && !lowerValue.equals("0") &&
                         !lowerValue.equals("是") && !lowerValue.equals("否")) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]类型错误,应为布尔值(true/false, 1/0, 是/否),实际值:%s",
-                                rowid, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型错误,应为布尔值(true/false, 1/0, 是/否),实际值:%s",
+                                rowDisplay, fieldEname, fieldName, value));
                     }
                     break;
 
@@ -1848,7 +1954,7 @@ public class CostProjectTaskSurveyGenericController {
         } catch (IllegalArgumentException e) {
             throw e;
         } catch (Exception e) {
-            throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]类型校验异常:%s", rowid, fieldEname, fieldName, e.getMessage()));
+            throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型校验异常:%s", rowDisplay, fieldEname, fieldName, e.getMessage()));
         }
     }
 
@@ -2084,7 +2190,7 @@ public class CostProjectTaskSurveyGenericController {
      */
     private void validateRowFormulasForPeriod(String rowid, Map<String, String> rowData,
                                               List<? extends Object> rowItems, Map<String, String> globalCellCodeMap,
-                                              String period, String type) {
+                                              String period, String type,Map<String, Integer> rowIdToExcelRowMap) {
         // 找到该行的计算公式(同一行的所有模板项共享同一个公式)
         String calculationFormula = null;
         String cellCode = null;
@@ -2159,8 +2265,11 @@ public class CostProjectTaskSurveyGenericController {
             if (Math.abs(calculatedValue - inputValue) > 0.01) {
                 System.out.println("校验结果: ❌ 不匹配");
                 System.out.println("========================================");
-                throw new IllegalArgumentException(String.format("行[%s] [%s]列汇总值错误:计算值[%.2f],填写值[%.2f]",
-                        rowid, period + "年", calculatedValue, inputValue));
+                // 获取友好的行号显示
+                Integer excelRow = rowIdToExcelRowMap.get(rowid);
+                String rowDisplay = excelRow != null ? "第" + excelRow + "行" : "行[" + rowid + "]";
+                throw new IllegalArgumentException(String.format("%s [%s]列汇总值错误:计算值[%.2f],填写值[%.2f]",
+                        rowDisplay, period + "年", calculatedValue, inputValue));
             } else {
                 System.out.println("校验结果: ✓ 通过");
                 System.out.println("========================================");
@@ -2631,8 +2740,62 @@ public class CostProjectTaskSurveyGenericController {
         }
     }
 
+    /**
+     * 按父子关系排序rowId(核定表)
+     */
+    private List<String> sortRowIdsByParentChildVerify(Map<String, List<CostVerifyTemplateItems>> itemsByRowId) {
+        List<String> result = new ArrayList<>();
+
+        // 构建rowId到parentid的映射
+        Map<String, String> rowIdToParentId = new HashMap<>();
+        for (Map.Entry<String, List<CostVerifyTemplateItems>> entry : itemsByRowId.entrySet()) {
+            String rowId = entry.getKey();
+            List<CostVerifyTemplateItems> items = entry.getValue();
+            if (!items.isEmpty()) {
+                String parentId = items.get(0).getParentid();
+                rowIdToParentId.put(rowId, parentId);
+            }
+        }
+
+        // 找出所有根节点(parentid为空或不存在的)
+        Set<String> allRowIds = new HashSet<>(itemsByRowId.keySet());
+        List<String> rootRowIds = allRowIds.stream()
+                .filter(rowId -> {
+                    String parentId = rowIdToParentId.get(rowId);
+                    return StringUtil.isEmpty(parentId) || !allRowIds.contains(parentId);
+                })
+                .sorted()
+                .collect(Collectors.toList());
+
+        // 递归添加节点及其子节点
+        for (String rootRowId : rootRowIds) {
+            addRowIdWithChildrenVerify(rootRowId, rowIdToParentId, allRowIds, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * 递归添加rowId及其所有子节点(核定表)
+     */
+    private void addRowIdWithChildrenVerify(String rowId, Map<String, String> rowIdToParentId,
+                                           Set<String> allRowIds, List<String> result) {
+        result.add(rowId);
+
+        // 找出所有子节点
+        List<String> children = allRowIds.stream()
+                .filter(id -> rowId.equals(rowIdToParentId.get(id)))
+                .sorted()
+                .collect(Collectors.toList());
+
+        // 递归处理子节点
+        for (String childRowId : children) {
+            addRowIdWithChildrenVerify(childRowId, rowIdToParentId, allRowIds, result);
+        }
+    }
+
     private void fillExcelDataVerify(Sheet sheet, List<CostVerifyTemplateItems> itemsList,
-                                     Map<String, Integer> headerIndexMap) {
+                                     Map<String, Integer> headerIndexMap, int rowIdColIndex, int parentIdColIndex) {
 
         if (itemsList == null || itemsList.isEmpty()) {
             return;
@@ -2643,22 +2806,41 @@ public class CostProjectTaskSurveyGenericController {
                 .filter(item -> StringUtil.isNotEmpty(item.getRowid()))
                 .collect(Collectors.groupingBy(CostVerifyTemplateItems::getRowid));
 
+        // 按父子关系排序
+        List<String> sortedRowIds = sortRowIdsByParentChildVerify(itemsByRowId);
+
         int rowNum = 1;
         int totalCellsWritten = 0;
         int cellsSkippedNoMapping = 0;
 
-        for (Map.Entry<String, List<CostVerifyTemplateItems>> entry : itemsByRowId.entrySet()) {
-            Row dataRow = sheet.createRow(rowNum++);
-            for (CostVerifyTemplateItems item : entry.getValue()) {
-                Integer colIndex = headerIndexMap.get(item.getHeadersId());
-                if (colIndex != null) {
-                    String cellValue = item.getRvalue();
-                    if (StringUtil.isNotEmpty(cellValue)) {
-                        dataRow.createCell(colIndex).setCellValue(cellValue);
-                        totalCellsWritten++;
+        for (String rowId : sortedRowIds) {
+            List<CostVerifyTemplateItems> rowItems = itemsByRowId.get(rowId);
+            if (rowItems != null && !rowItems.isEmpty()) {
+                Row dataRow = sheet.createRow(rowNum++);
+
+                // 填充数据列
+                for (CostVerifyTemplateItems item : rowItems) {
+                    Integer colIndex = headerIndexMap.get(item.getHeadersId());
+                    if (colIndex != null) {
+                        String cellValue = item.getRvalue();
+                        if (StringUtil.isNotEmpty(cellValue)) {
+                            dataRow.createCell(colIndex).setCellValue(cellValue);
+                            totalCellsWritten++;
+                        }
+                    } else {
+                        cellsSkippedNoMapping++;
+                    }
+                }
+
+                // 填充 rowId 和 parentId 列
+                if (rowIdColIndex >= 0) {
+                    dataRow.createCell(rowIdColIndex).setCellValue(rowId);
+                }
+                if (parentIdColIndex >= 0) {
+                    String parentId = rowItems.get(0).getParentid();
+                    if (StringUtil.isNotEmpty(parentId)) {
+                        dataRow.createCell(parentIdColIndex).setCellValue(parentId);
                     }
-                } else {
-                    cellsSkippedNoMapping++;
                 }
             }
         }

+ 3 - 8
assistMg/src/main/java/com/hotent/project/manager/impl/CostNoticeManagerImpl.java

@@ -92,14 +92,9 @@ public class CostNoticeManagerImpl extends BaseManagerImpl<CostNoticeDao, CostNo
 		if(ObjectUtil.isNotEmpty(req.getTaskId())){
 			qw.eq(CostNotice::getTaskId, req.getTaskId());
 		}
-		if(ObjectUtil.isNotEmpty(req.getEnterpriseId())){
-			qw.eq(CostNotice::getEnterpriseId, req.getEnterpriseId());
-		}
-		if(ContextUtil.getCurrentUser().isAdmin() == false){
-			if(ObjectUtil.isNotEmpty(req.getSendTarget())){
-				qw.eq(CostNotice::getSendTarget, req.getSendTarget());
-			}
-		}
+//		if(ObjectUtil.isNotEmpty(req.getEnterpriseId())){
+//			qw.eq(CostNotice::getEnterpriseId, req.getEnterpriseId());
+//		}
 		qw.orderByDesc(CostNotice::getCreateTime);
 		IPage<CostNotice> page=new Page<>(req.getPageNum(), req.getPageSize());
 		return this.page(page, qw);

+ 29 - 39
assistMg/src/main/java/com/hotent/project/manager/impl/CostProjectApprovalManagerImpl.java

@@ -371,45 +371,6 @@ public class CostProjectApprovalManagerImpl extends BaseManagerImpl<CostProjectA
             throw new BaseException("项目已发布");
         }
 
-        // 给所有被监审企业发送任务通知
-        if (ObjectUtil.isNotEmpty(req.getSendType())) {
-            String[] unitIds = costProjectApproval.getAuditedUnitId().split(",");
-            for (String unitId : unitIds) {
-                // 查询企业对应的账号(用户ID)
-                AuditedUnit auditedUnit = auditedUnitManager.getOne(
-                    new LambdaQueryWrapper<AuditedUnit>()
-                        .eq(AuditedUnit::getUnitId, unitId)
-                        .eq(AuditedUnit::getIsDeleted, "0")
-                );
-
-                if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
-                    String title = "监审任务发布通知";
-                    String content = "您有新的监审任务:" + costProjectApproval.getProjectName();
-                    if (StringUtil.isNotEmpty(req.getContent())) {
-                        content += "," + req.getContent();
-                    }
-
-                    if (req.getSendType().contains(",") || req.getSendType().equals("1")) {
-                        // 站内通知
-                        this.costNoticeManager.sendNotice(
-                            req.getProjectId(),
-                            null,
-                            "1",
-                            title,
-                            content,
-                            unitId,
-                            "系统",
-                            auditedUnit.getAccount()
-                        );
-                    }
-
-                    if (req.getSendType().contains(",") || req.getSendType().equals("2")) {
-                        // 短信发送(预留)
-                    }
-                }
-            }
-        }
-
         LambdaUpdateWrapper<CostProjectApproval> updateWrapper = new LambdaUpdateWrapper<>();
         updateWrapper.set(CostProjectApproval::getStatus, "2");
         updateWrapper.set(CostProjectApproval::getAuditGroup, req.getAuditGroup());
@@ -510,6 +471,35 @@ public class CostProjectApprovalManagerImpl extends BaseManagerImpl<CostProjectA
         // 保存所有子任务
         this.costProjectTaskManager.saveBatch(childList);
 
+        // 给每个子任务对应的企业发送任务通知(绑定taskId)
+        for (CostProjectTask childTask : childList) {
+            // 查询企业对应的账号(用户ID)
+            AuditedUnit auditedUnit = auditedUnitManager.getOne(
+                new LambdaQueryWrapper<AuditedUnit>()
+                    .eq(AuditedUnit::getUnitId, childTask.getAuditedUnitId())
+                    .eq(AuditedUnit::getIsDeleted, "0")
+            );
+            String sendTarget = childTask.getCreateBy() == null ? "" : childTask.getCreateBy();
+
+            String title = "监审任务发布通知";
+            String content = "您有新的监审任务:" + costProjectApproval.getProjectName();
+            if (StringUtil.isNotEmpty(req.getContent())) {
+                content += "," + req.getContent();
+            }
+            // 站内通知(绑定子任务ID)
+            this.costNoticeManager.sendNotice(
+                    req.getProjectId(),
+                    childTask.getId(),
+                    "1",
+                    title,
+                    content,
+                    childTask.getAuditedUnitId(),
+                    "系统",
+                    sendTarget
+            );
+
+        }
+
         // 设置父任务的审计单位名称
         if (auditUnitName.length() > 0) {
             costProjectTask.setAuditedUnitName(

+ 4 - 27
assistMg/src/main/java/com/hotent/project/manager/impl/CostProjectTaskPreliminaryOpinionManagerImpl.java

@@ -44,38 +44,15 @@ public class CostProjectTaskPreliminaryOpinionManagerImpl extends BaseManagerImp
     public CostProjectTaskPreliminaryOpinion getByTaskId(String taskId) {
         LambdaQueryWrapper<CostProjectTaskPreliminaryOpinion> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(CostProjectTaskPreliminaryOpinion::getTaskId, taskId);
-        List<CostProjectTaskPreliminaryOpinion> list = this.list(queryWrapper);
-        // 获取当前用户
-        IUser currentUser = ContextUtil.getCurrentUser();
-        AuditedUnit unit = auditedUnitManager.getOne(
-                new LambdaQueryWrapper<AuditedUnit>()
-                        .eq(AuditedUnit::getUnitId, currentUser.getUserId())
-                        .eq(AuditedUnit::getIsDeleted, "0")
-        );
-        if (unit == null){
-            return null ;
-        }
-        return list.stream().filter(item -> item.getUnitId().equals(unit.getUnitId())).findFirst().orElse(null);
+        queryWrapper.last("limit 1");
+        CostProjectTaskPreliminaryOpinion one = this.getOne(queryWrapper);
+        return one;
     }
 
     @Override
     @Transactional
     public void createOrUpdate(CostProjectTaskPreliminaryOpinion opinion) {
-        if (opinion.getId()==null){
-            // 监审用户 - 获取企业
-            String taskId = opinion.getTaskId();
-            List<CostProjectTask> list = costProjectTaskManager.list(
-                    new LambdaQueryWrapper<CostProjectTask>()
-                            .eq(CostProjectTask::getPid, taskId)
-            );
-            for (CostProjectTask costProjectTask : list) {
-                String auditedUnitId = costProjectTask.getAuditedUnitId();
-                opinion.setUnitId(auditedUnitId);
-                this.save( opinion);
-            }
-        }else {
-            this.updateById(opinion);
-        }
+        this.saveOrUpdate(opinion);
     }
 }
 

+ 5 - 1
assistMg/src/main/java/com/hotent/surveyinfo/manager/impl/CostSurveyTemplateManagerImpl.java

@@ -165,7 +165,11 @@ public class CostSurveyTemplateManagerImpl extends BaseManagerImpl<CostSurveyTem
 				new LambdaQueryWrapper<CostCatalogSurvey>()
 						.eq(CostCatalogSurvey::getCatalogId, catalogId)
 		);
-		return this.listByIds(list.stream().map(CostCatalogSurvey::getSurveyId).collect(Collectors.toList()));
+		List<String> ids = list.stream().map(CostCatalogSurvey::getSurveyId).collect(Collectors.toList());
+		if (ids.isEmpty()){
+			return Collections.emptyList();
+		}
+		return this.listByIds(ids);
 	}
 
 

+ 2 - 2
uc/src/main/java/com/hotent/uc/manager/impl/UserManagerImpl.java

@@ -4001,10 +4001,10 @@ public class UserManagerImpl extends BaseManagerImpl <UserDao, User> implements
 		QueryWrapper<User> wrapper = new QueryWrapper<>();
 		IUser iUser = ContextUtil.getCurrentUser();
 		User user = this.getByAccount(iUser.getAccount());
-		if (user.getDataScope().equals(1)) {
+		if (1==user.getDataScope()) {
 			wrapper.eq("CITY_CODE",user.getCityCode());
 		}
-		if (user.getDataScope().equals(2)) {
+		if (2==user.getDataScope()) {
 			wrapper.eq("COUNTY_CODE",user.getCountyCode());
 		}
 		wrapper.ne("ACCOUNT_","admin");