瀏覽代碼

Merge branch 'wvp-28181-2.0' into wvp-28181-2.0

648540858 2 年之前
父節點
當前提交
9e28923b8c
共有 35 個文件被更改,包括 4111 次插入632 次删除
  1. 2 2
      sql/2.6.8升级2.6.9.sql
  2. 0 2
      sql/初始化.sql
  3. 42 0
      src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java
  4. 101 0
      src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java
  5. 1 0
      src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
  6. 1 1
      src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
  7. 23 1
      src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
  8. 0 14
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  9. 0 14
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
  10. 0 10
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java
  11. 139 49
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  12. 2 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  13. 9 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
  14. 5 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
  15. 0 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  16. 6 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
  17. 328 181
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  18. 2 2
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
  19. 27 146
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
  20. 16 27
      src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
  21. 4 9
      src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
  22. 41 42
      src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
  23. 11 3
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  24. 0 9
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
  25. 2 3
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  26. 84 60
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
  27. 6 2
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  28. 4 0
      src/main/resources/all-application.yml
  29. 3220 0
      src/main/resources/civilCode.csv
  30. 1 1
      web_src/src/components/ParentPlatformList.vue
  31. 27 17
      web_src/src/components/dialog/catalogEdit.vue
  32. 2 4
      web_src/src/components/dialog/chooseChannel.vue
  33. 5 4
      web_src/src/components/dialog/chooseChannelForCatalog.vue
  34. 0 6
      web_src/src/components/dialog/deviceEdit.vue
  35. 0 18
      web_src/src/components/dialog/platformEdit.vue

+ 2 - 2
sql/2.6.8升级2.6.9.sql

@@ -38,7 +38,7 @@ alter table device
     change geoCoordSys geo_coord_sys varchar(50) not null;
 
 alter table device
-    change treeType tree_type varchar(50) not null;
+    drop column treeType;
 
 alter table device
     change mediaServerId media_server_id varchar(50) default 'auto' null;
@@ -297,7 +297,7 @@ alter table parent_platform
     change updateTime update_time varchar(50) null;
 
 alter table parent_platform
-    change treeType tree_type varchar(50) not null;
+    drop column treeType;
 
 alter table parent_platform
     change asMessageChannel as_message_channel bool default false;

+ 0 - 2
sql/初始化.sql

