瀏覽代碼

为级联平台增加虚拟目录功能

648540858 3 年之前
父節點
當前提交
6e0f7fae6e
共有 50 個文件被更改,包括 1494 次插入104 次删除
  1. 1 3
      README.md
  2. 231 0
      sql/dump-wvp-202201051515.sql
  3. 12 0
      sql/mysql.sql
  4. 21 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java
  5. 13 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
  6. 71 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java
  7. 8 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
  8. 8 0
      src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
  9. 2 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
  10. 5 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  11. 13 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
  12. 36 7
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
  13. 34 7
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
  14. 2 5
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  15. 1 1
      src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java
  16. 3 1
      src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
  17. 2 1
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
  18. 1 0
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
  19. 2 0
      src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
  20. 26 1
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  21. 2 1
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  22. 3 9
      src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
  23. 11 3
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  24. 42 0
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
  25. 19 2
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
  26. 22 2
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
  27. 6 0
      src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
  28. 93 2
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
  29. 12 3
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
  30. 1 1
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
  31. 10 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java
  32. 200 1
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  33. 13 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java
  34. 9 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java
  35. 1 1
      src/main/resources/all-application.yml
  36. 1 1
      src/main/resources/application-dev.yml
  37. 1 1
      src/main/resources/application-docker.yml
  38. 二進制
      src/main/resources/wvp.sqlite
  39. 11 0
      web_src/package-lock.json
  40. 1 0
      web_src/package.json
  41. 1 1
      web_src/src/components/ParentPlatformList.vue
  42. 101 0
      web_src/src/components/dialog/catalogEdit.vue
  43. 65 18
      web_src/src/components/dialog/chooseChannel.vue
  44. 311 0
      web_src/src/components/dialog/chooseChannelForCatalog.vue
  45. 33 22
      web_src/src/components/dialog/chooseChannelForGb.vue
  46. 9 2
      web_src/src/components/dialog/chooseChannelForStream.vue
  47. 1 0
      web_src/src/components/dialog/platformEdit.vue
  48. 2 0
      web_src/src/main.js
  49. 21 5
      web_src/static/css/iconfont.css
  50. 二進制
      web_src/static/css/iconfont.woff2

+ 1 - 3
README.md

@@ -95,15 +95,13 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
     - [X] 平台状态查询
     - [X] 平台状态查询
     - [X] 平台信息查询
     - [X] 平台信息查询
     - [X] 平台远程启动
     - [X] 平台远程启动
+    - [X] 每个级联平台可自定义的虚拟目录
 - [X] 添加RTSP视频
 - [X] 添加RTSP视频
 - [X] 添加接口鉴权
 - [X] 添加接口鉴权
-- [ ] 添加ONVIF探测局域网内的设备
 - [X] 添加RTMP视频
 - [X] 添加RTMP视频
 - [X] 云端录像(需要部署单独服务配合使用)
 - [X] 云端录像(需要部署单独服务配合使用)
 - [X] 多流媒体节点,自动选择负载最低的节点使用。
 - [X] 多流媒体节点,自动选择负载最低的节点使用。
 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。
 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。
-- [ ] 添加系统配置
-- [ ] 添加用户管理
 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
 
 
 # docker快速体验
 # docker快速体验

文件差異過大導致無法顯示
+ 231 - 0
sql/dump-wvp-202201051515.sql


+ 12 - 0
sql/mysql.sql

@@ -171,6 +171,7 @@ create table parent_platform
     keepTimeout    varchar(50)  null,
     keepTimeout    varchar(50)  null,
     transport      varchar(50)  null,
     transport      varchar(50)  null,
     characterSet   varchar(50)  null,
     characterSet   varchar(50)  null,
+    catalogId      varchar(50)  not null,
     ptz            int          null,
     ptz            int          null,
     rtcp           int          null,
     rtcp           int          null,
     status         bit          null,
     status         bit          null,
@@ -178,12 +179,22 @@ create table parent_platform
     primary key (id, serverGBId)
     primary key (id, serverGBId)
 );
 );
 
 
+
+create table platform_catalog
+(
+    id         varchar(50)  primary key,
+    platformId varchar(50) not null,
+    name       varchar(255) not null,
+    parentId   varchar(50)
+);
+
 create table platform_gb_channel
 create table platform_gb_channel
 (
 (
     channelId          varchar(50) not null,
     channelId          varchar(50) not null,
     deviceId           varchar(50) not null,
     deviceId           varchar(50) not null,
     platformId         varchar(50) not null,
     platformId         varchar(50) not null,
     deviceAndChannelId varchar(50) not null,
     deviceAndChannelId varchar(50) not null,
+    catalogId          varchar(50) not null,
     primary key (deviceAndChannelId, platformId)
     primary key (deviceAndChannelId, platformId)
 );
 );
 
 
@@ -192,6 +203,7 @@ create table platform_gb_stream
     platformId varchar(50)  not null,
     platformId varchar(50)  not null,
     app        varchar(255) not null,
     app        varchar(255) not null,
     stream     varchar(255) not null,
     stream     varchar(255) not null,
+    catalogId  varchar(50) not null,
     primary key (platformId, app, stream)
     primary key (platformId, app, stream)
 );
 );
 
 

+ 21 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java

@@ -0,0 +1,21 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import javax.sip.Dialog;
+import java.util.EventObject;
+
+public class DeviceNotFoundEvent extends EventObject {
+    /**
+     * Constructs a prototypical Event.
+     *
+     * @param dialog
+     * @throws IllegalArgumentException if source is null.
+     */
+    public DeviceNotFoundEvent(Dialog dialog) {
+        super(dialog);
+    }
+
+
+    public Dialog getDialog() {
+        return (Dialog)super.getSource();
+    }
+}

+ 13 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java

@@ -109,6 +109,11 @@ public class ParentPlatform {
      */
      */
     private boolean shareAllLiveStream;
     private boolean shareAllLiveStream;
 
 
+    /**
+     * 默认目录Id,自动添加的通道多放在这个目录下
+     */
+    private String catalogId;
+
     public Integer getId() {
     public Integer getId() {
         return id;
         return id;
     }
     }
@@ -277,4 +282,12 @@ public class ParentPlatform {
     public void setShareAllLiveStream(boolean shareAllLiveStream) {
     public void setShareAllLiveStream(boolean shareAllLiveStream) {
         this.shareAllLiveStream = shareAllLiveStream;
         this.shareAllLiveStream = shareAllLiveStream;
     }
     }
+
+    public String getCatalogId() {
+        return catalogId;
+    }
+
+    public void setCatalogId(String catalogId) {
+        this.catalogId = catalogId;
+    }
 }
 }

+ 71 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java

@@ -0,0 +1,71 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+public class PlatformCatalog {
+    private String id;
+    private String name;
+    private String platformId;
+    private String parentId;
+    private int childrenCount; // 子节点数
+    private int type; // 0 目录, 1 国标通道, 2 直播流
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPlatformId() {
+        return platformId;
+    }
+
+    public void setPlatformId(String platformId) {
+        this.platformId = platformId;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public int getChildrenCount() {
+        return childrenCount;
+    }
+
+    public void setChildrenCount(int childrenCount) {
+        this.childrenCount = childrenCount;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public void setTypeForCatalog() {
+        this.type = 0;
+    }
+
+    public void setTypeForGb() {
+        this.type = 1;
+    }
+
+    public void setTypeForStream() {
+        this.type = 2;
+    }
+
+}

+ 8 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java

@@ -4,6 +4,7 @@ public class PlatformGbStream {
     private String app;
     private String app;
     private String stream;
     private String stream;
     private String platformId;
     private String platformId;
+    private String catalogId;
 
 
     public String getApp() {
     public String getApp() {
         return app;
         return app;
@@ -29,4 +30,11 @@ public class PlatformGbStream {
         this.platformId = platformId;
         this.platformId = platformId;
     }
     }
 
 
+    public String getCatalogId() {
+        return catalogId;
+    }
+
+    public void setCatalogId(String catalogId) {
+        this.catalogId = catalogId;
+    }
 }
 }

+ 8 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.event;
 package com.genersoft.iot.vmp.gb28181.event;
 
 
+import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -91,6 +92,13 @@ public class SipSubscribe {
                 this.statusCode = -1024;
                 this.statusCode = -1024;
                 this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
                 this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
                 this.dialog = dialogTerminatedEvent.getDialog();
                 this.dialog = dialogTerminatedEvent.getDialog();
+            }else if (event instanceof DeviceNotFoundEvent) {
+                DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event;
+                this.type = "deviceNotFoundEvent";
+                this.msg = "设备未找到";
+                this.statusCode = -1024;
+                this.callId = deviceNotFoundEvent.getDialog().getCallId().getCallId();
+                this.dialog = deviceNotFoundEvent.getDialog();
             }
             }
         }
         }
     }
     }

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java

@@ -94,7 +94,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
         logger.debug(responseEvent.getResponse().toString());
         logger.debug(responseEvent.getResponse().toString());
         int status = response.getStatusCode();
         int status = response.getStatusCode();
         if (((status >= 200) && (status < 300)) || status == 401) { // Success!
         if (((status >= 200) && (status < 300)) || status == 401) { // Success!
-//            ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
             CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
             CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
             String method = cseqHeader.getMethod();
             String method = cseqHeader.getMethod();
             ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
             ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
@@ -108,6 +107,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
                     if (subscribe != null) {
                     if (subscribe != null) {
                         SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
                         SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
                         subscribe.response(eventResult);
                         subscribe.response(eventResult);
+                        sipSubscribe.removeOkSubscribe(callIdHeader.getCallId());
                     }
                     }
                 }
                 }
             }
             }
@@ -122,6 +122,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
                     if (subscribe != null) {
                     if (subscribe != null) {
                         SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
                         SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
                         subscribe.response(eventResult);
                         subscribe.response(eventResult);
+                        sipSubscribe.removeErrorSubscribe(callIdHeader.getCallId());
                     }
                     }
                 }
                 }
             }
             }

+ 5 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java

@@ -107,6 +107,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
 				// 查询平台下是否有该通道
 				// 查询平台下是否有该通道
 				DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
 				DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
 				List<GbStream> gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId);
 				List<GbStream> gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId);
+				PlatformCatalog catalog = storager.getCatalog(channelId);
 				GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null;
 				GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null;
 				MediaServerItem mediaServerItem = null;
 				MediaServerItem mediaServerItem = null;
 				// 不是通道可能是直播流
 				// 不是通道可能是直播流
@@ -132,7 +133,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
 						return;
 						return;
 					}
 					}
 					responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
 					responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
