zzw 1 неделя назад
Родитель
Сommit
4bc87ac800

+ 9 - 0
assistMg/src/main/java/com/hotent/enterpriseDeclare/controller/material/CostProjectTaskMaterialSummaryController.java

@@ -1,6 +1,7 @@
 package com.hotent.enterpriseDeclare.controller.material;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.hotent.base.annotation.ApiGroup;
 import com.hotent.base.constants.ApiGroupConsts;
 import com.hotent.base.controller.BaseController;
@@ -515,6 +516,14 @@ public class CostProjectTaskMaterialSummaryController extends BaseController<Cos
         task.setArchiveStatus("2");
         task.setArchiveTime(java.time.LocalDateTime.now());
         costProjectTaskManager.updateById(task);
+        List<CostProjectTask> list = costProjectTaskManager.list(
+                new LambdaQueryWrapper<CostProjectTask>()
+                        .eq(CostProjectTask::getPid, task.getId())
+        );
+        for (CostProjectTask costProjectTask : list) {
+            costProjectTask.setIsGd("1");
+            costProjectTaskManager.updateById(costProjectTask);
+        }
         return CommonResult.<String>ok().message("归档成功");
     }
 }

+ 276 - 91
assistMg/src/main/java/com/hotent/enterpriseDeclare/controller/material/CostProjectTaskSurveyGenericController.java

@@ -131,6 +131,90 @@ public class CostProjectTaskSurveyGenericController {
 
 
     /**
+     * 查询跨表引用的所有值
+     *
+     * @param taskId           任务ID
+     * @param surveyTemplateId 当前模板ID
+     * @param type             类型:1-成本调查表 2-财务数据表
+     * @return 跨表数据,格式:{"isCrossTable": true, "crossTableName": "表名", "data": {"2024": {"表名.Q1": "100"}}}
+     */
+    @GetMapping(value = "/getCrossTableData")
+    @ApiOperation(value = "查询跨表引用的所有值", httpMethod = "GET")
+    public CommonResult<Map<String, Object>> getCrossTableData(
+            @ApiParam(name = "taskId", value = "任务ID", required = true)
+            @RequestParam(required = true) String taskId,
+            @ApiParam(name = "surveyTemplateId", value = "当前模板ID", required = true)
+            @RequestParam(required = true) String surveyTemplateId,
+            @ApiParam(name = "type", value = "类型:1-成本调查表 2-财务数据表", required = true)
+            @RequestParam(required = true) String type) throws Exception {
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("isCrossTable", false);
+        result.put("data", new HashMap<>());
+
+        // 获取当前模板的跨表引用ID
+        String calculationTemplateId = null;
+        List<? extends Object> itemsList = getTemplateItems(type, surveyTemplateId);
+        System.out.println("getCrossTableData - itemsList size: " + (itemsList != null ? itemsList.size() : 0));
+        if (itemsList != null && !itemsList.isEmpty()) {
+            for (Object item : itemsList) {
+                String refId = getItemCalculationTemplateId(item);
+                System.out.println("getCrossTableData - refId: " + refId);
+                if (StringUtil.isNotEmpty(refId)) {
+                    calculationTemplateId = refId;
+                    break;
+                }
+            }
+        }
+
+        System.out.println("getCrossTableData - calculationTemplateId: " + calculationTemplateId);
+        if (StringUtil.isEmpty(calculationTemplateId)) {
+            return CommonResult.<Map<String, Object>>ok().value(result);
+        }
+
+        // 获取被引用表的名称
+        Object crossTemplate = getTemplateById(type, calculationTemplateId);
+        String crossTableName = getTemplateName(crossTemplate);
+        if (StringUtil.isEmpty(crossTableName)) {
+            return CommonResult.<Map<String, Object>>ok().value(result);
+        }
+
+        result.put("isCrossTable", true);
+        result.put("crossTableName", crossTableName);
+        Map<String, Object> dataByPeriod = new HashMap<>();
+
+        // 查询当前任务中的所有年限
+        Set<String> allPeriods = new HashSet<>();
+        QueryWrapper<CostSurveyTemplateUploadData> wrapper = new QueryWrapper<>();
+        wrapper.eq("task_id", taskId)
+                .eq("type", type)
+                .eq("is_deleted", "0");
+        List<CostSurveyTemplateUploadData> allData = costSurveyTemplateUploadDataManager.list(wrapper);
+
+        for (CostSurveyTemplateUploadData data : allData) {
+            if (StringUtil.isNotEmpty(data.getRkey()) && data.getRkey().matches("\\d{4}")) {
+                allPeriods.add(data.getRkey());
+            }
+        }
+
+        System.out.println("getCrossTableData - allPeriods: " + allPeriods);
+        for (String period : allPeriods) {
+            Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
+                    taskId, calculationTemplateId, type, period);
+            System.out.println("getCrossTableData - period: " + period + ", crossData size: " + (crossData != null ? crossData.size() : 0));
+            Map<String, String> periodData = new HashMap<>();
+            for (Map.Entry<String, String> entry : crossData.entrySet()) {
+                String cellCode = entry.getKey().split("_")[0];
+                periodData.put(crossTableName + "." + cellCode, entry.getValue());
+            }
+            dataByPeriod.put(period, periodData);
+        }
+
+        result.put("data", dataByPeriod);
+        return CommonResult.<Map<String, Object>>ok().value(result);
+    }
+
+    /**
      * 企业报送-调查表-列表
      *
      * @param taskId    任务ID
@@ -146,11 +230,12 @@ public class CostProjectTaskSurveyGenericController {
             @ApiParam(name = "type", value = "类型:1-成本调查表 2-财务数据表", required = true)
             @RequestParam(required = true) String type) throws Exception {
         CostProjectTask task = costProjectTaskManager.getById(taskId);
+        CostProjectApproval approval = costProjectApprovalManager.getById(task.getProjectId());
 
         switch (type) {
             case "1": {
                 List<CostCatalogSurvey> list = costCatalogSurveyManager.list(
-                        new LambdaQueryWrapper<CostCatalogSurvey>().eq(CostCatalogSurvey::getCatalogId, task.getCatalogId())
+                        new LambdaQueryWrapper<CostCatalogSurvey>().eq(CostCatalogSurvey::getCatalogId, approval.getCatalogId())
                 );
                 // 成本调查表逻辑
                 List<CostSurveyTemplateUpload> uploadList = costSurveyTemplateUploadManager.listByTaskId(taskId);
@@ -196,6 +281,8 @@ public class CostProjectTaskSurveyGenericController {
      * 企业报送-调查表-获取所需表格字段
      *
      * @param surveyTemplateId 调查表模板ID
+     *
+     *                         {"q1":123,"q2":123}
      * @param type             类型:1-成本调查表 2-财务数据表
      * @return 指标项数据列表(带key-value拼接)
      */