@@ -24,7 +24,6 @@ create table wvp_device (
                             charset character varying(50),
                             ssrc_check bool default false,
                             geo_coord_sys character varying(50),
-                            tree_type character varying(50),
                             media_server_id character varying(50),
                             custom_name character varying(255),
                             sdp_ip character varying(50),
@@ -187,7 +186,6 @@ create table wvp_platform (
                               catalog_group integer,
                               create_time character varying(50),
                               update_time character varying(50),
-                              tree_type character varying(50),
                               as_message_channel bool default false,
                               constraint uk_platform_unique_server_gb_id unique (server_gb_id)
 );

+ 42 - 0
src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java

@@ -0,0 +1,42 @@
+package com.genersoft.iot.vmp.common;
+
+public class CivilCodePo {
+
+    private String code;
+
+    private String name;
+
+    private String parentCode;
+
+    public static CivilCodePo getInstance(String[] infoArray) {
+        CivilCodePo civilCodePo = new CivilCodePo();
+        civilCodePo.setCode(infoArray[0]);
+        civilCodePo.setName(infoArray[1]);
+        civilCodePo.setParentCode(infoArray[2]);
+        return civilCodePo;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getParentCode() {
+        return parentCode;
+    }
+
+    public void setParentCode(String parentCode) {
+        this.parentCode = parentCode;
+    }
+}

+ 101 - 0
src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java

@@ -0,0 +1,101 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.genersoft.iot.vmp.common.CivilCodePo;
+import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.ObjectUtils;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.util.Map;
+
+/**
+ * 启动时读取行政区划表
+ */
+@Configuration
+@Order(value=14)
+public class CivilCodeFileConf implements CommandLineRunner {
+
+    private final static Logger logger = LoggerFactory.getLogger(CivilCodeFileConf.class);
+
+    private final Map<String, CivilCodePo> civilCodeMap= new ConcurrentHashMap<>();
+
+    @Autowired
+    @Lazy
+    private UserSetting userSetting;
+
+    @Override
+    public void run(String... args) throws Exception {
+        if (ObjectUtils.isEmpty(userSetting.getCivilCodeFile())) {
+            logger.warn("[行政区划] 文件未设置,可能造成目录刷新结果不完整");
+            return;
+        }
+        InputStream inputStream;
+        if (userSetting.getCivilCodeFile().startsWith("classpath:")){
+            String filePath = userSetting.getCivilCodeFile().substring("classpath:".length());
+            ClassPathResource civilCodeFile = new ClassPathResource(filePath);
+            if (!civilCodeFile.exists()) {
+                logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
+                return;
+            }
+            inputStream = civilCodeFile.getInputStream();
+
+        }else {
+            File civilCodeFile = new File(userSetting.getCivilCodeFile());
+            if (!civilCodeFile.exists()) {
+                logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
+                return;
+            }
+            inputStream = Files.newInputStream(civilCodeFile.toPath());
+        }
+
+        BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(inputStream));
+        int index = -1;
+        String line;
+        while ((line = inputStreamReader.readLine()) != null) {
+            index ++;
+            if (index == 0) {
+                continue;
+            }
+            String[] infoArray = line.split(",");
+            CivilCodePo civilCodePo = CivilCodePo.getInstance(infoArray);
+            civilCodeMap.put(civilCodePo.getCode(), civilCodePo);
+        }
+        inputStreamReader.close();
+        inputStream.close();
+        if (civilCodeMap.size() == 0) {
+            logger.warn("[行政区划] 文件内容为空,可能造成目录刷新结果不完整");
+        }else {
+            logger.info("[行政区划] 加载成功,共加载数据{}条", civilCodeMap.size());
+        }
+    }
+
+    public CivilCodePo getParentCode(String code) {
+        if (code.length() > 8) {
+            return null;
+        }
+        if (code.length() == 8) {
+            String parentCode = code.substring(0, 6);
+            return civilCodeMap.get(parentCode);
+        }else {
+            CivilCodePo civilCodePo = civilCodeMap.get(code);
+            if (civilCodePo == null){
+                return null;
+            }
+            String parentCode = civilCodePo.getParentCode();
+            if (parentCode == null) {
+                return null;
+            }
+            return civilCodeMap.get(parentCode);
+        }
+
+    }
+
+}

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java

@@ -45,6 +45,7 @@ public class DynamicTask {
      * @return
      */
     public void startCron(String key, Runnable task, int cycleForCatalog) {
+        System.out.println(cycleForCatalog);
         ScheduledFuture<?> future = futureMap.get(key);
         if (future != null) {
             if (future.isCancelled()) {

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java

@@ -56,7 +56,7 @@ public class SipPlatformRunner implements CommandLineRunner {
             }
 
             // 设置所有平台离线
-            platformService.offline(parentPlatform, true);
+            platformService.offline(parentPlatform, false);
         }
     }
 }

+ 23 - 1
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java

@@ -63,7 +63,7 @@ public class UserSetting {
 
     private String thirdPartyGBIdReg = "[\\s\\S]*";
 
-
+    private String civilCodeFile = "classpath:civilCode.csv";
 
     private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
 
@@ -71,6 +71,10 @@ public class UserSetting {
 
     private int maxNotifyCountQueue = 10000;
 
+    private int registerAgainAfterTime = 60;
+
+    private boolean registerKeepIntDialog = false;
+
     public Boolean getSavePositionHistory() {
         return savePositionHistory;
     }
@@ -299,9 +303,27 @@ public class UserSetting {
         this.sqlLog = sqlLog;
     }
 
+    public String getCivilCodeFile() {
+        return civilCodeFile;
+    }
 
+    public void setCivilCodeFile(String civilCodeFile) {
+        this.civilCodeFile = civilCodeFile;
+    }
 
+    public int getRegisterAgainAfterTime() {
+        return registerAgainAfterTime;
+    }
 
+    public void setRegisterAgainAfterTime(int registerAgainAfterTime) {
+        this.registerAgainAfterTime = registerAgainAfterTime;
+    }
 
+    public boolean isRegisterKeepIntDialog() {
+        return registerKeepIntDialog;
+    }
 
+    public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) {
+        this.registerKeepIntDialog = registerKeepIntDialog;
+    }
 }

+ 0 - 14
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -173,12 +173,6 @@ public class Device {
 	@Schema(description = "地理坐标系, 目前支持 WGS84,GCJ02")
 	private String geoCoordSys;
 
-	/**
-	 * 树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup
-	 */
-	@Schema(description = "树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup")
-	private String treeType;
-
 	@Schema(description = "密码")
 	private String password;
 
@@ -408,14 +402,6 @@ public class Device {
 		this.geoCoordSys = geoCoordSys;
 	}
 
-	public String getTreeType() {
-		return treeType;
-	}
-
-	public void setTreeType(String treeType) {
-		this.treeType = treeType;
-	}
-
 	public String getPassword() {
 		return password;
 	}

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

@@ -183,12 +183,6 @@ public class ParentPlatform {
     @Schema(description = "创建时间")
     private String createTime;
 
-    /**
-     * 树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGroup
-     */
-    @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou")
-    private String treeType;
-
     @Schema(description = "是否作为消息通道")
     private boolean asMessageChannel;
 
@@ -424,14 +418,6 @@ public class ParentPlatform {
         this.createTime = createTime;
     }
 
-    public String getTreeType() {
-        return treeType;
-    }
-
-    public void setTreeType(String treeType) {
-        this.treeType = treeType;
-    }
-
     public boolean isAsMessageChannel() {
         return asMessageChannel;
     }

+ 0 - 10
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java

@@ -1,10 +0,0 @@
-package com.genersoft.iot.vmp.gb28181.bean;
-
-/**
- * 目录结构类型
- * @author lin
- */
-public class TreeType {
-    public static final String BUSINESS_GROUP = "BusinessGroup";
-    public static final String CIVIL_CODE = "CivilCode";
-}

+ 139 - 49
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@@ -209,59 +209,149 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
                 // 行政区划分组只需要这两项就可以
                 catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
                 catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
-                if (channel.getParentId() != null) {
-                    // 业务分组加上这一项即可,提高兼容性,
-                    catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
-//                    catalogXml.append("<ParentID>" + parentPlatform.getDeviceGBId() + "/" + channel.getParentId() + "</ParentID>\r\n");
-                }
-                if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) {
-                    // 虚拟组织增加BusinessGroupID字段
-                    catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
-                }
-                if (!channel.getChannelId().equals(parentPlatform.getDeviceGBId())) {
-                    catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
-                    if (channel.getParental() == 0) {
-                        catalogXml.append("<Status>" + (channel.isStatus() ? "ON" : "OFF") + "</Status>\r\n");
+                if (channel.getChannelId().length() <= 8) {
+                    catalogXml.append("</Item>\r\n");
+                    continue;
+                }else {
+                    if (channel.getChannelId().length() != 20) {
+                        continue;
                     }
-                }
-                if (channel.getParental() == 0) {
-                    // 通道项
-                    catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
-                    catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
-                    catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
-                    String civilCode = channel.getCivilCode() == null?parentPlatform.getAdministrativeDivision() : channel.getCivilCode();
-                    if (channel.getChannelType() != 2) {  // 业务分组/虚拟组织/行政区划 不设置以下属性
-                        catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
-                        catalogXml.append("<Owner>" + parentPlatform.getDeviceGBId()+ "</Owner>\r\n");
-                        catalogXml.append("<CivilCode>" + civilCode + "</CivilCode>\r\n");
-                        if (channel.getAddress() == null) {
-                            catalogXml.append("<Address></Address>\r\n");
-                        }else {
-                            catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
-                        }
-                        catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
-                        catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
-                        catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
-                        catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
-                        catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
-                        catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
-                        catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
-                        catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
-                        catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
-                        catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n");
-                        catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
-                        catalogXml.append("<Status>" + (channel.isStatus() ? "ON":"OFF") + "</Status>\r\n");
-                        catalogXml.append("<Longitude>" +
-                                (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
-                                + "</Longitude>\r\n");
-                        catalogXml.append("<Latitude>" +
-                                (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
-                                + "</Latitude>\r\n");
-
+                    switch (Integer.parseInt(channel.getChannelId().substring(10, 13))){
+                        case 200:
+//                            catalogXml.append("<Manufacturer>三永华通</Manufacturer>\r\n");
+//                            GitUtil gitUtil = SpringBeanFactory.getBean("gitUtil");
+//                            String model = (gitUtil == null || gitUtil.getBuildVersion() == null)?"1.0": gitUtil.getBuildVersion();
+//                            catalogXml.append("<Model>" + model + "</Manufacturer>\r\n");
+//                            catalogXml.append("<Owner>三永华通</Owner>\r\n");
+                             if (channel.getCivilCode() != null) {
+                                 catalogXml.append("<CivilCode>"+channel.getCivilCode()+"</CivilCode>\r\n");
+                             }else {
+                                 catalogXml.append("<CivilCode></CivilCode>\r\n");
+                             }
+
+                            catalogXml.append("<RegisterWay>1</RegisterWay>\r\n");
+                            catalogXml.append("<Secrecy>0</Secrecy>\r\n");
+                            break;
+                        case 215:
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }
+
+                            break;
+                        case 216:
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }else {
+                                catalogXml.append("<ParentID></ParentID>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getBusinessGroupId())) {
+                                catalogXml.append("<BusinessGroupID>" + channel.getBusinessGroupId() + "</BusinessGroupID>\r\n");
+                            }else {
+                                catalogXml.append("<BusinessGroupID></BusinessGroupID>\r\n");
+                            }
+                            break;
+                        default:
+                            // 通道项
+                            if (channel.getManufacture() != null) {
+                                catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
+                            }else {
+                                catalogXml.append("<Manufacturer></Manufacturer>\r\n");
+                            }
+                            if (channel.getSecrecy() != null) {
+                                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
+                            }else {
+                                catalogXml.append("<Secrecy></Secrecy>\r\n");
+                            }
+                            catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
+                            if (channel.getModel() != null) {
+                                catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
+                            }else {
+                                catalogXml.append("<Model></Model>\r\n");
+                            }
+                            if (channel.getOwner() != null) {
+                                catalogXml.append("<Owner>" + channel.getOwner()+ "</Owner>\r\n");
+                            }else {
+                                catalogXml.append("<Owner></Owner>\r\n");
+                            }
+                            if (channel.getCivilCode() != null) {
+                                catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
+                            }else {
+                                catalogXml.append("<CivilCode></CivilCode>\r\n");
+                            }
+                            if (channel.getAddress() == null) {
+                                catalogXml.append("<Address></Address>\r\n");
+                            }else {
+                                catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getParentId())) {
+                                catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
+                            }else {
+                                catalogXml.append("<ParentID></ParentID>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getBlock())) {
+                                catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
+                            }else {
+                                catalogXml.append("<Block></Block>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getSafetyWay())) {
+                                catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
+                            }else {
+                                catalogXml.append("<SafetyWay></SafetyWay>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getCertNum())) {
+                                catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
+                            }else {
+                                catalogXml.append("<CertNum></CertNum>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getCertifiable())) {
+                                catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
+                            }else {
+                                catalogXml.append("<Certifiable></Certifiable>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getErrCode())) {
+                                catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
+                            }else {
+                                catalogXml.append("<ErrCode></ErrCode>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getEndTime())) {
+                                catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
+                            }else {
+                                catalogXml.append("<EndTime></EndTime>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getSecrecy())) {
+                                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
+                            }else {
+                                catalogXml.append("<Secrecy></Secrecy>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getIpAddress())) {
+                                catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
+                            }else {
+                                catalogXml.append("<IPAddress></IPAddress>\r\n");
+                            }
+                            catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
+                            if (!ObjectUtils.isEmpty(channel.getPassword())) {
+                                catalogXml.append("<Password>" + channel.getPassword() + "</Password>\r\n");
+                            }else {
+                                catalogXml.append("<Password></Password>\r\n");
+                            }
+                            if (!ObjectUtils.isEmpty(channel.getPTZType())) {
+                                catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
+                            }else {
+                                catalogXml.append("<PTZType></PTZType>\r\n");
+                            }
+                            catalogXml.append("<Status>" + (channel.isStatus() ?"ON":"OFF") + "</Status>\r\n");
+
+                            catalogXml.append("<Longitude>" +
+                                    (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
+                                    + "</Longitude>\r\n");
+                            catalogXml.append("<Latitude>" +
+                                    (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
+                                    + "</Latitude>\r\n");
+                            break;
 
                     }
+                    catalogXml.append("</Item>\r\n");
                 }
-                catalogXml.append("</Item>\r\n");
             }
         }
 

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

@@ -188,6 +188,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
                                     logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
                                 }
                                 return;
+                            }else {
+                                 // TODO 可能漏回复消息
                             }
                         }
                     } else {

+ 9 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -20,7 +21,10 @@ import org.springframework.stereotype.Component;
 
 import javax.sip.RequestEvent;
 import javax.sip.header.FromHeader;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -56,6 +60,9 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 	@Autowired
 	private DynamicTask dynamicTask;
 
+	@Autowired
+	private CivilCodeFileConf civilCodeFileConf;
+
 	private final static String talkKey = "notify-request-for-catalog-task";
 
 	public void process(RequestEvent evt) {
@@ -96,7 +103,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
 					}else {
 						event = eventElement.getText().toUpperCase();
 					}
-					DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
+					DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
 
 					channel.setDeviceId(device.getDeviceId());
 					logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());

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

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.*;
@@ -79,6 +80,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 	@Autowired
 	private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor;
 
+	@Autowired
+	private CivilCodeFileConf civilCodeFileConf;
+
 	private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
 
 	@Qualifier("taskExecutor")
@@ -408,7 +412,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
 					}else {
 						event = eventElement.getText().toUpperCase();
 					}
-					DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
+					DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
 					channel.setDeviceId(device.getDeviceId());
 					logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
 					switch (event) {

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

@@ -164,7 +164,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
                 device.setStreamMode("UDP");
                 device.setCharset("GB2312");
                 device.setGeoCoordSys("WGS84");
-                device.setTreeType("CivilCode");
                 device.setDeviceId(deviceId);
                 device.setOnLine(false);
             }

+ 6 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
 
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -53,6 +54,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
     @Autowired
     private ThreadPoolTaskExecutor taskExecutor;
 
+    @Autowired
+    private CivilCodeFileConf civilCodeFileConf;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         responseMessageHandler.addHandler(cmdType, this);
@@ -100,6 +104,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
                             Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
                             if (deviceListIterator != null) {
                                 List<DeviceChannel> channelList = new ArrayList<>();
+                                List<String> parentChannelIds = new ArrayList<>();
                                 // 遍历DeviceList
                                 while (deviceListIterator.hasNext()) {
                                     Element itemDevice = deviceListIterator.next();
@@ -107,7 +112,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
                                     if (channelDeviceElement == null) {
                                         continue;
                                     }
-                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
+                                    DeviceChannel deviceChannel = XmlUtil.channelContentHandler(itemDevice, device, null, civilCodeFileConf);
                                     deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys());
                                     deviceChannel.setDeviceId(take.getDevice().getDeviceId());
 

+ 328 - 181
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java

@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.utils;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.common.CivilCodePo;
+import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
@@ -192,7 +194,7 @@ public class XmlUtil {
         CivilCode, BusinessGroup,VirtualOrganization,Other
     }
 
-    public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){
+    public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){
         DeviceChannel deviceChannel = new DeviceChannel();
         deviceChannel.setDeviceId(device.getDeviceId());
         Element channdelIdElement = itemDevice.element("DeviceID");
@@ -210,208 +212,353 @@ public class XmlUtil {
             // 除了ADD和update情况下需要识别全部内容,
             return deviceChannel;
         }
-
-        ChannelType channelType = ChannelType.Other;
-        if (channelId.length() <= 8) {
-            channelType = ChannelType.CivilCode;
-            deviceChannel.setHasAudio(false);
-        }else {
-            if (channelId.length() == 20) {
-                int code = Integer.parseInt(channelId.substring(10, 13));
-                switch (code){
-                    case 215:
-                        channelType = ChannelType.BusinessGroup;
-                        deviceChannel.setHasAudio(false);
-                        break;
-                    case 216:
-                        channelType = ChannelType.VirtualOrganization;
-                        deviceChannel.setHasAudio(false);
-                        break;
-                    case 136:
-                    case 137:
-                    case 138:
-                        deviceChannel.setHasAudio(true);
-                        break;
-                    default:
-                        deviceChannel.setHasAudio(false);
-                        break;
-
-                }
-            }
+        Element nameElement = itemDevice.element("Name");
+        if (nameElement != null) {
+            deviceChannel.setName(nameElement.getText());
         }
-
-        Element channdelNameElement = itemDevice.element("Name");
-        String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : "";
-        deviceChannel.setName(channelName);
-
-        String civilCode = XmlUtil.getText(itemDevice, "CivilCode");
-        deviceChannel.setCivilCode(civilCode);
-        if (channelType == ChannelType.CivilCode && civilCode == null) {
-            deviceChannel.setParental(1);
-            // 行政区划如果没有传递具体值,则推测一个
-            if (channelId.length() > 2) {
-                deviceChannel.setCivilCode(channelId.substring(0, channelId.length() - 2));
+        if(channelId.length() <= 8) {
+            deviceChannel.setHasAudio(false);
+            CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId);
+            if (parentCode != null) {
+                deviceChannel.setParentId(parentCode.getCode());
+                deviceChannel.setCivilCode(parentCode.getCode());
+            }else {
+                logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId);
             }
-        }
-        if (channelType.equals(ChannelType.CivilCode)) {
-            // 行政区划其他字段没必要识别了,默认在线即可
             deviceChannel.setStatus(true);
-            deviceChannel.setParental(1);
-            deviceChannel.setCreateTime(DateUtil.getNow());
-            deviceChannel.setUpdateTime(DateUtil.getNow());
             return deviceChannel;
-        }
-        /**
-         * 行政区划展示设备树与业务分组展示设备树是两种不同的模式
-         * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下:
-         * 河北省
-         *    --> 石家庄市
-         *          --> 摄像头
-         *String parentId = XmlUtil.getText(itemDevice, "ParentID");
-         if (parentId != null) {
-         if (parentId.contains("/")) {
-         String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
-         String businessGroup = parentId.substring(0, parentId.indexOf("/"));
-         deviceChannel.setParentId(lastParentId);
-         }else {
-         deviceChannel.setParentId(parentId);
-         }
-         }
-         deviceCh          --> 正定县
-         *                  --> 摄像头
-         *                  --> 摄像头
-         *
-         * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织:
-         * 业务分组
-         *    --> 虚拟组织
-         *         --> 摄像头
-         *         --> 虚拟组织
-         *             --> 摄像头
-         *             --> 摄像头
-         */
-        String parentId = XmlUtil.getText(itemDevice, "ParentID");
-        String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID");
-        if (parentId != null) {
-            if (parentId.contains("/")) {
-                String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
-                if (businessGroupID == null) {
-                    businessGroupID = parentId.substring(0, parentId.indexOf("/"));
-                }
-                deviceChannel.setParentId(lastParentId);
+        }else {
+            if(channelId.length() != 20) {
+                logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId);
+                return null;
+            }
+
+            int code = Integer.parseInt(channelId.substring(10, 13));
+            if (code == 136 || code == 137 || code == 138) {
+                deviceChannel.setHasAudio(true);
             }else {
-                deviceChannel.setParentId(parentId);
+                deviceChannel.setHasAudio(false);
             }
-            // 兼容设备通道信息中自己为自己父节点的情况
-            if (deviceChannel.getParentId().equals(deviceChannel.getChannelId())) {
-                deviceChannel.setParentId(null);
+            // 设备厂商
+            String manufacturer = getText(itemDevice, "Manufacturer");
+            // 设备型号
+            String model = getText(itemDevice, "Model");
+            // 设备归属
+            String owner = getText(itemDevice, "Owner");
+            // 行政区域
+            String civilCode = getText(itemDevice, "CivilCode");
+            // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织
+            String businessGroupID = getText(itemDevice, "BusinessGroupID");
+            // 父设备/区域/系统ID
+            String parentID = getText(itemDevice, "ParentID");
+            if (parentID != null && parentID.equalsIgnoreCase("null")) {
+                parentID = null;
             }
-        }
-        deviceChannel.setBusinessGroupId(businessGroupID);
-        if (channelType.equals(ChannelType.BusinessGroup) || channelType.equals(ChannelType.VirtualOrganization)) {
-            // 业务分组和虚拟组织 其他字段没必要识别了,默认在线即可
-            deviceChannel.setStatus(true);
-            deviceChannel.setParental(1);
-            deviceChannel.setCreateTime(DateUtil.getNow());
-            deviceChannel.setUpdateTime(DateUtil.getNow());
-            return deviceChannel;
-        }
+            // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
+            String registerWay = getText(itemDevice, "RegisterWay");
+            // 保密属性(必选)缺省为0;0:不涉密,1:涉密
+            String secrecy = getText(itemDevice, "Secrecy");
+            // 安装地址
+            String address = getText(itemDevice, "Address");
+
+            switch (code){
+                case 200:
+                    // 系统目录
+                    if (!ObjectUtils.isEmpty(manufacturer)) {
+                        deviceChannel.setManufacture(manufacturer);
+                    }
+                    if (!ObjectUtils.isEmpty(model)) {
+                        deviceChannel.setModel(model);
+                    }
+                    if (!ObjectUtils.isEmpty(owner)) {
+                        deviceChannel.setOwner(owner);
+                    }
+                    if (!ObjectUtils.isEmpty(civilCode)) {
+                        deviceChannel.setCivilCode(civilCode);
+                        deviceChannel.setParentId(civilCode);
+                    }else {
+                        if (!ObjectUtils.isEmpty(parentID)) {
+                            deviceChannel.setParentId(parentID);
+                        }
+                    }
+                    if (!ObjectUtils.isEmpty(address)) {
+                        deviceChannel.setAddress(address);
+                    }
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(registerWay)) {
+                        try {
+                            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
+                        }catch (NumberFormatException exception) {
+                            logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
+                        }
+                    }
+                    if (!ObjectUtils.isEmpty(secrecy)) {
+                        deviceChannel.setSecrecy(secrecy);
+                    }
+                    return deviceChannel;
+                case 215:
+                    // 业务分组
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) {
+                            deviceChannel.setParentId(parentID);
+                        }
+                    }else {
+                        logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId");
+                        if (!ObjectUtils.isEmpty(civilCode)) {
+                            deviceChannel.setCivilCode(civilCode);
+                        }
+                    }
+                    break;
+                case 216:
+                    // 虚拟组织
+                    deviceChannel.setStatus(true);
+                    if (!ObjectUtils.isEmpty(businessGroupID)) {
+                        deviceChannel.setBusinessGroupId(businessGroupID);
+                    }
 
-        Element statusElement = itemDevice.element("Status");
 
-        if (statusElement != null) {
-            String status = statusElement.getTextTrim().trim();
-            // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
-            if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
-                deviceChannel.setStatus(true);
-            }
-            if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
-                deviceChannel.setStatus(false);
-            }
-        }else {
-            deviceChannel.setStatus(true);
-        }
-        // 识别自带的目录标识
-        String parental = XmlUtil.getText(itemDevice, "Parental");
-        // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
-        if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
-            deviceChannel.setParental(0);
-        }else {
-            deviceChannel.setParental(1);
-        }
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (parentID.contains("/")) {
+                            String[] parentIdArray = parentID.split("/");
+                            parentID = parentIdArray[parentIdArray.length - 1];
+                        }
+                        deviceChannel.setParentId(parentID);
+                    }else {
+                        if (!ObjectUtils.isEmpty(businessGroupID)) {
+                            deviceChannel.setParentId(businessGroupID);
+                        }
+                    }
+                    break;
+                default:
+                    // 设备目录
+                    if (!ObjectUtils.isEmpty(manufacturer)) {
+                        deviceChannel.setManufacture(manufacturer);
+                    }
+                    if (!ObjectUtils.isEmpty(model)) {
+                        deviceChannel.setModel(model);
+                    }
+                    if (!ObjectUtils.isEmpty(owner)) {
+                        deviceChannel.setOwner(owner);
+                    }
+                    if (!ObjectUtils.isEmpty(civilCode)) {
+                        deviceChannel.setCivilCode(civilCode);
+                    }
+                    if (!ObjectUtils.isEmpty(businessGroupID)) {
+                        deviceChannel.setBusinessGroupId(businessGroupID);
+                    }
 
+                    // 警区
+                    String block = getText(itemDevice, "Block");
+                    if (!ObjectUtils.isEmpty(block)) {
+                        deviceChannel.setBlock(block);
+                    }
+                    if (!ObjectUtils.isEmpty(address)) {
+                        deviceChannel.setAddress(address);
+                    }
 
-        deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
-        deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
-        deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
-        deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
-        deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
-        deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
-        deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
+                    if (!ObjectUtils.isEmpty(secrecy)) {
+                        deviceChannel.setSecrecy(secrecy);
+                    }
 
-        String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay");
-        if (ObjectUtils.isEmpty(safetyWay)) {
-            deviceChannel.setSafetyWay(0);
-        } else {
-            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
-        }
+                    // 当为设备时,是否有子设备(必选)1有,0没有
+                    String parental = getText(itemDevice, "Parental");
+                    if (!ObjectUtils.isEmpty(parental)) {
+                        try {
+                            // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
+                            if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
+                                deviceChannel.setParental(0);
+                            }else {
+                                deviceChannel.setParental(1);
+                            }
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental);
+                        }
+                    }
+                    // 父设备/区域/系统ID
+                    String realParentId = parentID;
+                    if (!ObjectUtils.isEmpty(parentID)) {
+                        if (parentID.contains("/")) {
+                            String[] parentIdArray = parentID.split("/");
+                            realParentId = parentIdArray[parentIdArray.length - 1];
+                        }
+                        deviceChannel.setParentId(realParentId);
+                    }else {
+                        if (!ObjectUtils.isEmpty(businessGroupID)) {
+                            deviceChannel.setParentId(businessGroupID);
+                        }else {
+                            if (!ObjectUtils.isEmpty(civilCode)) {
+                                deviceChannel.setParentId(civilCode);
+                            }
+                        }
+                    }
+                    // 注册方式
+                    if (!ObjectUtils.isEmpty(registerWay)) {
+                        try {
+                            int registerWayInt = Integer.parseInt(registerWay);
+                            deviceChannel.setRegisterWay(registerWayInt);
+                        }catch (NumberFormatException exception) {
+                            logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
+                            deviceChannel.setRegisterWay(1);
+                        }
+                    }else {
+                        deviceChannel.setRegisterWay(1);
+                    }
 
-        String registerWay = XmlUtil.getText(itemDevice, "RegisterWay");
-        if (ObjectUtils.isEmpty(registerWay)) {
-            deviceChannel.setRegisterWay(1);
-        } else {
-            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
-        }
+                    // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式
+                    String safetyWay = getText(itemDevice, "SafetyWay");
+                    if (!ObjectUtils.isEmpty(safetyWay)) {
+                        try {
+                            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay);
+                        }
+                    }
 
-        if (XmlUtil.getText(itemDevice, "Certifiable") == null
-                || XmlUtil.getText(itemDevice, "Certifiable") == "") {
-            deviceChannel.setCertifiable(0);
-        } else {
-            deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
-        }
+                    // 证书序列号(有证书的设备必选)
+                    String certNum = getText(itemDevice, "CertNum");
+                    if (!ObjectUtils.isEmpty(certNum)) {
+                        deviceChannel.setCertNum(certNum);
+                    }
 
-        if (XmlUtil.getText(itemDevice, "ErrCode") == null
-                || XmlUtil.getText(itemDevice, "ErrCode") == "") {
-            deviceChannel.setErrCode(0);
-        } else {
-            deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
-        }
+                    // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效
+                    String certifiable = getText(itemDevice, "Certifiable");
+                    if (!ObjectUtils.isEmpty(certifiable)) {
+                        try {
+                            deviceChannel.setCertifiable(Integer.parseInt(certifiable));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable);
+                        }
+                    }
 
-        deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
-        deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
-        deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
-        if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
-            deviceChannel.setPort(0);
-        } else {
-            deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
-        }
+                    // 无效原因码(有证书且证书无效的设备必选)
+                    String errCode = getText(itemDevice, "ErrCode");
+                    if (!ObjectUtils.isEmpty(errCode)) {
+                        try {
+                            deviceChannel.setErrCode(Integer.parseInt(errCode));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode);
+                        }
+                    }
 