-				}else {
+				}else if (catalog != null) {
+					responseAck(evt, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播
+					return;
+				} else {
 					logger.info("通道不存在,返回404");
 					logger.info("通道不存在,返回404");
 					responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
 					responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
 					return;
 					return;

+ 13 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java

@@ -1,7 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
 
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -19,6 +21,7 @@ import org.springframework.stereotype.Component;
 import javax.sip.InvalidArgumentException;
 import javax.sip.InvalidArgumentException;
 import javax.sip.RequestEvent;
 import javax.sip.RequestEvent;
 import javax.sip.SipException;
 import javax.sip.SipException;
+import javax.sip.header.CallIdHeader;
 import javax.sip.message.Response;
 import javax.sip.message.Response;
 import java.text.ParseException;
 import java.text.ParseException;
 import java.util.Map;
 import java.util.Map;
@@ -39,6 +42,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
     @Autowired
     @Autowired
     private IVideoManagerStorager storage;
     private IVideoManagerStorager storage;
 
 
+    @Autowired
+    private SipSubscribe sipSubscribe;
+
     @Autowired
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
     private IRedisCatchStorage redisCatchStorage;
 
 
@@ -56,6 +62,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
     public void process(RequestEvent evt) {
     public void process(RequestEvent evt) {
         logger.debug("接收到消息:" + evt.getRequest());
         logger.debug("接收到消息:" + evt.getRequest());
         String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
         String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
+        CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
         // 查询设备是否存在
         // 查询设备是否存在
         Device device = redisCatchStorage.getDevice(deviceId);
         Device device = redisCatchStorage.getDevice(deviceId);
         // 查询上级平台是否存在
         // 查询上级平台是否存在
@@ -63,7 +70,12 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
         try {
         try {
             if (device == null && parentPlatform == null) {
             if (device == null && parentPlatform == null) {
                 // 不存在则回复404
                 // 不存在则回复404
-                responseAck(evt, Response.NOT_FOUND, "device id not found");
+                responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
+                logger.warn("[设备未找到 ]: {}", deviceId);
+                if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
+                    SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog()));
+                    sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
+                };
             }else {
             }else {
                 Element rootElement = getRootElement(evt);
                 Element rootElement = getRootElement(evt);
                 String name = rootElement.getName();
                 String name = rootElement.getName();

+ 36 - 7
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java

@@ -1,10 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
 
 
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.SipConfig;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.GbStream;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@@ -71,11 +68,41 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
             // 查询关联的直播通道
             // 查询关联的直播通道
             List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
             List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
             int size = channelReduces.size() + gbStreams.size();
             int size = channelReduces.size() + gbStreams.size();
+            // 回复目录信息
+            List<PlatformCatalog> catalogs =  storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
+            if (catalogs.size() > 0) {
+                for (PlatformCatalog catalog : catalogs) {
+                    DeviceChannel deviceChannel = new DeviceChannel();
+                    deviceChannel.setChannelId(catalog.getId());
+                    deviceChannel.setName(catalog.getName());
+                    deviceChannel.setLongitude(0.0);
+                    deviceChannel.setLatitude(0.0);
+                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
+                    deviceChannel.setManufacture("wvp-pro");
+                    deviceChannel.setStatus(1);
+                    deviceChannel.setParental(1);
+                    deviceChannel.setParentId(catalog.getParentId());
+                    deviceChannel.setRegisterWay(1);
+                    deviceChannel.setCivilCode(config.getDomain());
+                    deviceChannel.setModel("live");
+                    deviceChannel.setOwner("wvp-pro");
+                    deviceChannel.setSecrecy("0");
+                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
+                    // 防止发送过快
+                    Thread.sleep(10);
+                }
+            }
             // 回复级联的通道
             // 回复级联的通道
             if (channelReduces.size() > 0) {
             if (channelReduces.size() > 0) {
                 for (ChannelReduce channelReduce : channelReduces) {
                 for (ChannelReduce channelReduce : channelReduces) {
                     DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
                     DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
+                    // TODO 目前暂时认为这里只用通道没有目录
+                    deviceChannel.setParental(0);
+                    deviceChannel.setParentId(channelReduce.getCatalogId());
+
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
+                    // 防止发送过快
+                    Thread.sleep(10);
                 }
                 }
             }
             }
             // 回复直播的通道
             // 回复直播的通道
@@ -89,16 +116,16 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setManufacture("wvp-pro");
                     deviceChannel.setManufacture("wvp-pro");
                     deviceChannel.setStatus(gbStream.isStatus()?1:0);
                     deviceChannel.setStatus(gbStream.isStatus()?1:0);
-    //							deviceChannel.setParentId(parentPlatform.getDeviceGBId());
+    				deviceChannel.setParentId(gbStream.getCatalogId());
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setCivilCode(config.getDomain());
                     deviceChannel.setCivilCode(config.getDomain());
                     deviceChannel.setModel("live");
                     deviceChannel.setModel("live");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setParental(0);
                     deviceChannel.setParental(0);
                     deviceChannel.setSecrecy("0");
                     deviceChannel.setSecrecy("0");
-                    deviceChannel.setSecrecy("0");
-
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
+                    // 防止发送过快
+                    Thread.sleep(10);
                 }
                 }
             }
             }
             if (size == 0) {
             if (size == 0) {
@@ -111,6 +138,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
             e.printStackTrace();
             e.printStackTrace();
         } catch (ParseException e) {
         } catch (ParseException e) {
             e.printStackTrace();
             e.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
         }
 
 
     }
     }

+ 34 - 7
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java

@@ -1,10 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
 
 
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.SipConfig;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.GbStream;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@@ -73,12 +70,41 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
             List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
             List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
             // 查询关联的直播通道
             // 查询关联的直播通道
             List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
             List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
-            int size = channelReduces.size() + gbStreams.size();
+            // 回复目录信息
+            List<PlatformCatalog> catalogs =  storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
+            int size = catalogs.size() + channelReduces.size() + gbStreams.size();
+            if (catalogs.size() > 0) {
+                for (PlatformCatalog catalog : catalogs) {
+                    DeviceChannel deviceChannel = new DeviceChannel();
+                    deviceChannel.setChannelId(catalog.getId());
+                    deviceChannel.setName(catalog.getName());
+                    deviceChannel.setLongitude(0.0);
+                    deviceChannel.setLatitude(0.0);
+                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
+                    deviceChannel.setManufacture("wvp-pro");
+                    deviceChannel.setStatus(1);
+                    deviceChannel.setParental(1);
+                    deviceChannel.setParentId(catalog.getParentId());
+                    deviceChannel.setRegisterWay(1);
+                    deviceChannel.setCivilCode(config.getDomain());
+                    deviceChannel.setModel("live");
+                    deviceChannel.setOwner("wvp-pro");
+                    deviceChannel.setSecrecy("0");
+                    cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
+                    // 防止发送过快
+                    Thread.sleep(10);
+                }
+            }
             // 回复级联的通道
             // 回复级联的通道
             if (channelReduces.size() > 0) {
             if (channelReduces.size() > 0) {
                 for (ChannelReduce channelReduce : channelReduces) {
                 for (ChannelReduce channelReduce : channelReduces) {
                     DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
                     DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
+                    // TODO 目前暂时认为这里只用通道没有目录
+                    deviceChannel.setParental(0);
+                    deviceChannel.setParentId(channelReduce.getCatalogId());
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
+                    // 防止发送过快
+                    Thread.sleep(10);
                 }
                 }
             }
             }
             // 回复直播的通道
             // 回复直播的通道
@@ -92,14 +118,13 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                     deviceChannel.setManufacture("wvp-pro");
                     deviceChannel.setManufacture("wvp-pro");
                     deviceChannel.setStatus(gbStream.isStatus()?1:0);
                     deviceChannel.setStatus(gbStream.isStatus()?1:0);
-    //							deviceChannel.setParentId(parentPlatform.getDeviceGBId());
+                    deviceChannel.setParentId(gbStream.getCatalogId());
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setRegisterWay(1);
                     deviceChannel.setCivilCode(config.getDomain());
                     deviceChannel.setCivilCode(config.getDomain());
                     deviceChannel.setModel("live");
                     deviceChannel.setModel("live");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setOwner("wvp-pro");
                     deviceChannel.setParental(0);
                     deviceChannel.setParental(0);
                     deviceChannel.setSecrecy("0");
                     deviceChannel.setSecrecy("0");
-                    deviceChannel.setSecrecy("0");
 
 
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
                     cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
                 }
                 }
@@ -114,6 +139,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
             e.printStackTrace();
             e.printStackTrace();
         } catch (ParseException e) {
         } catch (ParseException e) {
             e.printStackTrace();
             e.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
         }
         }
 
 
     }
     }

+ 2 - 5
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@@ -4,7 +4,6 @@ import java.util.List;
 import java.util.UUID;
 import java.util.UUID;
 
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.conf.MediaConfig;
 import com.genersoft.iot.vmp.conf.UserSetup;
 import com.genersoft.iot.vmp.conf.UserSetup;
@@ -302,7 +301,7 @@ public class ZLMHttpHookListener {
 	@ResponseBody
 	@ResponseBody
 	@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
 	@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
 	public ResponseEntity<String> onStreamChanged(@RequestBody MediaItem item){
 	public ResponseEntity<String> onStreamChanged(@RequestBody MediaItem item){
-		
+
 		if (logger.isDebugEnabled()) {
 		if (logger.isDebugEnabled()) {
 			logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item));
 			logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item));
 		}
 		}