@@ -584,7 +671,8 @@ public class CostProjectTaskSurveyGenericController {
             case ("1"): {
                 CostSurveyTemplate template = costSurveyTemplateManager.get(surveyTemplateId);
                 if (template == null) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到指定的调查模板");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到指定的调查模板")));
                     return;
                 }
                 templateType = template.getTemplateType();
@@ -594,7 +682,8 @@ public class CostProjectTaskSurveyGenericController {
                         costSurveyTemplateVersionManager.get(versionId) : costSurveyTemplateVersionManager.selectCurrentVersion(surveyTemplateId);
 
                 if (currentVersion == null) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到指定的模板版本");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到指定的模板版本")));
                     return;
                 }
 
@@ -618,7 +707,8 @@ public class CostProjectTaskSurveyGenericController {
 
 
                 if (headersList.isEmpty()) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到表头信息");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到表头信息")));
                     return;
                 }
 
@@ -628,12 +718,26 @@ public class CostProjectTaskSurveyGenericController {
                 // 校验跨表数据完整性
                 for (CostSurveyTemplateItems item : itemsList) {
                     if (StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
-                        // 有跨表引用,检查跨表数据是否存在
-                        Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
-                            taskId, item.getCalculationTemplateId(), type, "0");
-                        if (crossData.isEmpty()) {
-                            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
-                                "导出失败:该表有跨表引用,但另外一个表(ID: " + item.getCalculationTemplateId() + ")的数据缺失。请先完成另外一个表的数据导入。");
+                        // 有跨表引用,检查所有年限的跨表数据
+                        Object crossTemplate = getTemplateById(type, item.getCalculationTemplateId());
+                        String crossTableName = getTemplateName(crossTemplate);
+
+                        Set<String> missingPeriods = new HashSet<>();
+                        if (auditPeriods != null) {
+                            for (String period : auditPeriods) {
+                                Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
+                                    taskId, item.getCalculationTemplateId(), type, period.trim());
+                                if (crossData.isEmpty()) {
+                                    missingPeriods.add(period.trim());
+                                }
+                            }
+                        }
+
+                        if (!missingPeriods.isEmpty()) {
+                            response.setContentType("application/json;charset=UTF-8");
+                            response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message(
+                                "导出失败:该表有跨表引用 [" + crossTableName + "],以下年限数据缺失:" +
+                                String.join("、", missingPeriods) + "。请先完成 [" + crossTableName + "] 的数据导入。")));
                             return;
                         }
                         break;