+                    // 证书终止有效期(有证书的设备必选)
+                    String endTime = getText(itemDevice, "EndTime");
+                    if (!ObjectUtils.isEmpty(endTime)) {
+                        deviceChannel.setEndTime(endTime);
+                    }
 
-        String longitude = XmlUtil.getText(itemDevice, "Longitude");
-        if (NumericUtil.isDouble(longitude)) {
-            deviceChannel.setLongitude(Double.parseDouble(longitude));
-        } else {
-            deviceChannel.setLongitude(0.00);
-        }
-        String latitude = XmlUtil.getText(itemDevice, "Latitude");
-        if (NumericUtil.isDouble(latitude)) {
-            deviceChannel.setLatitude(Double.parseDouble(latitude));
-        } else {
-            deviceChannel.setLatitude(0.00);
-        }
 
-        deviceChannel.setGpsTime(DateUtil.getNow());
+                    // 设备/区域/系统IP地址
+                    String ipAddress = getText(itemDevice, "IPAddress");
+                    if (!ObjectUtils.isEmpty(ipAddress)) {
+                        deviceChannel.setIpAddress(ipAddress);
+                    }
+
+                    // 设备/区域/系统端口
+                    String port = getText(itemDevice, "Port");
+                    if (!ObjectUtils.isEmpty(port)) {
+                        try {
+                            deviceChannel.setPort(Integer.parseInt(port));
+                        }catch (NumberFormatException e) {
+                            logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port);
+                        }
+                    }
+
+                    // 设备口令
+                    String password = getText(itemDevice, "Password");
+                    if (!ObjectUtils.isEmpty(password)) {
+                        deviceChannel.setPassword(password);
+                    }
+
 