@@ -322,10 +321,8 @@ public class ZLMHttpHookListener {
 		String schema = item.getSchema();
 		String schema = item.getSchema();
 		List<MediaItem.MediaTrack> tracks = item.getTracks();
 		List<MediaItem.MediaTrack> tracks = item.getTracks();
 		boolean regist = item.isRegist();
 		boolean regist = item.isRegist();
-		if (tracks != null) {
-			logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema);
-		}
 		if ("rtmp".equals(schema)){
 		if ("rtmp".equals(schema)){
+			logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, streamId);
 			if (regist) {
 			if (regist) {
 				mediaServerService.addCount(mediaServerId);
 				mediaServerService.addCount(mediaServerId);
 			}else {
 			}else {

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java

@@ -30,7 +30,7 @@ public interface IGbStreamService {
      * 保存国标关联
      * 保存国标关联
      * @param gbStreams
      * @param gbStreams
      */
      */
-    boolean addPlatformInfo(List<GbStream> gbStreams, String platformId);
+    boolean addPlatformInfo(List<GbStream> gbStreams, String platformId, String catalogId);
 
 
     /**
     /**
      * 移除国标关联
      * 移除国标关联

+ 3 - 1
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java

@@ -47,13 +47,15 @@ public class GbStreamServiceImpl implements IGbStreamService {
 
 
 
 
     @Override
     @Override
-    public boolean addPlatformInfo(List<GbStream> gbStreams, String platformId) {
+    public boolean addPlatformInfo(List<GbStream> gbStreams, String platformId, String catalogId) {
         // 放在事务内执行
         // 放在事务内执行
         boolean result = false;
         boolean result = false;
         TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
         TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
         try {
         try {
             for (GbStream gbStream : gbStreams) {
             for (GbStream gbStream : gbStreams) {
+                gbStream.setCatalogId(catalogId);
                 gbStream.setPlatformId(platformId);
                 gbStream.setPlatformId(platformId);
+                // TODO 修改为批量提交
                 platformGbStreamMapper.add(gbStream);
                 platformGbStreamMapper.add(gbStream);
             }
             }
             dataSourceTransactionManager.commit(transactionStatus);     //手动提交
             dataSourceTransactionManager.commit(transactionStatus);     //手动提交

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java

@@ -130,7 +130,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
         if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) {
         if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) {
             List<GbStream> gbStreams = new ArrayList<>();
             List<GbStream> gbStreams = new ArrayList<>();
             gbStreams.add(param);
             gbStreams.add(param);
-            if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){
+            if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId(), param.getCatalogId())){
                 result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]成功");
                 result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]成功");
             }else {
             }else {
                 result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]失败");
                 result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]失败");
@@ -141,6 +141,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
         if (parentPlatforms.size() > 0) {
         if (parentPlatforms.size() > 0) {
             for (ParentPlatform parentPlatform : parentPlatforms) {
             for (ParentPlatform parentPlatform : parentPlatforms) {
                 param.setPlatformId(parentPlatform.getServerGBId());
                 param.setPlatformId(parentPlatform.getServerGBId());
+                param.setCatalogId(parentPlatform.getCatalogId());
                 String stream = param.getStream();
                 String stream = param.getStream();
                 StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId());
                 StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId());
                 if (streamProxyItems == null) {
                 if (streamProxyItems == null) {

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java

@@ -119,6 +119,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
         List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
         List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
         if (parentPlatforms.size() > 0) {
         if (parentPlatforms.size() > 0) {
             for (ParentPlatform parentPlatform : parentPlatforms) {
             for (ParentPlatform parentPlatform : parentPlatforms) {
+                stream.setCatalogId(parentPlatform.getCatalogId());
                 stream.setPlatformId(parentPlatform.getServerGBId());
                 stream.setPlatformId(parentPlatform.getServerGBId());
                 String streamId = stream.getStream();
                 String streamId = stream.getStream();
                 StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());
                 StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java

@@ -185,6 +185,8 @@ public interface IRedisCatchStorage {
      */
      */
     void updateDevice(Device device);
     void updateDevice(Device device);
 
 
+    void removeDevice(String deviceId);
+
     /**
     /**
      * 获取Device
      * 获取Device
      */
      */

+ 26 - 1
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@@ -243,7 +243,7 @@ public interface IVideoManagerStorager {
 	 * @param channelReduces
 	 * @param channelReduces
 	 * @return
 	 * @return
 	 */
 	 */
-	int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces);
+	int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId);
 
 
 	/**
 	/**
 	 *  移除上级平台的通道信息
 	 *  移除上级平台的通道信息
@@ -256,6 +256,9 @@ public interface IVideoManagerStorager {
 
 
     DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
     DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
 
 
+    List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
+    List<PlatformCatalog> queryStreamInParentPlatformAndCatalog(String platformId, String catalogId);
+
     Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
     Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
 
 
 
 
@@ -431,4 +434,26 @@ public interface IVideoManagerStorager {
 	 * @param deviceChannelList
 	 * @param deviceChannelList
 	 */
 	 */
 	boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList);
 	boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList);
+
+	/**
+	 * 获取目录信息
+	 * @param platformId
+	 * @param parentId
+	 * @return
+	 */
+    List<PlatformCatalog> getChildrenCatalogByPlatform(String platformId, String parentId);
+
+	int addCatalog(PlatformCatalog platformCatalog);
+
+	PlatformCatalog getCatalog(String id);
+
+	int delCatalog(String id);
+
+	int updateCatalog(PlatformCatalog platformCatalog);
+
+	int setDefaultCatalog(String platformId, String catalogId);
+
+	List<PlatformCatalog> queryCatalogInPlatform(String serverGBId);
+
+    int delRelation(PlatformCatalog platformCatalog);
 }
 }

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java

@@ -91,7 +91,8 @@ public interface DeviceChannelMapper {
             "SELECT * FROM ( "+
             "SELECT * FROM ( "+
                 " SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " +
                 " SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " +
                 "(SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount, " +
                 "(SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount, " +
-                "(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId " +
+                "(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId, " +
+                "(SELECT pc.catalogId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as catalogId " +
                 "FROM device_channel dc " +
                 "FROM device_channel dc " +
                 "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
                 "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
                 " WHERE 1=1 " +
                 " WHERE 1=1 " +

+ 3 - 9
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java

@@ -35,7 +35,7 @@ public interface GbStreamMapper {
     @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
     @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
     int del(String app, String stream);
     int del(String app, String stream);
 
 
-    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN  platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream")
+    @Select("SELECT gs.*, pgs.platformId AS platformId, pgs.catalogId AS catalogId  FROM gb_stream gs LEFT JOIN  platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream")
     List<GbStream> selectAll();
     List<GbStream> selectAll();
 
 
     @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
     @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
@@ -44,12 +44,12 @@ public interface GbStreamMapper {
     @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
     @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
     List<GbStream> selectByGBId(String gbId);
     List<GbStream> selectByGBId(String gbId);
 
 
-    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
+    @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
             "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
             "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
             "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
             "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
     List<GbStream> queryStreamInPlatform(String platformId, String gbId);
     List<GbStream> queryStreamInPlatform(String platformId, String gbId);
 
 
-    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " +
+    @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
             "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
             "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " +
             "WHERE pgs.platformId = '${platformId}'")
             "WHERE pgs.platformId = '${platformId}'")
     List<GbStream> queryGbStreamListInPlatform(String platformId);
     List<GbStream> queryGbStreamListInPlatform(String platformId);
@@ -59,17 +59,11 @@ public interface GbStreamMapper {
             "WHERE app=#{app} AND stream=#{stream}")
             "WHERE app=#{app} AND stream=#{stream}")
     int setStatus(String app, String stream, boolean status);
     int setStatus(String app, String stream, boolean status);
 
 
-    @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN  platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream WHERE mediaServerId=#{mediaServerId} ")
-    List<GbStream> selectAllByMediaServerId(String mediaServerId);
-
     @Update("UPDATE gb_stream " +
     @Update("UPDATE gb_stream " +
             "SET status=${status} " +
             "SET status=${status} " +
             "WHERE mediaServerId=#{mediaServerId} ")
             "WHERE mediaServerId=#{mediaServerId} ")
     void updateStatusByMediaServerId(String mediaServerId, boolean status);
     void updateStatusByMediaServerId(String mediaServerId, boolean status);
 
 
-    @Select("SELECT * FROM gb_stream WHERE mediaServerId=#{mediaServerId}")
-    void delByMediaServerId(String mediaServerId);
-
     @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}")
     @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}")
     void deleteWithoutGBId(String type, String mediaServerId);
     void deleteWithoutGBId(String type, String mediaServerId);
 
 

+ 11 - 3
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java

@@ -15,10 +15,10 @@ public interface ParentPlatformMapper {
 
 
     @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
     @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
             "            devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
             "            devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
-            "            status, shareAllLiveStream) " +
+            "            status, shareAllLiveStream, catalogId) " +
             "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
             "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
             "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
             "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
-            "            ${status}, ${shareAllLiveStream})")
+            "            ${status}, ${shareAllLiveStream}, #{catalogId})")
     int addParentPlatform(ParentPlatform parentPlatform);
     int addParentPlatform(ParentPlatform parentPlatform);
 
 
     @Update("UPDATE parent_platform " +
     @Update("UPDATE parent_platform " +
@@ -40,7 +40,8 @@ public interface ParentPlatformMapper {
             "ptz=#{ptz}, " +
             "ptz=#{ptz}, " +
             "rtcp=#{rtcp}, " +
             "rtcp=#{rtcp}, " +
             "status=#{status}, " +
             "status=#{status}, " +
-            "shareAllLiveStream=#{shareAllLiveStream} " +
+            "shareAllLiveStream=#{shareAllLiveStream}, " +
+            "catalogId=#{catalogId} " +
             "WHERE id=#{id}")
             "WHERE id=#{id}")
     int updateParentPlatform(ParentPlatform parentPlatform);
     int updateParentPlatform(ParentPlatform parentPlatform);
 
 
@@ -74,4 +75,11 @@ public interface ParentPlatformMapper {
 
 
     @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
     @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
     List<ParentPlatform> selectAllAhareAllLiveStream();
     List<ParentPlatform> selectAllAhareAllLiveStream();
+
+    @Update(value = {" <script>" +
+            "UPDATE parent_platform " +
+            "SET catalogId=#{catalogId}" +
+            "WHERE serverGBId=#{platformId}"+
+            "</script>"})
+    int setDefaultCatalog(String platformId, String catalogId);
 }
 }

+ 42 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java

@@ -0,0 +1,42 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
+import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+
+@Mapper
+@Repository
+public interface PlatformCatalogMapper {
+
+    @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId) VALUES" +
+            "(#{id}, #{name}, #{platformId}, #{parentId})")
+    int add(PlatformCatalog platformCatalog);
+
+    @Delete("DELETE FROM platform_catalog WHERE id=#{id}")
+    int del(String id);
+
+    @Delete("DELETE FROM platform_catalog WHERE platformId=#{platformId}")
+    int delByPlatformId(String platformId);
+
+    @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id AND platformId=#{platformId}) as childrenCount FROM platform_catalog pc WHERE parentId=#{parentId} AND platformId=#{platformId}")
+    List<PlatformCatalog> selectByParentId(String platformId, String parentId);
+
+    @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount  FROM platform_catalog pc WHERE pc.id=#{id}")
+    PlatformCatalog select(String id);
+
+    @Update(value = {" <script>" +
+            "UPDATE platform_catalog " +
+            "SET name=#{name}" +
+            "WHERE id=#{id}"+
+            "</script>"})
+    int update(PlatformCatalog platformCatalog);
+
+    @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount  FROM platform_catalog pc WHERE pc.platformId=#{platformId}")
+    List<PlatformCatalog> selectByPlatForm(String platformId);
+}

+ 19 - 2
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.storager.dao;
 
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import org.apache.ibatis.annotations.Delete;
 import org.apache.ibatis.annotations.Delete;
 import org.apache.ibatis.annotations.Insert;
 import org.apache.ibatis.annotations.Insert;
@@ -25,9 +26,9 @@ public interface PlatformChannelMapper {
     List<String> findChannelRelatedPlatform(String platformId, List<String> deviceAndChannelIds);
     List<String> findChannelRelatedPlatform(String platformId, List<String> deviceAndChannelIds);
 
 
     @Insert("<script> "+
     @Insert("<script> "+
-            "INSERT INTO platform_gb_channel (channelId, deviceId, platformId, deviceAndChannelId) VALUES" +
+            "INSERT INTO platform_gb_channel (channelId, deviceId, platformId, deviceAndChannelId, catalogId) VALUES" +
             "<foreach collection='channelReducesToAdd'  item='item' separator=','>" +
             "<foreach collection='channelReducesToAdd'  item='item' separator=','>" +
-            " ('${item.channelId}','${item.deviceId}', '${platformId}', '${item.deviceId}_${item.channelId}' )" +
+            " ('${item.channelId}','${item.deviceId}', '${platformId}', '${item.deviceId}_${item.channelId}' , '${item.catalogId}' )" +
             "</foreach>" +
             "</foreach>" +
             "</script>")
             "</script>")
     int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd);
     int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd);
@@ -54,6 +55,22 @@ public interface PlatformChannelMapper {
             "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'")
             "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'")
     DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
     DeviceChannel queryChannelInParentPlatform(String platformId, String channelId);
 
 
+
+    @Select("select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " +
+            "from device_channel dc left join platform_gb_channel pgc on dc.deviceId = pgc.deviceId and dc.channelId = pgc.channelId " +
+            "where pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}")
+    List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
+
     @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')")
     @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')")
     Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
     Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