@@ -752,7 +856,8 @@ public class CostProjectTaskSurveyGenericController {
                 // 1.获取模板信息
                 CostSurveyFdTemplate template = costSurveyFdTemplateManager.get(surveyTemplateId);
                 if (template == null) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到指定的财务数据表模板");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到指定的财务数据表模板")));
                     return;
                 }
                 templateType = template.getTemplateType();
@@ -763,7 +868,8 @@ public class CostProjectTaskSurveyGenericController {
                         costSurveyFdTemplateVersionManager.get(versionId) : costSurveyFdTemplateVersionManager.selectCurrentVersion(surveyTemplateId);
 
                 if (currentVersion == null) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到指定的模板版本");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到指定的模板版本")));
                     return;
                 }
 
@@ -788,7 +894,8 @@ public class CostProjectTaskSurveyGenericController {
 
 
                 if (headersList.isEmpty()) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到表头信息");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到表头信息")));
                     return;
                 }
 
@@ -799,12 +906,26 @@ public class CostProjectTaskSurveyGenericController {
                 // 校验跨表数据完整性
                 for (CostSurveyFdTemplateItems item : itemsList) {
                     if (StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
-                        // 有跨表引用,检查跨表数据是否存在
-                        Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
-                            taskId, item.getCalculationTemplateId(), type, "0");
-                        if (crossData.isEmpty()) {
-                            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
-                                "导出失败:该表有跨表引用,但另外一个表(ID: " + item.getCalculationTemplateId() + ")的数据缺失。请先完成另外一个表的数据导入。");
+                        // 有跨表引用,检查所有年限的跨表数据
+                        Object crossTemplate = getTemplateById(type, item.getCalculationTemplateId());
+                        String crossTableName = getTemplateName(crossTemplate);
+
+                        Set<String> missingPeriods = new HashSet<>();
+                        if (auditPeriods != null) {
+                            for (String period : auditPeriods) {
+                                Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
+                                    taskId, item.getCalculationTemplateId(), type, period.trim());
+                                if (crossData.isEmpty()) {
+                                    missingPeriods.add(period.trim());
+                                }
+                            }
+                        }
+
+                        if (!missingPeriods.isEmpty()) {
+                            response.setContentType("application/json;charset=UTF-8");
+                            response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message(
+                                "导出失败:该表有跨表引用 [" + crossTableName + "],以下年限数据缺失:" +
+                                String.join("、", missingPeriods) + "。请先完成 [" + crossTableName + "] 的数据导入。")));
                             return;
                         }
                         break;
@@ -923,7 +1044,8 @@ public class CostProjectTaskSurveyGenericController {
             case ("3"): {
                 CostVerifyTemplate template = costVerifyTemplateManager.get(surveyTemplateId);
                 if (template == null) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到指定的核定表模板");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到指定的核定表模板")));
                     return;
                 }
 
@@ -948,7 +1070,8 @@ public class CostProjectTaskSurveyGenericController {
                                 .collect(Collectors.toList());
 
                 if (headersList.isEmpty()) {
-                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, "未找到表头信息");
+                    response.setContentType("application/json;charset=UTF-8");
+                    response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("未找到表头信息")));
                     return;
                 }
 
@@ -1032,8 +1155,9 @@ public class CostProjectTaskSurveyGenericController {
             }
             // 其它不支持
             default: {
-                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "不支持的类型");
-                break;
+                response.setContentType("application/json;charset=UTF-8");
+                response.getWriter().write(JSON.toJSONString(CommonResult.<String>error().message("不支持的类型")));
+                return;
             }
         }
 
@@ -1781,35 +1905,6 @@ public class CostProjectTaskSurveyGenericController {
             return errors;
         }
 