+                    // 设备状态
+                    String status = getText(itemDevice, "Status");
+                    if (status != null) {
+                        // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
+                        if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
+                            deviceChannel.setStatus(true);
+                        }
+                        if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
+                            deviceChannel.setStatus(false);
+                        }
+                    }else {
+                        deviceChannel.setStatus(true);
+                    }
+
+                    // 经度
+                    String longitude = getText(itemDevice, "Longitude");
+                    if (NumericUtil.isDouble(longitude)) {
+                        deviceChannel.setLongitude(Double.parseDouble(longitude));
+                    } else {
+                        deviceChannel.setLongitude(0.00);
+                    }
+
+                    // 纬度
+                    String latitude = getText(itemDevice, "Latitude");
+                    if (NumericUtil.isDouble(latitude)) {
+                        deviceChannel.setLatitude(Double.parseDouble(latitude));
+                    } else {
+                        deviceChannel.setLatitude(0.00);
+                    }
+
+                    deviceChannel.setGpsTime(DateUtil.getNow());
+
+                    // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选
+                    String ptzType = getText(itemDevice, "PTZType");
+                    if (ObjectUtils.isEmpty(ptzType)) {
+                        //兼容INFO中的信息
+                        Element info = itemDevice.element("Info");
+                        String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
+                        if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
+                            try {
+                                deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo));
+                            }catch (NumberFormatException e){
+                                logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo);
+                            }
+                        }
+                    } else {
+                        try {
+                            deviceChannel.setPTZType(Integer.parseInt(ptzType));
+                        }catch (NumberFormatException e){
+                            logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType);
+                        }
+                    }
 
-        if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) {
-            //兼容INFO中的信息
-            Element info = itemDevice.element("Info");
-            if(XmlUtil.getText(info, "PTZType") == null || "".equals(XmlUtil.getText(info, "PTZType"))){
-                deviceChannel.setPTZType(0);
-            }else{
-                deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(info, "PTZType")));
+                    // TODO 摄像机位置类型扩展。
+                    // 1-省际检查站、
+                    // 2-党政机关、
+                    // 3-车站码头、
+                    // 4-中心广场、
+                    // 5-体育场馆、
+                    // 6-商业中心、
+                    // 7-宗教场所、
+                    // 8-校园周边、
+                    // 9-治安复杂区域、
+                    // 10-交通干线。
+                    // String positionType = getText(itemDevice, "PositionType");
+
+                    // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。
+                    // String roomType = getText(itemDevice, "RoomType");
+                    // TODO 摄像机用途属性
+                    // String useType = getText(itemDevice, "UseType");
+                    // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光
+                    // String supplyLightType = getText(itemDevice, "SupplyLightType");
+                    // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。
+                    // String directionType = getText(itemDevice, "DirectionType");
+                    // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定
+                    // String resolution = getText(itemDevice, "Resolution");
+
+                    // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4
+                    // String downloadSpeed = getText(itemDevice, "DownloadSpeed");
+                    // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层)
+                    // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode");
+                    // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强
+                    // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode");
+
+
+                    deviceChannel.setSecrecy(secrecy);
+                    break;
             }