+
+    @Delete("<script> "+
+            "DELETE FROM platform_gb_channel WHERE catalogId=#{id}"  +
+            "</script>")
+    int delByCatalogId(String id);
+
+    @Delete("<script> "+
+           "DELETE FROM platform_gb_channel WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}"  +
+           "</script>")
+    int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog);
 }
 }

+ 22 - 2
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java

@@ -1,5 +1,7 @@
 package com.genersoft.iot.vmp.storager.dao;
 package com.genersoft.iot.vmp.storager.dao;
 
 
+import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
 import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
 import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import org.apache.ibatis.annotations.*;
 import org.apache.ibatis.annotations.*;
@@ -12,8 +14,8 @@ import java.util.List;
 @Repository
 @Repository
 public interface PlatformGbStreamMapper {
 public interface PlatformGbStreamMapper {
 
 
-    @Insert("INSERT INTO platform_gb_stream (app, stream, platformId) VALUES" +
-            "('${app}', '${stream}', '${platformId}')")
+    @Insert("INSERT INTO platform_gb_stream (app, stream, platformId, catalogId) VALUES" +
+            "('${app}', '${stream}', '${platformId}', '${catalogId}')")
     int add(PlatformGbStream platformGbStream);
     int add(PlatformGbStream platformGbStream);
 
 
     @Delete("DELETE FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}")
     @Delete("DELETE FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}")
@@ -27,4 +29,22 @@ public interface PlatformGbStreamMapper {
 
 
     @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}")
     @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}")
     StreamProxyItem selectOne(String app, String stream, String serverGBId);
     StreamProxyItem selectOne(String app, String stream, String serverGBId);
+
+    @Select("select gs.* \n" +
+            "from gb_stream gs\n" +
+            "    left join platform_gb_stream pgs\n" +
+            "        on gs.app = pgs.app and gs.stream = pgs.stream\n" +
+            "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
+    List<GbStream> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
+
+    @Select("select gs.gbId as id, gs.name as name, pgs.platformId as platformId, pgs.catalogId as catalogId , 0 as childrenCount, 2 as type\n" +
+            "from gb_stream gs\n" +
+            "    left join platform_gb_stream pgs\n" +
+            "        on gs.app = pgs.app and gs.stream = pgs.stream\n" +
+            "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
+    List<PlatformCatalog> queryChannelInParentPlatformAndCatalogForCatlog(String platformId, String catalogId);
+
+    @Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}")
+    int delByCatalogId(String id);
+
 }
 }

+ 6 - 0
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java

@@ -406,6 +406,12 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
         redis.set(key, device);
         redis.set(key, device);
     }
     }
 
 
+    @Override
+    public void removeDevice(String deviceId) {
+        String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId;
+        redis.del(key);
+    }
+
     @Override
     @Override
     public Device getDevice(String deviceId) {
     public Device getDevice(String deviceId) {
         String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId;
         String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId;

+ 93 - 2
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java

@@ -71,6 +71,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 
 
 	@Autowired
 	@Autowired
     private GbStreamMapper gbStreamMapper;
     private GbStreamMapper gbStreamMapper;
+
+	@Autowired
+    private PlatformCatalogMapper catalogMapper;
 ;
 ;
 
 
 	@Autowired
 	@Autowired
@@ -449,6 +452,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 
 
 	@Override
 	@Override
 	public boolean addParentPlatform(ParentPlatform parentPlatform) {
 	public boolean addParentPlatform(ParentPlatform parentPlatform) {
+		if (parentPlatform.getCatalogId() == null) {
+			parentPlatform.setCatalogId(parentPlatform.getServerGBId());
+		}
 		int result = platformMapper.addParentPlatform(parentPlatform);
 		int result = platformMapper.addParentPlatform(parentPlatform);
 		return result > 0;
 		return result > 0;
 	}
 	}
@@ -458,6 +464,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 		int result = 0;
 		int result = 0;
 		ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId());
 		ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId());
 		if (parentPlatform.getId() == null ) {
 		if (parentPlatform.getId() == null ) {
+			if (parentPlatform.getCatalogId() == null) {
+				parentPlatform.setCatalogId(parentPlatform.getServerGBId());
+			}
 			result = platformMapper.addParentPlatform(parentPlatform);
 			result = platformMapper.addParentPlatform(parentPlatform);
 			if (parentPlatformCatch == null) {
 			if (parentPlatformCatch == null) {
 				parentPlatformCatch = new ParentPlatformCatch();
 				parentPlatformCatch = new ParentPlatformCatch();
@@ -480,8 +489,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 		// 共享所有视频流,需要将现有视频流添加到此平台
 		// 共享所有视频流,需要将现有视频流添加到此平台
 		List<GbStream> gbStreams = gbStreamMapper.selectAll();
 		List<GbStream> gbStreams = gbStreamMapper.selectAll();
 		if (gbStreams.size() > 0) {
 		if (gbStreams.size() > 0) {
+			for (GbStream gbStream : gbStreams) {
+				gbStream.setCatalogId(parentPlatform.getCatalogId());
+			}
 			if (parentPlatform.isShareAllLiveStream()) {
 			if (parentPlatform.isShareAllLiveStream()) {
-				gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId());
+				gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId());
 			}else {
 			}else {
 				gbStreamService.delPlatformInfo(gbStreams);
 				gbStreamService.delPlatformInfo(gbStreams);
 			}
 			}
@@ -536,10 +548,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 	}
 	}
 
 
 	@Override
 	@Override
-	public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces) {
+	public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) {
 
 
 		Map<String, ChannelReduce> deviceAndChannels = new HashMap<>();
 		Map<String, ChannelReduce> deviceAndChannels = new HashMap<>();
 		for (ChannelReduce channelReduce : channelReduces) {
 		for (ChannelReduce channelReduce : channelReduces) {
+			channelReduce.setCatalogId(catalogId);
 			deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce);
 			deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce);
 		}
 		}
 		List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
 		List<String> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
@@ -576,6 +589,18 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 		return channel;
 		return channel;
 	}
 	}
 
 
+	@Override
+	public List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId) {
+		List<PlatformCatalog> catalogs = platformChannelMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId);
+		return catalogs;
+	}
+
+	@Override
+	public List<PlatformCatalog> queryStreamInParentPlatformAndCatalog(String platformId, String catalogId) {
+		List<PlatformCatalog> catalogs = platformGbStreamMapper.queryChannelInParentPlatformAndCatalogForCatlog(platformId, catalogId);
+		return catalogs;
+	}
+
 	@Override
 	@Override
 	public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
 	public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) {
 		Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
 		Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId);
@@ -739,6 +764,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 			List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
 			List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
 			if (parentPlatforms.size() > 0) {
 			if (parentPlatforms.size() > 0) {
 				for (ParentPlatform parentPlatform : parentPlatforms) {
 				for (ParentPlatform parentPlatform : parentPlatforms) {
+					streamPushItem.setCatalogId(parentPlatform.getCatalogId());
 					streamPushItem.setPlatformId(parentPlatform.getServerGBId());
 					streamPushItem.setPlatformId(parentPlatform.getServerGBId());
 					String stream = streamPushItem.getStream();
 					String stream = streamPushItem.getStream();
 					StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId());
 					StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId());
@@ -804,4 +830,69 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 		return streamProxyMapper.selectOne(app, streamId);
 		return streamProxyMapper.selectOne(app, streamId);
 	}
 	}
 
 
+	@Override
+	public List<PlatformCatalog> getChildrenCatalogByPlatform(String platformId, String parentId) {
+		return catalogMapper.selectByParentId(platformId, parentId);
+	}
+
+	@Override
+	public int addCatalog(PlatformCatalog platformCatalog) {
+		return catalogMapper.add(platformCatalog);
+	}
+
+	@Override
+	public PlatformCatalog getCatalog(String id) {
+		return catalogMapper.select(id);
+	}
+
+	@Override
+	public int delCatalog(String id) {
+		PlatformCatalog platformCatalog = catalogMapper.select(id);
+		if (platformCatalog.getChildrenCount() > 0) {
+			List<PlatformCatalog> platformCatalogList = catalogMapper.selectByParentId(platformCatalog.getPlatformId(), platformCatalog.getId());
+			for (PlatformCatalog catalog : platformCatalogList) {
+				if (catalog.getChildrenCount() == 0) {
+					catalogMapper.del(catalog.getId());
+					platformGbStreamMapper.delByCatalogId(catalog.getId());
+					platformChannelMapper.delByCatalogId(catalog.getId());
+				}else {
+					delCatalog(catalog.getId());
+				}
+			}
+		}
+		int delresult =  catalogMapper.del(id);
+		int delStreamresult = platformGbStreamMapper.delByCatalogId(id);
+		int delChanneresult = platformChannelMapper.delByCatalogId(id);
+		return delresult + delChanneresult + delStreamresult;
+	}
+
+	@Override
+	public int updateCatalog(PlatformCatalog platformCatalog) {
+		return catalogMapper.update(platformCatalog);
+	}
+
+	@Override
+	public int setDefaultCatalog(String platformId, String catalogId) {
+		return platformMapper.setDefaultCatalog(platformId, catalogId);
+	}
+
+	@Override
+	public List<PlatformCatalog> queryCatalogInPlatform(String platformId) {
+		return catalogMapper.selectByPlatForm(platformId);
+	}
+
+	@Override
+	public int delRelation(PlatformCatalog platformCatalog) {
+		if (platformCatalog.getType() == 1) {
+			return platformChannelMapper.delByCatalogIdAndChannelIdAndPlatformId(platformCatalog);
+		}else if (platformCatalog.getType() == 2) {
+			List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformCatalog.getPlatformId(), platformCatalog.getParentId());
+			for (GbStream gbStream : gbStreams) {
+				if (gbStream.getGbId().equals(platformCatalog.getId())) {
+					return platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream());
+				}
+			}
+		}
+		return 0;
+	}
 }
 }

+ 12 - 3
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java

@@ -152,12 +152,16 @@ public class DeviceQuery {
 		String uuid = UUID.randomUUID().toString();
 		String uuid = UUID.randomUUID().toString();
 		DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(15*1000L);
 		DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(15*1000L);
 		result.onTimeout(()->{
 		result.onTimeout(()->{
-			logger.warn(String.format("设备通道信息同步超时"));
+			logger.warn("设备[{}]通道信息同步超时", deviceId);
 			// 释放rtpserver
 			// 释放rtpserver
 			RequestMessage msg = new RequestMessage();
 			RequestMessage msg = new RequestMessage();
 			msg.setKey(key);
 			msg.setKey(key);
 			msg.setId(uuid);
 			msg.setId(uuid);
-			msg.setData("Timeout");
+			WVPResult<Object> wvpResult = new WVPResult<>();
+			wvpResult.setCode(-1);
+			wvpResult.setData(device);
+			wvpResult.setMsg("更新超时");
+			msg.setData(wvpResult);
 			resultHolder.invokeAllResult(msg);
 			resultHolder.invokeAllResult(msg);
 		});
 		});
 		// 等待其他相同请求返回时一起返回
 		// 等待其他相同请求返回时一起返回
@@ -168,7 +172,11 @@ public class DeviceQuery {
 			RequestMessage msg = new RequestMessage();
 			RequestMessage msg = new RequestMessage();
 			msg.setKey(key);
 			msg.setKey(key);
 			msg.setId(uuid);
 			msg.setId(uuid);
-			msg.setData(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg));
+			WVPResult<Object> wvpResult = new WVPResult<>();
+			wvpResult.setCode(-1);
+			wvpResult.setData(device);
+			wvpResult.setMsg(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg));
+			msg.setData(wvpResult);
 			resultHolder.invokeAllResult(msg);
 			resultHolder.invokeAllResult(msg);
 		});
 		});
 
 