-        // 0. 检查是否修改了已有数据
-        String refId = dataList.get(0).getRefId();
-        if (StringUtil.isNotEmpty(refId)) {
-            QueryWrapper<CostSurveyTemplateUploadData> existingWrapper = new QueryWrapper<>();
-            existingWrapper.eq("ref_id", refId).eq("type", type).eq("is_deleted", "0");
-            List<CostSurveyTemplateUploadData> existingDataList = costSurveyTemplateUploadDataManager.list(existingWrapper);
-
-            if (!existingDataList.isEmpty()) {
-                // 构建已有数据的映射:rowid_rkey -> rvalue
-                Map<String, String> existingDataMap = new HashMap<>();
-                for (CostSurveyTemplateUploadData data : existingDataList) {
-                    String key = data.getRowid() + "_" + data.getRkey();
-                    existingDataMap.put(key, data.getRvalue());
-                }
-
-                // 检查导入数据是否修改了已有数据
-                for (CostSurveyTemplateUploadData data : dataList) {
-                    String key = data.getRowid() + "_" + data.getRkey();
-                    String existingValue = existingDataMap.get(key);
-                    if (existingValue != null && !existingValue.equals(data.getRvalue())) {
-                        Integer excelRowNum = rowIdToExcelRowMap.get(data.getRowid());
-                        String rowInfo = excelRowNum != null ? "第" + excelRowNum + "行" : "行[" + data.getRowid() + "]";
-                        errors.add(String.format("%s 字段[%s] 不能修改已有数据。原值:%s,新值:%s",
-                                rowInfo, data.getRkey(), existingValue, data.getRvalue()));
-                    }
-                }
-            }
-        }
-
         // 获取模板类型(templateType)
         String templateType = getTemplateType(type, surveyTemplateId);
 
@@ -1903,10 +1998,22 @@ public class CostProjectTaskSurveyGenericController {
                 }
 
                 // 处理跨表引用(检查模板项中的 calculation_template_id)
