diff --git a/pom.xml b/pom.xml
index abf4e9cc..9331de3b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -277,5 +277,16 @@
+
+
+ src/main/resources
+
+
+ src/main/java
+
+ **/*.xml
+
+
+
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index 5e2745a6..a1885716 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageInfo;
@@ -93,6 +94,13 @@ public interface IVideoManagerStorager {
public List queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit);
+ /**
+ * 获取某个设备的通道树
+ * @param deviceId 设备ID
+ * @return
+ */
+ List tree(String deviceId);
+
/**
* 获取某个设备的通道列表
*
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
index 7f52f797..f882766f 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@@ -201,4 +202,20 @@ public interface DeviceChannelMapper {
@Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
List queryOnlineChannelsByDeviceId(String deviceId);
+
+ @Select(" SELECT\n" +
+ " channelId,\n" +
+ " channelId as id,\n" +
+ " deviceId,\n" +
+ " parentId,\n" +
+ " status,\n" +
+ " name as title,\n" +
+ " channelId as \"value\",\n" +
+ " channelId as \"key\",\n" +
+ " channelId,\n" +
+ " longitude,\n" +
+ " latitude\n" +
+ " from device_channel\n" +
+ " where deviceId = #{deviceId}")
+ List tree(String deviceId);
}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
index f43f92f6..57b30f10 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -13,6 +13,8 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*;
+import com.genersoft.iot.vmp.utils.node.ForestNodeMerger;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -328,6 +330,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
return deviceChannelMapper.queryChannelsByDeviceIdWithStartAndLimit(deviceId, null, query, hasSubChannel, online, start, limit);
}
+ @Override
+ public List tree(String deviceId) {
+ return ForestNodeMerger.merge(deviceChannelMapper.tree(deviceId));
+ }
+
@Override
public List queryChannelsByDeviceId(String deviceId) {
return deviceChannelMapper.queryChannels(deviceId, null,null, null, null);
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java
new file mode 100644
index 00000000..4f7ca1f3
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/CollectionUtil.java
@@ -0,0 +1,12 @@
+package com.genersoft.iot.vmp.utils;
+
+import java.util.Arrays;
+
+public class CollectionUtil {
+
+ public static boolean contains(T[] array, final T element) {
+ return array != null && Arrays.stream(array).anyMatch((x) -> {
+ return ObjectUtils.nullSafeEquals(x, element);
+ });
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java b/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
new file mode 100644
index 00000000..1f429bc7
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.utils;
+
+import java.util.Arrays;
+
+public class ObjectUtils {
+ public static boolean nullSafeEquals(Object o1, Object o2) {
+ if (o1 == o2) {
+ return true;
+ } else if (o1 != null && o2 != null) {
+ if (o1.equals(o2)) {
+ return true;
+ } else {
+ return o1.getClass().isArray() && o2.getClass().isArray() && arrayEquals(o1, o2);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean arrayEquals(Object o1, Object o2) {
+ if (o1 instanceof Object[] && o2 instanceof Object[]) {
+ return Arrays.equals((Object[])((Object[])o1), (Object[])((Object[])o2));
+ } else if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
+ return Arrays.equals((boolean[])((boolean[])o1), (boolean[])((boolean[])o2));
+ } else if (o1 instanceof byte[] && o2 instanceof byte[]) {
+ return Arrays.equals((byte[])((byte[])o1), (byte[])((byte[])o2));
+ } else if (o1 instanceof char[] && o2 instanceof char[]) {
+ return Arrays.equals((char[])((char[])o1), (char[])((char[])o2));
+ } else if (o1 instanceof double[] && o2 instanceof double[]) {
+ return Arrays.equals((double[])((double[])o1), (double[])((double[])o2));
+ } else if (o1 instanceof float[] && o2 instanceof float[]) {
+ return Arrays.equals((float[])((float[])o1), (float[])((float[])o2));
+ } else if (o1 instanceof int[] && o2 instanceof int[]) {
+ return Arrays.equals((int[])((int[])o1), (int[])((int[])o2));
+ } else if (o1 instanceof long[] && o2 instanceof long[]) {
+ return Arrays.equals((long[])((long[])o1), (long[])((long[])o2));
+ } else {
+ return o1 instanceof short[] && o2 instanceof short[] && Arrays.equals((short[]) ((short[]) o1), (short[]) ((short[]) o2));
+ }
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
new file mode 100644
index 00000000..0de21608
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
@@ -0,0 +1,54 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 节点基类
+ *
+ */
+@Data
+public class BaseNode implements INode {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ protected String id;
+
+ /**
+ * 父节点ID
+ */
+ protected String parentId;
+
+ /**
+ * 子孙节点
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ protected List children = new ArrayList();
+
+ /**
+ * 是否有子孙节点
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Boolean hasChildren;
+
+ /**
+ * 是否有子孙节点
+ *
+ * @return Boolean
+ */
+ @Override
+ public Boolean getHasChildren() {
+ if (children.size() > 0) {
+ return true;
+ } else {
+ return this.hasChildren;
+ }
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
new file mode 100644
index 00000000..0ba72072
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
@@ -0,0 +1,28 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+ * 森林节点类
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class ForestNode extends BaseNode {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 节点内容
+ */
+ private Object content;
+
+ public ForestNode(String id, String parentId, Object content) {
+ this.id = id;
+ this.parentId = parentId;
+ this.content = content;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java
new file mode 100644
index 00000000..de98fdc7
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeManager.java
@@ -0,0 +1,68 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 森林管理类
+ *
+ * @author smallchill
+ */
+public class ForestNodeManager> {
+
+ /**
+ * 森林的所有节点
+ */
+ private final ImmutableMap nodeMap;
+
+ /**
+ * 森林的父节点ID
+ */
+ private final Map parentIdMap = Maps.newHashMap();
+
+ public ForestNodeManager(List nodes) {
+ nodeMap = Maps.uniqueIndex(nodes, INode::getId);
+ }
+
+ /**
+ * 根据节点ID获取一个节点
+ *
+ * @param id 节点ID
+ * @return 对应的节点对象
+ */
+ public INode getTreeNodeAt(String id) {
+ if (nodeMap.containsKey(id)) {
+ return nodeMap.get(id);
+ }
+ return null;
+ }
+
+ /**
+ * 增加父节点ID
+ *
+ * @param parentId 父节点ID
+ */
+ public void addParentId(String parentId) {
+ parentIdMap.put(parentId, "");
+ }
+
+ /**
+ * 获取树的根节点(一个森林对应多颗树)
+ *
+ * @return 树的根节点集合
+ */
+ public List getRoot() {
+ List roots = new ArrayList<>();
+ nodeMap.forEach((key, node) -> {
+ if (node.getParentId() == null || parentIdMap.containsKey(node.getId())) {
+ roots.add(node);
+ }
+ });
+ return roots;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java
new file mode 100644
index 00000000..062d4cd9
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNodeMerger.java
@@ -0,0 +1,51 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import com.genersoft.iot.vmp.utils.CollectionUtil;
+
+import java.util.List;
+
+/**
+ * 森林节点归并类
+ *
+ */
+public class ForestNodeMerger {
+
+ /**
+ * 将节点数组归并为一个森林(多棵树)(填充节点的children域)
+ * 时间复杂度为O(n^2)
+ *
+ * @param items 节点域
+ * @return 多棵树的根节点集合
+ */
+ public static > List merge(List items) {
+ ForestNodeManager forestNodeManager = new ForestNodeManager<>(items);
+ items.forEach(forestNode -> {
+ if (forestNode.getParentId() != null) {
+ INode node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
+ if (node != null) {
+ node.getChildren().add(forestNode);
+ } else {
+ forestNodeManager.addParentId(forestNode.getId());
+ }
+ }
+ });
+ return forestNodeManager.getRoot();
+ }
+
+ public static > List merge(List items, String[] parentIds) {
+ ForestNodeManager forestNodeManager = new ForestNodeManager<>(items);
+ items.forEach(forestNode -> {
+ if (forestNode.getParentId() != null) {
+ INode node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
+ if (CollectionUtil.contains(parentIds, forestNode.getId())){
+ forestNodeManager.addParentId(forestNode.getId());
+ } else {
+ if (node != null){
+ node.getChildren().add(forestNode);
+ }
+ }
+ }
+ });
+ return forestNodeManager.getRoot();
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
new file mode 100644
index 00000000..4d6ebfcb
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
@@ -0,0 +1,42 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ *
+ * 节点
+ */
+public interface INode extends Serializable {
+
+ /**
+ * 主键
+ *
+ * @return String
+ */
+ String getId();
+
+ /**
+ * 父主键
+ *
+ * @return String
+ */
+ String getParentId();
+
+ /**
+ * 子孙节点
+ *
+ * @return List
+ */
+ List getChildren();
+
+ /**
+ * 是否有子孙节点
+ *
+ * @return Boolean
+ */
+ default Boolean getHasChildren() {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
new file mode 100644
index 00000000..9df6f11f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
@@ -0,0 +1,21 @@
+package com.genersoft.iot.vmp.utils.node;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 树型节点类
+ *
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TreeNode extends BaseNode {
+
+ private static final long serialVersionUID = 1L;
+
+ private String title;
+
+ private String key;
+
+ private String value;
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
new file mode 100644
index 00000000..773f2c13
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
@@ -0,0 +1,65 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.utils.node.INode;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "DeviceChannelTree对象", description = "DeviceChannelTree对象")
+public class DeviceChannelTree extends DeviceChannel implements INode {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ private String id;
+
+ /**
+ * 父节点ID
+ */
+ private String parentId;
+
+ private String parentName;
+
+ private String title;
+
+ private String key;
+
+ private String value;
+
+ /**
+ * 子孙节点
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private List children;
+
+ /**
+ * 是否有子孙节点
+ */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Boolean hasChildren;
+
+ @Override
+ public List getChildren() {
+ if (this.children == null) {
+ this.children = new ArrayList<>();
+ }
+ return this.children;
+ }
+
+ @Override
+ public Boolean getHasChildren() {
+ if (children.size() > 0) {
+ return true;
+ } else {
+ return this.hasChildren;
+ }
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
new file mode 100644
index 00000000..29d82bed
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
@@ -0,0 +1,20 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.genersoft.iot.vmp.utils.node.TreeNode;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DeviceChannelTreeNode extends TreeNode {
+
+ private Integer status;
+
+ private String deviceId;
+
+ private String channelId;
+
+ private Double lng;
+
+ private Double lat;
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
index f8e2c1c0..b4e3eb41 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -1,32 +1,35 @@
package com.genersoft.iot.vmp.vmanager.bean;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
public class WVPResult {
private int code;
private String msg;
private T data;
- public int getCode() {
- return code;
- }
+ private static final Integer SUCCESS = 200;
+ private static final Integer FAILED = 400;
- public void setCode(int code) {
- this.code = code;
+ public static WVPResult Data(T t, String msg) {
+ return new WVPResult<>(SUCCESS, msg, t);
}
- public String getMsg() {
- return msg;
+ public static WVPResult Data(T t) {
+ return Data(t, "成功");
}
- public void setMsg(String msg) {
- this.msg = msg;
+ public static WVPResult fail(int code, String msg) {
+ return new WVPResult<>(code, msg, null);
}
- public T getData() {
- return data;
+ public static WVPResult fail(String msg) {
+ return fail(FAILED, msg);
}
- public void setData(T data) {
- this.data = data;
- }
}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
index d83094ed..d9357d20 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -10,8 +10,10 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -25,6 +27,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
+import java.util.List;
import java.util.UUID;
@Api(tags = "国标设备查询", value = "国标设备查询")
@@ -431,5 +434,9 @@ public class DeviceQuery {
return result;
}
-
+ @GetMapping("/{deviceId}/tree")
+ @ApiOperation(value = "通道树形结构", notes = "通道树形结构")
+ public WVPResult> tree(@PathVariable String deviceId) {
+ return WVPResult.Data(storager.tree(deviceId));
+ }
}
diff --git a/web_src/src/api/deviceApi.js b/web_src/src/api/deviceApi.js
new file mode 100644
index 00000000..830164f4
--- /dev/null
+++ b/web_src/src/api/deviceApi.js
@@ -0,0 +1,19 @@
+import axios from 'axios';
+
+export const tree = (deviceId) => {
+ return axios({
+ url: `/api/device/query/${deviceId}/tree`,
+ method: 'get'
+ })
+}
+
+export const deviceList = (page, count) => {
+ return axios({
+ method: 'get',
+ url:`/api/device/query/devices`,
+ params: {
+ page,
+ count
+ }
+ })
+}
\ No newline at end of file
diff --git a/web_src/src/components/UiHeader.vue b/web_src/src/components/UiHeader.vue
index 6391fe8c..4bbf639b 100644
--- a/web_src/src/components/UiHeader.vue
+++ b/web_src/src/components/UiHeader.vue
@@ -2,6 +2,7 @@