@@ -199,6 +207,7 @@ public class DeviceQuery {
 		boolean isSuccess = storager.delete(deviceId);
 		boolean isSuccess = storager.delete(deviceId);
 		if (isSuccess) {
 		if (isSuccess) {
 			redisCatchStorage.clearCatchByDeviceId(deviceId);
 			redisCatchStorage.clearCatchByDeviceId(deviceId);
+			redisCatchStorage.removeDevice(deviceId);
 			JSONObject json = new JSONObject();
 			JSONObject json = new JSONObject();
 			json.put("deviceId", deviceId);
 			json.put("deviceId", deviceId);
 			return new ResponseEntity<>(json.toString(),HttpStatus.OK);
 			return new ResponseEntity<>(json.toString(),HttpStatus.OK);

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java

@@ -82,7 +82,7 @@ public class GbStreamController {
     @PostMapping(value = "/add")
     @PostMapping(value = "/add")
     @ResponseBody
     @ResponseBody
     public Object add(@RequestBody GbStreamParam gbStreamParam){
     public Object add(@RequestBody GbStreamParam gbStreamParam){
-        if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId())) {
+        if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId(), gbStreamParam.getCatalogId())) {
             return "success";
             return "success";
         }else {
         }else {
             return "fail";
             return "fail";

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java

@@ -8,12 +8,22 @@ public class GbStreamParam {
 
 
     private String platformId;
     private String platformId;
 
 
+    private String catalogId;
+
     private List<GbStream> gbStreams;
     private List<GbStream> gbStreams;
 
 
     public String getPlatformId() {
     public String getPlatformId() {
         return platformId;
         return platformId;
     }
     }
 
 
+    public String getCatalogId() {
+        return catalogId;
+    }
+
+    public void setCatalogId(String catalogId) {
+        this.catalogId = catalogId;
+    }
+
     public void setPlatformId(String platformId) {
     public void setPlatformId(String platformId) {
         this.platformId = platformId;
         this.platformId = platformId;
     }
     }

+ 200 - 1
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java

@@ -1,10 +1,15 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.platform;
 package com.genersoft.iot.vmp.vmanager.gb28181.platform;
 
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.gb28181.bean.CatalogData;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam;
 import com.github.pagehelper.PageInfo;
 import com.github.pagehelper.PageInfo;
@@ -21,6 +26,8 @@ import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.SipConfig;
 
 
+import java.util.List;
+
 /**
 /**
  * 级联平台管理
  * 级联平台管理
  */
  */
@@ -253,7 +260,7 @@ public class PlatformController {
         if (logger.isDebugEnabled()) {
         if (logger.isDebugEnabled()) {
             logger.debug("给上级平台添加国标通道API调用");
             logger.debug("给上级平台添加国标通道API调用");
         }
         }
-        int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces());
+        int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
 
 
         return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
         return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
     }
     }
@@ -279,5 +286,197 @@ public class PlatformController {
         return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
         return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
     }
     }
 
 
+    /**
+     * 获取目录
+     * @param platformId 平台ID
+     * @param parentId 目录父ID
+     * @return
+     */
+    @ApiOperation("获取目录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "platformId", value = "平台ID", dataTypeClass = String.class, required = true),
+            @ApiImplicitParam(name = "parentId", value = "目录父ID", dataTypeClass = String.class, required = true),
+    })
+    @GetMapping("/catalog")
+    @ResponseBody
+    public ResponseEntity<WVPResult<List<PlatformCatalog>>> getCatalogByPlatform(String platformId, String parentId){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId);
+        }
+        List<PlatformCatalog> platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId);
+        // 查询下属的国标通道
+        List<PlatformCatalog> catalogsForChannel = storager.queryChannelInParentPlatformAndCatalog(platformId, parentId);
+        List<PlatformCatalog> catalogsForStream = storager.queryStreamInParentPlatformAndCatalog(platformId, parentId);
+        platformCatalogList.addAll(catalogsForChannel);
+        platformCatalogList.addAll(catalogsForStream);
+        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
+        result.setCode(0);
+        result.setMsg("success");
+        result.setData(platformCatalogList);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    /**
+     * 添加目录
+     * @param platformCatalog 目录
+     * @return
+     */
+    @ApiOperation("添加目录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true),
+    })
+    @PostMapping("/catalog/add")
+    @ResponseBody
+    public ResponseEntity<WVPResult<List<PlatformCatalog>>> addCatalog(@RequestBody PlatformCatalog platformCatalog){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("添加目录,{}", JSON.toJSONString(platformCatalog));
+        }
+        PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
+        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
+
+
+        if (platformCatalogInStore != null) {
+            result.setCode(-1);
+            result.setMsg( platformCatalog.getId() + " already exists");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+        int addResult = storager.addCatalog(platformCatalog);
+        if (addResult > 0) {
+            result.setCode(0);
+            result.setMsg("success");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }else {
+            result.setCode(-500);
+            result.setMsg("save error");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+    }
+
+    /**
+     * 编辑目录
+     * @param platformCatalog 目录
+     * @return
+     */
+    @ApiOperation("编辑目录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true),
+    })
+    @PostMapping("/catalog/edit")
+    @ResponseBody
+    public ResponseEntity<WVPResult<List<PlatformCatalog>>> editCatalog(@RequestBody PlatformCatalog platformCatalog){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("编辑目录,{}", JSON.toJSONString(platformCatalog));
+        }
+        PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
+        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
+        result.setCode(0);
+
+        if (platformCatalogInStore == null) {
+            result.setMsg( platformCatalog.getId() + " not exists");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+        int addResult = storager.updateCatalog(platformCatalog);
+        if (addResult > 0) {
+            result.setMsg("success");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }else {
+            result.setMsg("save error");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+    }
+
+    /**
+     * 删除目录
+     * @param id 目录Id
+     * @return
+     */
+    @ApiOperation("删除目录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "目录Id", dataTypeClass = String.class, required = true),
+    })
+    @DeleteMapping("/catalog/del")
+    @ResponseBody
+    public ResponseEntity<WVPResult<List<PlatformCatalog>>> delCatalog(String id){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("删除目录,{}", id);
+        }
+        int delResult = storager.delCatalog(id);
+        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
+        result.setCode(0);
+
+        if (delResult > 0) {
+            result.setMsg("success");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }else {
+            result.setMsg("save error");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+    }
+
+    /**
+     * 删除关联
+     * @param platformCatalog 关联的信息
+     * @return
+     */
+    @ApiOperation("删除关联")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "platformCatalog", value = "关联的信息", dataTypeClass = PlatformCatalog.class, required = true),
+    })
+    @DeleteMapping("/catalog/relation/del")
+    @ResponseBody
+    public ResponseEntity<WVPResult<List<PlatformCatalog>>> delRelation(@RequestBody PlatformCatalog platformCatalog){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("删除关联,{}", JSON.toJSONString(platformCatalog));
+        }
+        int delResult = storager.delRelation(platformCatalog);
+        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
+        result.setCode(0);
+
+        if (delResult > 0) {
+            result.setMsg("success");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }else {
+            result.setMsg("save error");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+    }
+
+
+    /**
+     * 修改默认目录
+     * @param platformId 平台Id
+     * @param catalogId 目录Id
+     * @return
+     */
+    @ApiOperation("修改默认目录")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "platformId", value = "平台Id", dataTypeClass = String.class, required = true),
+            @ApiImplicitParam(name = "catalogId", value = "目录Id", dataTypeClass = String.class, required = true),
+    })
+    @PostMapping("/catalog/default/update")
+    @ResponseBody
+    public ResponseEntity<WVPResult<String>> setDefaultCatalog(String platformId, String catalogId){
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("修改默认目录,{},{}", platformId, catalogId);
+        }
+        int updateResult = storager.setDefaultCatalog(platformId, catalogId);
+        WVPResult<String> result = new WVPResult<>();
+        result.setCode(0);
+
+        if (updateResult > 0) {
+            result.setMsg("success");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }else {
+            result.setMsg("save error");
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+    }
+
 
 
 }
 }

+ 13 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java

@@ -40,6 +40,11 @@ public class ChannelReduce {
      */
      */
     private String  platformId;
     private String  platformId;
 
 
+    /**
+     * 目录Id
+     */
+    private String  catalogId;
+
 
 
     public String getChannelId() {
     public String getChannelId() {
         return channelId;
         return channelId;
@@ -96,4 +101,12 @@ public class ChannelReduce {
     public void setPlatformId(String platformId) {
     public void setPlatformId(String platformId) {
         this.platformId = platformId;
         this.platformId = platformId;
     }
     }
+
+    public String getCatalogId() {
+        return catalogId;
+    }
+
+    public void setCatalogId(String catalogId) {
+        this.catalogId = catalogId;
+    }
 }
 }

+ 9 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java

@@ -4,6 +4,7 @@ import java.util.List;
 
 
 public class UpdateChannelParam {
 public class UpdateChannelParam {
     private String platformId;
     private String platformId;
+    private String catalogId;
     private List<ChannelReduce> channelReduces;
     private List<ChannelReduce> channelReduces;
 
 
     public String getPlatformId() {
     public String getPlatformId() {
@@ -21,4 +22,12 @@ public class UpdateChannelParam {
     public void setChannelReduces(List<ChannelReduce> channelReduces) {
     public void setChannelReduces(List<ChannelReduce> channelReduces) {
         this.channelReduces = channelReduces;
         this.channelReduces = channelReduces;
     }
     }
+
+    public String getCatalogId() {
+        return catalogId;
+    }
+
+    public void setCatalogId(String catalogId) {
+        this.catalogId = catalogId;
+    }
 }
 }

+ 1 - 1
src/main/resources/all-application.yml

@@ -27,7 +27,7 @@ spring:
     datasource:
     datasource:
         # 使用mysql 打开23-28行注释, 删除29-36行
         # 使用mysql 打开23-28行注释, 删除29-36行
         # name: wvp
         # name: wvp
-        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
         # username:
         # username:
         # password:
         # password:
         # type: com.alibaba.druid.pool.DruidDataSource
         # type: com.alibaba.druid.pool.DruidDataSource

+ 1 - 1
src/main/resources/application-dev.yml

@@ -15,7 +15,7 @@ spring:
     datasource:
     datasource:
         # 使用mysql 打开23-28行注释, 删除29-36行
         # 使用mysql 打开23-28行注释, 删除29-36行
         # name: wvp
         # name: wvp
-        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
         # username:
         # username:
         # password:
         # password:
         # type: com.alibaba.druid.pool.DruidDataSource
         # type: com.alibaba.druid.pool.DruidDataSource

+ 1 - 1
src/main/resources/application-docker.yml

@@ -15,7 +15,7 @@ spring:
     datasource:
     datasource:
         # 使用mysql 打开23-28行注释, 删除29-36行
         # 使用mysql 打开23-28行注释, 删除29-36行
         # name: wvp
         # name: wvp
-        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true
         # username:
         # username:
         # password:
         # password:
         # type: com.alibaba.druid.pool.DruidDataSource
         # type: com.alibaba.druid.pool.DruidDataSource

二進制
src/main/resources/wvp.sqlite


+ 11 - 0
web_src/package-lock.json

@@ -19,6 +19,7 @@
         "vue-baidu-map": "^0.21.22",
         "vue-baidu-map": "^0.21.22",
         "vue-clipboard2": "^0.3.1",
         "vue-clipboard2": "^0.3.1",
         "vue-clipboards": "^1.3.0",
         "vue-clipboards": "^1.3.0",
+        "vue-contextmenujs": "^1.3.13",
         "vue-cookies": "^1.7.4",
         "vue-cookies": "^1.7.4",
         "vue-router": "^3.1.6"
         "vue-router": "^3.1.6"
       },
       },
@@ -12920,6 +12921,11 @@
         "tiny-emitter": "^2.0.0"
         "tiny-emitter": "^2.0.0"
       }
       }
     },
     },
