|
|
@@ -73,6 +73,8 @@ public class HikvisionController {
|
|
|
private static final String CAMERA_SEARCH_ADDRESS = "/api/resource/v2/camera/search";
|
|
|
/** 批量获取区域详情,用 parentIndexCode 还原监控点的完整目录。 */
|
|
|
private static final String REGION_INFO_ADDRESS = "/api/resource/v1/region/regionCatalog/regionInfo";
|
|
|
+ /** 按区域(包含子区域)统计在线监控点。 */
|
|
|
+ private static final String CAMERA_ONLINE_ADDRESS = "/api/nms/v1/online/camera/get";
|
|
|
/** 获取监控点实时预览地址。 */
|
|
|
private static final String PREVIEW_URL_ADDRESS = "/api/video/v2/cameras/previewURLs";
|
|
|
/** 获取监控点对讲地址。 */
|
|
|
@@ -126,6 +128,7 @@ public class HikvisionController {
|
|
|
: error(403, "无权查看该监控目录");
|
|
|
}
|
|
|
if ("-1".equals(regionIndexCode)) {
|
|
|
+ populateRegionOnlineStatus(company);
|
|
|
company.setChildren(queryTreeChildren(company.getIndexCode()));
|
|
|
return success(Collections.singletonList(company));
|
|
|
}
|
|
|
@@ -176,7 +179,9 @@ public class HikvisionController {
|
|
|
String keywordLowerCase = name.toLowerCase(Locale.ROOT);
|
|
|
cameras.removeIf(camera -> camera == null || camera.getString("name") == null
|
|
|
|| !camera.getString("name").toLowerCase(Locale.ROOT).contains(keywordLowerCase));
|
|
|
- return success(buildSearchTree(root, cameras));
|
|
|
+ List<HikvisionTreeNodeRespVO> tree = buildSearchTree(root, cameras);
|
|
|
+ populateRegionOnlineStatus(tree);
|
|
|
+ return success(tree);
|
|
|
} catch (Exception e) {
|
|
|
log.error("搜索海康监控点目录树失败", e);
|
|
|
return error(500, "搜索海康监控点目录树失败");
|
|
|
@@ -467,6 +472,7 @@ public class HikvisionController {
|
|
|
*/
|
|
|
private HikvisionTreeNodeRespVO queryRootWithChildren() throws Exception {
|
|
|
HikvisionTreeNodeRespVO root = queryRoot();
|
|
|
+ populateRegionOnlineStatus(root);
|
|
|
List<HikvisionTreeNodeRespVO> children = queryTreeChildren(root.getIndexCode());
|
|
|
root.setChildren(children);
|
|
|
if (root.getLeaf() == null) {
|
|
|
@@ -502,11 +508,50 @@ public class HikvisionController {
|
|
|
*/
|
|
|
private List<HikvisionTreeNodeRespVO> queryTreeChildren(String regionIndexCode) throws Exception {
|
|
|
List<HikvisionTreeNodeRespVO> nodes = new ArrayList<>();
|
|
|
- nodes.addAll(querySubRegions(regionIndexCode));
|
|
|
+ List<HikvisionTreeNodeRespVO> regions = querySubRegions(regionIndexCode);
|
|
|
+ populateRegionOnlineStatus(regions);
|
|
|
+ nodes.addAll(regions);
|
|
|
nodes.addAll(querySubCameras(regionIndexCode));
|
|
|
return nodes;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 为响应中的区域节点补充在线状态和在线监控点数量。
|
|
|
+ *
|
|
|
+ * <p>
|
|
|
+ * 海康在线状态接口支持通过 {@code regionId} 限定区域,并通过
|
|
|
+ * {@code includeSubNode=1} 统计其全部子孙区域。这里只筛选在线监控点且每页取 1 条,
|
|
|
+ * 因为响应中的 {@code total} 已经是所需的在线总数,无需下载全部监控点明细。
|
|
|
+ * </p>
|
|
|
+ */
|
|
|
+ private void populateRegionOnlineStatus(List<HikvisionTreeNodeRespVO> nodes) throws Exception {
|
|
|
+ for (HikvisionTreeNodeRespVO node : nodes) {
|
|
|
+ if (!NODE_TYPE_REGION.equals(node.getNodeType())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ populateRegionOnlineStatus(node);
|
|
|
+ if (node.getChildren() != null && !node.getChildren().isEmpty()) {
|
|
|
+ populateRegionOnlineStatus(node.getChildren());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void populateRegionOnlineStatus(HikvisionTreeNodeRespVO region) throws Exception {
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("regionId", region.getIndexCode());
|
|
|
+ params.put("includeSubNode", "1");
|
|
|
+ params.put("status", "1");
|
|
|
+ params.put("pageNo", 1);
|
|
|
+ params.put("pageSize", 1);
|
|
|
+ JSONObject data = parseArtemisData(invokeArtemis(CAMERA_ONLINE_ADDRESS, params));
|
|
|
+ Integer onlineCount = data.getInteger("total");
|
|
|
+ if (onlineCount == null) {
|
|
|
+ throw new IllegalStateException("海康监控点在线状态响应缺少 total");
|
|
|
+ }
|
|
|
+ region.setOnlineCount(onlineCount);
|
|
|
+ region.setOnlineStatus(onlineCount > 0);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 查询父区域的所有直接子区域,并转换成统一树节点。
|
|
|
*
|