-        } else {
-            deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
         }
 
         return deviceChannel;

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

@@ -50,8 +50,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
                 device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
             }
 
-
-
             if ("WGS84".equals(device.getGeoCoordSys())) {
                 deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                 deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
@@ -262,4 +260,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
             }
         }
     }
+
+
 }

+ 27 - 146
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java

@@ -122,9 +122,10 @@ public class DeviceServiceImpl implements IDeviceService {
         }
 
         // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
-        if (device.getCreateTime() == null) {
+        if (deviceInDb == null) {
             device.setOnLine(true);
             device.setCreateTime(now);
+            device.setUpdateTime(now);
             logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId());
             deviceMapper.add(device);
             redisCatchStorage.updateDevice(device);
@@ -389,63 +390,11 @@ public class DeviceServiceImpl implements IDeviceService {
         if (device == null) {
             return null;
         }
-        if (parentId == null || parentId.equals(deviceId)) {
-            // 字根节点开始查询
-            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog);
-            return transportChannelsToTree(rootNodes, "");
+        if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
+            parentId = null;
         }
-
-        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
-            if (parentId.length()%2 != 0) {
-                return null;
-            }
-            // 使用行政区划展示树
-//            if (parentId.length() > 10) {
-//                // TODO 可能是行政区划与业务分组混杂的情形
-//                return null;
-//            }
-
-            if (parentId.length() == 10 ) {
-                if (onlyCatalog) {
-                    return null;
-                }
-                // parentId为行业编码, 其下不会再有行政区划
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-                List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channels, parentId);
-                return trees;
-            }
-            // 查询其下的行政区划和摄像机
-            List<DeviceChannel> channelsForCivilCode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, parentId, parentId.length() + 2);
-            if (!onlyCatalog) {
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-
-                for(DeviceChannel channel : channels) {
-                    boolean flag = false;
-                    for(DeviceChannel deviceChannel : channelsForCivilCode) {
-                        if(channel.getChannelId().equals(deviceChannel.getChannelId())) {
-                            flag = true;
-                        }
-                    }
-                    if(!flag) {
-                        channelsForCivilCode.add(channel);
-                    }
-                }
-            }
-            List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channelsForCivilCode, parentId);
-            return trees;
-
-        }
-        // 使用业务分组展示树
-        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
-            if (parentId.length() < 14 ) {
-                return null;
-            }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
-            List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(deviceChannels, parentId);
-            return trees;
-        }
-
-        return null;
+        List<DeviceChannel> rootNodes = deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, onlyCatalog);
+        return transportChannelsToTree(rootNodes, "");
     }
 
     @Override
@@ -454,42 +403,11 @@ public class DeviceServiceImpl implements IDeviceService {
         if (device == null) {
             return null;
         }
-        if (parentId == null || parentId.equals(deviceId)) {
-            // 字根节点开始查询
-            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true);
-            return rootNodes;
-        }
-
-        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
-            if (parentId.length()%2 != 0) {
-                return null;
-            }
-            // 使用行政区划展示树
-            if (parentId.length() > 10) {
-                // TODO 可能是行政区划与业务分组混杂的情形
-                return null;
-            }
-
-            if (parentId.length() == 10 ) {
-                // parentId为行业编码, 其下不会再有行政区划
-                List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-                return channels;
-            }
-            // 查询其下的行政区划和摄像机
-            List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
-            return channels;
-
-        }
-        // 使用业务分组展示树
-        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
-            if (parentId.length() < 14 ) {
-                return null;
-            }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
-            return deviceChannels;
+        if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
+            return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, null, false);
+        }else {
+            return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, false);
         }
-
-        return null;
     }
 
     private List<BaseTree<DeviceChannel>> transportChannelsToTree(List<DeviceChannel> channels, String parentId) {
@@ -509,65 +427,26 @@ public class DeviceServiceImpl implements IDeviceService {
             node.setPid(parentId);
             node.setBasicData(channel);
             node.setParent(false);
-            if (channel.getChannelId().length() > 8) {
-                if (channel.getChannelId().length() > 13) {
-                    String gbCodeType = channel.getChannelId().substring(10, 13);
-                    node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
-                }
-            }else {
+            if (channel.getChannelId().length() <= 8) {
                 node.setParent(true);
-            }
-            treeNotes.add(node);
-        }
-        Collections.sort(treeNotes);
-        return treeNotes;
-    }
-
-    private List<DeviceChannel> getRootNodes(String deviceId, boolean isCivilCode, boolean haveCatalog, boolean haveChannel) {
-        if (!haveCatalog && !haveChannel) {
-            return null;
-        }
-        List<DeviceChannel> result = new ArrayList<>();
-        if (isCivilCode) {
-            // 使用行政区划
-            Integer length= deviceChannelMapper.getChannelMinLength(deviceId);
-            if (length == null) {
-                return null;
-            }
-            if (length <= 10) {
-                if (haveCatalog) {
-                    List<DeviceChannel> provinceNode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, null, length);
-                    if (provinceNode != null && provinceNode.size() > 0) {
-                        result.addAll(provinceNode);
-                    }
-                }
-
-                if (haveChannel) {
-                    // 查询那些civilCode不在通道中的不规范通道,放置在根目录
-                    List<DeviceChannel> nonstandardNode = deviceChannelMapper.getChannelWithoutCivilCode(deviceId);
-                    if (nonstandardNode != null && nonstandardNode.size() > 0) {
-                        result.addAll(nonstandardNode);
-                    }
-                }
             }else {
-                if (haveChannel) {
-                    List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null,null);
-                    if (deviceChannels != null && deviceChannels.size() > 0) {
-                        result.addAll(deviceChannels);
+                if (channel.getChannelId().length() != 20) {
+                    node.setParent(channel.getParental() == 1);
+                }else {
+                    try {
+                        int type = Integer.parseInt(channel.getChannelId().substring(10, 13));
+                        if (type == 215 || type == 216 || type == 200) {
+                            node.setParent(true);
+                        }
+                    }catch (NumberFormatException e) {
+                        node.setParent(false);
                     }
                 }
             }
-
-        }else {
-            // 使用业务分组+虚拟组织
-
-            // 只获取业务分组
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.getBusinessGroups(deviceId, ChannelIdType.BUSINESS_GROUP);
-            if (deviceChannels != null && deviceChannels.size() > 0) {
-                result.addAll(deviceChannels);
-            }
+            treeNotes.add(node);
         }
-        return result;
+        Collections.sort(treeNotes);
+        return treeNotes;
     }
 
     @Override
@@ -617,7 +496,6 @@ public class DeviceServiceImpl implements IDeviceService {
         }
         deviceInStore.setSdpIp(device.getSdpIp());
         deviceInStore.setCharset(device.getCharset());
-        deviceInStore.setTreeType(device.getTreeType());
 
         //  目录订阅相关的信息
         if (device.getSubscribeCycleForCatalog() > 0) {
@@ -673,6 +551,9 @@ public class DeviceServiceImpl implements IDeviceService {
         }catch (Exception e) {
             dataSourceTransactionManager.rollback(transactionStatus);
         }
+        if (result) {
+            redisCatchStorage.removeDevice(deviceId);
+        }
         return result;
     }
 

+ 16 - 27
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java

@@ -113,20 +113,15 @@ public class GbStreamServiceImpl implements IGbStreamService {
         deviceChannel.setStatus(gbStream.isStatus());
 
         deviceChannel.setRegisterWay(1);
-        deviceChannel.setCivilCode(platform.getAdministrativeDivision());
-
-        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
-            deviceChannel.setCivilCode(catalogId);
-        }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
-            PlatformCatalog catalog = catalogMapper.select(catalogId);
-            if (catalog == null) {
-                deviceChannel.setParentId(platform.getDeviceGBId());
-                deviceChannel.setBusinessGroupId(null);
-            }else {
-                deviceChannel.setParentId(catalog.getId());
-                deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-            }
 
+        PlatformCatalog catalog = catalogMapper.select(catalogId);
+        if (catalog != null) {
+            deviceChannel.setCivilCode(catalog.getCivilCode());
+            deviceChannel.setParentId(catalog.getParentId());
+            deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
+        }else {
+            deviceChannel.setCivilCode(platform.getAdministrativeDivision());
+            deviceChannel.setParentId(platform.getDeviceGBId());
         }
 
         deviceChannel.setModel("live");
@@ -221,20 +216,14 @@ public class GbStreamServiceImpl implements IGbStreamService {
         deviceChannel.setStatus(status != null && status);
 
         deviceChannel.setRegisterWay(1);
-        deviceChannel.setCivilCode(platform.getAdministrativeDivision());
-
-        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
-            deviceChannel.setCivilCode(catalogId);
-        }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
-            PlatformCatalog catalog = catalogMapper.select(catalogId);
-            if (catalog == null) {
-                deviceChannel.setParentId(platform.getDeviceGBId());
-                deviceChannel.setBusinessGroupId(null);
-            }else {
-                deviceChannel.setParentId(catalog.getId());
-                deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-            }
-
+        PlatformCatalog catalog = catalogMapper.select(catalogId);
+        if (catalog != null) {
+            deviceChannel.setCivilCode(catalog.getCivilCode());
+            deviceChannel.setParentId(catalog.getParentId());
+            deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
+        }else {
+            deviceChannel.setCivilCode(platform.getAdministrativeDivision());
+            deviceChannel.setParentId(platform.getDeviceGBId());
         }
 
         deviceChannel.setModel("live");

+ 4 - 9
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java

@@ -126,22 +126,17 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
         List<DeviceChannel> deviceChannelList = new ArrayList<>();
         if (channelReduces.size() > 0){
             PlatformCatalog catalog = catalogManager.select(catalogId);
-            if (catalog == null && !catalogId.equals(platform.getDeviceGBId())) {
+            if (catalog == null || !catalogId.equals(platform.getDeviceGBId())) {
                 logger.warn("未查询到目录{}的信息", catalogId);
                 return null;
             }
             for (ChannelReduce channelReduce : channelReduces) {
                 DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
                 deviceChannel.setParental(0);
+                deviceChannel.setCivilCode(catalog.getCivilCode());
+                deviceChannel.setParentId(catalog.getParentId());
+                deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
                 deviceChannelList.add(deviceChannel);
-                if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
-                    deviceChannel.setCivilCode(catalogId);
-                }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
-                    deviceChannel.setParentId(catalogId);
-                    if (catalog != null) {
-                        deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-                    }
-                }
             }
         }
         return deviceChannelList;