+    "node_modules/vue-contextmenujs": {
+      "version": "1.3.13",
+      "resolved": "https://registry.npmmirror.com/vue-contextmenujs/download/vue-contextmenujs-1.3.13.tgz",
+      "integrity": "sha1-O9rgI8e9QgleeNpCWAACUNUKuO8="
+    },
     "node_modules/vue-cookies": {
     "node_modules/vue-cookies": {
       "version": "1.7.4",
       "version": "1.7.4",
       "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",
       "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",
@@ -25077,6 +25083,11 @@
         }
         }
       }
       }
     },
     },
+    "vue-contextmenujs": {
+      "version": "1.3.13",
+      "resolved": "https://registry.npmmirror.com/vue-contextmenujs/download/vue-contextmenujs-1.3.13.tgz",
+      "integrity": "sha1-O9rgI8e9QgleeNpCWAACUNUKuO8="
+    },
     "vue-cookies": {
     "vue-cookies": {
       "version": "1.7.4",
       "version": "1.7.4",
       "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",
       "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",

+ 1 - 0
web_src/package.json

@@ -21,6 +21,7 @@
     "vue-baidu-map": "^0.21.22",
     "vue-baidu-map": "^0.21.22",
     "vue-clipboard2": "^0.3.1",
     "vue-clipboard2": "^0.3.1",
     "vue-clipboards": "^1.3.0",
     "vue-clipboards": "^1.3.0",
+    "vue-contextmenujs": "^1.3.13",
     "vue-cookies": "^1.7.4",
     "vue-cookies": "^1.7.4",
     "vue-router": "^3.1.6"
     "vue-router": "^3.1.6"
   },
   },

+ 1 - 1
web_src/src/components/ParentPlatformList.vue

@@ -138,7 +138,7 @@ export default {
         });
         });
     },
     },
     chooseChannel: function(platform) {
     chooseChannel: function(platform) {
-       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, this.initData)
+       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, this.initData)
     },
     },
     initData: function() {
     initData: function() {
       this.getPlatformList();
       this.getPlatformList();

+ 101 - 0
web_src/src/components/dialog/catalogEdit.vue

@@ -0,0 +1,101 @@
+<template>
+  <div id="catalogEdit" v-loading="isLoging">
+    <el-dialog
+      title="节点编辑"
+      width="40%"
+      top="2rem"
+      :append-to-body="true"
+      :close-on-click-modal="false"
+      :visible.sync="showDialog"
+      :destroy-on-close="true"
+      @close="close()"
+    >
+      <div id="shared" style="margin-top: 1rem;margin-right: 100px;">
+        <el-form ref="form" :rules="rules" :model="form" label-width="140px" >
+          <el-form-item label="节点编号" prop="id" >
+            <el-input v-model="form.id" :disabled="isEdit"></el-input>
+          </el-form-item>
+          <el-form-item label="节点名称" prop="name">
+            <el-input v-model="form.name" clearable></el-input>
+          </el-form-item>
+          <el-form-item>
+            <div style="float: right;">
+              <el-button type="primary" @click="onSubmit" >确认</el-button>
+              <el-button @click="close">取消</el-button>
+            </div>
+
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: "catalogEdit",
+  computed: {},
+  props: ['platformId'],
+  created() {},
+  data() {
+    return {
+      submitCallback: null,
+      showDialog: false,
+      isLoging: false,
+      isEdit: false,
+      form: {
+        id: null,
+        name: null,
+        platformId: null,
+        parentId: null,
+      },
+      rules: {
+        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
+        id: [{ required: true, message: "请输入id", trigger: "blur" }]
+      },
+    };
+  },
+  methods: {
+    openDialog: function (isEdit, id, name, parentId, callback) {
+      console.log("parentId: " + parentId)
+      this.isEdit = isEdit;
+      this.form.id = id;
+      this.form.name = name;
+      this.form.platformId = this.platformId;
+      this.form.parentId = parentId;
+      this.showDialog = true;
+      this.submitCallback = callback;
+    },
+    onSubmit: function () {
+      console.log("onSubmit");
+      console.log(this.form);
+      this.$axios({
+        method:"post",
+        url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
+        data: this.form
+      })
+        .then((res)=> {
+          if (res.data.code === 0) {
+            console.log("添加/修改成功")
+            if (this.submitCallback)this.submitCallback()
+          }else {
+            this.$message({
+              showClose: true,
+              message: res.data.msg,
+              type: "error",
+            });
+          }
+          this.close();
+        })
+        .catch((error)=> {
+          console.log(error);
+        });
+    },
+    close: function () {
+      this.showDialog = false;
+      this.$refs.form.resetFields();
+    },
+  },
+};
+</script>

+ 65 - 18
web_src/src/components/dialog/chooseChannel.vue

@@ -1,25 +1,40 @@
 <template>
 <template>
 <div id="chooseChannel" v-loading="isLoging">
 <div id="chooseChannel" v-loading="isLoging">
 
 
-    <el-dialog title="选择通道" v-if="showDialog" top="2rem" width="70%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()">
-        <el-tabs v-model="tabActiveName" >
-            <el-tab-pane label="国标通道" name="gbChannel">
-                <el-container>
-                    <el-main style="background-color: #FFF;">
-                     <chooseChannelForGb :platformId=platformId ></chooseChannelForGb>
-                    </el-main>
-            </el-container>
-
+    <el-dialog title="选择通道" v-if="showDialog" top="2rem" width="90%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()">
+      <el-row>
+        <el-col :span="10">
+          <el-tabs v-model="catalogTabActiveName" >
+            <el-tab-pane label="目录结构" name="catalog">
+              <el-container>
+                <el-main style="background-color: #FFF;">
+                  <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange"></chooseChannelForCatalog>
+                </el-main>
+              </el-container>
+            </el-tab-pane>
+          </el-tabs>
 
 
+        </el-col>
+        <el-col :span="14">
+          <el-tabs v-model="tabActiveName" @tab-click="tabClick">
+            <el-tab-pane label="国标通道" name="gbChannel">
+              <el-container>
+                <el-main style="background-color: #FFF;">
+                  <chooseChannelForGb ref="chooseChannelForGb" :platformId=platformId :updateChoosedCallback="updateChooseChannelCallback"></chooseChannelForGb>
+                </el-main>
+              </el-container>
             </el-tab-pane>
             </el-tab-pane>
             <el-tab-pane label="直播流通道" name="streamchannel">
             <el-tab-pane label="直播流通道" name="streamchannel">
-                <el-container>
-                    <el-main style="background-color: #FFF;">
-                     <chooseChannelFoStream :platformId=platformId ></chooseChannelFoStream>
-                    </el-main>
-            </el-container>
+              <el-container>
+                <el-main style="background-color: #FFF;">
+                  <chooseChannelFoStream ref="chooseChannelFoStream" :platformId=platformId :updateChoosedCallback="updateChooseChannelCallback"></chooseChannelFoStream>
+                </el-main>
+              </el-container>
             </el-tab-pane>
             </el-tab-pane>
-        </el-tabs>
+          </el-tabs>
+        </el-col>
+      </el-row>
+
     </el-dialog>
     </el-dialog>
 </div>
 </div>
 </template>
 </template>
@@ -27,12 +42,14 @@
 <script>
 <script>
 import chooseChannelForGb from '../dialog/chooseChannelForGb.vue'
 import chooseChannelForGb from '../dialog/chooseChannelForGb.vue'
 import chooseChannelFoStream from '../dialog/chooseChannelForStream.vue'
 import chooseChannelFoStream from '../dialog/chooseChannelForStream.vue'
+import chooseChannelForCatalog from '../dialog/chooseChannelForCatalog.vue'
 export default {
 export default {
     name: 'chooseChannel',
     name: 'chooseChannel',
     props: {},
     props: {},
     components: {
     components: {
         chooseChannelForGb,
         chooseChannelForGb,
         chooseChannelFoStream,
         chooseChannelFoStream,
+        chooseChannelForCatalog,
     },
     },
     computed: {
     computed: {
         // getPlayerShared: function () {
         // getPlayerShared: function () {
@@ -47,20 +64,35 @@ export default {
         return {
         return {
             isLoging: false,
             isLoging: false,
             tabActiveName: "gbChannel",
             tabActiveName: "gbChannel",
+            catalogTabActiveName: "catalog",
             platformId: "",
             platformId: "",
-            isLoging: false,
+            catalogId: "",
+            platformName: "",
+            defaultCatalogId: "",
             showDialog: false,
             showDialog: false,
             chooseData: {}
             chooseData: {}
 
 
         };
         };
     },
     },
     methods: {
     methods: {
-        openDialog: function (platformId,  closeCallback) {
-            console.log(platformId)
+        openDialog(platformId, platformName, defaultCatalogId, closeCallback) {
             this.platformId = platformId
             this.platformId = platformId
+            this.platformName = platformName
+            this.defaultCatalogId = defaultCatalogId
             this.showDialog = true
             this.showDialog = true
             this.closeCallback = closeCallback
             this.closeCallback = closeCallback
         },
         },
+        tabClick (tab, event){
+          console.log(tab.label)
+          if (tab.label === "gbChannel") {
+            this.$refs.chooseChannelForGb.catalogIdChange(this.catalogId);
+            this.$refs.chooseChannelForGb.initData();
+          }else {
+            this.$refs.chooseChannelFoStream.catalogIdChange(this.catalogId);
+            this.$refs.chooseChannelFoStream.initData();
+          }
+
+        },
         close: function() {
         close: function() {
           this.closeCallback()
           this.closeCallback()
         },
         },
@@ -88,6 +120,21 @@ export default {
             }).catch(function (error) {
             }).catch(function (error) {
                 console.log(error);
                 console.log(error);
             });
             });
+        },
+        catalogIdChange: function (id) {
+            console.log("中间模块收到: " + id)
+            this.catalogId = id;
+            if (this.tabActiveName === "gbChannel") {
+              this.$refs.chooseChannelForGb.catalogIdChange(id);
+            }else {
+              this.$refs.chooseChannelFoStream.catalogIdChange(id);
+            }
+        },
+        updateChooseChannelCallback (id, nodeIds){
+          console.log("中间模块收到选择通道变化: " + id)
+          console.log("中间模块收到选择通道变化: " + nodeIds)
+          console.log("中间模块收到选择通道变化: " + typeof (nodeIds))
+          this.$refs.chooseChannelForCatalog.refreshCatalogById(id, nodeIds)
         }
         }
     }
     }
 };
 };

