From 9409efa0c3360fb8dbaceac9861a9480e0881b5b Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 22 Jun 2026 17:12:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=86=E9=A2=91=E7=AB=99=E6=A0=91?= =?UTF-8?q?=E7=BA=A7=E7=BB=93=E6=9E=84=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vd/controller/VdMonitorController.java | 6 + .../qgc_env/vd/entity/vo/VdTreeNodeVo.java | 71 ++++ .../qgc_env/vd/entity/vo/VdTreeRowVo.java | 39 +++ .../qgc_env/vd/service/VdMonitorService.java | 3 + .../vd/service/impl/VdMonitorServiceImpl.java | 329 +++++++++++++++++- 5 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeNodeVo.java create mode 100644 backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeRowVo.java diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vd/controller/VdMonitorController.java b/backend/src/main/java/com/yfd/platform/qgc_env/vd/controller/VdMonitorController.java index 1e670bfe..3bd3f3f0 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vd/controller/VdMonitorController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vd/controller/VdMonitorController.java @@ -47,6 +47,12 @@ public class VdMonitorController { return ResponseResult.successData(vdMonitorService.getKendoListCust(dataSourceRequest)); } + @PostMapping("/tree/GetKendoListCust") + @Operation(summary = "视频站树级结构查询") + public ResponseResult getVdTreeKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(vdMonitorService.getVdTreeKendoListCust(dataSourceRequest)); + } + @PostMapping("/vdpoint/GetKendoListCust") @Operation(summary = "视频站锚点接口") public ResponseResult getVdPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeNodeVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeNodeVo.java new file mode 100644 index 00000000..8b31efb7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeNodeVo.java @@ -0,0 +1,71 @@ +package com.yfd.platform.qgc_env.vd.entity.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +@Schema(description = "视频站树节点") +public class VdTreeNodeVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "节点ID") + private String id; + + @Schema(description = "节点名称") + private String name; + + @Schema(description = "节点类型") + private String type; + + @Schema(description = "节点类型名称") + private String typeName; + + @Schema(description = "排序值") + private Integer sort; + + @Schema(description = "父节点ID") + private String parentId; + + @Schema(description = "父节点名称") + private String parentName; + + @Schema(description = "是否有子节点") + private Integer hasChildren; + + @Schema(description = "播放地址") + private String url; + + @Schema(description = "播放方式") + private String playWay; + + @Schema(description = "设备序列号") + private String deviceSerial; + + @Schema(description = "接入方式") + private String accessWay; + + @Schema(description = "流协议") + private String protocol; + + @Schema(description = "清晰度") + private String quality; + + @Schema(description = "控制方式") + private String controlMode; + + @Schema(description = "设备状态") + private Integer status; + + @Schema(description = "状态时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date statusTm; + + @Schema(description = "子节点") + private List children; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeRowVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeRowVo.java new file mode 100644 index 00000000..eeea11bb --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vd/entity/vo/VdTreeRowVo.java @@ -0,0 +1,39 @@ +package com.yfd.platform.qgc_env.vd.entity.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class VdTreeRowVo implements Serializable { + + private static final long serialVersionUID = 1L; + + private String stcd; + private String stCode; + private String stName; + private String stnm; + private String sttpCode; + private String sttpName; + private String sttpFullPath; + private String rstcd; + private String ennm; + private String baseId; + private String baseName; + private String url; + private String playWay; + private Integer baseSort; + private Integer rstcdStepSort; + private Integer siteStepSort; + private String deviceSerial; + private String accessWay; + private String protocol; + private String quality; + private String controlMode; + private Integer status; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date statusTm; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/VdMonitorService.java b/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/VdMonitorService.java index 3b21de15..58d6e69a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/VdMonitorService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/VdMonitorService.java @@ -2,6 +2,7 @@ package com.yfd.platform.qgc_env.vd.service; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.qgc_env.vd.entity.vo.VdTreeNodeVo; import com.yfd.platform.qgc_env.vd.entity.vo.VdRunDataVo; import com.yfd.platform.qgc_env.vd.entity.vo.VdVmsstbprptVo; @@ -13,6 +14,8 @@ public interface VdMonitorService { DataSourceResult getKendoListCust(DataSourceRequest dataSourceRequest); + DataSourceResult getVdTreeKendoListCust(DataSourceRequest dataSourceRequest); + DataSourceResult getVdPointKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult getRunDataKendoListCust(DataSourceRequest dataSourceRequest); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/impl/VdMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/impl/VdMonitorServiceImpl.java index d1931ea5..f13f0ed0 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/impl/VdMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vd/service/impl/VdMonitorServiceImpl.java @@ -11,6 +11,8 @@ import com.yfd.platform.common.GroupingInfo; import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.qgc_env.vd.entity.vo.VdPointVo; import com.yfd.platform.qgc_env.vd.entity.vo.VdRunDataVo; +import com.yfd.platform.qgc_env.vd.entity.vo.VdTreeNodeVo; +import com.yfd.platform.qgc_env.vd.entity.vo.VdTreeRowVo; import com.yfd.platform.qgc_env.vd.entity.vo.VdVmsstbprptVo; import com.yfd.platform.qgc_env.vd.service.VdMonitorService; import com.yfd.platform.utils.QgcQueryWrapperUtil; @@ -19,6 +21,7 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -119,6 +122,55 @@ public class VdMonitorServiceImpl implements VdMonitorService { return queryLatestRunDataGroupList(dataSourceRequest, loadOptions); } + @Override + public DataSourceResult getVdTreeKendoListCust(DataSourceRequest dataSourceRequest) { + Map paramMap = new HashMap<>(); + String filterSql = buildVdTreeFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("t.stcd AS stcd, ") + .append("t.stCode AS stCode, ") + .append("t.stName AS stName, ") + .append("t.stnm AS stnm, ") + .append("t.sttpCode AS sttpCode, ") + .append("t.sttpName AS sttpName, ") + .append("t.sttpFullPath AS sttpFullPath, ") + .append("t.rstcd AS rstcd, ") + .append("t.ennm AS ennm, ") + .append("t.baseId AS baseId, ") + .append("t.baseName AS baseName, ") + .append("t.url AS url, ") + .append("t.playWay AS playWay, ") + .append("t.baseSort AS baseSort, ") + .append("t.rstcdStepSort AS rstcdStepSort, ") + .append("t.siteStepSort AS siteStepSort, ") + .append("t.deviceSerial AS deviceSerial, ") + .append("t.accessWay AS accessWay, ") + .append("t.protocol AS protocol, ") + .append("t.quality AS quality, ") + .append("t.controlMode AS controlMode, ") + .append("t.status AS status, ") + .append("t.statusTm AS statusTm ") + .append("FROM (") + .append(buildVdTreeCoreSql()) + .append(") t WHERE 1 = 1 "); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + sql.append(" ORDER BY t.baseSort ASC NULLS LAST, t.rstcdStepSort ASC NULLS LAST, t.siteStepSort ASC NULLS LAST, t.stcd ASC"); + + List rows = microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, VdTreeRowVo.class); + boolean baseScoped = containsNonBlankFilterValue(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), "baseId"); + + DataSourceResult result = new DataSourceResult<>(); + List treeData = buildVdTreeNodes(rows, baseScoped); + result.setData(treeData); + result.setTotal((long) treeData.size()); + result.setAggregates(new HashMap<>()); + return result; + } + @Override public DataSourceResult getVdPointKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -491,12 +543,57 @@ public class VdMonitorServiceImpl implements VdMonitorService { " AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 "; } + private String buildVdTreeCoreSql() { + return "SELECT " + + "base.STCD AS stcd, " + + "base.STNM AS stnm, " + + "base.CSTCD AS stCode, " + + "cst.STNM AS stName, " + + "base.STTP AS sttpCode, " + + "sttp.STTP_NAME AS sttpName, " + + "sttp.FULL_PATH AS sttpFullPath, " + + "base.RSTCD AS rstcd, " + + "eng.ENNM AS ennm, " + + "NVL(eng.BASE_ID, base.BASE_ID) AS baseId, " + + "hb.BASENAME AS baseName, " + + "base.URL AS url, " + + "CASE WHEN base.URL IS NULL THEN NULL WHEN INSTR(base.URL, 'm3u8') > 0 THEN '1' ELSE '0' END AS playWay, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseSort, " + + "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + + "NVL(base.ORDER_INDEX, 999999) AS siteStepSort, " + + "base.DEVICE_SERIAL AS deviceSerial, " + + "base.ACCESS_WAY AS accessWay, " + + "base.PROTOCOL AS protocol, " + + "base.QUALITY AS quality, " + + "base.CONTROL_MODE AS controlMode, " + + "status.STATUS AS status, " + + "status.TM AS statusTm " + + "FROM (" + buildVdDeviceBaseSql() + ") base " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = base.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eng.BASE_ID, base.BASE_ID) " + + " AND NVL(hb.IS_DELETED, 0) = 0 AND NVL(hb.ENABLED, 1) = 1 " + + "LEFT JOIN (" + buildStationBaseSql() + ") cst ON cst.STCD = base.CSTCD " + + "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = base.STTP " + + " AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + "LEFT JOIN ( " + + "SELECT detail.STCD, detail.TM, detail.STATUS " + + "FROM MS_SBGZSTAT_B detail " + + "INNER JOIN ( " + + "SELECT STCD, MAX(TM) AS MAX_TM FROM MS_SBGZSTAT_B " + + "WHERE NVL(IS_DELETED, 0) = 0 GROUP BY STCD " + + ") latest ON detail.STCD = latest.STCD AND detail.TM = latest.MAX_TM " + + "WHERE NVL(detail.IS_DELETED, 0) = 0 " + + ") status ON status.STCD = base.STCD " + + "WHERE base.STTP LIKE 'VD_%' "; + } + private String buildVdDeviceBaseSql() { return "SELECT vd.STCD, vd.STNM, vd.MNTP, vd.STTP, vd.LGTD, vd.LTTD, vd.ELEV, vd.STLC, " + " vd.JCDT, vd.WDDT, vd.BLDSTT_CODE, vd.USFL, vd.DTIN, vd.STINDX, vd.RSTCD, vd.BASE_ID, " + " vd.HBRVCD, vd.RVCD, vd.ADDVCD, vd.CSTCD, vd.FHSTCD, CAST(NULL AS VARCHAR2(3000)) AS INTRODUCE, " + " CAST(NULL AS VARCHAR2(255)) AS LOGO, CAST(NULL AS VARCHAR2(1000)) AS INFFILE, " + - " vd.DTFRQCY, vd.REMARK, vd.VLSR, vd.VLSR_TM, vd.URL AS URL, CAST(NULL AS NUMBER(8,0)) AS ORDER_INDEX, " + + " vd.DTFRQCY, vd.REMARK, vd.VLSR, vd.VLSR_TM, vd.URL AS URL, vd.DEVICE_SERIAL, vd.ACCESS_WAY, " + + " vd.PROTOCOL, vd.QUALITY, vd.CONTROL_MODE, CAST(NULL AS NUMBER(8,0)) AS ORDER_INDEX, " + " 'SD_VDINFO_B' AS SOURCE_TABLE " + "FROM SD_VDINFO_B vd WHERE 1=1 " + // " AND vd.STTP = 'VD_FP' "+ @@ -504,7 +601,9 @@ public class VdMonitorServiceImpl implements VdMonitorService { "SELECT sonar.STCD, sonar.STNM, sonar.MNTP, sonar.STTP, sonar.LGTD, sonar.LTTD, sonar.ELEV, sonar.STLC, " + " sonar.JCDT, sonar.WDDT, sonar.BLDSTT_CODE, sonar.USFL, sonar.DTIN, sonar.STINDX, sonar.RSTCD, sonar.BASE_ID, " + " sonar.HBRVCD, sonar.RVCD, sonar.ADDVCD, CAST(NULL AS VARCHAR2(36)) AS CSTCD, CAST(NULL AS VARCHAR2(36)) AS FHSTCD, " + - " sonar.INTRODUCE, sonar.LOGO, sonar.INFFILE, sonar.DTFRQCY, sonar.REMARK, sonar.VLSR, sonar.VLSR_TM, CAST(NULL AS VARCHAR2(512)) AS URL, sonar.ORDER_INDEX, " + + " sonar.INTRODUCE, sonar.LOGO, sonar.INFFILE, sonar.DTFRQCY, sonar.REMARK, sonar.VLSR, sonar.VLSR_TM, CAST(NULL AS VARCHAR2(512)) AS URL, " + + " CAST(NULL AS VARCHAR2(255)) AS DEVICE_SERIAL, CAST(NULL AS VARCHAR2(10)) AS ACCESS_WAY, " + + " CAST(NULL AS VARCHAR2(50)) AS PROTOCOL, CAST(NULL AS VARCHAR2(50)) AS QUALITY, CAST(NULL AS VARCHAR2(2048)) AS CONTROL_MODE, sonar.ORDER_INDEX, " + " 'SD_SONAR_B_H' AS SOURCE_TABLE " + "FROM SD_SONAR_B_H sonar WHERE NVL(sonar.IS_DELETED, 0) = 0 AND sonar.STTP IN ('VD_WVD', 'VD_SN') "; } @@ -809,6 +908,42 @@ public class VdMonitorServiceImpl implements VdMonitorService { }; } + private String buildVdTreeFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildVdTreeLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildVdTreeFilterCondition(child, paramMap, indexHolder); + if (StrUtil.isNotBlank(childSql)) { + conditions.add("(" + childSql + ")"); + } + } + if (conditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return String.join(logic, conditions); + } + + private String buildVdTreeLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String column = mapVdTreeColumn(filter.getField()); + if (StrUtil.isBlank(column)) { + return ""; + } + return buildSimpleCondition(column, "vdTreeParam", filter, paramMap, indexHolder, isVdTreeDateField(filter)); + } + private String buildFilterCondition(DataSourceRequest.FilterDescriptor filter, Map paramMap, int[] indexHolder) { @@ -972,6 +1107,16 @@ public class VdMonitorServiceImpl implements VdMonitorService { return "date".equalsIgnoreCase(filter.getDataType()); } + private boolean isVdTreeDateField(DataSourceRequest.FilterDescriptor filter) { + if (filter == null || StrUtil.isBlank(filter.getField())) { + return false; + } + if ("statusTm".equalsIgnoreCase(filter.getField())) { + return true; + } + return "date".equalsIgnoreCase(filter.getDataType()); + } + private String buildValueExpr(String paramKey, boolean dateField, Object value) { if (!dateField || value == null) { return "#{map." + paramKey + "}"; @@ -1007,6 +1152,35 @@ public class VdMonitorServiceImpl implements VdMonitorService { return values; } + private String mapVdTreeColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "t.stcd"; + case "stCode" -> "t.stCode"; + case "stName" -> "t.stName"; + case "stnm" -> "t.stnm"; + case "sttpCode" -> "t.sttpCode"; + case "sttpName" -> "t.sttpName"; + case "sttpFullPath" -> "t.sttpFullPath"; + case "rstcd" -> "t.rstcd"; + case "ennm" -> "t.ennm"; + case "baseId" -> "t.baseId"; + case "baseName" -> "t.baseName"; + case "url" -> "t.url"; + case "playWay" -> "t.playWay"; + case "deviceSerial" -> "t.deviceSerial"; + case "accessWay" -> "t.accessWay"; + case "protocol" -> "t.protocol"; + case "quality" -> "t.quality"; + case "controlMode" -> "t.controlMode"; + case "status" -> "NVL(t.status, 0)"; + case "statusTm" -> "t.statusTm"; + default -> null; + }; + } + private String mapColumn(String field) { if (StrUtil.isBlank(field)) { return null; @@ -1144,4 +1318,155 @@ public class VdMonitorServiceImpl implements VdMonitorService { } return " ORDER BY " + String.join(", ", orderItems); } + + private boolean containsNonBlankFilterValue(DataSourceRequest.FilterDescriptor filter, String fieldName) { + if (filter == null || StrUtil.isBlank(fieldName)) { + return false; + } + if (fieldName.equalsIgnoreCase(filter.getField())) { + if (filter.getValue() instanceof List list) { + return CollUtil.isNotEmpty(list); + } + return StrUtil.isNotBlank(filter.getValue() == null ? null : String.valueOf(filter.getValue())); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return false; + } + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + if (containsNonBlankFilterValue(child, fieldName)) { + return true; + } + } + return false; + } + + private List buildVdTreeNodes(List rows, boolean baseScoped) { + List stationNodes = buildStationTreeNodes(rows, baseScoped); + if (baseScoped) { + return sortTreeNodes(stationNodes); + } + + LinkedHashMap baseNodeMap = new LinkedHashMap<>(); + List topLevelWithoutBase = new ArrayList<>(); + for (VdTreeRowVo row : rows) { + if (row == null) { + continue; + } + if (StrUtil.isBlank(row.getBaseId())) { + continue; + } + baseNodeMap.computeIfAbsent(row.getBaseId(), key -> { + VdTreeNodeVo node = new VdTreeNodeVo(); + node.setId(key); + node.setName(StrUtil.blankToDefault(row.getBaseName(), key)); + node.setType("PSB"); + node.setTypeName("基地"); + node.setSort(defaultSort(row.getBaseSort())); + node.setHasChildren(1); + node.setParentId(null); + node.setParentName(null); + return node; + }); + } + + Map> stationByBase = new LinkedHashMap<>(); + for (VdTreeNodeVo stationNode : stationNodes) { + if (StrUtil.isBlank(stationNode.getParentId())) { + topLevelWithoutBase.add(stationNode); + continue; + } + stationByBase.computeIfAbsent(stationNode.getParentId(), key -> new ArrayList<>()).add(stationNode); + } + + List result = new ArrayList<>(); + for (Map.Entry entry : baseNodeMap.entrySet()) { + VdTreeNodeVo baseNode = entry.getValue(); + baseNode.setChildren(sortTreeNodes(stationByBase.get(entry.getKey()))); + result.add(baseNode); + } + result.addAll(topLevelWithoutBase); + return sortTreeNodes(result); + } + + private List buildStationTreeNodes(List rows, boolean baseScoped) { + LinkedHashMap> stationRowMap = new LinkedHashMap<>(); + for (VdTreeRowVo row : rows) { + if (row == null || StrUtil.isBlank(row.getRstcd())) { + continue; + } + stationRowMap.computeIfAbsent(row.getRstcd(), key -> new ArrayList<>()).add(row); + } + + List stationNodes = new ArrayList<>(); + for (Map.Entry> entry : stationRowMap.entrySet()) { + List stationRows = entry.getValue(); + if (CollUtil.isEmpty(stationRows)) { + continue; + } + VdTreeRowVo sample = stationRows.get(0); + VdTreeNodeVo stationNode = new VdTreeNodeVo(); + stationNode.setId(entry.getKey()); + stationNode.setName(StrUtil.blankToDefault(sample.getEnnm(), entry.getKey())); + stationNode.setType("ENG"); + stationNode.setTypeName("电站"); + stationNode.setSort(defaultSort(sample.getRstcdStepSort())); + stationNode.setHasChildren(1); + if (baseScoped) { + stationNode.setParentId(null); + stationNode.setParentName(null); + } else { + stationNode.setParentId(sample.getBaseId()); + stationNode.setParentName(sample.getBaseName()); + } + stationNode.setChildren(buildSiteTreeNodes(stationRows)); + stationNodes.add(stationNode); + } + return sortTreeNodes(stationNodes); + } + + private List buildSiteTreeNodes(List rows) { + LinkedHashMap siteNodeMap = new LinkedHashMap<>(); + for (VdTreeRowVo row : rows) { + if (row == null || StrUtil.isBlank(row.getStcd()) || siteNodeMap.containsKey(row.getStcd())) { + continue; + } + VdTreeNodeVo node = new VdTreeNodeVo(); + node.setId(row.getStcd()); + node.setName(StrUtil.blankToDefault(row.getStnm(), row.getStcd())); + node.setType(row.getSttpCode()); + node.setTypeName(row.getSttpName()); + node.setSort(defaultSort(row.getSiteStepSort())); + node.setHasChildren(0); + node.setParentId(row.getRstcd()); + node.setParentName(row.getEnnm()); + node.setUrl(row.getUrl()); + node.setPlayWay(row.getPlayWay()); + node.setDeviceSerial(row.getDeviceSerial()); + node.setAccessWay(row.getAccessWay()); + node.setProtocol(row.getProtocol()); + node.setQuality(row.getQuality()); + node.setControlMode(row.getControlMode()); + node.setStatus(row.getStatus()); + node.setStatusTm(row.getStatusTm()); + siteNodeMap.put(row.getStcd(), node); + } + return sortTreeNodes(new ArrayList<>(siteNodeMap.values())); + } + + private List sortTreeNodes(List nodes) { + if (CollUtil.isEmpty(nodes)) { + return new ArrayList<>(); + } + nodes.sort(Comparator.comparing(VdMonitorServiceImpl::sortValue) + .thenComparing(node -> StrUtil.blankToDefault(node.getId(), ""))); + return nodes; + } + + private static Integer sortValue(VdTreeNodeVo node) { + return node == null ? 999999 : defaultSort(node.getSort()); + } + + private static Integer defaultSort(Integer sort) { + return sort == null ? 999999 : sort; + } }