+ 41 - 42
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java

@@ -35,6 +35,8 @@ import java.util.Map;
 public class PlatformServiceImpl implements IPlatformService {
 
     private final static String REGISTER_KEY_PREFIX = "platform_register_";
+
+    private final static String REGISTER_FAIL_AGAIN_KEY_PREFIX = "platform_register_fail_again_";
     private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_";
 
     private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
@@ -132,14 +134,6 @@ public class PlatformServiceImpl implements IPlatformService {
         ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId());
         ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId());
         parentPlatform.setUpdateTime(DateUtil.getNow());
-        if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
-            // 目录结构发生变化,清空之前的关联关系
-            logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());
-            catalogMapper.delByPlatformId(parentPlatformOld.getServerGBId());
-            platformChannelMapper.delByPlatformId(parentPlatformOld.getServerGBId());
-            platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId());
-        }
-
 
         // 停止心跳定时
         final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId();
@@ -150,12 +144,11 @@ public class PlatformServiceImpl implements IPlatformService {
         // 注销旧的
         try {
             if (parentPlatformOld.isStatus()) {
-                logger.info("保存平台{}时发现平台在线,发送注销命令", parentPlatformOld.getServerGBId());
+                logger.info("保存平台{}时发现平台在线,发送注销命令", parentPlatformOld.getServerGBId());
                 commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> {
                     logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId());
                 });
             }
-
         } catch (InvalidArgumentException | ParseException | SipException e) {
             logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
         }
@@ -188,9 +181,6 @@ public class PlatformServiceImpl implements IPlatformService {
                 logger.error("[命令发送失败] 国标级联: {}", e.getMessage());
             }
         }
-        // 重新开启定时注册, 使用续订消息
-        // 重新开始心跳保活
-
 
         return false;
     }
@@ -199,6 +189,9 @@ public class PlatformServiceImpl implements IPlatformService {
     @Override
     public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) {
         logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId());
+        final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId();
+        dynamicTask.stop(registerFailAgainTaskKey);
+
         platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true);
         ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
         if (parentPlatformCatch == null) {
@@ -239,15 +232,9 @@ public class PlatformServiceImpl implements IPlatformService {
                                     // 此时是第三次心跳超时, 平台离线
                                     if (platformCatch.getKeepAliveReply()  == 2) {
                                         // 设置平台离线,并重新注册
-                                        logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId());
-                                        try {
-                                            commanderForPlatform.register(parentPlatform, eventResult1 -> {
-                                                logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId());
-                                                offline(parentPlatform, false);
-                                            }, null);
-                                        } catch (InvalidArgumentException | ParseException | SipException e) {
-                                            logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage());
-                                        }
+                                        logger.info("[国标级联] 三次心跳超时, 平台{}({})离线", parentPlatform.getName(), parentPlatform.getServerGBId());
+                                        offline(parentPlatform, false);
+
                                     }
 
                                 }else {
@@ -273,21 +260,22 @@ public class PlatformServiceImpl implements IPlatformService {
 
     private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){
         try {
-            // 设置超时重发, 后续从底层支持消息重发
-            String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout";
-            if (dynamicTask.isAlive(key)) {
-                return;
+            // 不在同一个会话中续订则每次全新注册
+            if (!userSetting.isRegisterKeepIntDialog()) {
+                sipTransactionInfo = null;
+            }
+
+            if (sipTransactionInfo == null) {
+                logger.info("[国标级联] 平台:{}注册即将到期,开始重新注册", parentPlatform.getServerGBId());
+            }else {
+                logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
             }
-            dynamicTask.startDelay(key, ()->{
-                registerTask(parentPlatform, sipTransactionInfo);
-            }, 1000);
-            logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
+
             commanderForPlatform.register(parentPlatform, sipTransactionInfo,  eventResult -> {
-                dynamicTask.stop(key);
+                logger.info("[国标级联] 平台:{}注册失败,{}:{}", parentPlatform.getServerGBId(),
+                        eventResult.statusCode, eventResult.msg);
                 offline(parentPlatform, false);
-            },eventResult -> {
-                dynamicTask.stop(key);
-            });
+            }, null);
         } catch (InvalidArgumentException | ParseException | SipException e) {
             logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage());
         }
@@ -308,24 +296,35 @@ public class PlatformServiceImpl implements IPlatformService {
         // 停止所有推流
         logger.info("[平台离线] {}, 停止所有推流", parentPlatform.getServerGBId());
         stopAllPush(parentPlatform.getServerGBId());
-        if (stopRegister) {
-            // 清除注册定时
-            logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId());
-            final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
-            if (dynamicTask.contains(registerTaskKey)) {
-                dynamicTask.stop(registerTaskKey);
-            }
+
+        // 清除注册定时
+        logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId());
+        final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
+        if (dynamicTask.contains(registerTaskKey)) {
+            dynamicTask.stop(registerTaskKey);
         }
         // 清除心跳定时
         logger.info("[平台离线] {}, 停止定时发送心跳任务", parentPlatform.getServerGBId());
         final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
         if (dynamicTask.contains(keepaliveTaskKey)) {
-            // 添加心跳任务
+            // 清除心跳任务
             dynamicTask.stop(keepaliveTaskKey);
         }
         // 停止目录订阅回复
         logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId());
         subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