+ 311 - 0
web_src/src/components/dialog/chooseChannelForCatalog.vue

@@ -0,0 +1,311 @@
+<template>
+<div id="chooseChannelForCatalog" >
+   <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;">
+     <el-tree class="el-scrollbar"
+       ref="tree"
+       id="catalogTree"
+       empty-text="未知节点"
+       node-key="id"
+       default-expand-all
+       :highlight-current="true"
+       :expand-on-click-node="false"
+       :props="props"
+       :load="loadNode"
+       @node-contextmenu="contextmenuEventHandler"
+       lazy>
+       <span class="custom-tree-node" slot-scope="{ node, data }" style="width: 100%">
+         <el-radio v-if="node.data.type === 0" style="margin-right: 0" v-model="chooseId" :label="node.data.id">{{''}}</el-radio>
+         <span v-if="node.data.type === 0 && node.level === 1" class="el-icon-s-home"></span>
+         <span v-if="node.data.type === 0 && node.level > 1"  class="el-icon-folder-opened"></span>
+         <span v-if="node.data.type === 1" class="iconfont icon-shexiangtou"></span>
+         <span v-if="node.data.type === 2" class="iconfont icon-zhibo"></span>
+        <span style="padding-left: 1px">{{ node.label }}</span>
+        <span>
+          <i style="margin-left: 5rem; color: #9d9d9d; padding-right: 20px" v-if="node.data.id === defaultCatalogId">默认</i>
+        </span>
+      </span>
+     </el-tree>
+   </div>
+    <catalogEdit ref="catalogEdit" :platformId="platformId"></catalogEdit>
+</div>
+</template>
+
+
+<script>
+
+import catalogEdit from './catalogEdit.vue'
+export default {
+    name: 'chooseChannelForCatalog',
+    props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange'],
+    created() {
+        this.initData();
+        setTimeout(()=>{
+          if (this.catalogIdChange)this.catalogIdChange(this.defaultCatalogId);
+        }, 100)
+
+    },
+    components: {
+      catalogEdit,
+    },
+    data() {
+        return {
+          props: {
+            label: 'name',
+            children: 'children',
+            isLeaf: 'leaf'
+          },
+          chooseNode: null,
+          chooseId: this.defaultCatalogId,
+          catalogTree: null,
+          contextmenuShow: false
+
+        };
+    },
+    watch:{
+        platformId(newData, oldData){
+            console.log(newData)
+            this.initData()
+        },
+        chooseId(newData, oldData){
+          console.log("发送: " + newData)
+          if (this.catalogIdChange)this.catalogIdChange(newData);
+        },
+    },
+    methods: {
+        initData: function () {
+            this.getCatalog();
+        },
+
+        getCatalog: function(parentId, callback) {
+            let that = this;
+            this.$axios({
+                    method:"get",
+                    url:`/api/platform/catalog`,
+                    params: {
+                        platformId: that.platformId,
+                        parentId: parentId
+                    }
+                })
+                .then((res)=> {
+                  if (res.data.code === 0) {
+                    if (typeof(callback) === 'function') {
+                      callback(res.data.data)
+                    }
+                    //
+
+                    // if (typeof (this.$refs.tree.setCurrentKey) == "undefined") {
+                    //   this.$refs.tree.setCurrentKey(this.defaultCatalogId)
+                    //   let data = this.$refs.tree.getCurrentNode()
+                    //   if (data != null && data.id === this.defaultCatalogId) {
+                    //     this.currentCatalogChange(data, this.$refs.tree.getNode(data.id))
+                    //   }
+                    // }
+
+                  }
+                })
+                .catch(function (error) {
+                    console.log(error);
+                });
+
+        },
+        addCatalog: function (parentId, node){
+          let that = this;
+          // 打开添加弹窗
+          that.$refs.catalogEdit.openDialog(false, null, null, parentId, ()=>{
+            node.loaded = false
+            node.expand();
+          });
+
+        },
+        refreshCatalog: function (node){
+          node.loaded = false
+          node.expand();
+        },
+        refreshCatalogById: function (id, nodeIds) {
+          if (id) {
+            console.log("refreshCatalogById:  " + id)
+            let node = this.$refs.tree.getNode(id);
+            console.log(node)
+            this.refreshCatalog(node);
+          }
+          if (nodeIds !== null) {
+            let refreshNode = {}
+            for (let i = 0; i < nodeIds.length; i++) {
+              let node = this.$refs.tree.getNode(nodeIds[i]);
+              refreshNode[node.parent.data.id] = node.parent
+            }
+            if (Object.values(refreshNode).length > 0) {
+              for (let j = 0; j < Object.values(refreshNode).length; j++) {
+                this.refreshCatalog(Object.values(refreshNode)[j]);
+              }
+            }
+          }
+        },
+        editCatalog: function (data, node){
+          let that = this;
+          // 打开添加弹窗
+          that.$refs.catalogEdit.openDialog(true, data.id, data.name, data.parentId, (data)=>{
+            node.parent.loaded = false
+            node.parent.expand();
+          });
+
+        },
+        removeCatalog: function (id, node){
+          this.$axios({
+            method:"delete",
+            url:`/api/platform/catalog/del`,
+            params: {
+              id: id,
+            }
+          })
+            .then((res) => {
+              if (res.data.code === 0) {
+                console.log("移除成功")
+                node.parent.loaded = false
+                node.parent.expand();
+              }
+            })
+            .catch(function (error) {
+              console.log(error);
+            });
+        },
+        setDefaultCatalog: function (id){
+          this.$axios({
+            method:"post",
+            url:`/api/platform/catalog/default/update`,
+            params: {
+              platformId: this.platformId,
+              catalogId: id,
+            }
+          })
+            .then((res)=> {
+              if (res.data.code === 0) {
+                this.defaultCatalogId = id;
+              }
+            })
+            .catch(function (error) {
+              console.log(error);
+            });
+        },
+        loadNode: function(node, resolve){
+          if (node.level === 0) {
+            resolve([{
+              name: this.platformName,
+              id:  this.platformId,
+              type:  0
+            }]);
+          }
+          if (node.level >= 1){
+            this.getCatalog(node.data.id, resolve)
+          }
+        },
+      contextmenuEventHandler: function (event,data,node,element){
+          if (node.data.type !== 0) {
+            data.parentId = node.parent.data.id;
+            this.$contextmenu({
+              items: [
+                {
+                  label: "移除通道",
+                  icon: "el-icon-delete",
+                  disabled: false,
+                  onClick: () => {
+                    this.$axios({
+                      method:"delete",
+                      url:"/api/platform/catalog/relation/del",
+                      data: data
+                    }).then((res)=>{
+                      console.log("移除成功")
+                      node.parent.loaded = false
+                      node.parent.expand();
+                    }).catch(function (error) {
+                      console.log(error);
+                    });
+                  }
+                }
+              ],
+              event, // 鼠标事件信息
+              customClass: "custom-class", // 自定义菜单 class
+              zIndex: 3000, // 菜单样式 z-index
+            });
+          }else {
+            this.$contextmenu({
+              items: [
+                {
+                  label: "刷新节点",
+                  icon: "el-icon-refresh",
+                  disabled: false,
+                  onClick: () => {
+                    this.refreshCatalog(node);
+                  }
+                },
+                {
+                  label: "新建节点",
+                  icon: "el-icon-plus",
+                  disabled: false,
+                  onClick: () => {
+                    this.addCatalog(data.id, node);
+                  }
+                },
+                {
+                  label: "修改节点",
+                  icon: "el-icon-edit",
+                  disabled: node.level === 1,
+                  onClick: () => {
+                    this.editCatalog(data, node);
+                  }
+                },
+                {
+                  label: "删除节点",
+                  icon: "el-icon-delete",
+                  disabled: node.level === 1,
+                  divided: true,
+                  onClick: () => {
+                    this.removeCatalog(data.id, node)
+                  }
+                },
+                {
+                  label: "设为默认",
+                  icon: "el-icon-folder-checked",
+                  disabled: node.data.id === this.defaultCatalogId,
+                  onClick: () => {
+                    this.setDefaultCatalog(data.id)
+                  },
+                },
+                // {
+                //   label: "导出",
+                //   icon: "el-icon-download",
+                //   disabled: false,
+                //   children: [
+                //     {
+                //       label: "导出到文件",
+                //       onClick: () => {
+                //
+                //       },
+                //     },
+                //     {
+                //       label: "导出到其他平台",
+                //       onClick: () => {
+                //
+                //       },
+                //     }
+                //   ]
+                // },
+
+              ],
+              event, // 鼠标事件信息
+              customClass: "custom-class", // 自定义菜单 class
+              zIndex: 3000, // 菜单样式 z-index
+            });
+          }
+
+        return false;
+      },
+    }
+};
+</script>
+
+<style>
+#catalogTree{
+  display: inline-block;
+}
+</style>

+ 33 - 22
web_src/src/components/dialog/chooseChannelForGb.vue

@@ -21,9 +21,9 @@
             <el-option label="离线" value="false"></el-option>
             <el-option label="离线" value="false"></el-option>
         </el-select>
         </el-select>
 
 
-        <el-checkbox @change="shareAllCheckedChanage">全部共享</el-checkbox>
+        <el-checkbox @change="shareAllCheckedChange">全部共享</el-checkbox>
     </div>
     </div>
-    <el-table ref="gbChannelsTable" :data="gbChannels" border style="width: 100%" @selection-change="checkedChanage" >
+    <el-table ref="gbChannelsTable" :data="gbChannels" border style="width: 100%" @selection-change="checkedChange" >
         <el-table-column type="selection" width="55" align="center" fixed > </el-table-column>
         <el-table-column type="selection" width="55" align="center" fixed > </el-table-column>
         <el-table-column prop="channelId" label="通道编号" width="210">
         <el-table-column prop="channelId" label="通道编号" width="210">
         </el-table-column>
         </el-table-column>
