|
|
@@ -8,20 +8,23 @@ 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.manager.CostCatalogUnitManager;
|
|
|
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;
|
|
|
import com.hotent.enterpriseDeclare.model.CostSurveyTemplateUploadData;
|
|
|
+import com.hotent.enterpriseDeclare.service.CellDataQueryService;
|
|
|
import com.hotent.project.manager.CostProjectApprovalManager;
|
|
|
import com.hotent.project.manager.CostProjectTaskManager;
|
|
|
import com.hotent.project.manager.CostProjectTaskMaterialManager;
|
|
|
import com.hotent.project.model.CostProjectApproval;
|
|
|
import com.hotent.project.model.CostProjectTask;
|
|
|
import com.hotent.project.model.CostProjectTaskMaterial;
|
|
|
-import com.hotent.surveyinfo.dao.*;
|
|
|
+import com.hotent.surveyinfo.dao.CostSurveyFdTemplateItemsDao;
|
|
|
+import com.hotent.surveyinfo.dao.CostSurveyTemplateItemsDao;
|
|
|
+import com.hotent.surveyinfo.dao.CostVerifyTemplateHeadersDao;
|
|
|
+import com.hotent.surveyinfo.dao.CostVerifyTemplateItemsDao;
|
|
|
import com.hotent.surveyinfo.manager.*;
|
|
|
import com.hotent.surveyinfo.model.*;
|
|
|
import com.hotent.surveyinfo.model.dto.CostItemData;
|
|
|
@@ -36,7 +39,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
|
import org.apache.poi.ss.usermodel.*;
|
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
import org.nfunk.jep.JEP;
|
|
|
-import org.nfunk.jep.function.Str;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
@@ -71,17 +73,12 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
private CostSurveyTemplateVersionManager costSurveyTemplateVersionManager;
|
|
|
|
|
|
@Autowired
|
|
|
- private CostSurveyTemplateHeadersDao costSurveyTemplateHeadersDao;
|
|
|
-
|
|
|
- @Autowired
|
|
|
private CostSurveyTemplateItemsDao costSurveyTemplateItemsDao;
|
|
|
@Resource
|
|
|
DataDictManager dataDictManager;
|
|
|
@Resource
|
|
|
SysTypeManager sysTypeManager;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
// 财务数据表相关
|
|
|
@Autowired
|
|
|
private CostSurveyFdTemplateManager costSurveyFdTemplateManager;
|
|
|
@@ -90,9 +87,6 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
private CostSurveyFdTemplateVersionManager costSurveyFdTemplateVersionManager;
|
|
|
|
|
|
@Autowired
|
|
|
- private CostSurveyFdTemplateHeadersDao costSurveyFdTemplateHeadersDao;
|
|
|
-
|
|
|
- @Autowired
|
|
|
private CostSurveyFdTemplateItemsDao costSurveyFdTemplateItemsDao;
|
|
|
|
|
|
// 核定表
|
|
|
@@ -105,8 +99,6 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
@Autowired
|
|
|
private CostVerifyTemplateItemsDao costVerifyTemplateItemsDao;
|
|
|
|
|
|
-
|
|
|
- // 通用组件
|
|
|
@Autowired
|
|
|
private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;
|
|
|
@Autowired
|
|
|
@@ -131,11 +123,17 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
private CostSurveyFdTemplateHeadersManager costSurveyFdTemplateHeadersManager;
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private CostCatalogSurveyManager costCatalogSurveyManager;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CellDataQueryService cellDataQueryService;
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* 企业报送-调查表-列表
|
|
|
*
|
|
|
* @param taskId 任务ID
|
|
|
- * @param catalogId 目录ID(成本调查表使用)
|
|
|
* @param type 类型:1-成本调查表 2-财务数据表
|
|
|
* @return 上传记录列表
|
|
|
* @throws Exception
|
|
|
@@ -145,21 +143,21 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
public CommonResult<?> listByTaskId(
|
|
|
@ApiParam(name = "taskId", value = "任务ID", required = true)
|
|
|
@RequestParam(required = true) String taskId,
|
|
|
- @ApiParam(name = "catalogId", value = "目录ID(成本调查表使用)")
|
|
|
- @RequestParam(required = false) String catalogId,
|
|
|
@ApiParam(name = "type", value = "类型:1-成本调查表 2-财务数据表", required = true)
|
|
|
@RequestParam(required = true) String type) throws Exception {
|
|
|
+ CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
|
|
|
switch (type) {
|
|
|
case "1": {
|
|
|
+ List<CostCatalogSurvey> list = costCatalogSurveyManager.list(
|
|
|
+ new LambdaQueryWrapper<CostCatalogSurvey>().eq(CostCatalogSurvey::getCatalogId, task.getCatalogId())
|
|
|
+ );
|
|
|
// 成本调查表逻辑
|
|
|
List<CostSurveyTemplateUpload> uploadList = costSurveyTemplateUploadManager.listByTaskId(taskId);
|
|
|
//创建记录
|
|
|
if (uploadList.isEmpty()) {
|
|
|
- CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
- CostProjectApproval approval = costProjectApprovalManager.getById(task.getProjectId());
|
|
|
- List<CostSurveyTemplate> costSurveyTemplates = costSurveyTemplateManager.taskListByCatalogId(approval.getCatalogId());
|
|
|
- for (CostSurveyTemplate template : costSurveyTemplates) {
|
|
|
+ for (CostCatalogSurvey survey : list) {
|
|
|
+ CostSurveyTemplate template = costSurveyTemplateManager.getById(survey.getSurveyId());
|
|
|
CostSurveyTemplateUpload upload = new CostSurveyTemplateUpload();
|
|
|
upload.setSurveyTemplateId(template.getSurveyTemplateId());
|
|
|
upload.setSurveyTemplateName(template.getSurveyTemplateName());
|
|
|
@@ -175,7 +173,6 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
}
|
|
|
List<CostSurveyTemplateUpload> costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(taskId);
|
|
|
for (CostSurveyTemplateUpload costSurveyTemplateUpload : costSurveyTemplateUploads) {
|
|
|
- CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
costSurveyTemplateUpload.setAuditedUnitId(task.getAuditedUnitId());
|
|
|
}
|
|
|
return CommonResult.ok().value(costSurveyTemplateUploads);
|
|
|
@@ -186,7 +183,6 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
wrapper.eq("task_id", taskId);
|
|
|
List<CostProjectTaskMaterial> materialList = costProjectTaskMaterialManager.list(wrapper);
|
|
|
for (CostProjectTaskMaterial costProjectTaskMaterial : materialList) {
|
|
|
- CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
costProjectTaskMaterial.setAuditedUnitId(task.getAuditedUnitId()); ;
|
|
|
}
|
|
|
return CommonResult.ok().value(materialList);
|
|
|
@@ -629,6 +625,21 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
List<CostSurveyTemplateItems> itemsList = costSurveyTemplateItemsDao.selectBySurveyTemplateIdAndVersion(
|
|
|
surveyTemplateId, currentVersion.getId());
|
|
|
|
|
|
+ // 校验跨表数据完整性
|
|
|
+ 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() + ")的数据缺失。请先完成另外一个表的数据导入。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Workbook workbook = new XSSFWorkbook();
|
|
|
String sheetName = "成本调查表";
|
|
|
Sheet sheet = workbook.createSheet(sheetName);
|
|
|
@@ -703,7 +714,7 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
for (int i = 0; i < headersList.size(); i++) {
|
|
|
headerIndexMap.put(headersList.get(i).getId(), i);
|
|
|
}
|
|
|
- fillExcelData(sheet, itemsList, headerIndexMap, templateType, type, rowIdColIndex, parentIdColIndex, dataStyle);
|
|
|
+ fillExcelData(sheet, itemsList, headerIndexMap, templateType, type, rowIdColIndex, parentIdColIndex, dataStyle, taskId);
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < headersList.size(); i++) {
|
|
|
@@ -785,6 +796,21 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
List<CostSurveyFdTemplateItems> itemsList = costSurveyFdTemplateItemsDao.selectBySurveyTemplateIdAndVersion(
|
|
|
surveyTemplateId, currentVersion.getId());
|
|
|
|
|
|
+ // 校验跨表数据完整性
|
|
|
+ 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() + ")的数据缺失。请先完成另外一个表的数据导入。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 5.返回excel
|
|
|
Workbook workbook = new XSSFWorkbook();
|
|
|
String sheetName = "财务数据表";
|
|
|
@@ -860,7 +886,7 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
for (int i = 0; i < headersList.size(); i++) {
|
|
|
headerIndexMap.put(headersList.get(i).getId(), i);
|
|
|
}
|
|
|
- fillExcelDataFd(sheet, itemsList, headerIndexMap, templateType, rowIdColIndex, parentIdColIndex, dataStyle);
|
|
|
+ fillExcelDataFd(sheet, itemsList, headerIndexMap, templateType, rowIdColIndex, parentIdColIndex, dataStyle, taskId);
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < headersList.size(); i++) {
|
|
|
@@ -1144,10 +1170,10 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
// 固定表和动态表必须包含行ID和父行ID列
|
|
|
if ("2".equals(templateType) || "3".equals(templateType)) {
|
|
|
if (rowIdColumnIndex == null) {
|
|
|
- return CommonResult.<String>error().message("固定表/动态表导入失败:Excel文件缺少【行ID】列。请使用系统导出的模板,不要删除隐藏列。");
|
|
|
+ return CommonResult.<String>error().message("固定表/动态表导入失败:请使用系统导出的模板,不要删除隐藏列。");
|
|
|
}
|
|
|
if (parentIdColumnIndex == null) {
|
|
|
- return CommonResult.<String>error().message("固定表/动态表导入失败:Excel文件缺少【父行ID】列。请使用系统导出的模板,不要删除隐藏列。");
|
|
|
+ return CommonResult.<String>error().message("固定表/动态表导入失败:请使用系统导出的模板,不要删除隐藏列。");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1755,6 +1781,35 @@ 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);
|
|
|
|
|
|
@@ -1847,6 +1902,58 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 处理跨表引用(检查模板项中的 calculation_template_id)
|
|
|
+ for (Object item : itemsList) {
|
|
|
+ String calculationTemplateId = getItemCalculationTemplateId(item);
|
|
|
+ if (StringUtil.isNotEmpty(calculationTemplateId)) {
|
|
|
+ String crossTableType = type;
|
|
|
+
|
|
|
+ // 收集所有年限
|
|
|
+ Set<String> allPeriods = new HashSet<>();
|
|
|
+ for (Map<String, String> rowData : rowDataMap.values()) {
|
|
|
+ for (String key : rowData.keySet()) {
|
|
|
+ if (key.matches("\\d{4}")) {
|
|
|
+ allPeriods.add(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用 Service 获取跨表数据
|
|
|
+ String taskId = dataList.get(0).getTaskId();
|
|
|
+ List<String> missingCrossTableData = new ArrayList<>();
|
|
|
+
|
|
|
+ for (String period : allPeriods) {
|
|
|
+ Map<String, String> crossData = cellDataQueryService.getCrossTableFormulaData(
|
|
|
+ taskId,
|
|
|
+ calculationTemplateId,
|
|
|
+ crossTableType,
|
|
|
+ period
|
|
|
+ );
|
|
|
+
|
|
|
+ // 检查跨表数据是否完整
|
|
|
+ if (crossData.isEmpty()) {
|
|
|
+ missingCrossTableData.add(period);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为跨表数据加上表ID前缀,避免与当前表数据冲突
|
|
|
+ for (Map.Entry<String, String> entry : crossData.entrySet()) {
|
|
|
+ String prefixedKey = calculationTemplateId + "_" + entry.getKey();
|
|
|
+ globalCellCodeMap.put(prefixedKey, entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果跨表数据缺失,报错
|
|
|
+ if (!missingCrossTableData.isEmpty()) {
|
|
|
+ List<String> errorList = new ArrayList<>();
|
|
|
+ errorList.add("导入失败:该表有跨表引用,但另外一个表(ID: " + calculationTemplateId + ")的以下年限数据缺失:" +
|
|
|
+ String.join("、", missingCrossTableData) + "。请先完成另外一个表的数据导入。");
|
|
|
+ return errorList;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 收集所有的年限(年限的key是4位数字,如"2024")
|
|
|
Set<String> periods = new HashSet<>();
|
|
|
for (Map<String, String> rowData : rowDataMap.values()) {
|
|
|
@@ -1899,13 +2006,23 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
.filter(StringUtil::isNotEmpty)
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
- int expectedRowCount = templateRowIds.size();
|
|
|
- int actualRowCount = rowDataMap.size();
|
|
|
+ Set<String> actualRowIds = rowDataMap.keySet();
|
|
|
+
|
|
|
+ // 2. 校验行数是否匹配(检查rowId集合是否完全相同)
|
|
|
+ if (!actualRowIds.equals(templateRowIds)) {
|
|
|
+ Set<String> missingRowIds = new HashSet<>(templateRowIds);
|
|
|
+ missingRowIds.removeAll(actualRowIds);
|
|
|
+ Set<String> extraRowIds = new HashSet<>(actualRowIds);
|
|
|
+ extraRowIds.removeAll(templateRowIds);
|
|
|
|
|
|
- // 2. 校验行数是否匹配
|
|
|
- if (actualRowCount != expectedRowCount) {
|
|
|
- errors.add(String.format("固定表行数不匹配!模板定义:%d 行,导入数据:%d 行。固定表不允许增加或减少行。",
|
|
|
- expectedRowCount, actualRowCount));
|
|
|
+ StringBuilder errorMsg = new StringBuilder("固定表行不匹配!");
|
|
|
+ if (!missingRowIds.isEmpty()) {
|
|
|
+ errorMsg.append("缺少行:").append(String.join(", ", missingRowIds)).append(";");
|
|
|
+ }
|
|
|
+ if (!extraRowIds.isEmpty()) {
|
|
|
+ errorMsg.append("多余行:").append(String.join(", ", extraRowIds)).append(";");
|
|
|
+ }
|
|
|
+ errors.add(errorMsg.toString());
|
|
|
}
|
|
|
|
|
|
// 3. 校验每一行的字段是否完整
|
|
|
@@ -2466,11 +2583,13 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
// 找到该行的计算公式(同一行的所有模板项共享同一个公式)
|
|
|
String calculationFormula = null;
|
|
|
String cellCode = null;
|
|
|
+ String calculationTemplateId = null;
|
|
|
for (Object item : rowItems) {
|
|
|
String formula = getItemCalculationFormula(item);
|
|
|
if (StringUtil.isNotEmpty(formula)) {
|
|
|
calculationFormula = formula;
|
|
|
cellCode = getItemCellCode(item);
|
|
|
+ calculationTemplateId = getItemCalculationTemplateId(item);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -2490,9 +2609,23 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
while (matcher.find()) {
|
|
|
String referencedCell = matcher.group();
|
|
|
String mapKey = referencedCell + "_" + period;
|
|
|
- String value = globalCellCodeMap.get(mapKey);
|
|
|
- String displayValue = StringUtil.isNotEmpty(value) ? value : "0";
|
|
|
+ String value = null;
|
|
|
+
|
|
|
+ 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(referencedCell + "=" + displayValue);
|
|
|
if (StringUtil.isNotEmpty(value)) {
|
|
|
hasAnyReferencedValue = true;
|
|
|
@@ -2510,12 +2643,22 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
try {
|
|
|
// 将公式中的单元格引用替换为 cellCode_年限 的形式
|
|
|
// 例如:(A1+A2+A3) -> (A1_2024+A2_2024+A3_2024)
|
|
|
+ // 对于跨表引用,需要加上表ID前缀:(B1) -> (calculationTemplateId_B1_2024)
|
|
|
String formulaWithPeriod = calculationFormula;
|
|
|
matcher = pattern.matcher(calculationFormula);
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
while (matcher.find()) {
|
|
|
String referencedCell = matcher.group();
|
|
|
- matcher.appendReplacement(sb, referencedCell + "_" + period);
|
|
|
+ String mapKey = referencedCell + "_" + period;
|
|
|
+
|
|
|
+ // 检查是否是跨表引用
|
|
|
+ String currentTableRowId = cellCodeToRowIdMap.get(referencedCell);
|
|
|
+ if (StringUtil.isEmpty(currentTableRowId) && StringUtil.isNotEmpty(calculationTemplateId)) {
|
|
|
+ // 是跨表引用,使用表ID前缀
|
|
|
+ mapKey = calculationTemplateId + "_" + mapKey;
|
|
|
+ }
|
|
|
+
|
|
|
+ matcher.appendReplacement(sb, mapKey);
|
|
|
}
|
|
|
matcher.appendTail(sb);
|
|
|
formulaWithPeriod = sb.toString();
|
|
|
@@ -2826,14 +2969,23 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
|
|
|
private void fillExcelData(Sheet sheet, List<CostSurveyTemplateItems> itemsList,
|
|
|
Map<String, Integer> headerIndexMap, String templateType, String dataType,
|
|
|
- int rowIdColIndex, int parentIdColIndex, CellStyle dataStyle) {
|
|
|
+ int rowIdColIndex, int parentIdColIndex, CellStyle dataStyle, String taskId) {
|
|
|
if ("1".equals(templateType)) {
|
|
|
Row dataRow = sheet.createRow(2);
|
|
|
for (CostSurveyTemplateItems item : itemsList) {
|
|
|
Integer colIndex = headerIndexMap.get(item.getHeadersId());
|
|
|
if (colIndex != null) {
|
|
|
Cell cell = dataRow.createCell(colIndex);
|
|
|
- cell.setCellValue(item.getRvalue());
|
|
|
+
|
|
|
+ // 检查是否有跨表引用
|
|
|
+ String value = item.getRvalue();
|
|
|
+ if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
|
|
|
+ // 从跨表获取数据
|
|
|
+ value = cellDataQueryService.getCellValueByPeriod(taskId, item.getCalculationTemplateId(),
|
|
|
+ item.getCellCode(), "0", dataType);
|
|
|
+ }
|
|
|
+
|
|
|
+ cell.setCellValue(StringUtil.isNotEmpty(value) ? value : "");
|
|
|
cell.setCellStyle(dataStyle);
|
|
|
}
|
|
|
}
|
|
|
@@ -2861,7 +3013,16 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
Integer colIndex = headerIndexMap.get(item.getHeadersId());
|
|
|
if (colIndex != null) {
|
|
|
Cell cell = dataRow.createCell(colIndex);
|
|
|
- cell.setCellValue(item.getRvalue());
|
|
|
+
|
|
|
+ // 检查是否有跨表引用
|
|
|
+ String value = item.getRvalue();
|
|
|
+ if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
|
|
|
+ // 从跨表获取数据
|
|
|
+ value = cellDataQueryService.getCellValueByPeriod(taskId, item.getCalculationTemplateId(),
|
|
|
+ item.getCellCode(), "0", dataType);
|
|
|
+ }
|
|
|
+
|
|
|
+ cell.setCellValue(StringUtil.isNotEmpty(value) ? value : "");
|
|
|
cell.setCellStyle(dataStyle);
|
|
|
}
|
|
|
}
|
|
|
@@ -2975,7 +3136,7 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
|
|
|
private void fillExcelDataFd(Sheet sheet, List<CostSurveyFdTemplateItems> itemsList,
|
|
|
Map<String, Integer> headerIndexMap, String templateType,
|
|
|
- int rowIdColIndex, int parentIdColIndex, CellStyle dataStyle) {
|
|
|
+ int rowIdColIndex, int parentIdColIndex, CellStyle dataStyle, String taskId) {
|
|
|
if ("1".equals(templateType)) {
|
|
|
// 单表:所有数据在一行
|
|
|
Row dataRow = sheet.createRow(2);
|
|
|
@@ -2983,7 +3144,16 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
Integer colIndex = headerIndexMap.get(item.getHeadersId());
|
|
|
if (colIndex != null) {
|
|
|
Cell cell = dataRow.createCell(colIndex);
|
|
|
- cell.setCellValue(item.getRvalue());
|
|
|
+
|
|
|
+ // 检查是否有跨表引用
|
|
|
+ String value = item.getRvalue();
|
|
|
+ if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
|
|
|
+ // 从跨表获取数据
|
|
|
+ value = cellDataQueryService.getCellValueByPeriod(taskId, item.getCalculationTemplateId(),
|
|
|
+ item.getCellCode(), "0", "2");
|
|
|
+ }
|
|
|
+
|
|
|
+ cell.setCellValue(StringUtil.isNotEmpty(value) ? value : "");
|
|
|
cell.setCellStyle(dataStyle);
|
|
|
}
|
|
|
}
|
|
|
@@ -3011,7 +3181,16 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
Integer colIndex = headerIndexMap.get(item.getHeadersId());
|
|
|
if (colIndex != null) {
|
|
|
Cell cell = dataRow.createCell(colIndex);
|
|
|
- cell.setCellValue(item.getRvalue());
|
|
|
+
|
|
|
+ // 检查是否有跨表引用
|
|
|
+ String value = item.getRvalue();
|
|
|
+ if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(item.getCalculationTemplateId())) {
|
|
|
+ // 从跨表获取数据
|
|
|
+ value = cellDataQueryService.getCellValueByPeriod(taskId, item.getCalculationTemplateId(),
|
|
|
+ item.getCellCode(), "0", "2");
|
|
|
+ }
|
|
|
+
|
|
|
+ cell.setCellValue(StringUtil.isNotEmpty(value) ? value : "");
|
|
|
cell.setCellStyle(dataStyle);
|
|
|
}
|
|
|
}
|
|
|
@@ -3490,18 +3669,12 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 5. 检查是否有多余的表头
|
|
|
- Set<String> extraHeaders = new HashSet<>(actualHeaders);
|
|
|
- extraHeaders.removeAll(expectedHeaders);
|
|
|
- if (!extraHeaders.isEmpty()) {
|
|
|
- errors.add(String.format("Excel文件包含多余的表头列:%s", String.join("、", extraHeaders)));
|
|
|
- }
|
|
|
-
|
|
|
- // 6. 检查是否缺少必需的表头
|
|
|
- Set<String> missingHeaders = new HashSet<>(expectedHeaders);
|
|
|
- missingHeaders.removeAll(actualHeaders);
|
|
|
- if (!missingHeaders.isEmpty()) {
|
|
|
- errors.add(String.format("Excel文件缺少必需的表头列:%s", String.join("、", missingHeaders)));
|
|
|
+ // 5. 检查表头是否完全匹配
|
|
|
+ if (!actualHeaders.equals(expectedHeaders)) {
|
|
|
+ Set<String> displayHeaders = new HashSet<>(expectedHeaders);
|
|
|
+ displayHeaders.remove("行ID");
|
|
|
+ displayHeaders.remove("父行ID");
|
|
|
+ errors.add(String.format("表头校验不通过,应该的表头是:%s,请使用系统导出的模板", String.join("、", displayHeaders)));
|
|
|
}
|
|
|
|
|
|
return errors;
|
|
|
@@ -3557,18 +3730,12 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 5. 检查是否有多余的表头
|
|
|
- Set<String> extraHeaders = new HashSet<>(actualHeaders);
|
|
|
- extraHeaders.removeAll(expectedHeaders);
|
|
|
- if (!extraHeaders.isEmpty()) {
|
|
|
- errors.add(String.format("Excel文件包含多余的表头列:%s", String.join("、", extraHeaders)));
|
|
|
- }
|
|
|
-
|
|
|
- // 6. 检查是否缺少必需的表头
|
|
|
- Set<String> missingHeaders = new HashSet<>(expectedHeaders);
|
|
|
- missingHeaders.removeAll(actualHeaders);
|
|
|
- if (!missingHeaders.isEmpty()) {
|
|
|
- errors.add(String.format("Excel文件缺少必需的表头列:%s", String.join("、", missingHeaders)));
|
|
|
+ // 5. 检查表头是否完全匹配
|
|
|
+ if (!actualHeaders.equals(expectedHeaders)) {
|
|
|
+ Set<String> displayHeaders = new HashSet<>(expectedHeaders);
|
|
|
+ displayHeaders.remove("行ID");
|
|
|
+ displayHeaders.remove("父行ID");
|
|
|
+ errors.add(String.format("表头校验不通过,应该的表头是:%s,请使用系统导出的模板", String.join("、", displayHeaders)));
|
|
|
}
|
|
|
|
|
|
return errors;
|
|
|
@@ -3581,7 +3748,7 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
* @param cellCodeToRowIdMap cellCode到rowid的映射
|
|
|
* @param rowIdToExcelRowMap rowid到Excel行号的映射
|
|
|
* @param period 当前校验的年限
|
|
|
- * @return 计算过程字符串,如 "第3行2024年列(值=10)*(第6行2024年列(值=20)-第5行2024年列(值=5))"
|
|
|
+ * @return 计算过程字符串,如 "第3行2024年列(值=10)*(第6行2024年列(值=20)-第5行2024年列(值=5))+财务数据表B1(值=50)"
|
|
|
*/
|
|
|
private String buildCalculationProcessWithNames(String formula, List<String> referencedCellsDebug,
|
|
|
Map<String, String> cellCodeToRowIdMap,
|
|
|
@@ -3600,15 +3767,17 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
// 获取该cellCode对应的Excel行号
|
|
|
String rowId = cellCodeToRowIdMap.get(cellCode);
|
|
|
String rowDisplay;
|
|
|
+
|
|
|
if (rowId != null && rowIdToExcelRowMap.get(rowId) != null) {
|
|
|
+ // 当前表的单元格
|
|
|
rowDisplay = "第" + rowIdToExcelRowMap.get(rowId) + "行";
|
|
|
+ rowDisplay = String.format("%s%s年列(值=%s)", rowDisplay, period, value);
|
|
|
} else {
|
|
|
- rowDisplay = "行[" + cellCode + "]";
|
|
|
+ // 跨表引用的单元格
|
|
|
+ rowDisplay = String.format("其他表%s(值=%s)", cellCode, value);
|
|
|
}
|
|
|
|
|
|
- // 构建替换字符串:第3行2024年列(值=10)
|
|
|
- String replacement = String.format("%s%s年列(值=%s)", rowDisplay, period, value);
|
|
|
- replacementMap.put(cellCode, replacement);
|
|
|
+ replacementMap.put(cellCode, rowDisplay);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -3700,4 +3869,18 @@ public class CostProjectTaskSurveyGenericController {
|
|
|
|
|
|
return style;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取 item 的 calculation_template_id(跨表引用的模板ID)
|
|
|
+ */
|
|
|
+ private String getItemCalculationTemplateId(Object item) {
|
|
|
+ if (item instanceof CostSurveyTemplateItems) {
|
|
|
+ return ((CostSurveyTemplateItems) item).getCalculationTemplateId();
|
|
|
+ } else if (item instanceof CostSurveyFdTemplateItems) {
|
|
|
+ return ((CostSurveyFdTemplateItems) item).getCalculationTemplateId();
|
|
|
+ } else if (item instanceof CostVerifyTemplateItems) {
|
|
|
+ return ((CostVerifyTemplateItems) item).getCalculationTemplateId();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
}
|