Jelajahi Sumber

fit:三表导入导出

zzw 4 minggu lalu
induk
melakukan
8c6ab28f9f

+ 204 - 110
assistMg/src/main/java/com/hotent/enterpriseDeclare/controller/material/CostProjectTaskSurveyGenericController.java

@@ -8,7 +8,9 @@ import com.hotent.base.constants.ApiGroupConsts;
 import com.hotent.base.model.CommonResult;
 import com.hotent.base.util.StringUtil;
 import com.hotent.baseInfo.manager.CostCatalogSurveyManager;
+import com.hotent.baseInfo.manager.CostDictTypeManager;
 import com.hotent.baseInfo.model.CostCatalogSurvey;
+import com.hotent.baseInfo.model.CostDictType;
 import com.hotent.enterpriseDeclare.manager.CostAuditPeriodRecordManager;
 import com.hotent.enterpriseDeclare.manager.CostSurveyTemplateUploadDataManager;
 import com.hotent.enterpriseDeclare.model.CostAuditPeriodRecord;
@@ -23,8 +25,10 @@ import com.hotent.surveyinfo.dao.*;
 import com.hotent.surveyinfo.manager.*;
 import com.hotent.surveyinfo.model.*;
 import com.hotent.surveyinfo.model.dto.CostItemData;
-import com.hotent.baseInfo.manager.CostDictDataManager;
-import com.hotent.baseInfo.model.CostDictData;
+import com.hotent.sys.persistence.manager.DataDictManager;
+import com.hotent.sys.persistence.manager.SysTypeManager;
+import com.hotent.sys.persistence.model.DataDict;
+import com.hotent.sys.persistence.model.SysType;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -37,6 +41,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.io.InputStream;
 import java.net.URLEncoder;