@@ -49,7 +49,6 @@
 <script>
 <script>
 export default {
 export default {
     name: 'chooseChannelForGb',
     name: 'chooseChannelForGb',
-    props: {},
     computed: {
     computed: {
         // getPlayerShared: function () {
         // getPlayerShared: function () {
         //     return {
         //     return {
@@ -59,7 +58,7 @@ export default {
         //     };
         //     };
         // }
         // }
     },
     },
-    props: ['platformId'],
+    props: ['platformId', 'updateChoosedCallback'],
     created() {
     created() {
         this.initData();
         this.initData();
     },
     },
@@ -71,6 +70,7 @@ export default {
             channelType: "",
             channelType: "",
             online: "",
             online: "",
             choosed: "",
             choosed: "",
+            catalogId: null,
             currentPage: 1,
             currentPage: 1,
             count: 10,
             count: 10,
             total: 0,
             total: 0,
@@ -97,28 +97,28 @@ export default {
             this.count = val;
             this.count = val;
             console.log(val)
             console.log(val)
             this.initData();
             this.initData();
-
         },
         },
-        rowcheckedChanage: function (val, row) {
+        rowcheckedChange: function (val, row) {
             console.log(val)
             console.log(val)
             console.log(row)
             console.log(row)
         },
         },
-        checkedChanage: function (val) {
-            var that = this;
+        // selectDisable: function (){
+        //   if (this.catalogId == null) {
+        //     return false;
+        //   }
+        // },
+        checkedChange: function (val) {
+            let that = this;
             if (!that.eventEnanle) {
             if (!that.eventEnanle) {
                 return;
                 return;
             }
             }
-            var tabelData = JSON.parse(JSON.stringify(this.$refs.gbChannelsTable.data));
-            console.log("checkedChanage")
-            console.log(val)
-
-            var newData = {};
-            var addData = [];
-            var delData = [];
+            let newData = {};
+            let addData = [];
+            let delData = [];
             if (val.length > 0) {
             if (val.length > 0) {
                 for (let i = 0; i < val.length; i++) {
                 for (let i = 0; i < val.length; i++) {
                     const element = val[i];
                     const element = val[i];
-                    var key = element.deviceId + "_" + element.channelId;
+                    let key = element.deviceId + "_" + element.channelId;
                     newData[key] = element;
                     newData[key] = element;
                     if (!!!that.gbChoosechannel[key]){
                     if (!!!that.gbChoosechannel[key]){
                         addData.push(element)
                         addData.push(element)
@@ -127,7 +127,7 @@ export default {
                     }
                     }
                 }
                 }
 
 
-                 var oldKeys = Object.keys(that.gbChoosechannel);
+                let oldKeys = Object.keys(that.gbChoosechannel);
                 if (oldKeys.length > 0) {
                 if (oldKeys.length > 0) {
                     for (let i = 0; i < oldKeys.length; i++) {
                     for (let i = 0; i < oldKeys.length; i++) {
                         const key = oldKeys[i];
                         const key = oldKeys[i];
@@ -136,7 +136,7 @@ export default {
                 }
                 }
 
 
             }else{
             }else{
-                var oldKeys = Object.keys(that.gbChoosechannel);
+                let oldKeys = Object.keys(that.gbChoosechannel);
                 if (oldKeys.length > 0) {
                 if (oldKeys.length > 0) {
                     for (let i = 0; i < oldKeys.length; i++) {
                     for (let i = 0; i < oldKeys.length; i++) {
                         const key = oldKeys[i];
                         const key = oldKeys[i];
@@ -152,15 +152,17 @@ export default {
                     url:"/api/platform/update_channel_for_gb",
                     url:"/api/platform/update_channel_for_gb",
                     data:{
                     data:{
                         platformId:  that.platformId,
                         platformId:  that.platformId,
-                        channelReduces: addData
+                        channelReduces: addData,
+                        catalogId: that.catalogId
                     }
                     }
                 }).then((res)=>{
                 }).then((res)=>{
                     console.log("保存成功")
                     console.log("保存成功")
+                    if(that.updateChoosedCallback)that.updateChoosedCallback(that.catalogId)
                 }).catch(function (error) {
                 }).catch(function (error) {
                     console.log(error);
                     console.log(error);
                 });
                 });
             }
             }
-            if (Object.keys(delData).length >0) {
+            if (delData.length >0) {
                  that.$axios({
                  that.$axios({
                     method:"delete",
                     method:"delete",
                     url:"/api/platform/del_channel_for_gb",
                     url:"/api/platform/del_channel_for_gb",
@@ -170,13 +172,18 @@ export default {
                     }
                     }
                 }).then((res)=>{
                 }).then((res)=>{
                     console.log("移除成功")
                     console.log("移除成功")
+                   let nodeIds = new Array();
+                   for (let i = 0; i < delData.length; i++) {
+                     nodeIds.push(delData[i].channelId)
+                   }
+                   if(that.updateChoosedCallback)that.updateChoosedCallback(null, nodeIds)
                 }).catch(function (error) {
                 }).catch(function (error) {
                     console.log(error);
                     console.log(error);
                 });
                 });
             }
             }
 
 
         },
         },
-        shareAllCheckedChanage: function (val) {
+        shareAllCheckedChange: function (val) {
             this.chooseChanage(null, val)
             this.chooseChanage(null, val)
         },
         },
         getChannelList: function () {
         getChannelList: function () {
@@ -215,7 +222,7 @@ export default {
                             }
                             }
                         }
                         }
                          that.eventEnanle = true;
                          that.eventEnanle = true;
-                        // that.checkedChanage(chooseGBS)
+                        // that.checkedChange(chooseGBS)
                     })
                     })
                     console.log(that.gbChoosechannel)
                     console.log(that.gbChoosechannel)
                 })
                 })
@@ -230,6 +237,10 @@ export default {
         handleGBSelectionChange: function() {
         handleGBSelectionChange: function() {
             this.initData();
             this.initData();
         },
         },
+        catalogIdChange: function(id) {
+            this.catalogId = id;
+            console.log("通道选择模块收到: " + id)
+        },
     }
     }
 };
 };
 </script>
 </script>

+ 9 - 2
web_src/src/components/dialog/chooseChannelForStream.vue

@@ -27,7 +27,6 @@
 <script>
 <script>
 export default {
 export default {
     name: 'chooseChannelFoStream',
     name: 'chooseChannelFoStream',
-    props: {},
     computed: {
     computed: {
         // getPlayerShared: function () {
         // getPlayerShared: function () {
         //     return {
         //     return {
@@ -37,7 +36,7 @@ export default {
         //     };
         //     };
         // }
         // }
     },
     },
-    props: ['platformId'],
+    props: ['platformId',  'updateChoosedCallback'],
     created() {
     created() {
         this.initData();
         this.initData();
     },
     },
@@ -49,6 +48,7 @@ export default {
             channelType: "",
             channelType: "",
             online: "",
             online: "",
             choosed: "",
             choosed: "",
+            catalogId: null,
             currentPage: 1,
             currentPage: 1,
             count: 10,
             count: 10,
             total: 0,
             total: 0,
@@ -131,10 +131,12 @@ export default {
                      url:"/api/gbStream/add",
                      url:"/api/gbStream/add",
                     data:{
                     data:{
                         platformId: that.platformId,
                         platformId: that.platformId,
+                        catalogId: that.catalogId,
                         gbStreams:  addData,
                         gbStreams:  addData,
                     }
                     }
                 }).then((res)=>{
                 }).then((res)=>{
                     console.log("保存成功")
                     console.log("保存成功")
+                    if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
                 }).catch(function (error) {
                 }).catch(function (error) {
                     console.log(error);
                     console.log(error);
                 });
                 });
@@ -149,6 +151,7 @@ export default {
                     }
                     }
                 }).then((res)=>{
                 }).then((res)=>{
                     console.log("移除成功")
                     console.log("移除成功")
+                   if(this.updateChoosedCallback)this.updateChoosedCallback(this.catalogId)
                 }).catch(function (error) {
                 }).catch(function (error) {
                     console.log(error);
                     console.log(error);
                 });
                 });
@@ -207,6 +210,10 @@ export default {
         handleGBSelectionChange: function() {
         handleGBSelectionChange: function() {
             this.initData();
             this.initData();
         },
         },
+        catalogIdChange: function(id) {
+          this.catalogId = id;
+          console.log("直播通道选择模块收到: " + id)
+        },
     }
     }
 };
 };
 </script>
 </script>

+ 1 - 0
web_src/src/components/dialog/platformEdit.vue

@@ -196,6 +196,7 @@ export default {
         this.platform.transport = platform.transport;
         this.platform.transport = platform.transport;
         this.platform.characterSet = platform.characterSet;
         this.platform.characterSet = platform.characterSet;
         this.platform.shareAllLiveStream = platform.shareAllLiveStream;
         this.platform.shareAllLiveStream = platform.shareAllLiveStream;
+        this.platform.catalogId = platform.catalogId;
         this.onSubmit_text = "保存";
         this.onSubmit_text = "保存";
       }
       }
       this.showDialog = true;
       this.showDialog = true;

+ 2 - 0
web_src/src/main.js

@@ -12,6 +12,7 @@ import VueClipboard from 'vue-clipboard2';
 import { Notification } from 'element-ui';
 import { Notification } from 'element-ui';
 import Fingerprint2 from 'fingerprintjs2';
 import Fingerprint2 from 'fingerprintjs2';
 import VueClipboards from 'vue-clipboards';
 import VueClipboards from 'vue-clipboards';
+import Contextmenu from "vue-contextmenujs"
 
 
 
 
 // 生成唯一ID
 // 生成唯一ID
@@ -37,6 +38,7 @@ Vue.use(VueCookies);
 Vue.use(VueClipboards);
 Vue.use(VueClipboards);
 Vue.prototype.$axios = axios;
 Vue.prototype.$axios = axios;
 Vue.prototype.$notify = Notification;
 Vue.prototype.$notify = Notification;
+Vue.use(Contextmenu);
 
 
 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";
 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";
 
 

+ 21 - 5
web_src/static/css/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
 @font-face {
   font-family: "iconfont"; /* Project id 1291092 */
   font-family: "iconfont"; /* Project id 1291092 */
-  src: url('iconfont.woff2?t=1637741914969') format('woff2'),
-       url('iconfont.woff?t=1637741914969') format('woff'),
-       url('iconfont.ttf?t=1637741914969') format('truetype');
+  src: url('iconfont.woff2?t=1640922722742') format('woff2'),
+       url('iconfont.woff?t=1640922722742') format('woff'),
+       url('iconfont.ttf?t=1640922722742') format('truetype');
 }
 }
 
 
 .iconfont {
 .iconfont {
@@ -13,6 +13,22 @@
   -moz-osx-font-smoothing: grayscale;
   -moz-osx-font-smoothing: grayscale;
 }
 }
 
 
+.icon-wxbzhuye:before {
+  content: "\e7d1";
+}
+
+.icon-mulu:before {
+  content: "\e7d2";
+}
+
+.icon-zhibo:before {
+  content: "\e8c1";
+}
+
+.icon-shexiangtou:before {
+  content: "\e7d3";
+}
+
 .icon-suoxiao:before {
 .icon-suoxiao:before {
   content: "\e79a";
   content: "\e79a";
 }
 }
@@ -49,7 +65,7 @@
   content: "\e7a2";
   content: "\e7a2";
 }
 }
 
 
-.icon-kuaijin:before {
+.icon-houtui:before {
   content: "\e7a3";
   content: "\e7a3";
 }
 }
 
 
@@ -57,7 +73,7 @@
   content: "\e7a4";
   content: "\e7a4";
 }
 }
 
 
-.icon-kuaitui:before {
+.icon-kuaijin:before {
   content: "\e7a5";
   content: "\e7a5";
 }
 }
 
 

二進制
web_src/static/css/iconfont.woff2


部分文件因文件數量過多而無法顯示