+        // 发起定时自动重新注册
+        if (!stopRegister) {
+            // 设置为60秒自动尝试重新注册
+            final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId();
+            ParentPlatform platform = platformMapper.getParentPlatById(parentPlatform.getId());
+            if (platform.isEnable()) {
+                dynamicTask.startCron(registerFailAgainTaskKey,
+                        ()-> registerTask(platform, null),
+                        userSetting.getRegisterAgainAfterTime() * 1000);
+            }
+
+        }
     }
 
     private void stopAllPush(String platformId) {

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

@@ -451,10 +451,18 @@ public interface DeviceChannelMapper {
     @Select("select count(1) from wvp_device_channel")
     int getAllChannelCount();
 
-
-    /*=================设备主子码流逻辑START==============*/
+    // 设备主子码流逻辑START
     @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_id=#{deviceId}"})
     void clearPlay(String deviceId);
-    /*=================设备主子码流逻辑END==============*/
+    // 设备主子码流逻辑END
+    @Select(value = {" <script>" +
+            "select * " +
+            "from device_channel " +
+            "where device_id=#{deviceId}" +
+            " <if test='parentId != null '> and parent_id = #{parentId} </if>" +
+            " <if test='parentId == null '> and parent_id is null </if>" +
+            " <if test='onlyCatalog == true '> and parental = 1 </if>" +
+            " </script>"})
+    List<DeviceChannel> getSubChannelsByDeviceId(String deviceId, String parentId, boolean onlyCatalog);
 
 }

+ 0 - 9
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java

@@ -40,7 +40,6 @@ public interface DeviceMapper {
             "ssrc_check," +
             "as_message_channel," +
             "geo_coord_sys," +
-            "tree_type," +
             "on_line," +
             "media_server_id," +
             "switch_primary_sub_stream," +
@@ -75,7 +74,6 @@ public interface DeviceMapper {
                 "ssrc_check,"+
                 "as_message_channel,"+
                 "geo_coord_sys,"+
-                "tree_type,"+
                 "on_line"+
             ") VALUES (" +
                 "#{deviceId}," +
@@ -104,7 +102,6 @@ public interface DeviceMapper {
                 "#{ssrcCheck}," +
                 "#{asMessageChannel}," +
                 "#{geoCoordSys}," +
-                "#{treeType}," +
                 "#{onLine}" +
             ")")
     int add(Device device);
@@ -159,7 +156,6 @@ public interface DeviceMapper {
             "ssrc_check,"+
             "as_message_channel,"+
             "geo_coord_sys,"+
-            "tree_type,"+
             "on_line,"+
             "media_server_id,"+
             "switch_primary_sub_stream switchPrimarySubStream,"+
@@ -201,7 +197,6 @@ public interface DeviceMapper {
             "ssrc_check,"+
             "as_message_channel,"+
             "geo_coord_sys,"+
-            "tree_type,"+
             "on_line"+
             " FROM wvp_device WHERE on_line = true")
     List<Device> getOnlineDevices();
@@ -232,7 +227,6 @@ public interface DeviceMapper {
             "ssrc_check,"+
             "as_message_channel,"+
             "geo_coord_sys,"+
-            "tree_type,"+
             "on_line"+
             " FROM wvp_device WHERE ip = #{host} AND port=#{port}")
     Device getDeviceByHostAndPort(String host, int port);
@@ -254,7 +248,6 @@ public interface DeviceMapper {
             "<if test=\"ssrcCheck != null\">, ssrc_check=#{ssrcCheck}</if>" +
             "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" +
             "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" +
-            "<if test=\"treeType != null\">, tree_type=#{treeType}</if>" +
             "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" +
             "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" +
             "WHERE device_id=#{deviceId}"+
@@ -272,7 +265,6 @@ public interface DeviceMapper {
             "ssrc_check,"+
             "as_message_channel,"+
             "geo_coord_sys,"+
-            "tree_type,"+
             "on_line,"+
             "media_server_id,"+
             "switch_primary_sub_stream"+
@@ -287,7 +279,6 @@ public interface DeviceMapper {
             "#{ssrcCheck}," +
             "#{asMessageChannel}," +
             "#{geoCoordSys}," +
-            "#{treeType}," +
             "#{onLine}," +
             "#{mediaServerId}," +
             "#{switchPrimarySubStream}" +

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

@@ -16,10 +16,10 @@ public interface ParentPlatformMapper {
 
     @Insert("INSERT INTO wvp_platform (enable, name, server_gb_id, server_gb_domain, server_ip, server_port,device_gb_id,device_ip,"+
             "device_port,username,password,expires,keep_timeout,transport,character_set,ptz,rtcp,as_message_channel,"+
-            "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time,tree_type) " +
+            "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time) " +
             "            VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " +
             "            #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{asMessageChannel}, " +
-            "            #{status},  #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
+            "            #{status},  #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})")
     int addParentPlatform(ParentPlatform parentPlatform);
 
     @Update("UPDATE wvp_platform " +
@@ -47,7 +47,6 @@ public interface ParentPlatformMapper {
             "administrative_division=#{administrativeDivision}, " +
             "create_time=#{createTime}, " +
             "update_time=#{updateTime}, " +
-            "tree_type=#{treeType}, " +
             "catalog_id=#{catalogId} " +
             "WHERE id=#{id}")
     int updateParentPlatform(ParentPlatform parentPlatform);

+ 84 - 60
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java

@@ -128,51 +128,56 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		List<DeviceChannel> addChannels = new ArrayList<>();
 		StringBuilder stringBuilder = new StringBuilder();
 		Map<String, Integer> subContMap = new HashMap<>();
-		if (deviceChannelList.size() > 0) {
-			// 数据去重
-			Set<String> gbIdSet = new HashSet<>();
-			for (DeviceChannel deviceChannel : deviceChannelList) {
-				if (!gbIdSet.contains(deviceChannel.getChannelId())) {
-					gbIdSet.add(deviceChannel.getChannelId());
-					deviceChannel.setUpdateTime(DateUtil.getNow());
-					if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
-						deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
-						deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
-						if (allChannelMap.get(deviceChannel.getChannelId()).isStatus() !=deviceChannel.isStatus()){
-							List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
-							if (!CollectionUtils.isEmpty(strings)){
-								strings.forEach(platformId->{
-									eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.isStatus()?CatalogEvent.ON:CatalogEvent.OFF);
-								});
-							}
-						}
-						updateChannels.add(deviceChannel);
-					}else {
-						deviceChannel.setCreateTime(DateUtil.getNow());
-						addChannels.add(deviceChannel);
-					}
-					channels.add(deviceChannel);
-					if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
-						if (subContMap.get(deviceChannel.getParentId()) == null) {
-							subContMap.put(deviceChannel.getParentId(), 1);
-						}else {
-							Integer count = subContMap.get(deviceChannel.getParentId());
-							subContMap.put(deviceChannel.getParentId(), count++);
-						}
+
+		// 数据去重
+		Set<String> gbIdSet = new HashSet<>();
+		for (DeviceChannel deviceChannel : deviceChannelList) {
+			if (gbIdSet.contains(deviceChannel.getChannelId())) {
+				stringBuilder.append(deviceChannel.getChannelId()).append(",");
+				continue;
+			}
+			gbIdSet.add(deviceChannel.getChannelId());
+			if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
+				deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
+				deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
+				if (allChannelMap.get(deviceChannel.getChannelId()).isStatus() !=deviceChannel.isStatus()){
+					List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
+					if (!CollectionUtils.isEmpty(strings)){
+						strings.forEach(platformId->{
+							eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.isStatus()?CatalogEvent.ON:CatalogEvent.OFF);
+						});
 					}
+
+				}
+				deviceChannel.setUpdateTime(DateUtil.getNow());
+				updateChannels.add(deviceChannel);
+			}else {
+				deviceChannel.setCreateTime(DateUtil.getNow());
+				deviceChannel.setUpdateTime(DateUtil.getNow());
+				addChannels.add(deviceChannel);
+			}
+			channels.add(deviceChannel);
+			if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
+				if (subContMap.get(deviceChannel.getParentId()) == null) {
+					subContMap.put(deviceChannel.getParentId(), 1);
 				}else {
-					stringBuilder.append(deviceChannel.getChannelId()).append(",");
+					Integer count = subContMap.get(deviceChannel.getParentId());
+					subContMap.put(deviceChannel.getParentId(), count++);
 				}
 			}
-			if (channels.size() > 0) {
-				for (DeviceChannel channel : channels) {
-					if (subContMap.get(channel.getChannelId()) != null){
-						channel.setSubCount(subContMap.get(channel.getChannelId()));
+		}
+		if (channels.size() > 0) {
+			for (DeviceChannel channel : channels) {
+				if (subContMap.get(channel.getChannelId()) != null){
+					Integer count = subContMap.get(channel.getChannelId());
+					if (count > 0) {
+						channel.setSubCount(count);
+						channel.setParental(1);
 					}
 				}
 			}
-
 		}
+
 		if (stringBuilder.length() > 0) {
 			logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder);
 		}
@@ -795,25 +800,49 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		if (platform == null) {
 			return 0;
 		}
-		if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
-			if (platform.getDeviceGBId().equals(platformCatalog.getParentId())) {
-				// 第一层节点
-				platformCatalog.setBusinessGroupId(platformCatalog.getId());
-				platformCatalog.setParentId(platform.getDeviceGBId());
-			}else {
-				// 获取顶层的
-				PlatformCatalog topCatalog = getTopCatalog(platformCatalog.getParentId(), platform.getDeviceGBId());
-				platformCatalog.setBusinessGroupId(topCatalog.getId());
+		if (platformCatalog.getId().length() <= 8) {
+			platformCatalog.setCivilCode(platformCatalog.getParentId());
+		}else {
+			if (platformCatalog.getId().length() != 20) {
+				return 0;
 			}
-		}
-		if (platform.getTreeType().equals(TreeType.CIVIL_CODE)) {
-			platformCatalog.setCivilCode(platformCatalog.getId());
-			if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) {
-				// 第一层节点
-				platformCatalog.setParentId(platform.getDeviceGBId());
+			if (platformCatalog.getParentId() != null) {
+				switch (Integer.parseInt(platformCatalog.getId().substring(10, 13))){
+					case 200:
+					case 215:
+						if (platformCatalog.getParentId().length() <= 8) {
+							platformCatalog.setCivilCode(platformCatalog.getParentId());
+						}else {
+							PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId());
+							if (catalog != null) {
+								platformCatalog.setCivilCode(catalog.getCivilCode());
+							}
+						}
+						break;
+					case 216:
+						if (platformCatalog.getParentId().length() <= 8) {
+							platformCatalog.setCivilCode(platformCatalog.getParentId());
+						}else {
+							PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId());
+							if (catalog == null) {
+								logger.warn("[添加目录] 无法获取目录{}的CivilCode和BusinessGroupId", platformCatalog.getPlatformId());
+								break;
+							}
+							platformCatalog.setCivilCode(catalog.getCivilCode());
+							if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 215) {
+								platformCatalog.setBusinessGroupId(platformCatalog.getParentId());
+							}else {
+								if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 216) {
+									platformCatalog.setBusinessGroupId(catalog.getBusinessGroupId());
+								}
+							}
+						}
+						break;
+					default:
+						break;
+				}
 			}
 		}
-
 		int result = catalogMapper.add(platformCatalog);
 		if (result > 0) {
 			DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog);
@@ -937,19 +966,14 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		DeviceChannel deviceChannel = new DeviceChannel();
 		deviceChannel.setChannelId(catalog.getId());
 		deviceChannel.setName(catalog.getName());
-		deviceChannel.setLongitude(0.0);
-		deviceChannel.setLatitude(0.0);
 		deviceChannel.setDeviceId(platform.getDeviceGBId());
 		deviceChannel.setManufacture("wvp-pro");
 		deviceChannel.setStatus(true);
 		deviceChannel.setParental(1);
 
 		deviceChannel.setRegisterWay(1);
-		// 行政区划应该是Domain的前八位
-		if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
-			deviceChannel.setParentId(catalog.getParentId());
-			deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
-		}
+		deviceChannel.setParentId(catalog.getParentId());
+		deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
 
 		deviceChannel.setModel("live");
 		deviceChannel.setOwner("wvp-pro");

+ 6 - 2
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java

@@ -403,8 +403,12 @@ public class PlatformController {
         if (platform == null) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台未找到");
         }
-        if (platformId.equals(parentId)) {
-            parentId = platform.getDeviceGBId();
+//        if (platformId.equals(parentId)) {
+//            parentId = platform.getDeviceGBId();
+//        }
+
+        if (platformId.equals(platform.getDeviceGBId())) {
+            parentId = null;
         }
 
         return storager.getChildrenCatalogByPlatform(platformId, parentId);

+ 4 - 0
src/main/resources/all-application.yml

@@ -202,6 +202,10 @@ user-settings:
     device-status-notify: false
     # 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
     use-custom-ssrc-for-parent-invite: true
+    # 国标级联离线后多久重试一次注册
+    register-again-after-time: 60
+    # 国标续订方式,true为续订,每次注册在同一个会话里,false为重新注册,每次使用新的会话
+    register-keep-int-dialog: false
     # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
     allowed-origins:
         - http://localhost:8008

文件差異過大導致無法顯示
+ 3220 - 0
src/main/resources/civilCode.csv


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

@@ -144,7 +144,7 @@ export default {
     },
     chooseChannel: function(platform) {
         console.log("platform.name: " + platform.name)
-       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, platform.treeType, this.initData)
+       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, this.initData)
     },
     initData: function() {
       this.getPlatformList();

+ 27 - 17
web_src/src/components/dialog/catalogEdit.vue

@@ -46,12 +46,11 @@
 export default {
   name: "catalogEdit",
   computed: {},
-  props: ['platformId'],
+  props: ['platformId', 'platformDeviceId'],
   created() {},
   data() {
     let checkId = (rule, value, callback) => {
       console.log("checkId")
-      console.log(this.treeType)
       console.log(rule)
       console.log(value)
       console.log(value.length)
@@ -59,21 +58,34 @@ export default {
       if (!value) {
         return callback(new Error('编号不能为空'));
       }
-      if (this.treeType === "BusinessGroup" && value.length !== 20) {
-        return callback(new Error('编号必须由20位数字组成'));
-      }
-      if (this.treeType === "CivilCode" && value.length <= 8 && value.length%2 !== 0) {
-        return callback(new Error('行政区划必须是八位以下的偶数个数字组成'));
-      }
-      if (this.treeType === "BusinessGroup") {
+      if (value.trim().length <= 8) {
+        if (value.trim().length%2 !== 0) {
+          return callback(new Error('行政区划编号必须为2/4/6/8位'));
+        }
+        if (this.form.parentId !== this.platformDeviceId && this.form.parentId.length >= value.trim().length) {
+          return callback(new Error('行政区划编号长度应该每次两位递增'));
+        }
+      }else {
+        if (value.trim().length !== 20) {
+          return callback(new Error('编号必须为2/4/6/8位的行政区划或20位的虚拟组织/业务分组'));
+        }
         let catalogType = value.substring(10, 13);
         console.log(catalogType)
-        // 216 为虚拟组织 215 为业务分组;目录第一级必须为业务分组, 业务分组下为虚拟组织,虚拟组织下可以有其他虚拟组织
-        if (this.level === 1 && catalogType !== "215") {
-          return callback(new Error('业务分组模式下第一层目录的编号11到13位必须为215'));
+        if (catalogType !== "215" && catalogType !== "216") {
+          return callback(new Error('编号错误,业务分组11-13位为215,虚拟组织11-13位为216'));
         }
-        if (this.level > 1 && catalogType !== "216") {
-          return callback(new Error('业务分组模式下第一层以下目录的编号11到13位必须为216'));
+        if (catalogType === "216") {
+
+          if (this.form.parentId !== this.platformDeviceId){
+            if (this.form.parentId.length <= 8) {
+              return callback(new Error('编号错误,建立虚拟组织前必须先建立业务分组(11-13位为215)'));
+            }
+          }
+        }
+        if (catalogType === "215") {
+          if (this.form.parentId.length === "215") {
+            return callback(new Error('编号错误,业务分组下只能建立虚拟组织(11-13位为216)'));
+          }
         }
       }
       callback();
@@ -83,7 +95,6 @@ export default {
       showDialog: false,
       isLoging: false,
       isEdit: false,
-      treeType: null,
       level: 0,
       form: {
         id: null,
@@ -98,7 +109,7 @@ export default {
     };
   },
   methods: {
-    openDialog: function (isEdit, id, name, parentId, treeType, level, callback) {
+    openDialog: function (isEdit, id, name, parentId, level, callback) {
       console.log("parentId: " + parentId)
       console.log(this.form)
       this.isEdit = isEdit;
@@ -108,7 +119,6 @@ export default {
       this.form.parentId = parentId;
       this.showDialog = true;
       this.submitCallback = callback;
-      this.treeType = treeType;
       this.level = level;
     },
     onSubmit: function () {

+ 2 - 4
web_src/src/components/dialog/chooseChannel.vue

@@ -8,7 +8,7 @@
             <el-tab-pane label="目录结构" name="catalog">
               <el-container>
                 <el-main v-bind:style="{backgroundColor: '#FFF', maxHeight:  winHeight + 'px'}">
-                  <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog>
+                  <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" ></chooseChannelForCatalog>
                 </el-main>
               </el-container>
             </el-tab-pane>
@@ -67,14 +67,13 @@ export default {
             platformName: "",
             defaultCatalogId: "",
             showDialog: false,
-            treeType: null,
             chooseData: {},
             winHeight: window.innerHeight - 250,
 
         };
     },
     methods: {
-        openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, treeType, closeCallback) {
+        openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, closeCallback) {
             console.log("defaultCatalogId: " + defaultCatalogId)
             this.platformId = platformId
             this.platformDeviceId = platformDeviceId
@@ -82,7 +81,6 @@ export default {
             this.defaultCatalogId = defaultCatalogId
             this.showDialog = true
             this.closeCallback = closeCallback
-            this.treeType = treeType
         },
         tabClick (tab, event){
 

+ 5 - 4
web_src/src/components/dialog/chooseChannelForCatalog.vue

@@ -28,7 +28,7 @@
       </span>
      </el-tree>
    </div>
-    <catalogEdit ref="catalogEdit" :platformId="platformId"></catalogEdit>
+    <catalogEdit ref="catalogEdit" :platformId="platformId" :platformDeviceId="platformDeviceId"></catalogEdit>
 </div>
 </template>
 
@@ -38,7 +38,7 @@
 import catalogEdit from './catalogEdit.vue'
 export default {
     name: 'chooseChannelForCatalog',
-    props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'],
+    props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange'],
     created() {
         this.chooseId = this.defaultCatalogId;
         this.defaultCatalogIdSign = this.defaultCatalogId;
@@ -101,9 +101,10 @@ export default {
         },
         addCatalog: function (parentId, node){
           let that = this;
-          console.log(this.treeType)
+          console.log(this.platformId)
+          console.log(parentId)
           // 打开添加弹窗
-          that.$refs.catalogEdit.openDialog(false, null, null, parentId, this.treeType, node.level, ()=>{
+          that.$refs.catalogEdit.openDialog(false, null, null, parentId, node.level, ()=>{
             node.loaded = false
             node.expand();
           });

+ 0 - 6
web_src/src/components/dialog/deviceEdit.vue

@@ -49,12 +49,6 @@
               <el-option key="GCJ02" label="GCJ02" value="GCJ02"></el-option>
             </el-select>
           </el-form-item>
-          <el-form-item label="目录结构" prop="treeType" >
-            <el-select v-model="form.treeType" style="float: left; width: 100%" >
-              <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option>
-              <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option>
-            </el-select>
-          </el-form-item>
           <el-form-item v-if="this.isEdit" label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" >
             <el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input>
           </el-form-item>

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

@@ -78,12 +78,6 @@
                   <el-option label="8" value="8"></el-option>
                 </el-select>
               </el-form-item>
-              <el-form-item label="目录结构" prop="treeType" >
-                <el-select v-model="platform.treeType" style="width: 100%" @change="treeTypeChange">
-                  <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option>
-                  <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option>
-                </el-select>
-              </el-form-item>
               <el-form-item label="字符集" prop="characterSet">
                 <el-select
                   v-model="platform.characterSet"
@@ -164,7 +158,6 @@ export default {
         startOfflinePush: false,
         catalogGroup: 1,
         administrativeDivision: null,
-        treeType: "BusinessGroup",
       },
       rules: {
         name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
@@ -203,7 +196,6 @@ export default {
             that.platform.devicePort = res.data.data.devicePort;
             that.platform.username = res.data.data.username;
             that.platform.password = res.data.data.password;
-            that.platform.treeType = "BusinessGroup";
             that.platform.administrativeDivision = res.data.data.username.substr(0, 6);
           }
 
@@ -234,7 +226,6 @@ export default {
         this.platform.startOfflinePush = platform.startOfflinePush;
         this.platform.catalogGroup = platform.catalogGroup;
         this.platform.administrativeDivision = platform.administrativeDivision;
-        this.platform.treeType = platform.treeType;
         this.onSubmit_text = "保存";
         this.saveUrl = "/api/platform/save";
       }
@@ -252,7 +243,6 @@ export default {
       if (this.platform.administrativeDivision == null) {
         this.platform.administrativeDivision = this.platform.deviceGBId.substr(0, 6);
       }
-
     },
     onSubmit: function () {
       this.saveForm()
@@ -309,7 +299,6 @@ export default {
         keepTimeout: 60,
         transport: "UDP",
         characterSet: "GB2312",
-        treeType: "BusinessGroup",
         startOfflinePush: false,
         catalogGroup: 1,
       }
@@ -344,13 +333,6 @@ export default {
         });
       }
     },
-    treeTypeChange: function (){
-      this.$message({
-        showClose: true,
-        message: "修改目录结构会导致关联目录与通道数据被清空,保存后生效",
-        type: "warning",
-      });
-    }
   },
 };
 </script>