@@ -69,6 +74,11 @@ public class CostProjectTaskSurveyGenericController {
 
     @Autowired
     private CostSurveyTemplateItemsDao costSurveyTemplateItemsDao;
+    @Resource
+    DataDictManager dataDictManager;
+    @Resource
+    SysTypeManager sysTypeManager;
+
 
 
     // 财务数据表相关
@@ -119,8 +129,6 @@ public class CostProjectTaskSurveyGenericController {
     @Autowired
     private CostSurveyFdTemplateHeadersManager costSurveyFdTemplateHeadersManager;
 
-    @Autowired
-    private CostDictDataManager costDictDataManager;
 
     /**
      * 企业报送-调查表-列表
@@ -148,7 +156,8 @@ public class CostProjectTaskSurveyGenericController {
                 //创建记录
                 if (uploadList.isEmpty()) {
                     CostProjectTask task = costProjectTaskManager.getById(taskId);
-                     List<CostSurveyTemplate> costSurveyTemplates = costSurveyTemplateManager.taskListByCatalogId(task.getCatalogId());
+                    CostProjectApproval approval = costProjectApprovalManager.getById(task.getProjectId());
+                    List<CostSurveyTemplate> costSurveyTemplates = costSurveyTemplateManager.taskListByCatalogId(approval.getCatalogId());
                     for (CostSurveyTemplate template : costSurveyTemplates) {
                         CostSurveyTemplateUpload upload = new CostSurveyTemplateUpload();
                         upload.setSurveyTemplateId(template.getSurveyTemplateId());
@@ -201,7 +210,7 @@ public class CostProjectTaskSurveyGenericController {
                 }
 
                 List<CostSurveyTemplateItems> items = costSurveyTemplateItemsDao.selectBySurveyTemplateIdAndVersion(surveyTemplateId, versionTemplate.getId());
-                // 使用已有的manager方法替代新接口
+
                 List<CostSurveyTemplateHeaders> headList = costSurveyTemplateHeadersManager.listVisibleBySurveyTemplateIdAndVersion(surveyTemplateId, versionTemplate.getId());
                 CostItemData costItemData = buildCostItemData(items, headList);
                 return CommonResult.<CostItemData>ok().value(costItemData);
@@ -214,7 +223,7 @@ public class CostProjectTaskSurveyGenericController {
                 }
 
                 List<CostSurveyFdTemplateItems> items = costSurveyFdTemplateItemsDao.selectBySurveyTemplateIdAndVersion(surveyTemplateId, versionTemplate.getId());
-                // 使用已有的manager方法替代新接口
+
                 List<CostSurveyFdTemplateHeaders> headList = costSurveyFdTemplateHeadersManager.listVisibleBySurveyTemplateIdAndVersion(surveyTemplateId, versionTemplate.getId());
                 CostItemData costItemData = buildCostItemDataFd(items, headList);
                 return CommonResult.<CostItemData>ok().value(costItemData);
@@ -291,14 +300,13 @@ public class CostProjectTaskSurveyGenericController {
             }
         }
 
-        // 设置 type
         for (CostSurveyTemplateUploadData data : dataList) {
             data.setType(type);
         }
 
         costSurveyTemplateUploadDataManager.saveData(dataList);
 
-        // 只有成本调查表需要更新upload状态dataList = {ArrayList@29238}  size = 27
+        // 更新成本调查表
         if ("1".equals(type) && refId != null && !refId.isEmpty()) {
             CostSurveyTemplateUpload upload = costSurveyTemplateUploadManager.getById(refId);
             if (upload != null) {
@@ -1061,7 +1069,7 @@ public class CostProjectTaskSurveyGenericController {
                     }
 
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
-                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>();
                     int dataRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
@@ -1078,16 +1086,12 @@ public class CostProjectTaskSurveyGenericController {
                                 currentRowId = excelRowId.trim();
                             } else {
                                 // 固定表和动态表都不支持新增行,行ID不能为空
-                                // 如果为空则使用行号作为兜底
-                                currentRowId = "row_" + rowIndex;
+                                return CommonResult.<String>error().message(String.format("第%d行 行ID不能为空,请使用系统导出的模板文件", rowIndex + 1));
                             }
                         } else {
-                            // 没有行ID列,使用原有逻辑
-                            currentRowId = "1".equals(templateType) ?
-                                    "row_" + System.currentTimeMillis() : "row_" + rowIndex;
+                            return CommonResult.<String>error().message("固定表/动态表导入失败:Excel文件缺少【行ID】列。请使用系统导出的模板,不要删除隐藏列。");
                         }
 
-                        // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
                         rowIdToExcelRowMap.put(currentRowId, rowIndex + 1);
 
                         // 读取父行ID
@@ -1167,11 +1171,14 @@ public class CostProjectTaskSurveyGenericController {
                         return CommonResult.<String>error().message("Excel文件中没有有效数据");
                     }
 
-                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    List<String> errors = verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    if (!errors.isEmpty()) {
+                        return CommonResult.<String>error().message("导入失败,发现以下问题:\n" + String.join("\n", errors));
+                    }
                     costSurveyTemplateUploadDataManager.saveData(dataList);
 
                     // 更新上传状态
-                    CostSurveyTemplateUpload upload = costSurveyTemplateUploadManager.getById(uploadId);
+                    CostSurveyTemplateUpload upload = costSurveyTemplateUploadManager.getById(materialId);
                     if (upload != null) {
                         upload.setIsUpload("1");
                         costSurveyTemplateUploadManager.updateById(upload);
@@ -1199,7 +1206,7 @@ public class CostProjectTaskSurveyGenericController {
                     return CommonResult.<String>error().message("未找到启用的模板版本");
                 }
 
-                // 使用已有的manager方法替代新接口
+
                 List<CostSurveyFdTemplateHeaders> headersList = costSurveyFdTemplateHeadersManager.listVisibleBySurveyTemplateIdAndVersion(
                                 surveyTemplateId, currentVersion.getId()).stream()
                         .filter(header -> StringUtil.isEmpty(header.getShowVisible()) || "1".equals(header.getShowVisible()))
@@ -1267,7 +1274,7 @@ public class CostProjectTaskSurveyGenericController {
                     }
 
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
-                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>();
                     int dataRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
@@ -1284,13 +1291,10 @@ public class CostProjectTaskSurveyGenericController {
                                 currentRowId = excelRowId.trim();
                             } else {
                                 // 固定表和动态表都不支持新增行,行ID不能为空
-                                // 如果为空则使用行号作为兜底
-                                currentRowId = "row_" + rowIndex;
+                                return CommonResult.<String>error().message(String.format("第%d行 行ID不能为空,请使用系统导出的模板文件", rowIndex + 1));
                             }
                         } else {
-                            // 没有行ID列,使用原有逻辑
-                            currentRowId = "1".equals(templateType) ?
-                                    "row_" + System.currentTimeMillis() : "row_" + rowIndex;
+                            return CommonResult.<String>error().message("固定表/动态表导入失败:Excel文件缺少【行ID】列。请使用系统导出的模板,不要删除隐藏列。");
                         }
 
                         // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
@@ -1315,6 +1319,8 @@ public class CostProjectTaskSurveyGenericController {
                             CostSurveyTemplateUploadData uploadData = createUploadData(
                                     surveyTemplateId, taskId, uploadId, currentRowId,
                                     entry.getValue(), cellValue != null ? cellValue : "", periodRecordId, type);
+                            uploadData.setUploadId(uploadId);
+                            uploadData.setRefId(refId);
                             dataList.add(uploadData);
                         }
 
@@ -1333,7 +1339,7 @@ public class CostProjectTaskSurveyGenericController {
                             periodData.setUploadId(uploadId);
                             periodData.setType(type);
                             periodData.setRowid(currentRowId);
-                            periodData.setRkey(period); // 年限,如:2024
+                            periodData.setRkey(period);
                             periodData.setRvalue(cellValue != null ? cellValue.trim() : "");
                             if (StringUtil.isNotEmpty(periodRecordId)) {
                                 periodData.setPeriodRecordId(periodRecordId);
@@ -1371,7 +1377,10 @@ public class CostProjectTaskSurveyGenericController {
                     if (dataList.isEmpty()) {
                         return CommonResult.<String>error().message("Excel文件中没有有效数据");
                     }
-                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    List<String> errors = verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    if (!errors.isEmpty()) {
+                        return CommonResult.<String>error().message("导入失败,发现以下问题:\n" + String.join("\n", errors));
+                    }
                     costSurveyTemplateUploadDataManager.saveData(dataList);
                     CostProjectTaskMaterial material = costProjectTaskMaterialManager.getById(materialId);
                     material.setIsUpload("1");
@@ -1455,7 +1464,7 @@ public class CostProjectTaskSurveyGenericController {
 
                     // 读取数据行
                     List<CostSurveyTemplateUploadData> dataList = new ArrayList<>();
-                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>(); // rowId -> Excel行号映射
+                    Map<String, Integer> rowIdToExcelRowMap = new HashMap<>();
                     int importRowCount = 0;
 
                     for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
@@ -1471,13 +1480,12 @@ public class CostProjectTaskSurveyGenericController {
                             if (StringUtil.isNotEmpty(excelRowId)) {
                                 currentRowId = excelRowId.trim();
                             } else {
-                                // 固定表不支持新增行,行ID不能为空
-                                // 如果为空则使用行号作为兜底
-                                currentRowId = "row_" + rowIndex;
+                                // 核定表不支持新增行,行ID不能为空
+                                return CommonResult.<String>error().message(String.format("第%d行 行ID不能为空,请使用系统导出的模板文件", rowIndex + 1));
                             }
                         } else {
-                            // 没有行ID列,使用行号
-                            currentRowId = "row_" + rowIndex;
+                            // 核定表必须有行ID列
+                            return CommonResult.<String>error().message("核定表导入失败:Excel文件缺少【行ID】列。请使用系统导出的模板文件。");
                         }
 
                         // 记录 rowId 到 Excel 行号的映射(Excel行号从1开始,加上表头行,所以是 rowIndex + 1)
@@ -1511,7 +1519,10 @@ public class CostProjectTaskSurveyGenericController {
                     if (dataList.isEmpty()) {
                         return CommonResult.<String>error().message("Excel文件没有有效数据");
                     }
-                    verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    List<String> errors = verifyImportData(dataList, type, surveyTemplateId, rowIdToExcelRowMap);
+                    if (!errors.isEmpty()) {
+                        return CommonResult.<String>error().message("导入失败,发现以下问题:\n" + String.join("\n", errors));
+                    }
                     // 保存
                     costSurveyTemplateUploadDataManager.saveData(dataList);
 
@@ -1542,9 +1553,10 @@ public class CostProjectTaskSurveyGenericController {
     }
 
     // 校验逻辑
-    private void verifyImportData(List<CostSurveyTemplateUploadData> dataList, String type, String surveyTemplateId, Map<String, Integer> rowIdToExcelRowMap) throws Exception {
+    private List<String> verifyImportData(List<CostSurveyTemplateUploadData> dataList, String type, String surveyTemplateId, Map<String, Integer> rowIdToExcelRowMap) {
+        List<String> errors = new ArrayList<>();
         if (dataList == null || dataList.isEmpty()) {
-            return;
+            return errors;
         }
 
         // 获取模板类型(templateType)
@@ -1563,7 +1575,7 @@ public class CostProjectTaskSurveyGenericController {
         // 获取表头信息(用于字段校验)
         List<? extends Object> headersList = getTemplateHeaders(type, surveyTemplateId);
         if (headersList == null || headersList.isEmpty()) {
-            return;
+            return errors;
         }
 
         // 1. 字段级别校验(必填、类型、长度等)
@@ -1571,14 +1583,16 @@ 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, rowIdToExcelRowMap);
+            List<String> fieldErrors = validateFieldRulesExcludingPeriods(rowid, rowData, headersList, rowIdToExcelRowMap);
+            errors.addAll(fieldErrors);
         }
 
         // 2. 计算公式校验/结构校验(仅针对固定表,动态表不需要)
-        if ("2".equals(templateType)) {
+        if ("2".equals(templateType))   {
             System.out.println("========================================");
             System.out.println("固定表校验:开始结构校验和公式校验");
-            validateFixedTableStructure(rowDataMap, headersList, surveyTemplateId, type);
+            List<String> structureErrors = validateFixedTableStructure(rowDataMap, headersList, surveyTemplateId, type);
+            errors.addAll(structureErrors);
 
             // 根据类型获取模板项
             List<? extends Object> itemsList = getTemplateItems(type, surveyTemplateId);
@@ -1611,8 +1625,9 @@ public class CostProjectTaskSurveyGenericController {
                     String cellCode = rowidToCellCodeMap.get(rowid);
 
                     if (StringUtil.isEmpty(cellCode)) {
-                        // rowid 不匹配说明导入的Excel不是从当前模板导出的,直接报错
-                        throw new IllegalArgumentException(String.format("行[%s] 的行ID在模板中不存在,请使用系统导出的最新模板文件", rowid));
+                        // rowid 不匹配说明导入的Excel不是从当前模板导出的,添加到错误列表
+                        errors.add(String.format("行[%s] 的行ID在模板中不存在,请使用系统导出的最新模板文件", rowid));
+                        continue;
                     }
 
                     // 处理年限列的数据(key是4位数字,如"2024")
@@ -1650,25 +1665,29 @@ public class CostProjectTaskSurveyGenericController {
                         continue;
                     }
 
-                    // 针对每个年限分别校验(直接抛异常,不需要检查errors
+                    // 针对每个年限分别校验(收集错误
                     for (String period : periods) {
-                        validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type,rowIdToExcelRowMap);
+                        List<String> formulaErrors = validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type, rowIdToExcelRowMap);
+                        errors.addAll(formulaErrors);
                     }
                 }
             }
         }
+        return errors;
     }
 
     /**
      * 固定表结构校验:行列数量必须匹配
      */
-    private void validateFixedTableStructure(Map<String, Map<String, String>> rowDataMap,
+    private List<String> validateFixedTableStructure(Map<String, Map<String, String>> rowDataMap,
                                              List<? extends Object> headersList,
                                              String surveyTemplateId, String type) {
+        List<String> errors = new ArrayList<>();
         // 1. 获取模板定义的行数
         List<? extends Object> templateItems = getTemplateItems(type, surveyTemplateId);
         if (templateItems == null || templateItems.isEmpty()) {
-            throw new IllegalArgumentException("固定表模板未定义任何数据行,无法导入");
+            errors.add("固定表模板未定义任何数据行,无法导入");
+            return errors;
         }
 
         // 按 rowid 分组模板项,得到模板定义的行数
@@ -1682,7 +1701,7 @@ public class CostProjectTaskSurveyGenericController {
 
         // 2. 校验行数是否匹配
         if (actualRowCount != expectedRowCount) {
-            throw new IllegalArgumentException(String.format("固定表行数不匹配!模板定义:%d 行,导入数据:%d 行。固定表不允许增加或减少行。",
+            errors.add(String.format("固定表行数不匹配!模板定义:%d 行,导入数据:%d 行。固定表不允许增加或减少行。",
                     expectedRowCount, actualRowCount));
         }
 
@@ -1703,7 +1722,7 @@ public class CostProjectTaskSurveyGenericController {
             // 移除年限列(4位数字的字段,如"2024")和备注列(remark)
             extraFields.removeIf(field -> field.matches("\\d{4}") || "remark".equals(field));
             if (!extraFields.isEmpty()) {
-                throw new IllegalArgumentException(String.format("行[%s] 包含模板中未定义的字段:%s。固定表不允许添加额外字段。",
+                errors.add(String.format("行[%s] 包含模板中未定义的字段:%s。固定表不允许添加额外字段。",
                         rowid, String.join(", ", extraFields)));
             }
 
@@ -1715,11 +1734,12 @@ public class CostProjectTaskSurveyGenericController {
 
                 // 如果是必填字段但导入数据中没有这个字段
                 if ("1".equals(isRequired) && !actualFields.contains(fieldEname)) {
-                    throw new IllegalArgumentException(String.format("行[%s] 缺少必填字段:%s(%s)。固定表必须包含所有必填字段。",
+                    errors.add(String.format("行[%s] 缺少必填字段:%s(%s)。固定表必须包含所有必填字段。",
                             rowid, fieldEname, fieldName));
                 }
             }
         }
+        return errors;
     }
 
     /**
@@ -1781,8 +1801,9 @@ public class CostProjectTaskSurveyGenericController {
     /**
      * 字段级别校验
      */
-    private void validateFieldRulesExcludingPeriods(String rowid, Map<String, String> rowData,
+    private List<String> validateFieldRulesExcludingPeriods(String rowid, Map<String, String> rowData,
                                                     List<? extends Object> headersList, Map<String, Integer> rowIdToExcelRowMap) {
+        List<String> errors = new ArrayList<>();
         String rowDisplay = getRowDisplay(rowid, rowIdToExcelRowMap);
         System.out.println("========================================");
         System.out.println("开始校验" + rowDisplay + "的字段(排除年限列)");
@@ -1807,8 +1828,8 @@ 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)]为必填项,不能为空", rowDisplay, fieldEname, fieldName));
+                errors.add(String.format("%s [%s]为必填项,不能为空", rowDisplay, fieldName));
+                continue;
             }
 
             // 如果值为空且非必填,跳过后续校验
@@ -1818,22 +1839,33 @@ public class CostProjectTaskSurveyGenericController {
 
             // 2. 字典校验(支持 "1" 和 "true" 两种格式)
             if (("1".equals(isDict) || "true".equalsIgnoreCase(isDict)) && StringUtil.isNotEmpty(dictCode)) {
-                validateDictValue(rowid, fieldEname, fieldName, value, dictCode);
+                try {
+                    validateDictValue(rowid, fieldEname, fieldName, value, dictCode);
+                } catch (IllegalArgumentException e) {
+                    errors.add(e.getMessage());
+                }
             }
 
             // 3. 字段类型校验
             if (StringUtil.isNotEmpty(fieldType)) {
-                validateFieldType(rowid, fieldEname, fieldName, value, fieldType);
+                try {
+                    validateFieldType(rowDisplay, fieldEname, fieldName, value, fieldType);
+                } catch (IllegalArgumentException e) {
+                    errors.add(e.getMessage());
+                }
             }
 
             // 4. 字段长度校验
             if (fieldTypelen != null && fieldTypelen > 0) {
-                validateFieldLength(rowid, fieldEname, fieldName, value, fieldType, fieldTypelen, fieldTypenointlen);
+                try {
+                    validateFieldLength(rowid, fieldEname, fieldName, value, fieldType, fieldTypelen, fieldTypenointlen);
+                } catch (IllegalArgumentException e) {
+                    errors.add(e.getMessage());
+                }
             }
         }
 
-        // 注意:年限列(如2024、2025)和备注列(remark)不在headersList中,
-        // 它们存储在rowData中但不会被上面的循环处理,因此自动被排除
+        return errors;
     }
 
     /**
@@ -1847,20 +1879,23 @@ public class CostProjectTaskSurveyGenericController {
 
         try {
             // 查询字典数据
-            QueryWrapper<CostDictData> wrapper = new QueryWrapper<>();
-            wrapper.eq("dict_type", dictCode)
-                   .eq("status", "0"); // 只查询正常状态的字典项
-            List<CostDictData> dictDataList = costDictDataManager.list(wrapper);
+            SysType TYPE = sysTypeManager.getOne(
+                    new QueryWrapper<SysType>()
+                            .eq("TYPE_KEY_", dictCode)
+            );
+            QueryWrapper<DataDict> wrapper = new QueryWrapper<>();
+            wrapper.eq("TYPE_ID_", TYPE.getId());
+            List<DataDict> dictDataList = dataDictManager.list(wrapper);
 
             if (dictDataList == null || dictDataList.isEmpty()) {
-                throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]的字典配置[%s]不存在或未配置字典项",
-                        rowid, fieldEname, fieldName, dictCode));
+                throw new IllegalArgumentException(String.format("行[%s] [%s]的选项配置异常",
+                        rowid, fieldName));
             }
 
             // 检查值是否在字典允许的范围内(支持多选,用逗号分隔)
             String[] values = value.split(",");
             Set<String> validValues = dictDataList.stream()
-                    .map(CostDictData::getDictValue)
+                    .map(DataDict::getKey)
                     .filter(StringUtil::isNotEmpty)
                     .collect(Collectors.toSet());
 
@@ -1873,17 +1908,14 @@ public class CostProjectTaskSurveyGenericController {
             }
 
             if (!invalidValues.isEmpty()) {
-                throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]的值[%s]不在字典[%s]允许的范围内,有效值:%s",
-                        rowid, fieldEname, fieldName,
-                        String.join(", ", invalidValues),
-                        dictCode,
-                        String.join(", ", validValues)));
+                throw new IllegalArgumentException(String.format("行[%s] [%s]的值[%s]不在允许的选项范围内",
+                        rowid, fieldName, String.join(", ", invalidValues)));
             }
         } 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",
+                    rowid, fieldName, e.getMessage()));
         }
     }
 
@@ -1900,32 +1932,32 @@ public class CostProjectTaskSurveyGenericController {
                     try {
                         Long.parseLong(value);
                     } catch (NumberFormatException e) {
-                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型错误,应为整数,实际值:%s", rowDisplay, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s [%s]应为整数,实际值:%s", rowDisplay, fieldName, value));
                     }
                     break;
 
                 case "decimal":
                 case "double":
-                case "float":
+                case "zi":
                 case "number":
                     try {
                         Double.parseDouble(value);
                     } catch (NumberFormatException e) {
-                        throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型错误,应为数字,实际值:%s", rowDisplay, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s [%s]应为数字,实际值:%s", rowDisplay, 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", rowDisplay, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s [%s]日期格式应为yyyy-MM-dd,实际值:%s", rowDisplay, 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", rowDisplay, fieldEname, fieldName, value));
+                    // 日期时间格式校验 - 支持两种格式
+                    if (!value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}") && !value.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        throw new IllegalArgumentException(String.format("%s [%s]日期格式应为yyyy-MM-dd或yyyy-MM-dd HH:mm:ss,实际值:%s", rowDisplay, fieldName, value));
                     }
                     break;
 
@@ -1936,8 +1968,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",
-                                rowDisplay, fieldEname, fieldName, value));
+                        throw new IllegalArgumentException(String.format("%s [%s]应为布尔值(true/false, 1/0, 是/否),实际值:%s",
+                                rowDisplay, fieldName, value));
                     }
                     break;
 
@@ -1946,7 +1978,6 @@ public class CostProjectTaskSurveyGenericController {
                 case "text":
                     // 字符串类型,无需特殊校验
                     break;
-
                 default:
                     // 未知类型,不校验
                     break;
@@ -1954,7 +1985,7 @@ public class CostProjectTaskSurveyGenericController {
         } catch (IllegalArgumentException e) {
             throw e;
         } catch (Exception e) {
-            throw new IllegalArgumentException(String.format("%s 字段[%s(%s)]类型校验异常:%s", rowDisplay, fieldEname, fieldName, e.getMessage()));
+            throw new IllegalArgumentException(String.format("%s [%s]格式校验异常:%s", rowDisplay, fieldName, e.getMessage()));
         }
     }
 
@@ -1970,8 +2001,8 @@ public class CostProjectTaskSurveyGenericController {
                 case "text":
                     // 字符串长度校验
                     if (value.length() > fieldTypelen) {
-                        throw new IllegalArgumentException(String.format("行[%s] 字段[%s(%s)]长度超限,最大长度:%d,实际长度:%d",
-                                rowid, fieldEname, fieldName, fieldTypelen, value.length()));
+                        throw new IllegalArgumentException(String.format("行[%s] [%s]长度超限,最大长度:%d,实际长度:%d",
+                                rowid, fieldName, fieldTypelen, value.length()));
                     }
                     break;
 
@@ -2188,9 +2219,10 @@ public class CostProjectTaskSurveyGenericController {
     /**
      * 校验一行数据的计算公式(针对特定年限)
      */
-    private void validateRowFormulasForPeriod(String rowid, Map<String, String> rowData,
+    private List<String> validateRowFormulasForPeriod(String rowid, Map<String, String> rowData,
                                               List<? extends Object> rowItems, Map<String, String> globalCellCodeMap,
-                                              String period, String type,Map<String, Integer> rowIdToExcelRowMap) {
+                                              String period, String type, Map<String, Integer> rowIdToExcelRowMap) {
+        List<String> errors = new ArrayList<>();
         // 找到该行的计算公式(同一行的所有模板项共享同一个公式)
         String calculationFormula = null;
         String cellCode = null;
@@ -2205,7 +2237,7 @@ public class CostProjectTaskSurveyGenericController {
 
         // 如果该行没有公式,跳过
         if (StringUtil.isEmpty(calculationFormula)) {
-            return;
+            return errors;
         }
 
         // 检查公式引用的单元格在当前年限是否有任何一个有值
@@ -2216,7 +2248,6 @@ public class CostProjectTaskSurveyGenericController {
         List<String> referencedCellsDebug = new ArrayList<>();
         while (matcher.find()) {
             String referencedCell = matcher.group();
-            // 构建 cellCode_年限 的key(如 A1_2024)
             String mapKey = referencedCell + "_" + period;
             String value = globalCellCodeMap.get(mapKey);
             String displayValue = StringUtil.isNotEmpty(value) ? value : "0";
@@ -2228,7 +2259,7 @@ public class CostProjectTaskSurveyGenericController {
 
         // 如果公式引用的单元格在当前年限都没有值,跳过校验
         if (!hasAnyReferencedValue) {
-            return;
+            return errors;
         }
 
         // 获取用户输入的汇总值(当前年限)
@@ -2263,30 +2294,43 @@ public class CostProjectTaskSurveyGenericController {
 
             // 比较计算值和输入值(允许小数点后2位的误差)
             if (Math.abs(calculatedValue - inputValue) > 0.01) {
-                System.out.println("校验结果: 不匹配");
+                System.out.println("校验结果: 不匹配");
                 System.out.println("========================================");
                 // 获取友好的行号显示
                 Integer excelRow = rowIdToExcelRowMap.get(rowid);
                 String rowDisplay = excelRow != null ? "第" + excelRow + "行" : "行[" + rowid + "]";
-                throw new IllegalArgumentException(String.format("%s [%s]列汇总值错误:计算值[%.2f],填写值[%.2f]",
-                        rowDisplay, period + "年", calculatedValue, inputValue));
+                errors.add(String.format("%s %s年列数据错误:计算结果应为%.2f,实际填写%.2f",
+                        rowDisplay, period, calculatedValue, inputValue));
             } else {
                 System.out.println("校验结果: ✓ 通过");
                 System.out.println("========================================");
             }
-        } catch (IllegalArgumentException e) {
-            // 重新抛出校验错误
-            throw e;
         } catch (Exception e) {
+            // 统一处理计算错误,提供更详细但不重复的错误信息
             System.out.println("========================================");
             System.out.println("行[" + rowid + "] [" + period + "年]列公式校验");
             System.out.println("公式: " + calculationFormula);
             System.out.println("引用值: " + String.join(", ", referencedCellsDebug));
-            System.out.println("校验结果: 计算错误 - " + e.getMessage());
+            System.out.println("校验结果: 计算错误 - " + e.getMessage());
             System.out.println("========================================");
-            throw new IllegalArgumentException(String.format("行[%s] [%s]列计算错误:%s",
-                    rowid, period + "年", e.getMessage()));
+
+            // 获取友好的行号显示
+            Integer excelRow = rowIdToExcelRowMap.get(rowid);
+            String rowDisplay = excelRow != null ? "第" + excelRow + "行" : "行[" + rowid + "]";
+
+            // 简化错误信息,只显示关键信息
+            String simpleError;
+            if (e.getMessage().contains("除以零") || e.getMessage().contains("无穷大")) {
+                simpleError = "除数为0,无法计算";
+            } else if (e.getMessage().contains("溢出")) {
+                simpleError = "数值过大,计算溢出";
+            } else {
+                simpleError = "公式计算错误";
+            }
+
+            errors.add(String.format("%s %s年列计算错误:%s", rowDisplay, period, simpleError));
         }
+        return errors;
     }
 
     /**
@@ -2851,12 +2895,30 @@ public class CostProjectTaskSurveyGenericController {
 
     private String getCellStringValue(Cell cell) {
         if (cell == null) return "";
-        switch (cell.getCellType()) {
-            case STRING:
-                return cell.getStringCellValue();
+
+        try {
+            switch (cell.getCellType()) {
+                case STRING:
+                    return cell.getStringCellValue();
             case NUMERIC:
                 if (DateUtil.isCellDateFormatted(cell)) {
-                    return cell.getDateCellValue().toString();
+                    // 格式化日期,根据单元格的格式判断是日期还是日期时间
+                    java.util.Date dateValue = cell.getDateCellValue();
+                    java.text.SimpleDateFormat dateFormat;
+
+                    // 检查是否包含时间信息(时分秒不全为0)
+                    java.util.Calendar cal = java.util.Calendar.getInstance();
+                    cal.setTime(dateValue);
+                    boolean hasTime = cal.get(java.util.Calendar.HOUR_OF_DAY) != 0 ||
+                                     cal.get(java.util.Calendar.MINUTE) != 0 ||
+                                     cal.get(java.util.Calendar.SECOND) != 0;
+
+                    if (hasTime) {
+                        dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    } else {
+                        dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd");
+                    }
+                    return dateFormat.format(dateValue);
                 } else {
                     double numericValue = cell.getNumericCellValue();
                     return numericValue == (long) numericValue ?
@@ -2866,16 +2928,48 @@ public class CostProjectTaskSurveyGenericController {
                 return String.valueOf(cell.getBooleanCellValue());
             case FORMULA:
                 try {
-                    return cell.getStringCellValue();
-                } catch (Exception e) {
-                    try {
-                        return String.valueOf(cell.getNumericCellValue());
-                    } catch (Exception ex) {
-                        return "";
+                    // 先尝试获取公式计算后的值类型
+                    switch (cell.getCachedFormulaResultType()) {
+                        case STRING:
+                            return cell.getStringCellValue();
+                        case NUMERIC:
+                            if (DateUtil.isCellDateFormatted(cell)) {
+                                // 处理公式结果为日期的情况
+                                java.util.Date dateValue = cell.getDateCellValue();
+                                java.text.SimpleDateFormat dateFormat;
+                                java.util.Calendar cal = java.util.Calendar.getInstance();
+                                cal.setTime(dateValue);
+                                boolean hasTime = cal.get(java.util.Calendar.HOUR_OF_DAY) != 0 ||
+                                                 cal.get(java.util.Calendar.MINUTE) != 0 ||
+                                                 cal.get(java.util.Calendar.SECOND) != 0;
+                                if (hasTime) {
+                                    dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                                } else {
+                                    dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd");
+                                }
+                                return dateFormat.format(dateValue);
+                            } else {
+                                double numericValue = cell.getNumericCellValue();
+                                return numericValue == (long) numericValue ?
+                                        String.valueOf((long) numericValue) : String.valueOf(numericValue);
+                            }
+                        case BOOLEAN:
+                            return String.valueOf(cell.getBooleanCellValue());
+                        default:
+                            return "";
                     }
+                } catch (Exception e) {
+                    // 如果无法获取公式计算结果,返回空字符串
+                    return "";
                 }
-            default:
-                return "";
+                default:
+                    return "";
+            }
+        } catch (Exception e) {
+            // 如果读取单元格时发生任何异常,返回空字符串并记录错误
+            System.err.println("Error reading cell at row " + cell.getRowIndex() +
+                              ", column " + cell.getColumnIndex() + ": " + e.getMessage());
+            return "";
         }
     }
 

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

@@ -411,16 +411,16 @@ public class CostProjectApprovalManagerImpl extends BaseManagerImpl<CostProjectA
         //财务表
         List<CostSurveyFdTemplate> costSurveyFdTemplates = costSurveyFdTemplateManager.listByCatalogId(catalogId);
 
-        if (ObjectUtil.isNotEmpty(costSurveyFdTemplates)) {
-            if (costSurveyFdTemplates.size() == 1) {
-                CostSurveyFdTemplate costSurveyFdTemplate = costSurveyFdTemplates.get(0);
-                List<CostSurveyFdTemplateHeaders> costSurveyFdTemplateHeaders = this.costSurveyFdTemplateHeadersManager.listBySurveyTemplateId(costSurveyFdTemplate.getSurveyTemplateId());
-                List<CostSurveyFdTemplateItems> costSurveyFdTemplateItems = this.costSurveyFdTemplateItemsManager.selectBySurveyTemplateId(costSurveyFdTemplate.getSurveyTemplateId());
-
-            } else {
-                throw new BaseException("财务表关系为一对一");
-            }
-        }
+//        if (ObjectUtil.isNotEmpty(costSurveyFdTemplates)) {
+//            if (costSurveyFdTemplates.size() == 1) {
+//                CostSurveyFdTemplate costSurveyFdTemplate = costSurveyFdTemplates.get(0);
+//                List<CostSurveyFdTemplateHeaders> costSurveyFdTemplateHeaders = this.costSurveyFdTemplateHeadersManager.listBySurveyTemplateId(costSurveyFdTemplate.getSurveyTemplateId());
+//                List<CostSurveyFdTemplateItems> costSurveyFdTemplateItems = this.costSurveyFdTemplateItemsManager.selectBySurveyTemplateId(costSurveyFdTemplate.getSurveyTemplateId());
+//
+//            } else {
+//                throw new BaseException("财务表关系为一对一");
+//            }
+//        }
 
 
         //成本表

+ 93 - 74
assistMg/src/main/java/com/hotent/project/manager/impl/CostProjectTaskManagerImpl.java

@@ -141,6 +141,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
     /**
      * 计算任务预警状态
+     *
      * @param task 任务对象
      * @return 预警状态:green-绿色预警(在办理期限内) yellow-黄色预警(超过环节期限但没超过流程期限) red-红色预警(超过流程期限)
      */
@@ -150,39 +151,39 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                 new LambdaQueryWrapper<CostProjectTaskProccess>()
                         .eq(CostProjectTaskProccess::getTaskId, task.getId())
         );
-        
+
         if (process == null) {
             return "green"; // 默认绿色预警
         }
-        
+
         // 获取当前环节的节点信息
         CostProjectTaskNode currentNode = costProjectTaskNodeManager.getOne(
                 new LambdaQueryWrapper<CostProjectTaskNode>()
                         .eq(CostProjectTaskNode::getTaskId, task.getId())
                         .eq(CostProjectTaskNode::getProcessNodeKey, task.getCurrentNode())
         );
-        
+
         // 获取当前时间
         LocalDateTime now = LocalDateTime.now();
-        
+
         // 1. 如果超过流程期限,红色预警
-        if (process.getPlannedAuditEndDate() != null && 
-            now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
+        if (process.getPlannedAuditEndDate() != null &&
+                now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
             return "red";
         }
-        
+
         // 2. 如果当前环节有截止时间且已超过,但未超过流程期限,黄色预警
-        if (currentNode != null && currentNode.getEndTime() != null && 
-            now.isAfter(currentNode.getEndTime())) {
+        if (currentNode != null && currentNode.getEndTime() != null &&
+                now.isAfter(currentNode.getEndTime())) {
             // 检查是否超过流程期限
-            if (process.getPlannedAuditEndDate() != null && 
-                now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
+            if (process.getPlannedAuditEndDate() != null &&
+                    now.toLocalDate().isAfter(process.getPlannedAuditEndDate())) {
                 return "red"; // 超过流程期限,红色预警
             } else {
                 return "yellow"; // 超过环节期限但未超过流程期限,黄色预警
             }
         }
-        
+
         // 3. 默认绿色预警(在办理期限内)
         return "green";
     }
@@ -216,7 +217,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                 .distinct()
                 .collect(java.util.stream.Collectors.toList());
 
-        if (req.getAreaCode()!=null){
+        if (req.getAreaCode() != null) {
             List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
                     new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
             );
@@ -253,9 +254,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
         if (StringUtil.isNotEmpty(req.getYear())) {
             queryWrapper.eq(CostProjectTask::getYear, req.getYear());
         }
-        queryWrapper.eq(req.getCurrentNode()!=null,CostProjectTask::getCurrentNode,req.getCurrentNode());
-        queryWrapper.ne(req.getNCurrentNode()!=null,CostProjectTask::getCurrentNode,req.getNCurrentNode());
-        queryWrapper.ne(req.getNStatus()!=null,CostProjectTask::getStatus,req.getNStatus() );
+        queryWrapper.eq(req.getCurrentNode() != null, CostProjectTask::getCurrentNode, req.getCurrentNode());
+        queryWrapper.ne(req.getNCurrentNode() != null, CostProjectTask::getCurrentNode, req.getNCurrentNode());
+        queryWrapper.ne(req.getNStatus() != null, CostProjectTask::getStatus, req.getNStatus());
         // 按创建时间倒序排列
         queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
 
@@ -338,19 +339,19 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
         // 1.校验内容是否填写完毕!t
         List<CostProjectTaskMaterial> costProjectTaskMaterials = costProjectTaskMaterialManager.listByTaskId(costTaskPageReq.getTaskId());
         boolean c = costProjectTaskMaterials.stream()
-                .filter(item ->"1".equals(item.getIsRequired()))
+                .filter(item -> "1".equals(item.getIsRequired()))
                 .allMatch(
-                item -> "1".equals(item.getIsUpload())
-        );
+                        item -> "1".equals(item.getIsUpload())
+                );
         if (!c) {
             throw new RuntimeException("报送资料必填文件未全部填写完成!");
         }
         List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(costTaskPageReq.getTaskId());
         boolean d = costSurveyTemplateUploads.stream()
-                .filter(item ->"1".equals(item.getIsRequired()))
+                .filter(item -> "1".equals(item.getIsRequired()))
                 .allMatch(
                         item -> "1".equals(item.getIsUpload())
-        );
+                );
         if (!d) {
             throw new RuntimeException("成本调查必填文件未全部填写完成!");
         }
@@ -459,17 +460,17 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
             boolean c = costProjectTaskMaterials.stream()
                     .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
                     .allMatch(
-                    item -> "1".equals(item.getAuditedStatus())
-            );
+                            item -> "1".equals(item.getAuditedStatus())
+                    );
             if (!c) {
                 throw new RuntimeException("报送资料未全部通过!");
             }
             List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(nTask.getId());
             boolean d = costSurveyTemplateUploads.stream()
-                    .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()) )
+                    .filter(item -> "1".equals(item.getIsRequired()) && "1".equals(item.getIsUpload()))
                     .allMatch(
                             item -> "1".equals(item.getAuditedStatus())
-            );
+                    );
             if (!d) {
                 throw new RuntimeException("成本调查表未全部通过!");
             }
@@ -640,7 +641,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
         // 更新流程节点时间:清空当前节点的结束时间,重置上一节点的开始时间
         CostProjectProccess proccess = costProjectProccessManager.getOne(
-                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId,task.getProjectId())
+                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
         );
 
         // 清空当前节点的实际结束时间和操作信息
@@ -707,9 +708,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                 // 如果退回到意见反馈节点,通知企业
                 if ("yjfk".equals(prevNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
                     AuditedUnit auditedUnit = auditedUnitManager.getOne(
-                        new LambdaQueryWrapper<AuditedUnit>()
-                            .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
-                            .eq(AuditedUnit::getIsDeleted, "0")
+                            new LambdaQueryWrapper<AuditedUnit>()
+                                    .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
+                                    .eq(AuditedUnit::getIsDeleted, "0")
                     );
                     if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
                         String noticeTitle = "意见反馈通知";
@@ -718,14 +719,14 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                         Org org = orgManager.getById(orgId);
                         String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
                         costNoticeManager.sendNotice(
-                            child.getProjectId(),
-                            child.getId(),
-                            "1",
-                            noticeTitle,
-                            noticeContent,
-                            child.getAuditedUnitId(),
-                            noticeSource,
-                            auditedUnit.getAccount()
+                                child.getProjectId(),
+                                child.getId(),
+                                "1",
+                                noticeTitle,
+                                noticeContent,
+                                child.getAuditedUnitId(),
+                                noticeSource,
+                                auditedUnit.getAccount()
                         );
                     }
                 }
@@ -787,7 +788,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
         // 修改当前节点的结束时间
         CostProjectProccess proccess = costProjectProccessManager.getOne(
-                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId,task.getProjectId())
+                new LambdaQueryWrapper<CostProjectProccess>().eq(CostProjectProccess::getProjectId, task.getProjectId())
         );
         CostProjectProccessNode one = costProjectProccessNodeManager.getOne(
                 new LambdaQueryWrapper<CostProjectProccessNode>()
@@ -841,9 +842,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                 // 如果扭转到意见反馈节点,通知企业
                 if ("yjfk".equals(nextNodeStatus) && StringUtil.isNotEmpty(child.getAuditedUnitId())) {
                     AuditedUnit auditedUnit = auditedUnitManager.getOne(
-                        new LambdaQueryWrapper<AuditedUnit>()
-                            .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
-                            .eq(AuditedUnit::getIsDeleted, "0")
+                            new LambdaQueryWrapper<AuditedUnit>()
+                                    .eq(AuditedUnit::getUnitId, child.getAuditedUnitId())
+                                    .eq(AuditedUnit::getIsDeleted, "0")
                     );
                     if (auditedUnit != null && StringUtil.isNotEmpty(auditedUnit.getAccount())) {
                         String noticeTitle = "意见反馈通知";
@@ -852,14 +853,14 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                         Org org = orgManager.getById(orgId);
                         String noticeSource = (org != null ? org.getName() : "系统") + " " + AuthenticationUtil.getCurrentUserFullname();
                         costNoticeManager.sendNotice(
-                            child.getProjectId(),
-                            child.getId(),
-                            "1",
-                            noticeTitle,
-                            noticeContent,
-                            child.getAuditedUnitId(),
-                            noticeSource,
-                            auditedUnit.getAccount()
+                                child.getProjectId(),
+                                child.getId(),
+                                "1",
+                                noticeTitle,
+                                noticeContent,
+                                child.getAuditedUnitId(),
+                                noticeSource,
+                                auditedUnit.getAccount()
                         );
                     }
                 }
@@ -924,7 +925,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
         queryWrapper.in(CostProjectTask::getProjectId, accessibleProjectIds);
 
         // 根据请求参数添加查询条件
-        queryWrapper.eq(projectId!=null,CostProjectTask::getProjectId, projectId);
+        queryWrapper.eq(projectId != null, CostProjectTask::getProjectId, projectId);
 
         // 按创建时间倒序排列
         queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
@@ -942,7 +943,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
     @Override
     public List<Map<String, Object>> getDoChartList(String year, String region) {
         List<CostCatalog> list = costCatalogManager.list(
-            new LambdaQueryWrapper<CostCatalog>().eq( CostCatalog::getParentId,"1969351600934948833")
+                new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, "1969351600934948833")
         );
         List<Map<String, Object>> maps = new ArrayList<>();
 
@@ -952,9 +953,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
             // 通过项目立项表关联查询目录
             List<CostProjectApproval> approvals = costProjectApprovalManager.list(
-                new LambdaQueryWrapper<CostProjectApproval>()
-                    .in(CostProjectApproval::getCatalogId, allCatalogIds)
-                    .eq(CostProjectApproval::getIsDeleted, "0")
+                    new LambdaQueryWrapper<CostProjectApproval>()
+                            .in(CostProjectApproval::getCatalogId, allCatalogIds)
+                            .eq(CostProjectApproval::getIsDeleted, "0")
             );
 
             if (approvals.isEmpty()) {
@@ -967,8 +968,8 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
             }
 
             List<String> projectIds = approvals.stream()
-                .map(CostProjectApproval::getProjectId)
-                .collect(Collectors.toList());
+                    .map(CostProjectApproval::getProjectId)
+                    .collect(Collectors.toList());
 
             // 查询子任务
             LambdaQueryWrapper<CostProjectTask> taskQuery = new LambdaQueryWrapper<>();
@@ -983,8 +984,8 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
             // 统计完成和未完成的任务
             long finishCount = tasks.stream()
-                .filter(task -> TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus()))
-                .count();
+                    .filter(task -> TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus()))
+                    .count();
             long nFinishCount = tasks.size() - finishCount;
 
             Map<String, Object> map = new HashMap<>();
@@ -998,19 +999,34 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
     @Override
     public List<CostNotice> getDoMsgList() {
-        // 获取当前用户
         IUser currentUser = ContextUtil.getCurrentUser();
         String currentUserId = currentUser.getUserId();
-        // 查询发送给当前用户的消息
+
+        AuditedUnit unit = auditedUnitManager.getOne(
+                new LambdaQueryWrapper<AuditedUnit>()
+                        .eq(AuditedUnit::getAccount, currentUserId)
+                        .last("limit 1")
+        );
+
         LambdaQueryWrapper<CostNotice> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(CostNotice::getIsDeleted, "0")
-                   .eq(CostNotice::getSendTarget, currentUserId)
-                   .orderByDesc(CostNotice::getCreateTime)
-                    .last("limit 8");
+        queryWrapper.eq(CostNotice::getIsDeleted, "0");
+
+        if (unit != null) {
+            queryWrapper.and(q -> q.eq(CostNotice::getEnterpriseId, unit.getUnitId())
+                    .or()
+                    .eq(CostNotice::getSendTarget, currentUserId));
+        } else {
+            // unit 为空时,只看是否发给当前用户
+            queryWrapper.eq(CostNotice::getSendTarget, currentUserId);
+        }
+
+        queryWrapper.orderByDesc(CostNotice::getCreateTime)
+                .last("limit 8");
 
         return costNoticeManager.list(queryWrapper);
     }
 
+
     @Override
     public IPage<CostProjectTask> pageListForReviewTaskChild(CostTaskReviewPageReq req) {
         // 获取当前用户
@@ -1040,7 +1056,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
                 .distinct()
                 .collect(java.util.stream.Collectors.toList());
 
-        if (req.getAreaCode()!=null){
+        if (req.getAreaCode() != null) {
             List<CostProjectTaskApproval> list = costProjectTaskApprovalManager.list(
                     new LambdaQueryWrapper<CostProjectTaskApproval>().eq(CostProjectTaskApproval::getAreaCode, req.getAreaCode())
             );
@@ -1077,9 +1093,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
         if (StringUtil.isNotEmpty(req.getYear())) {
             queryWrapper.eq(CostProjectTask::getYear, req.getYear());
         }
-        queryWrapper.eq(req.getCurrentNode()!=null,CostProjectTask::getCurrentNode,req.getCurrentNode());
-        queryWrapper.ne(req.getNCurrentNode()!=null,CostProjectTask::getCurrentNode,req.getNCurrentNode());
-        queryWrapper.ne(req.getNStatus()!=null,CostProjectTask::getStatus,req.getNStatus() );
+        queryWrapper.eq(req.getCurrentNode() != null, CostProjectTask::getCurrentNode, req.getCurrentNode());
+        queryWrapper.ne(req.getNCurrentNode() != null, CostProjectTask::getCurrentNode, req.getNCurrentNode());
+        queryWrapper.ne(req.getNStatus() != null, CostProjectTask::getStatus, req.getNStatus());
         // 按创建时间倒序排列
         queryWrapper.orderByDesc(CostProjectTask::getCreateTime);
 
@@ -1107,9 +1123,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
             rootTask.setWarningStatus(calculateWarningStatus(rootTask));
             // 找根任务
             String pid = rootTask.getPid();
-            if(StringUtils.isNotBlank( pid)){
+            if (StringUtils.isNotBlank(pid)) {
                 CostProjectTask rrootTask = this.getById(pid);
-                if(rrootTask != null){
+                if (rrootTask != null) {
                     rootTask.setAuditPeriod(rrootTask.getAuditPeriod());
                 }
             }
@@ -1135,7 +1151,7 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
         result.add(catalogId);
 
         List<CostCatalog> children = costCatalogManager.list(
-            new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, catalogId)
+                new LambdaQueryWrapper<CostCatalog>().eq(CostCatalog::getParentId, catalogId)
         );
 
         for (CostCatalog child : children) {
@@ -1147,8 +1163,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
     /**
      * 催办任务,仅记录消息
+     *
      * @param task 任务对象
-     * @param req 请求参数
+     * @param req  请求参数
      * @return 催办结果消息
      */
     private String remindTask(CostProjectTask task, CostTaskPageReq req) {
@@ -1178,8 +1195,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
     /**
      * 催办任务,仅记录消息
+     *
      * @param task 任务对象
-     * @param req 请求参数
+     * @param req  请求参数
      * @return 催办结果消息
      */
     private String remindUnitTask(CostProjectTask task, CostTaskPageReq req) {
@@ -1209,8 +1227,9 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
     /**
      * 复核,主任务退回到实地审核节点,子任务恢复到流程初始状态
+     *
      * @param task 任务对象
-     * @param req 请求参数
+     * @param req  请求参数
      * @return 复核结果消息
      */
     private String reviewTask(CostProjectTask task, CostTaskPageReq req) {

+ 16 - 1
assistMg/src/main/java/com/hotent/surveyinfo/controller/CostSurveyTemplateController.java

@@ -320,14 +320,29 @@ public class CostSurveyTemplateController extends BaseController<CostSurveyTempl
                     verifyHeader.setFieldName(header.getFieldName());
                     verifyHeader.setFieldEname(header.getFieldEname());
                     verifyHeader.setFieldType(header.getFieldType());
+
+                    // 关键:复制字段验证相关属性
+                    verifyHeader.setFieldTypelen(header.getFieldTypelen());           // 字段类型长度
+                    verifyHeader.setFieldTypenointlen(header.getFieldTypenointlen()); // 字段类型小数位长度
+                    verifyHeader.setFormat(header.getFormat());                       // 格式
+                    verifyHeader.setIsDict(header.getIsDict());                       // 是否绑定字典
+                    verifyHeader.setIsAuditPeriod(header.getIsAuditPeriod());         // 是否绑定监审期间
+                    verifyHeader.setShowVisible(header.getShowVisible());             // 隐藏字段显示
+
                     verifyHeader.setTabtype(header.getTabtype());
                     verifyHeader.setIsRequired(header.getIsRequired());
                     verifyHeader.setOrderNum(header.getOrderNum());
                     verifyHeader.setDictid(header.getDictid());
                     verifyHeader.setDictCode(header.getDictCode());
-                    verifyHeader.setCreateBy(user.getAccount());
                     verifyHeader.setColumnComment(header.getColumnComment());
                     verifyHeader.setColumnType(header.getColumnType());
+
+                    // 区域相关属性
+                    verifyHeader.setAreaCode(header.getAreaCode());
+                    verifyHeader.setAreaLevel(header.getAreaLevel());
+
+                    // 系统字段
+                    verifyHeader.setCreateBy(user.getAccount());
                     verifyHeader.setCreateTime(LocalDateTime.now());
 
 

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

@@ -3998,19 +3998,33 @@ public class UserManagerImpl extends BaseManagerImpl <UserDao, User> implements
 
 	@Override
 	public List<User> getUserList() {
-		QueryWrapper<User> wrapper = new QueryWrapper<>();
 		IUser iUser = ContextUtil.getCurrentUser();
+		if (iUser == null || iUser.getAccount() == null) {
+			return new ArrayList<>();
+		}
+
 		User user = this.getByAccount(iUser.getAccount());
-		if (1==user.getDataScope()) {
-			wrapper.eq("CITY_CODE",user.getCityCode());
+		if (user == null) {
+			return new ArrayList<>();
 		}
-		if (2==user.getDataScope()) {
-			wrapper.eq("COUNTY_CODE",user.getCountyCode());
+
+		QueryWrapper<User> wrapper = new QueryWrapper<>();
+
+		Integer scope = user.getDataScope();
+		if (scope != null) {
+			if (scope.equals(1)) {
+				wrapper.eq("CITY_CODE", user.getCityCode());
+			} else if (scope.equals(2)) {
+				wrapper.eq("COUNTY_CODE", user.getCountyCode());
+			}
 		}
-		wrapper.ne("ACCOUNT_","admin");
+
+		wrapper.ne("ACCOUNT_", "admin");
+
 		return this.list(wrapper);
 	}
 
+
 	private boolean isUserNotInList(List<UserVo> list, UserVo user){
 		for (UserVo userVo : list) {
 			if(userVo.getId().equals(user.getId())){