+                Map<String, String> tableNameToIdMap = new HashMap<>(); // 表名 -> 表ID映射
                 for (Object item : itemsList) {
                     String calculationTemplateId = getItemCalculationTemplateId(item);
                     if (StringUtil.isNotEmpty(calculationTemplateId)) {
-                        String crossTableType = type;
+                        // 自动检测被引用表的类型
+                        String crossTableType = detectTemplateType(calculationTemplateId);
+                        if (StringUtil.isEmpty(crossTableType)) {
+                            crossTableType = type; // 默认使用当前表的类型
+                        }
+
+                        // 获取被引用表的名称
+                        Object crossTemplate = getTemplateById(crossTableType, calculationTemplateId);
+                        String crossTableName = getTemplateName(crossTemplate);
+                        if (StringUtil.isNotEmpty(crossTableName)) {
+                            tableNameToIdMap.put(crossTableName, calculationTemplateId);
+                        }
 
                         // 收集所有年限
                         Set<String> allPeriods = new HashSet<>();
@@ -1977,7 +2084,7 @@ public class CostProjectTaskSurveyGenericController {
 
                     // 针对每个年限分别校验(收集错误)
                     for (String period : periods) {
-                        List<String> formulaErrors = validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type, rowIdToExcelRowMap, cellCodeToRowIdMap);
+                        List<String> formulaErrors = validateRowFormulasForPeriod(rowid, rowData, rowItems, globalCellCodeMap, period, type, rowIdToExcelRowMap, cellCodeToRowIdMap, tableNameToIdMap);
                         errors.addAll(formulaErrors);
                     }
                 }
@@ -2578,7 +2685,7 @@ public class CostProjectTaskSurveyGenericController {
     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,
-                                              Map<String, String> cellCodeToRowIdMap) {
+                                              Map<String, String> cellCodeToRowIdMap, Map<String, String> tableNameToIdMap) {
         List<String> errors = new ArrayList<>();
         // 找到该行的计算公式(同一行的所有模板项共享同一个公式)
         String calculationFormula = null;
@@ -2600,31 +2707,43 @@ public class CostProjectTaskSurveyGenericController {
         }
 
         // 检查公式引用的单元格在当前年限是否有任何一个有值
-        // 提取公式中的所有单元格引用(如 A1, A2, A3
+        // 提取公式中的所有单元格引用(支持 "表名.单元格代码" 或 "单元格代码" 两种格式
         boolean hasAnyReferencedValue = false;
-        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[A-Z]+\\d+");
-        java.util.regex.Matcher matcher = pattern.matcher(calculationFormula);
+        java.util.regex.Pattern tableRefPattern = java.util.regex.Pattern.compile("([\\u4e00-\\u9fa5a-zA-Z0-9_]+)\\.([A-Z]+\\d+)");
+        java.util.regex.Pattern cellPattern = java.util.regex.Pattern.compile("[A-Z]+\\d+");
+        java.util.regex.Matcher matcher = tableRefPattern.matcher(calculationFormula);
         List<String> referencedCellsDebug = new ArrayList<>();
 
+        // 先处理 "表名.单元格" 格式
+        Set<String> processedCells = new HashSet<>();
         while (matcher.find()) {
-            String referencedCell = matcher.group();
-            String mapKey = referencedCell + "_" + period;
-            String value = null;
+            String tableName = matcher.group(1);
+            String cellCode_ref = matcher.group(2);
+            String tableId = tableNameToIdMap.get(tableName);
+            String mapKey = (tableId != null ? tableId + "_" : "") + cellCode_ref + "_" + period;
+            String value = globalCellCodeMap.get(mapKey);
 
-            if (StringUtil.isNotEmpty(calculationTemplateId)) {
-                // 有跨表引用
-                if (cellCodeToRowIdMap.containsKey(referencedCell)) {
-                    // 单元格在当前表
-                    value = globalCellCodeMap.get(mapKey);
-                } else {
-                    // 单元格在跨表
-                    value = globalCellCodeMap.get(calculationTemplateId + "_" + mapKey);
-                }
-            } else {
-                // 没有跨表引用,只查当前表
-                value = globalCellCodeMap.get(mapKey);
+            String displayValue = StringUtil.isNotEmpty(value) ? value : "0";
+            referencedCellsDebug.add(tableName + "." + cellCode_ref + "=" + displayValue);
+            processedCells.add(cellCode_ref);
+            if (StringUtil.isNotEmpty(value)) {
+                hasAnyReferencedValue = true;
+            }
+        }
+
+        // 处理不含表名的单元格引用(当前表)
+        // 避免重复处理已经在 "表名.单元格" 中出现过的单元格
+        matcher = cellPattern.matcher(calculationFormula);
+        while (matcher.find()) {
+            String referencedCell = matcher.group();
+            // 检查是否已在 "表名.单元格" 中处理过
+            if (processedCells.contains(referencedCell)) {
+                continue;
             }
 
+            String mapKey = referencedCell + "_" + period;
+            String value = globalCellCodeMap.get(mapKey);
+
             String displayValue = StringUtil.isNotEmpty(value) ? value : "0";
             referencedCellsDebug.add(referencedCell + "=" + displayValue);
             if (StringUtil.isNotEmpty(value)) {
@@ -2641,24 +2760,34 @@ public class CostProjectTaskSurveyGenericController {
         String inputValueStr = rowData.get(period);
 
         try {
-            // 将公式中的单元格引用替换为 cellCode_年限 的形式
-            // 例如:(A1+A2+A3) -> (A1_2024+A2_2024+A3_2024)
-            // 对于跨表引用,需要加上表ID前缀:(B1) -> (calculationTemplateId_B1_2024)
+            // 将公式中的单元格引用替换为带年限的形式
+            // 例如:(A1+A2) -> (A1_2024+A2_2024)
+            // 例如:(表1.Q1+表1.Q3) -> (tableId1_Q1_2024+tableId1_Q3_2024)
+            // 例如:(表1.Q1+A1) -> (tableId1_Q1_2024+A1_2024)
             String formulaWithPeriod = calculationFormula;
-            matcher = pattern.matcher(calculationFormula);
+
+            // 先处理 "表名.单元格" 格式
+            matcher = tableRefPattern.matcher(formulaWithPeriod);
             StringBuffer sb = new StringBuffer();
             while (matcher.find()) {
-                String referencedCell = matcher.group();
-                String mapKey = referencedCell + "_" + period;
-
-                // 检查是否是跨表引用
-                String currentTableRowId = cellCodeToRowIdMap.get(referencedCell);
-                if (StringUtil.isEmpty(currentTableRowId) && StringUtil.isNotEmpty(calculationTemplateId)) {
-                    // 是跨表引用,使用表ID前缀
-                    mapKey = calculationTemplateId + "_" + mapKey;
-                }
+                String tableName = matcher.group(1);
+                String cellCode_ref = matcher.group(2);
+                String tableId = tableNameToIdMap.get(tableName);
+                String mapKey = (tableId != null ? tableId + "_" : "") + cellCode_ref + "_" + period;
+                matcher.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(mapKey));
+            }
+            matcher.appendTail(sb);
+            formulaWithPeriod = sb.toString();
 
-                matcher.appendReplacement(sb, mapKey);
+            // 处理不含表名的单元格引用(当前表)
+            // 使用负向断言避免匹配已被替换的部分(如 tableId_A2_2026 中的 A2)
+            java.util.regex.Pattern cellPatternWithNegativeLookbehind = java.util.regex.Pattern.compile("(?<!_)([A-Z]+\\d+)(?!_)");
+            matcher = cellPatternWithNegativeLookbehind.matcher(formulaWithPeriod);
+            sb = new StringBuffer();
+            while (matcher.find()) {
+                String referencedCell = matcher.group(1);
+                String mapKey = referencedCell + "_" + period;
+                matcher.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(mapKey));
             }
             matcher.appendTail(sb);
             formulaWithPeriod = sb.toString();
@@ -2742,8 +2871,8 @@ public class CostProjectTaskSurveyGenericController {
         jep.setAllowUndeclared(true);
         jep.setImplicitMul(true);
 
-        // 提取公式中所有的单元格引用(如 A1_2024, Q2_2024)
-        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[A-Z]+\\d+_\\d{4}");
+        // 提取公式中所有的单元格引用(支持两种格式:A1_2024 或 tableId_A1_2024)
+        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(?:\\d+_)?[A-Z]+\\d+_\\d{4}");
         java.util.regex.Matcher matcher = pattern.matcher(formula);
         Set<String> referencedCells = new HashSet<>();
         while (matcher.find()) {
@@ -2752,6 +2881,9 @@ public class CostProjectTaskSurveyGenericController {
 
         // 为所有引用的单元格设置变量值
         Map<String, Double> variableValues = new HashMap<>();
+        Map<String, String> cellCodeToVarName = new HashMap<>(); // 原始cellCode -> 合法变量名映射
+        String processedFormula = formula;
+
         for (String cellCode : referencedCells) {
             String value = cellCodeMap.get(cellCode);
             Double numValue;
@@ -2766,12 +2898,21 @@ public class CostProjectTaskSurveyGenericController {
                 // 如果单元格没有值(用户未填写),默认为0
                 numValue = 0.0;
             }
+
+            // 如果变量名以数字开头,添加前缀 v_
+            String varName = cellCode;
+            if (Character.isDigit(cellCode.charAt(0))) {
+                varName = "v_" + cellCode;
+                processedFormula = processedFormula.replace(cellCode, varName);
+            }
+
             variableValues.put(cellCode, numValue);
-            jep.addVariable(cellCode, numValue);
+            cellCodeToVarName.put(cellCode, varName);
+            jep.addVariable(varName, numValue);
         }
 
         // 解析并计算公式
-        jep.parseExpression(formula);
+        jep.parseExpression(processedFormula);
         if (jep.hasError()) {
             throw new IllegalArgumentException("公式语法错误,请检查模板配置。公式: " + formula + ", 错误: " + jep.getErrorInfo());
         }
@@ -3869,6 +4010,50 @@ public class CostProjectTaskSurveyGenericController {
 
         return style;
     }
+    /**
+     * 自动检测模板的类型
+     */
+    private String detectTemplateType(String templateId) {
+        if (StringUtil.isEmpty(templateId)) {
+            return null;
+        }
+        // 尝试从三种表类型中查找
+        if (costSurveyTemplateManager.getDetail(templateId) != null) {
+            return "1";
+        }
+        if (costSurveyFdTemplateManager.getDetail(templateId) != null) {
+            return "2";
+        }
+        if (costVerifyTemplateManager.get(templateId) != null) {
+            return "3";
+        }
+        return null;
+    }
+
+    private Object getTemplateById(String type, String templateId) {
+        if ("1".equals(type)) {
+            return costSurveyTemplateManager.getDetail(templateId);
+        } else if ("2".equals(type)) {
+            return costSurveyFdTemplateManager.getDetail(templateId);
+        } else if ("3".equals(type)) {
+            return costVerifyTemplateManager.get(templateId);
+        }
+        return null;
+    }
+
+    /**
+     * 从模板对象获取名称
+     */
+    private String getTemplateName(Object template) {
+        if (template instanceof CostSurveyTemplate) {
+            return ((CostSurveyTemplate) template).getSurveyTemplateName();
+        } else if (template instanceof CostSurveyFdTemplate) {
+            return ((CostSurveyFdTemplate) template).getSurveyTemplateName();
+        } else if (template instanceof CostVerifyTemplate) {
+            return ((CostVerifyTemplate) template).getSurveyTemplateName();
+        }
+        return null;
+    }
 
     /**
      * 获取 item 的 calculation_template_id(跨表引用的模板ID)

+ 2 - 3
assistMg/src/main/java/com/hotent/enterpriseDeclare/service/CellDataQueryService.java

@@ -85,17 +85,16 @@ public class CellDataQueryService {
             return result;
         }
 
-        // 查询该模板下所有的上传数据
+        // 查询该任务下所有的上传数据
         QueryWrapper<CostSurveyTemplateUploadData> wrapper = new QueryWrapper<>();
         wrapper.eq("task_id", taskId)
-               .eq("survey_template_id", calculationTemplateId)
                .eq("rkey", period)
                .eq("type", calculationType)
                .eq("is_deleted", "0");
 
         List<CostSurveyTemplateUploadData> dataList = costSurveyTemplateUploadDataManager.list(wrapper);
 
-        // 构建 cellCode_年限 -> 值 的映射
+        // 构建 cellCode_年限 -> 值 的映射(通过 getItemCellCodeByRowId 过滤属于指定模板的数据)
         for (CostSurveyTemplateUploadData data : dataList) {
             String rowid = data.getRowid();
             String cellCode = getItemCellCodeByRowId(calculationTemplateId, rowid, calculationType);

+ 0 - 6
assistMg/src/main/java/com/hotent/project/manager/impl/CostProjectTaskManagerImpl.java

@@ -526,12 +526,6 @@ public class CostProjectTaskManagerImpl extends BaseManagerImpl<CostProjectTaskD
 
         CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
 
-        // 检查任务是否已办结,只允许恢复操作
-        if (TaskStatusConstant.COMPLETED.getStatusCode().equals(task.getStatus())) {
-            if (!"2".equals(req.getKey())) {
-                throw new RuntimeException("任务已办结,仅支持恢复操作");
-            }
-        }
 
         String resultMessage = "";
         switch (req.getKey()) {

+ 5 - 5
assistMg/src/main/java/com/hotent/project/service/AsyncMaterialSummaryService.java

@@ -242,7 +242,7 @@ public class AsyncMaterialSummaryService {
         // 获取"成本监审报告"、"成本监审报告签发稿"、"送达回证"
         List<CostProjectDocument> matchedDocuments = documents.stream()
                 .filter(doc -> "3".equals(doc.getDocumentType())
-                        || "3-送达回证".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())
+                        || "3-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())
                 )
                 .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
                 .collect(Collectors.toList());
@@ -316,7 +316,7 @@ public class AsyncMaterialSummaryService {
         // "成本监审通知书"和"送达回证"
         List<CostProjectDocument> matchedDocuments = documents.stream()
                 .filter(doc -> "4".equals(doc.getDocumentType())
-                        || "4-送达回证".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
+                        || "4-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
                 .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
                 .collect(Collectors.toList());
 
@@ -424,7 +424,7 @@ public class AsyncMaterialSummaryService {
         int orderNum = 1;
         List<CostProjectDocument> matchedDocuments = documents.stream()
                 .filter(doc -> "10".equals(doc.getDocumentType())
-                        || "10-送达回证".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
+                        || "10-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
                 .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
                 .collect(Collectors.toList());
 
@@ -453,7 +453,7 @@ public class AsyncMaterialSummaryService {
         // 获取"成本审核初步意见告知书"和"送达回证"
         List<CostProjectDocument> matchedDocuments = documents.stream()
                 .filter(doc -> "5".equals(doc.getDocumentType())
-                        || "5-送达回证".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
+                        || "5-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
                 .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
                 .collect(Collectors.toList());
 
@@ -763,7 +763,7 @@ public class AsyncMaterialSummaryService {
         // 获取"中止定价成本监审通知书"(来源:被监审单位提交的资料)
         List<CostProjectDocument> matchedDocuments = documents.stream()
                 .filter(doc -> "11".equals(doc.getDocumentType())
-                        || "11-送达回证".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
+                        || "11-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()))
                 .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
                 .collect(Collectors.toList());
 

+ 9 - 0
assistMg/src/main/java/com/hotent/surveyinfo/controller/CostSurveyTemplateVersionController.java

@@ -56,6 +56,15 @@ public class CostSurveyTemplateVersionController extends BaseController<CostSurv
 		return CommonResult.<List<CostSurveyTemplateVersion>>ok().value(versions);
 	}
 
+	@GetMapping(value = "/listOtherCurrentVersions")
+	@ApiOperation(value = "查询相同监审类别和模板类型的所有现行版本", httpMethod = "GET", notes = "查询相同监审类别和模板类型的所有现行版本(包括自己)")
+	public CommonResult<List<CostSurveyTemplateVersion>> listOtherCurrentVersions(
+			@ApiParam(name = "surveyTemplateId", value = "模板ID", required = true)
+			@RequestParam(required = true) String surveyTemplateId) throws Exception {
+
+		List<CostSurveyTemplateVersion> versions = baseService.selectOtherCurrentVersions(surveyTemplateId);
+		return CommonResult.<List<CostSurveyTemplateVersion>>ok().value(versions);
+	}
 
 
 	/**

+ 7 - 0
assistMg/src/main/java/com/hotent/surveyinfo/manager/CostSurveyTemplateVersionManager.java

@@ -54,4 +54,11 @@ public interface CostSurveyTemplateVersionManager extends BaseManager<CostSurvey
 	 */
 	List<CostSurveyTemplateVersion> selectByTemplateIdAndStatus(String surveyTemplateId, String status);
 
+	/**
+	 * 查询除了指定模板外其他模板的现行版本
+	 * @param surveyTemplateId 要排除的模板ID
+	 * @return 其他模板的现行版本列表
+	 */
+	List<CostSurveyTemplateVersion> selectOtherCurrentVersions(String surveyTemplateId);
+
 }

+ 23 - 0
assistMg/src/main/java/com/hotent/surveyinfo/manager/impl/CostSurveyTemplateVersionManagerImpl.java

@@ -16,6 +16,7 @@ import java.util.Collections;
 import java.util.List;
 import javax.annotation.Resource;
 import com.hotent.base.util.BeanUtils;
+import com.hotent.surveyinfo.manager.CostSurveyTemplateManager;
 
 
 /**
@@ -29,6 +30,8 @@ import com.hotent.base.util.BeanUtils;
 public class CostSurveyTemplateVersionManagerImpl extends BaseManagerImpl<CostSurveyTemplateVersionDao, CostSurveyTemplateVersion> implements CostSurveyTemplateVersionManager {
 	@Autowired
 	CostSurveyTemplateVersionDao  costSurveyTemplateVersionDao;
+	@Autowired
+	CostSurveyTemplateManager costSurveyTemplateManager;
 
 	@Override
 	public CostSurveyTemplateVersion getDetail(String id) {
@@ -148,4 +151,24 @@ public class CostSurveyTemplateVersionManagerImpl extends BaseManagerImpl<CostSu
 		return this.list(wrapper);
 	}
 
+	@Override
+	public List<CostSurveyTemplateVersion> selectOtherCurrentVersions(String surveyTemplateId) {
+		if (surveyTemplateId == null || surveyTemplateId.trim().isEmpty()) {
+			return Collections.emptyList();
+		}
+
+		CostSurveyTemplate currentTemplate = costSurveyTemplateManager.getDetail(surveyTemplateId);
+		if (currentTemplate == null) {
+			return Collections.emptyList();
+		}
+
+		QueryWrapper<CostSurveyTemplateVersion> wrapper = new QueryWrapper<>();
+		wrapper.eq("status", "0")
+			.inSql("survey_template_id",
+				"SELECT survey_template_id FROM cost_survey_template WHERE catalog_id = '" + currentTemplate.getCatalogId() +
+				"' AND template_type = '" + currentTemplate.getTemplateType() + "' AND survey_template_id != '" + surveyTemplateId + "'");
+		wrapper.orderByDesc("create_time");
+		return this.list(wrapper);
+	}
+
 }