|
|
@@ -12,6 +12,7 @@ import com.siwei.apply.domain.vo.ProjectFilterVo;
|
|
|
import com.siwei.apply.domain.vo.ProjectUpdateVo;
|
|
|
import com.siwei.apply.domain.vo.ProjectVo;
|
|
|
import com.siwei.apply.enums.AloneWorkFlowEnum;
|
|
|
+import com.siwei.apply.enums.ProjectType;
|
|
|
import com.siwei.apply.mapper.*;
|
|
|
import com.siwei.apply.service.NodeAttachmentService;
|
|
|
import com.siwei.apply.service.NodeLandService;
|
|
|
@@ -46,6 +47,7 @@ import java.io.FileInputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.PrintWriter;
|
|
|
import java.io.Serializable;
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.Charset;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
@@ -68,6 +70,13 @@ import static com.siwei.apply.common.Common.UserId;
|
|
|
public class ProjectImpl implements ProjectService {
|
|
|
private static final Map<String, String> CYCLE_TABLE_WORKTYPE_MAP;
|
|
|
private static final Map<String, String> CYCLE_RESOURCE_TABLE_MAP;
|
|
|
+ private static final Map<String, String> CYCLE_TABLE_FIELD_PREFIX_MAP;
|
|
|
+ private static final Map<String, String> CYCLE_TABLE_STAGE_NO_MAP;
|
|
|
+ private static final String BP_ALONE_TABLE = "t_ydbp";
|
|
|
+ private static final String BP_BATCH_TABLE = "t_ydbp_data";
|
|
|
+ private static final String GY_TABLE = "t_tdgy";
|
|
|
+ private static final String BP_NAME_FIELD = "BP_name";
|
|
|
+ private static final String BP_PFWH_FIELD = "BP_pfwh";
|
|
|
|
|
|
static {
|
|
|
Map<String, String> tableWorktypeMap = new HashMap<>();
|
|
|
@@ -94,6 +103,33 @@ public class ProjectImpl implements ProjectService {
|
|
|
resourceTableMap.put("8", "t_tdhyhs");
|
|
|
resourceTableMap.put("9", "t_gyjsydjfwscdj");
|
|
|
CYCLE_RESOURCE_TABLE_MAP = Collections.unmodifiableMap(resourceTableMap);
|
|
|
+
|
|
|
+ Map<String, String> fieldPrefixMap = new HashMap<>();
|
|
|
+ fieldPrefixMap.put("t_ydysyxz", "YS");
|
|
|
+ fieldPrefixMap.put("t_tjyydhx", "GH");
|
|
|
+ fieldPrefixMap.put("t_ydbp", "BP");
|
|
|
+ fieldPrefixMap.put("t_ydbp_data", "BP");
|
|
|
+ fieldPrefixMap.put("t_tdgy", "GY");
|
|
|
+ fieldPrefixMap.put("t_gyjsydscdj", "SD");
|
|
|
+ fieldPrefixMap.put("t_jsydghxk", "YG");
|
|
|
+ fieldPrefixMap.put("t_jsgcghxk", "GG");
|
|
|
+ fieldPrefixMap.put("t_tdhyhs", "HY");
|
|
|
+ fieldPrefixMap.put("t_gyjsydjfwscdj", "FSD");
|
|
|
+ CYCLE_TABLE_FIELD_PREFIX_MAP = Collections.unmodifiableMap(fieldPrefixMap);
|
|
|
+
|
|
|
+ Map<String, String> stageNoMap = new HashMap<>();
|
|
|
+ stageNoMap.put("t_ydysyxz", "01");
|
|
|
+ stageNoMap.put("t_tjyydhx", "02");
|
|
|
+ stageNoMap.put("t_ydbp", "03");
|
|
|
+ stageNoMap.put("t_ydbp_data", "03");
|
|
|
+ stageNoMap.put("t_tdgy", "04");
|
|
|
+ stageNoMap.put("t_gyjsydscdj", "05");
|
|
|
+ stageNoMap.put("t_jsydghxk", "06");
|
|
|
+ stageNoMap.put("t_jsgcghxk", "07");
|
|
|
+ stageNoMap.put("t_tdhyhs", "08");
|
|
|
+ stageNoMap.put("t_gyjsydjfwscdj", "09");
|
|
|
+ CYCLE_TABLE_STAGE_NO_MAP = Collections.unmodifiableMap(stageNoMap);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
@Autowired
|
|
|
@@ -221,6 +257,7 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ rows = filterCycleProjectRows(rows, projectCycleProjectVo.getQueryParams());
|
|
|
int count = rows.size();
|
|
|
int fromIndex = Math.min(projectCycleProjectVo.getOffset(), count);
|
|
|
int toIndex = Math.min(fromIndex + projectCycleProjectVo.getPageSize(), count);
|
|
|
@@ -434,6 +471,8 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
|
|
|
List<CycleShpRow> rows = new ArrayList<>();
|
|
|
+ List<CycleShpRow> bpIntersectRows = new ArrayList<>();
|
|
|
+ List<CycleFieldAlias> fieldAliases = buildBaseFieldAliases();
|
|
|
List<String> projectNames = new ArrayList<>();
|
|
|
for (String projectId : projectIds) {
|
|
|
if (StringUtils.isBlank(projectId)) {
|
|
|
@@ -445,15 +484,17 @@ public class ProjectImpl implements ProjectService {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- List<ProjectCycleExportNode> exportNodes = buildCycleExportNodes(project);
|
|
|
- if (CollectionUtils.isEmpty(exportNodes)) {
|
|
|
+ CycleExportBuildResult exportResult = buildCycleExportNodes(project);
|
|
|
+ if (CollectionUtils.isEmpty(exportResult.exportNodes)) {
|
|
|
log.warn("批量导出项目全生命周期SHP时项目无已上链生命周期数据,projectId={}", projectId);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- List<CycleShpRow> projectRows = buildCycleShpRows(project, exportNodes);
|
|
|
+ List<CycleShpRow> projectRows = buildCycleShpRows(project, exportResult.exportNodes, fieldAliases,
|
|
|
+ exportResult.batchBpByGyGeomKey);
|
|
|
if (CollectionUtils.isNotEmpty(projectRows)) {
|
|
|
rows.addAll(projectRows);
|
|
|
+ bpIntersectRows.addAll(exportResult.bpIntersectRows);
|
|
|
projectNames.add(project.getName());
|
|
|
}
|
|
|
}
|
|
|
@@ -464,21 +505,45 @@ public class ProjectImpl implements ProjectService {
|
|
|
String shpName = "project_cycle_" + System.currentTimeMillis();
|
|
|
tempDir = Files.createTempDirectory("project-cycle-shp-").toFile();
|
|
|
File shpFile = new File(tempDir, shpName + ".shp");
|
|
|
- writeCycleShapefile(shpFile, rows);
|
|
|
+ List<CycleFieldAlias> orderedFieldAliases = buildOrderedFieldAliases(fieldAliases);
|
|
|
+ List<String> shpFields = buildCycleShpFields(rows, orderedFieldAliases);
|
|
|
+ writeCycleShapefile(shpFile, rows, shpFields);
|
|
|
|
|
|
File cpgFile = new File(tempDir, shpName + ".cpg");
|
|
|
try (PrintWriter writer = new PrintWriter(cpgFile, "UTF-8")) {
|
|
|
writer.print("UTF-8");
|
|
|
}
|
|
|
+ File aliasFile = new File(tempDir, "字段说明.csv");
|
|
|
+ writeFieldAliasCsv(aliasFile, orderedFieldAliases);
|
|
|
+ File shpXmlFile = new File(tempDir, shpName + ".shp.xml");
|
|
|
+ writeShpXml(shpXmlFile, shpName, orderedFieldAliases, shpFields);
|
|
|
+
|
|
|
+ List<File> zipFiles = new ArrayList<>();
|
|
|
+ zipFiles.add(new File(tempDir, shpName + ".shp"));
|
|
|
+ zipFiles.add(new File(tempDir, shpName + ".shx"));
|
|
|
+ zipFiles.add(new File(tempDir, shpName + ".dbf"));
|
|
|
+ zipFiles.add(new File(tempDir, shpName + ".prj"));
|
|
|
+ zipFiles.add(cpgFile);
|
|
|
+ zipFiles.add(shpXmlFile);
|
|
|
+ zipFiles.add(aliasFile);
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(bpIntersectRows)) {
|
|
|
+ String bpShpName = shpName + "_bp_intersect";
|
|
|
+ File bpShpFile = new File(tempDir, bpShpName + ".shp");
|
|
|
+ writeCycleShapefile(bpShpFile, bpIntersectRows);
|
|
|
+ File bpCpgFile = new File(tempDir, bpShpName + ".cpg");
|
|
|
+ try (PrintWriter writer = new PrintWriter(bpCpgFile, "UTF-8")) {
|
|
|
+ writer.print("UTF-8");
|
|
|
+ }
|
|
|
+ zipFiles.add(new File(tempDir, bpShpName + ".shp"));
|
|
|
+ zipFiles.add(new File(tempDir, bpShpName + ".shx"));
|
|
|
+ zipFiles.add(new File(tempDir, bpShpName + ".dbf"));
|
|
|
+ zipFiles.add(new File(tempDir, bpShpName + ".prj"));
|
|
|
+ zipFiles.add(bpCpgFile);
|
|
|
+ }
|
|
|
|
|
|
File zipFile = new File(tempDir, shpName + ".zip");
|
|
|
- ServiceFileUtil.zipFiles(Arrays.asList(
|
|
|
- new File(tempDir, shpName + ".shp"),
|
|
|
- new File(tempDir, shpName + ".shx"),
|
|
|
- new File(tempDir, shpName + ".dbf"),
|
|
|
- new File(tempDir, shpName + ".prj"),
|
|
|
- cpgFile
|
|
|
- ), zipFile);
|
|
|
+ ServiceFileUtil.zipFiles(zipFiles, zipFile);
|
|
|
|
|
|
String downloadName = projectNames.size() == 1
|
|
|
? safeFileName(projectNames.get(0)) + "_全生命周期.zip"
|
|
|
@@ -618,7 +683,7 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private List<ProjectCycleExportNode> buildCycleExportNodes(Project project) {
|
|
|
+ private CycleExportBuildResult buildCycleExportNodes(Project project) {
|
|
|
Integer projectType = project.getProjectType();
|
|
|
List<ProjectCycleRes> workflows = workflowMapper.selectByProjectTypeOrderByIndex(projectType);
|
|
|
List<String> allowTables = workflows.stream().map(ProjectCycleRes::getTableName).collect(Collectors.toList());
|
|
|
@@ -628,7 +693,9 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
|
|
|
List<ProjectWorkflowRes> projectWorkflows = projectWorkflowMapper.selectCycleByProjectId(project.getId());
|
|
|
- List<ProjectCycleExportNode> exportNodes = new ArrayList<>();
|
|
|
+ CycleExportBuildResult result = new CycleExportBuildResult();
|
|
|
+ List<ProjectCycleExportNode> gyNodes = new ArrayList<>();
|
|
|
+ List<ProjectCycleExportNode> batchBpNodes = new ArrayList<>();
|
|
|
for (ProjectWorkflowRes workflowRes : projectWorkflows) {
|
|
|
String tableName = workflowRes.getNodeTableName();
|
|
|
if (!allowTables.contains(tableName)) {
|
|
|
@@ -645,26 +712,126 @@ public class ProjectImpl implements ProjectService {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- Map<String, String> geomInfo = nodeLandMapper.selectUnionGeomByNodeId(workflowRes.getNodeId());
|
|
|
- if ((geomInfo == null || StringUtils.isBlank(geomInfo.get("geom")))
|
|
|
- && shouldUseGyjsydscdjGeom(tableName)) {
|
|
|
- geomInfo = nodeLandMapper.selectUnionGeomByNodeId(findProjectNodeId(project.getId(), "t_gyjsydscdj"));
|
|
|
+ ProjectWorkflow workflow = new ProjectWorkflow();
|
|
|
+ workflow.setNodeId(workflowRes.getNodeId());
|
|
|
+ workflow.setNodeTableName(tableName);
|
|
|
+ List<Map<String, String>> geomDetails = getCycleProjectGeomDetails(project.getId(), tableName, workflow);
|
|
|
+ if (CollectionUtils.isEmpty(geomDetails)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ int level = levelMap.getOrDefault(workflowRes.getWorkflowId(), result.exportNodes.size() + 1);
|
|
|
+ for (Map<String, String> geomDetail : geomDetails) {
|
|
|
+ String geom = getMapString(geomDetail, "geom");
|
|
|
+ if (StringUtils.isBlank(geom)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ ProjectCycleExportNode node = new ProjectCycleExportNode();
|
|
|
+ node.level = level;
|
|
|
+ node.tableName = tableName;
|
|
|
+ node.node = currentNode;
|
|
|
+ node.geom = geom;
|
|
|
+ node.geomId = getMapString(geomDetail, "id");
|
|
|
+ node.geomDbId = getMapString(geomDetail, "uploadId", "upload_id");
|
|
|
+ node.geomKey = buildGeomDetailKey(node.geomDbId, node.geomId, node.geom);
|
|
|
+ if (isBatchProject(project) && isBatchBpTable(tableName)) {
|
|
|
+ batchBpNodes.add(node);
|
|
|
+ } else {
|
|
|
+ result.exportNodes.add(node);
|
|
|
+ if (isGyTable(tableName)) {
|
|
|
+ gyNodes.add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ applyBatchBpIntersections(project, result, gyNodes, batchBpNodes);
|
|
|
+ result.exportNodes.sort(Comparator.comparingInt(o -> o.level));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void applyBatchBpIntersections(Project project, CycleExportBuildResult result,
|
|
|
+ List<ProjectCycleExportNode> gyNodes,
|
|
|
+ List<ProjectCycleExportNode> batchBpNodes) {
|
|
|
+ if (!isBatchProject(project) || CollectionUtils.isEmpty(gyNodes) || CollectionUtils.isEmpty(batchBpNodes)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (ProjectCycleExportNode bpNode : batchBpNodes) {
|
|
|
+ if (StringUtils.isBlank(bpNode.geomId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String bpName = getObjectString(bpNode.node, "name");
|
|
|
+ String bpPfwh = getObjectString(bpNode.node, "pfwh");
|
|
|
+ for (ProjectCycleExportNode gyNode : gyNodes) {
|
|
|
+ if (StringUtils.isBlank(gyNode.geomId)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Boolean intersects = nodeLandMapper.existsGeomIntersect(bpNode.geomId, gyNode.geomId);
|
|
|
+ if (!Boolean.TRUE.equals(intersects)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ BpBatchAggregate aggregate = result.batchBpByGyGeomKey.computeIfAbsent(gyNode.geomKey,
|
|
|
+ key -> new BpBatchAggregate());
|
|
|
+ if (StringUtils.isNotBlank(bpName)) {
|
|
|
+ aggregate.names.add(bpName);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(bpPfwh)) {
|
|
|
+ aggregate.pfwhs.add(bpPfwh);
|
|
|
+ }
|
|
|
+ result.bpIntersectRows.add(buildBpIntersectRow(project, bpNode, gyNode, bpName, bpPfwh));
|
|
|
}
|
|
|
- if (geomInfo == null || StringUtils.isBlank(geomInfo.get("geom"))) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private CycleShpRow buildBpIntersectRow(Project project, ProjectCycleExportNode bpNode,
|
|
|
+ ProjectCycleExportNode gyNode, String bpName, String bpPfwh) {
|
|
|
+ CycleShpRow row = new CycleShpRow();
|
|
|
+ row.geom = bpNode.geom;
|
|
|
+ row.geomKey = bpNode.geomKey;
|
|
|
+ row.attributes.put("id", project.getId());
|
|
|
+ row.attributes.put("xmmc", project.getName());
|
|
|
+ row.attributes.put("xmbm", project.getCode());
|
|
|
+ row.attributes.put("jsdw", project.getCompany());
|
|
|
+ row.attributes.put("bp_dkid", bpNode.geomId);
|
|
|
+ row.attributes.put("gy_dkid", gyNode.geomId);
|
|
|
+ row.attributes.put("bp_name", StringUtils.defaultString(bpName));
|
|
|
+ row.attributes.put("bp_pfwh", StringUtils.defaultString(bpPfwh));
|
|
|
+ return row;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void applyBatchBpAttributes(List<CycleShpRow> rows, Map<String, BpBatchAggregate> batchBpByGyGeomKey) {
|
|
|
+ if (CollectionUtils.isEmpty(rows) || batchBpByGyGeomKey == null || batchBpByGyGeomKey.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (CycleShpRow row : rows) {
|
|
|
+ BpBatchAggregate aggregate = batchBpByGyGeomKey.get(row.geomKey);
|
|
|
+ if (aggregate == null) {
|
|
|
continue;
|
|
|
}
|
|
|
+ row.attributes.put(BP_NAME_FIELD, joinAggregateValues(aggregate.names));
|
|
|
+ row.attributes.put(BP_PFWH_FIELD, joinAggregateValues(aggregate.pfwhs));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- int level = levelMap.getOrDefault(workflowRes.getWorkflowId(), exportNodes.size() + 1);
|
|
|
- ProjectCycleExportNode node = new ProjectCycleExportNode();
|
|
|
- node.level = level;
|
|
|
- node.tableName = tableName;
|
|
|
- node.node = currentNode;
|
|
|
- node.geom = geomInfo.get("geom");
|
|
|
- node.geomKey = StringUtils.defaultIfBlank(geomInfo.get("geomDbId"), normalizeGeomKey(node.geom));
|
|
|
- exportNodes.add(node);
|
|
|
+ private String joinAggregateValues(Set<String> values) {
|
|
|
+ if (CollectionUtils.isEmpty(values)) {
|
|
|
+ return "";
|
|
|
}
|
|
|
- exportNodes.sort(Comparator.comparingInt(o -> o.level));
|
|
|
- return exportNodes;
|
|
|
+ return values.stream()
|
|
|
+ .filter(StringUtils::isNotBlank)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.joining(","));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isBatchProject(Project project) {
|
|
|
+ return project != null && ProjectType.BATCH.getCode().equals(String.valueOf(project.getProjectType()));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isBatchBpTable(String tableName) {
|
|
|
+ return BP_BATCH_TABLE.equalsIgnoreCase(tableName);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isGyTable(String tableName) {
|
|
|
+ return GY_TABLE.equalsIgnoreCase(tableName);
|
|
|
}
|
|
|
|
|
|
private ProjectWorkflow findExportWorkflow(ProjectCycleCurrentShpVo.Item item, String nodeTableName) {
|
|
|
@@ -726,20 +893,26 @@ public class ProjectImpl implements ProjectService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private List<CycleShpRow> buildCycleShpRows(Project project, List<ProjectCycleExportNode> exportNodes) {
|
|
|
+ private List<CycleShpRow> buildCycleShpRows(Project project, List<ProjectCycleExportNode> exportNodes,
|
|
|
+ List<CycleFieldAlias> fieldAliases,
|
|
|
+ Map<String, BpBatchAggregate> batchBpByGyGeomKey) {
|
|
|
List<CycleShpRow> rows = new ArrayList<>();
|
|
|
Map<String, CycleShpRow> rowMap = new LinkedHashMap<>();
|
|
|
Map<String, Map<String, String>> tableColumnMap = new HashMap<>();
|
|
|
- Map<String, Map<String, String>> cycleFieldMap = buildCycleFieldMap(project.getProjectType(), tableColumnMap);
|
|
|
+ CycleFieldBuildResult fieldBuildResult = buildCycleFieldResult(project.getProjectType(), tableColumnMap);
|
|
|
+ Map<String, Map<String, String>> cycleFieldMap = fieldBuildResult.fieldMap;
|
|
|
+ addFieldAliases(fieldAliases, fieldBuildResult.aliases);
|
|
|
|
|
|
for (ProjectCycleExportNode node : exportNodes) {
|
|
|
CycleShpRow row = rowMap.computeIfAbsent(node.geomKey, key -> {
|
|
|
CycleShpRow newRow = new CycleShpRow();
|
|
|
newRow.geom = node.geom;
|
|
|
+ newRow.geomKey = node.geomKey;
|
|
|
newRow.attributes.put("id", project.getId());
|
|
|
newRow.attributes.put("xmmc", project.getName());
|
|
|
newRow.attributes.put("xmbm", project.getCode());
|
|
|
newRow.attributes.put("jsdw", project.getCompany());
|
|
|
+ newRow.attributes.put("dkid", node.geomId);
|
|
|
for (Map<String, String> fieldMap : cycleFieldMap.values()) {
|
|
|
for (String fieldName : fieldMap.values()) {
|
|
|
newRow.attributes.put(fieldName, "");
|
|
|
@@ -761,6 +934,7 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ applyBatchBpAttributes(rows, batchBpByGyGeomKey);
|
|
|
return rows;
|
|
|
}
|
|
|
|
|
|
@@ -778,31 +952,87 @@ public class ProjectImpl implements ProjectService {
|
|
|
return fieldMap;
|
|
|
}
|
|
|
|
|
|
- private Map<String, Map<String, String>> buildCycleFieldMap(Integer projectType, Map<String, Map<String, String>> tableColumnMap) {
|
|
|
+ private CycleFieldBuildResult buildCycleFieldResult(Integer projectType, Map<String, Map<String, String>> tableColumnMap) {
|
|
|
Map<String, Map<String, String>> result = new LinkedHashMap<>();
|
|
|
+ List<CycleFieldAlias> aliases = new ArrayList<>();
|
|
|
Set<String> usedFieldNames = new HashSet<>();
|
|
|
- List<ProjectCycleRes> workflows = workflowMapper.selectByProjectTypeOrderByIndex(projectType);
|
|
|
+ List<ProjectCycleRes> workflows = sortCycleWorkflowsByExportOrder(
|
|
|
+ workflowMapper.selectByProjectTypeOrderByIndex(projectType));
|
|
|
for (int i = 0; i < workflows.size(); i++) {
|
|
|
ProjectCycleRes workflow = workflows.get(i);
|
|
|
String tableName = workflow.getTableName();
|
|
|
+ String fieldPrefix = getCycleFieldPrefix(tableName, i + 1);
|
|
|
+ String stageNo = getCycleStageNo(tableName, i + 1);
|
|
|
+ String stageName = StringUtils.defaultIfBlank(workflow.getName(), tableName);
|
|
|
+ if ("BP".equals(fieldPrefix)) {
|
|
|
+ result.put(tableName, buildBpCycleFieldMap(stageNo, fieldPrefix, stageName, aliases,
|
|
|
+ usedFieldNames, tableColumnMap));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
Map<String, String> columnCommentMap = tableColumnMap.computeIfAbsent(tableName, this::getColumnCommentMap);
|
|
|
Map<String, String> fieldMap = new LinkedHashMap<>();
|
|
|
+ aliases.add(CycleFieldAlias.stage(stageNo, fieldPrefix, stageName, tableName));
|
|
|
for (Map.Entry<String, String> entry : columnCommentMap.entrySet()) {
|
|
|
String columnName = entry.getKey();
|
|
|
if (shouldSkipExportColumn(columnName)) {
|
|
|
continue;
|
|
|
}
|
|
|
- String fieldName = buildShpFieldName("L" + (i + 1), entry.getValue(), columnName, usedFieldNames);
|
|
|
+ String comment = StringUtils.defaultIfBlank(entry.getValue(), columnName);
|
|
|
+ String fieldName = buildShpFieldName(fieldPrefix, comment, columnName, usedFieldNames);
|
|
|
fieldMap.put(columnName, fieldName);
|
|
|
+ aliases.add(CycleFieldAlias.field(stageNo, fieldPrefix, stageName, fieldName,
|
|
|
+ fieldPrefix + "-" + comment, tableName, columnName));
|
|
|
}
|
|
|
result.put(tableName, fieldMap);
|
|
|
}
|
|
|
- return result;
|
|
|
+ return new CycleFieldBuildResult(result, aliases);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, String> buildBpCycleFieldMap(String stageNo, String fieldPrefix, String stageName,
|
|
|
+ List<CycleFieldAlias> aliases, Set<String> usedFieldNames,
|
|
|
+ Map<String, Map<String, String>> tableColumnMap) {
|
|
|
+ Map<String, String> fieldMap = new LinkedHashMap<>();
|
|
|
+ Map<String, String> columnCommentMap = tableColumnMap.computeIfAbsent(BP_ALONE_TABLE, this::getColumnCommentMap);
|
|
|
+ aliases.add(CycleFieldAlias.stage(stageNo, fieldPrefix, stageName, BP_ALONE_TABLE));
|
|
|
+
|
|
|
+ putFixedBpField(fieldMap, aliases, usedFieldNames, stageNo, fieldPrefix, stageName,
|
|
|
+ "name", BP_NAME_FIELD, "报批项目名称", BP_BATCH_TABLE, "name");
|
|
|
+ for (Map.Entry<String, String> entry : columnCommentMap.entrySet()) {
|
|
|
+ String columnName = entry.getKey();
|
|
|
+ if (shouldSkipExportColumn(columnName)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String comment = StringUtils.defaultIfBlank(entry.getValue(), columnName);
|
|
|
+ if ("pfwh".equalsIgnoreCase(columnName)) {
|
|
|
+ putFixedBpField(fieldMap, aliases, usedFieldNames, stageNo, fieldPrefix, stageName,
|
|
|
+ columnName, BP_PFWH_FIELD, comment, BP_ALONE_TABLE, columnName);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String fieldName = buildShpFieldName(fieldPrefix, comment, columnName, usedFieldNames);
|
|
|
+ fieldMap.put(columnName, fieldName);
|
|
|
+ aliases.add(CycleFieldAlias.field(stageNo, fieldPrefix, stageName, fieldName,
|
|
|
+ fieldPrefix + "-" + comment, BP_ALONE_TABLE, columnName));
|
|
|
+ }
|
|
|
+ if (!fieldMap.containsKey("pfwh")) {
|
|
|
+ putFixedBpField(fieldMap, aliases, usedFieldNames, stageNo, fieldPrefix, stageName,
|
|
|
+ "pfwh", BP_PFWH_FIELD, "批复文号", BP_ALONE_TABLE, "pfwh");
|
|
|
+ }
|
|
|
+ return fieldMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void putFixedBpField(Map<String, String> fieldMap, List<CycleFieldAlias> aliases,
|
|
|
+ Set<String> usedFieldNames, String stageNo, String fieldPrefix, String stageName,
|
|
|
+ String columnName, String fieldName, String comment,
|
|
|
+ String sourceTable, String sourceColumn) {
|
|
|
+ fieldMap.put(columnName, fieldName);
|
|
|
+ usedFieldNames.add(fieldName);
|
|
|
+ aliases.add(CycleFieldAlias.field(stageNo, fieldPrefix, stageName, fieldName,
|
|
|
+ fieldPrefix + "-" + comment, sourceTable, sourceColumn));
|
|
|
}
|
|
|
|
|
|
private Map<String, String> getColumnCommentMap(String tableName) {
|
|
|
List<Map<String, String>> columnComments = projectWorkflowMapper.selectTableColumnComments(tableName);
|
|
|
- Map<String, String> result = new HashMap<>();
|
|
|
+ Map<String, String> result = new LinkedHashMap<>();
|
|
|
if (CollectionUtils.isNotEmpty(columnComments)) {
|
|
|
for (Map<String, String> columnComment : columnComments) {
|
|
|
result.put(columnComment.get("columnName"), columnComment.get("columnComment"));
|
|
|
@@ -811,18 +1041,78 @@ public class ProjectImpl implements ProjectService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ private List<String> buildCycleShpFields(List<CycleShpRow> rows) {
|
|
|
+ return rows.stream()
|
|
|
+ .flatMap(row -> row.attributes.keySet().stream())
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> buildCycleShpFields(List<CycleShpRow> rows, List<CycleFieldAlias> fieldAliases) {
|
|
|
+ Set<String> rowFields = rows.stream()
|
|
|
+ .flatMap(row -> row.attributes.keySet().stream())
|
|
|
+ .collect(Collectors.toCollection(LinkedHashSet::new));
|
|
|
+ List<String> fields = new ArrayList<>();
|
|
|
+ for (CycleFieldAlias alias : fieldAliases) {
|
|
|
+ if (StringUtils.isNotBlank(alias.fieldName) && rowFields.contains(alias.fieldName)
|
|
|
+ && !fields.contains(alias.fieldName)) {
|
|
|
+ fields.add(alias.fieldName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (String rowField : rowFields) {
|
|
|
+ if (!fields.contains(rowField)) {
|
|
|
+ fields.add(rowField);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return fields;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<CycleFieldAlias> buildOrderedFieldAliases(List<CycleFieldAlias> fieldAliases) {
|
|
|
+ if (CollectionUtils.isEmpty(fieldAliases)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ Map<CycleFieldAlias, Integer> originalIndexMap = new IdentityHashMap<>();
|
|
|
+ for (int i = 0; i < fieldAliases.size(); i++) {
|
|
|
+ originalIndexMap.put(fieldAliases.get(i), i);
|
|
|
+ }
|
|
|
+ List<CycleFieldAlias> orderedAliases = new ArrayList<>(fieldAliases);
|
|
|
+ orderedAliases.sort(Comparator
|
|
|
+ .comparingInt(this::getCycleFieldAliasOrder)
|
|
|
+ .thenComparingInt(alias -> originalIndexMap.getOrDefault(alias, 0)));
|
|
|
+ return orderedAliases;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int getCycleFieldAliasOrder(CycleFieldAlias alias) {
|
|
|
+ int baseOrder = getBaseFieldOrder(alias.fieldName);
|
|
|
+ if (baseOrder >= 0) {
|
|
|
+ return baseOrder;
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(alias.stageNo)) {
|
|
|
+ try {
|
|
|
+ return 100 + Integer.parseInt(alias.stageNo);
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ return 1000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int getBaseFieldOrder(String fieldName) {
|
|
|
+ List<String> baseFields = Arrays.asList("id", "xmmc", "xmbm", "jsdw", "dkid");
|
|
|
+ return baseFields.indexOf(fieldName);
|
|
|
+ }
|
|
|
+
|
|
|
private void writeCycleShapefile(File shpFile, List<CycleShpRow> rows) throws Exception {
|
|
|
+ writeCycleShapefile(shpFile, rows, buildCycleShpFields(rows));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void writeCycleShapefile(File shpFile, List<CycleShpRow> rows, List<String> fields) throws Exception {
|
|
|
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
|
|
|
typeBuilder.setName("project_cycle");
|
|
|
CoordinateReferenceSystem crs = CRS.decode("EPSG:4490");
|
|
|
typeBuilder.setCRS(crs);
|
|
|
typeBuilder.add("the_geom", MultiPolygon.class);
|
|
|
|
|
|
- List<String> fields = rows.stream()
|
|
|
- .flatMap(row -> row.attributes.keySet().stream())
|
|
|
- .distinct()
|
|
|
- .sorted(this::compareCycleField)
|
|
|
- .collect(Collectors.toList());
|
|
|
for (String field : fields) {
|
|
|
typeBuilder.length(254).add(field, String.class);
|
|
|
}
|
|
|
@@ -879,6 +1169,79 @@ public class ProjectImpl implements ProjectService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void writeFieldAliasCsv(File aliasFile, List<CycleFieldAlias> aliases) throws IOException {
|
|
|
+ try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(aliasFile.toPath(), StandardCharsets.UTF_8))) {
|
|
|
+ writer.print('\ufeff');
|
|
|
+ writer.println("阶段编号,阶段名称,字段名,中文别名,原表名,原字段名");
|
|
|
+ for (CycleFieldAlias alias : aliases) {
|
|
|
+ writer.println(csv(alias.stageNo) + ","
|
|
|
+ + csv(alias.stageName) + ","
|
|
|
+ + csv(alias.fieldName) + ","
|
|
|
+ + csv(alias.aliasName) + ","
|
|
|
+ + csv(alias.sourceTable) + ","
|
|
|
+ + csv(alias.sourceColumn));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void writeShpXml(File shpXmlFile, String shpName, List<CycleFieldAlias> aliases,
|
|
|
+ List<String> shpFields) throws IOException {
|
|
|
+ Set<String> fieldSet = new HashSet<>(shpFields);
|
|
|
+ Set<String> writtenFields = new HashSet<>();
|
|
|
+ StringBuilder xml = new StringBuilder();
|
|
|
+ xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
|
|
+ xml.append("<metadata>\n");
|
|
|
+ xml.append(" <idinfo>\n");
|
|
|
+ xml.append(" <citation><citeinfo><title>")
|
|
|
+ .append(escapeXml(shpName))
|
|
|
+ .append("</title></citeinfo></citation>\n");
|
|
|
+ xml.append(" </idinfo>\n");
|
|
|
+ xml.append(" <eainfo>\n");
|
|
|
+ xml.append(" <detailed>\n");
|
|
|
+ xml.append(" <enttyp><enttypl>project_cycle</enttypl><enttypd>项目全生命周期SHP</enttypd></enttyp>\n");
|
|
|
+ for (CycleFieldAlias alias : aliases) {
|
|
|
+ if (StringUtils.isBlank(alias.fieldName)
|
|
|
+ || !fieldSet.contains(alias.fieldName)
|
|
|
+ || !writtenFields.add(alias.fieldName)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ xml.append(" <attr>\n");
|
|
|
+ xml.append(" <attrlabl>").append(escapeXml(alias.fieldName)).append("</attrlabl>\n");
|
|
|
+ xml.append(" <attalias>").append(escapeXml(alias.aliasName)).append("</attalias>\n");
|
|
|
+ xml.append(" <attrdef>").append(escapeXml(buildAliasDescription(alias))).append("</attrdef>\n");
|
|
|
+ xml.append(" </attr>\n");
|
|
|
+ }
|
|
|
+ xml.append(" </detailed>\n");
|
|
|
+ xml.append(" </eainfo>\n");
|
|
|
+ xml.append("</metadata>\n");
|
|
|
+ Files.write(shpXmlFile.toPath(), xml.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildAliasDescription(CycleFieldAlias alias) {
|
|
|
+ if (StringUtils.isBlank(alias.fieldPrefix)) {
|
|
|
+ return alias.aliasName;
|
|
|
+ }
|
|
|
+ String fieldAlias = alias.aliasName.substring(Math.min(alias.aliasName.length(), alias.fieldPrefix.length() + 1));
|
|
|
+ return alias.fieldPrefix + "-" + alias.stageName + "-" + fieldAlias;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String csv(String value) {
|
|
|
+ String text = StringUtils.defaultString(value);
|
|
|
+ if (text.contains("\"") || text.contains(",") || text.contains("\n") || text.contains("\r")) {
|
|
|
+ return "\"" + text.replace("\"", "\"\"") + "\"";
|
|
|
+ }
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String escapeXml(String value) {
|
|
|
+ return StringUtils.defaultString(value)
|
|
|
+ .replace("&", "&")
|
|
|
+ .replace("<", "<")
|
|
|
+ .replace(">", ">")
|
|
|
+ .replace("\"", """)
|
|
|
+ .replace("'", "'");
|
|
|
+ }
|
|
|
+
|
|
|
private boolean shouldUseGyjsydscdjGeom(String tableName) {
|
|
|
return AloneWorkFlowEnum.NODE_4.getTableName().equalsIgnoreCase(tableName)
|
|
|
|| AloneWorkFlowEnum.NODE_5.getTableName().equalsIgnoreCase(tableName)
|
|
|
@@ -927,41 +1290,78 @@ public class ProjectImpl implements ProjectService {
|
|
|
return fieldName;
|
|
|
}
|
|
|
|
|
|
- private int compareCycleField(String field1, String field2) {
|
|
|
- List<String> baseFields = Arrays.asList("id", "xmmc", "xmbm", "jsdw");
|
|
|
- int baseIndex1 = baseFields.indexOf(field1);
|
|
|
- int baseIndex2 = baseFields.indexOf(field2);
|
|
|
- if (baseIndex1 >= 0 || baseIndex2 >= 0) {
|
|
|
- if (baseIndex1 < 0) {
|
|
|
- return 1;
|
|
|
- }
|
|
|
- if (baseIndex2 < 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- return Integer.compare(baseIndex1, baseIndex2);
|
|
|
+ private List<CycleFieldAlias> buildBaseFieldAliases() {
|
|
|
+ List<CycleFieldAlias> aliases = new ArrayList<>();
|
|
|
+ aliases.add(CycleFieldAlias.base("id", "项目ID"));
|
|
|
+ aliases.add(CycleFieldAlias.base("xmmc", "项目名称"));
|
|
|
+ aliases.add(CycleFieldAlias.base("xmbm", "项目编码"));
|
|
|
+ aliases.add(CycleFieldAlias.base("jsdw", "建设单位"));
|
|
|
+ aliases.add(CycleFieldAlias.base("dkid", "地块ID"));
|
|
|
+ return aliases;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<ProjectCycleRes> sortCycleWorkflowsByExportOrder(List<ProjectCycleRes> workflows) {
|
|
|
+ if (CollectionUtils.isEmpty(workflows)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ Map<ProjectCycleRes, Integer> originalIndexMap = new IdentityHashMap<>();
|
|
|
+ for (int i = 0; i < workflows.size(); i++) {
|
|
|
+ originalIndexMap.put(workflows.get(i), i);
|
|
|
}
|
|
|
+ List<ProjectCycleRes> sortedWorkflows = new ArrayList<>(workflows);
|
|
|
+ sortedWorkflows.sort(Comparator
|
|
|
+ .comparingInt((ProjectCycleRes workflow) -> getCycleStageOrder(workflow.getTableName(),
|
|
|
+ originalIndexMap.getOrDefault(workflow, 0) + 1))
|
|
|
+ .thenComparingInt(workflow -> originalIndexMap.getOrDefault(workflow, 0)));
|
|
|
+ return sortedWorkflows;
|
|
|
+ }
|
|
|
|
|
|
- int level1 = getCycleFieldLevel(field1);
|
|
|
- int level2 = getCycleFieldLevel(field2);
|
|
|
- if (level1 != level2) {
|
|
|
- return Integer.compare(level1, level2);
|
|
|
+ private void addFieldAliases(List<CycleFieldAlias> target, List<CycleFieldAlias> aliases) {
|
|
|
+ Set<String> exists = target.stream()
|
|
|
+ .map(alias -> StringUtils.defaultString(alias.stageNo) + "|"
|
|
|
+ + StringUtils.defaultString(alias.fieldPrefix) + "|"
|
|
|
+ + StringUtils.defaultString(alias.fieldName) + "|"
|
|
|
+ + StringUtils.defaultString(alias.sourceTable) + "|"
|
|
|
+ + StringUtils.defaultString(alias.sourceColumn))
|
|
|
+ .collect(Collectors.toCollection(LinkedHashSet::new));
|
|
|
+ for (CycleFieldAlias alias : aliases) {
|
|
|
+ String key = StringUtils.defaultString(alias.stageNo) + "|"
|
|
|
+ + StringUtils.defaultString(alias.fieldPrefix) + "|"
|
|
|
+ + StringUtils.defaultString(alias.fieldName) + "|"
|
|
|
+ + StringUtils.defaultString(alias.sourceTable) + "|"
|
|
|
+ + StringUtils.defaultString(alias.sourceColumn);
|
|
|
+ if (exists.add(key)) {
|
|
|
+ target.add(alias);
|
|
|
+ }
|
|
|
}
|
|
|
- return field1.compareToIgnoreCase(field2);
|
|
|
}
|
|
|
|
|
|
- private int getCycleFieldLevel(String field) {
|
|
|
- if (StringUtils.isBlank(field) || !field.startsWith("L")) {
|
|
|
- return Integer.MAX_VALUE;
|
|
|
+ private String getCycleFieldPrefix(String tableName, int index) {
|
|
|
+ String prefix = CYCLE_TABLE_FIELD_PREFIX_MAP.get(tableName);
|
|
|
+ if (StringUtils.isNotBlank(prefix)) {
|
|
|
+ return prefix;
|
|
|
}
|
|
|
- int end = field.indexOf('_');
|
|
|
- if (end <= 1) {
|
|
|
- return Integer.MAX_VALUE;
|
|
|
+ return "L" + index;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int getCycleStageOrder(String tableName, int index) {
|
|
|
+ String stageNo = CYCLE_TABLE_STAGE_NO_MAP.get(tableName);
|
|
|
+ if (StringUtils.isBlank(stageNo)) {
|
|
|
+ return 1000 + index;
|
|
|
}
|
|
|
try {
|
|
|
- return Integer.parseInt(field.substring(1, end));
|
|
|
+ return Integer.parseInt(stageNo);
|
|
|
} catch (NumberFormatException e) {
|
|
|
- return Integer.MAX_VALUE;
|
|
|
+ return 1000 + index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getCycleStageNo(String tableName, int index) {
|
|
|
+ String stageNo = CYCLE_TABLE_STAGE_NO_MAP.get(tableName);
|
|
|
+ if (StringUtils.isNotBlank(stageNo)) {
|
|
|
+ return stageNo;
|
|
|
}
|
|
|
+ return String.format(Locale.ROOT, "%02d", index);
|
|
|
}
|
|
|
|
|
|
private String toInitials(String text) {
|
|
|
@@ -1008,6 +1408,37 @@ public class ProjectImpl implements ProjectService {
|
|
|
return ewkt.replaceAll("\\s+", "").toUpperCase(Locale.ROOT);
|
|
|
}
|
|
|
|
|
|
+ private String buildGeomDetailKey(String geomDbId, String geomId, String geom) {
|
|
|
+ if (StringUtils.isNotBlank(geomDbId) && StringUtils.isNotBlank(geomId)) {
|
|
|
+ return geomDbId + "|" + geomId;
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(geomId)) {
|
|
|
+ return geomId;
|
|
|
+ }
|
|
|
+ return normalizeGeomKey(geom);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getMapString(Map<String, String> map, String... keys) {
|
|
|
+ if (map == null || ArrayUtils.isEmpty(keys)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ for (String key : keys) {
|
|
|
+ String value = map.get(key);
|
|
|
+ if (StringUtils.isNotBlank(value)) {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getObjectString(Map<String, Object> map, String key) {
|
|
|
+ if (map == null || StringUtils.isBlank(key)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Object value = map.get(key);
|
|
|
+ return value == null ? null : String.valueOf(value);
|
|
|
+ }
|
|
|
+
|
|
|
private String trimDbfValue(String value) {
|
|
|
if (value == null) {
|
|
|
return "";
|
|
|
@@ -1042,16 +1473,80 @@ public class ProjectImpl implements ProjectService {
|
|
|
response.getOutputStream().flush();
|
|
|
}
|
|
|
|
|
|
+ private static class CycleFieldBuildResult {
|
|
|
+ private final Map<String, Map<String, String>> fieldMap;
|
|
|
+ private final List<CycleFieldAlias> aliases;
|
|
|
+
|
|
|
+ private CycleFieldBuildResult(Map<String, Map<String, String>> fieldMap, List<CycleFieldAlias> aliases) {
|
|
|
+ this.fieldMap = fieldMap;
|
|
|
+ this.aliases = aliases;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class CycleExportBuildResult {
|
|
|
+ private final List<ProjectCycleExportNode> exportNodes = new ArrayList<>();
|
|
|
+ private final Map<String, BpBatchAggregate> batchBpByGyGeomKey = new LinkedHashMap<>();
|
|
|
+ private final List<CycleShpRow> bpIntersectRows = new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class BpBatchAggregate {
|
|
|
+ private final Set<String> names = new LinkedHashSet<>();
|
|
|
+ private final Set<String> pfwhs = new LinkedHashSet<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static class CycleFieldAlias {
|
|
|
+ private String stageNo;
|
|
|
+ private String fieldPrefix;
|
|
|
+ private String stageName;
|
|
|
+ private String fieldName;
|
|
|
+ private String aliasName;
|
|
|
+ private String sourceTable;
|
|
|
+ private String sourceColumn;
|
|
|
+
|
|
|
+ private static CycleFieldAlias base(String fieldName, String aliasName) {
|
|
|
+ CycleFieldAlias alias = new CycleFieldAlias();
|
|
|
+ alias.fieldName = fieldName;
|
|
|
+ alias.aliasName = aliasName;
|
|
|
+ return alias;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static CycleFieldAlias stage(String stageNo, String fieldPrefix, String stageName, String sourceTable) {
|
|
|
+ CycleFieldAlias alias = new CycleFieldAlias();
|
|
|
+ alias.stageNo = stageNo;
|
|
|
+ alias.fieldPrefix = fieldPrefix;
|
|
|
+ alias.stageName = stageName;
|
|
|
+ alias.aliasName = stageNo + "-" + stageName + "阶段";
|
|
|
+ alias.sourceTable = sourceTable;
|
|
|
+ return alias;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static CycleFieldAlias field(String stageNo, String fieldPrefix, String stageName, String fieldName,
|
|
|
+ String aliasName, String sourceTable, String sourceColumn) {
|
|
|
+ CycleFieldAlias alias = new CycleFieldAlias();
|
|
|
+ alias.stageNo = stageNo;
|
|
|
+ alias.fieldPrefix = fieldPrefix;
|
|
|
+ alias.stageName = stageName;
|
|
|
+ alias.fieldName = fieldName;
|
|
|
+ alias.aliasName = aliasName;
|
|
|
+ alias.sourceTable = sourceTable;
|
|
|
+ alias.sourceColumn = sourceColumn;
|
|
|
+ return alias;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private static class ProjectCycleExportNode {
|
|
|
private int level;
|
|
|
private String tableName;
|
|
|
private Map<String, Object> node;
|
|
|
private String geom;
|
|
|
private String geomKey;
|
|
|
+ private String geomId;
|
|
|
+ private String geomDbId;
|
|
|
}
|
|
|
|
|
|
private static class CycleShpRow {
|
|
|
private String geom;
|
|
|
+ private String geomKey;
|
|
|
private final Map<String, Object> attributes = new LinkedHashMap<>();
|
|
|
}
|
|
|
|
|
|
@@ -1069,6 +1564,185 @@ public class ProjectImpl implements ProjectService {
|
|
|
return rows;
|
|
|
}
|
|
|
|
|
|
+ private List<Map<String, Object>> filterCycleProjectRows(List<Map<String, Object>> rows,
|
|
|
+ Map<String, Object> queryParams) {
|
|
|
+ if (CollectionUtils.isEmpty(rows) || queryParams == null || queryParams.isEmpty()) {
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> effectiveQuery = new LinkedHashMap<>();
|
|
|
+ for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
|
|
|
+ if (StringUtils.isNotBlank(entry.getKey()) && !isBlankQueryValue(entry.getValue())) {
|
|
|
+ effectiveQuery.put(entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (effectiveQuery.isEmpty()) {
|
|
|
+ return rows;
|
|
|
+ }
|
|
|
+
|
|
|
+ return rows.stream()
|
|
|
+ .filter(row -> matchesCycleQuery(row, effectiveQuery))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean matchesCycleQuery(Map<String, Object> row, Map<String, Object> queryParams) {
|
|
|
+ for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
|
|
|
+ if (!matchesCycleValue(entry.getKey(), row.get(entry.getKey()), entry.getValue())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean matchesCycleValue(String field, Object rowValue, Object queryValue) {
|
|
|
+ if (isBlankQueryValue(queryValue)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (rowValue == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (queryValue instanceof Collection) {
|
|
|
+ List<Object> values = ((Collection<?>) queryValue).stream()
|
|
|
+ .filter(value -> !isBlankQueryValue(value))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if (values.isEmpty()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (values.size() == 2 && isDateField(field, rowValue, values.get(0))) {
|
|
|
+ return matchesDateRange(rowValue, values.get(0), values.get(1));
|
|
|
+ }
|
|
|
+ return values.stream().anyMatch(value -> matchesCycleValue(field, rowValue, value));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (queryValue.getClass().isArray()) {
|
|
|
+ int length = java.lang.reflect.Array.getLength(queryValue);
|
|
|
+ List<Object> values = new ArrayList<>();
|
|
|
+ for (int i = 0; i < length; i++) {
|
|
|
+ values.add(java.lang.reflect.Array.get(queryValue, i));
|
|
|
+ }
|
|
|
+ return matchesCycleValue(field, rowValue, values);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isDateField(field, rowValue, queryValue)) {
|
|
|
+ String rowDate = normalizeDateValue(rowValue);
|
|
|
+ String queryDate = normalizeDateValue(queryValue);
|
|
|
+ return StringUtils.isNotBlank(rowDate) && rowDate.equals(queryDate);
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal rowNumber = toBigDecimal(rowValue);
|
|
|
+ BigDecimal queryNumber = toBigDecimal(queryValue);
|
|
|
+ if (rowNumber != null && queryNumber != null) {
|
|
|
+ return rowNumber.compareTo(queryNumber) == 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ String rowText = String.valueOf(rowValue).trim();
|
|
|
+ String queryText = String.valueOf(queryValue).trim();
|
|
|
+ if (isExactMatchField(field)) {
|
|
|
+ return rowText.equals(queryText);
|
|
|
+ }
|
|
|
+ return rowText.toLowerCase(Locale.ROOT).contains(queryText.toLowerCase(Locale.ROOT));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean matchesDateRange(Object rowValue, Object startValue, Object endValue) {
|
|
|
+ String rowDate = normalizeDateValue(rowValue);
|
|
|
+ String startDate = normalizeDateValue(startValue);
|
|
|
+ String endDate = normalizeDateValue(endValue);
|
|
|
+ if (StringUtils.isBlank(rowDate)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(startDate) && rowDate.compareTo(startDate) < 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return StringUtils.isBlank(endDate) || rowDate.compareTo(endDate) <= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isBlankQueryValue(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (value instanceof String) {
|
|
|
+ return StringUtils.isBlank((String) value);
|
|
|
+ }
|
|
|
+ if (value instanceof Collection) {
|
|
|
+ return ((Collection<?>) value).stream().allMatch(this::isBlankQueryValue);
|
|
|
+ }
|
|
|
+ if (value.getClass().isArray()) {
|
|
|
+ int length = java.lang.reflect.Array.getLength(value);
|
|
|
+ for (int i = 0; i < length; i++) {
|
|
|
+ if (!isBlankQueryValue(java.lang.reflect.Array.get(value, i))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isDateField(String field, Object rowValue, Object queryValue) {
|
|
|
+ String lowerField = field == null ? "" : field.toLowerCase(Locale.ROOT);
|
|
|
+ return lowerField.contains("date")
|
|
|
+ || lowerField.contains("time")
|
|
|
+ || lowerField.endsWith("rq")
|
|
|
+ || looksLikeDate(rowValue)
|
|
|
+ || looksLikeDate(queryValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isUnitField(String field) {
|
|
|
+ if (StringUtils.isBlank(field)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String lowerField = field.toLowerCase(Locale.ROOT);
|
|
|
+ return lowerField.endsWith("unit") || lowerField.equals("unit");
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isExactMatchField(String field) {
|
|
|
+ if (StringUtils.isBlank(field)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String lowerField = field.toLowerCase(Locale.ROOT);
|
|
|
+ return isUnitField(field)
|
|
|
+ || lowerField.contains("status")
|
|
|
+ || lowerField.endsWith("state")
|
|
|
+ || lowerField.endsWith("type")
|
|
|
+ || lowerField.endsWith("zt");
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean looksLikeDate(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String text = String.valueOf(value).trim();
|
|
|
+ return text.matches("\\d{4}-\\d{1,2}-\\d{1,2}.*")
|
|
|
+ || text.matches("\\d{4}/\\d{1,2}/\\d{1,2}.*");
|
|
|
+ }
|
|
|
+
|
|
|
+ private String normalizeDateValue(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ String text = String.valueOf(value).trim().replace('/', '-');
|
|
|
+ if (text.length() >= 10 && looksLikeDate(text)) {
|
|
|
+ return text.substring(0, 10);
|
|
|
+ }
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal toBigDecimal(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String text = String.valueOf(value).trim();
|
|
|
+ if (StringUtils.isBlank(text)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return new BigDecimal(text);
|
|
|
+ } catch (NumberFormatException ex) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private Map<String, Object> buildCycleProjectRow(Project project, ProjectWorkflow workflow,
|
|
|
Map<String, Object> nodeData, String worktype,
|
|
|
Map<String, String> geomDetail) {
|