Просмотр исходного кода

优化国标级联的目录创建以及推送规则,优化接收目录规则,更加规范

648540858 2 лет назад
Родитель
Сommit
8942ab0112
26 измененных файлов с 8849 добавлено и 16539 удалено
  1. 42 0
      src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java
  2. 101 0
      src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java
  3. 10 0
      src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
  4. 0 10
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java
  5. 139 49
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  6. 2 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  7. 9 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
  8. 5 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
  9. 6 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
  10. 328 181
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
  11. 2 2
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
  12. 22 142
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
  13. 16 27
      src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
  14. 4 9
      src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
  15. 2 8
      src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
  16. 11 1
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  17. 77 55
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
  18. 6 2
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  19. 3220 0
      src/main/resources/civilCode.csv
  20. 4812 15999
      web_src/package-lock.json
  21. 1 1
      web_src/src/components/ParentPlatformList.vue
  22. 27 17
      web_src/src/components/dialog/catalogEdit.vue
  23. 2 4
      web_src/src/components/dialog/chooseChannel.vue
  24. 5 4
      web_src/src/components/dialog/chooseChannelForCatalog.vue
  25. 0 6
      web_src/src/components/dialog/deviceEdit.vue
  26. 0 18
      web_src/src/components/dialog/platformEdit.vue

+ 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);
+        }
+
+    }
+
+}

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java

@@ -60,6 +60,8 @@ public class UserSetting {
 
     private String thirdPartyGBIdReg = "[\\s\\S]*";
 
+    private String civilCodeFile = "classpath:civilCode.csv";
+
     private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
 
     private List<String> allowedOrigins = new ArrayList<>();
@@ -277,4 +279,12 @@ public class UserSetting {
     public void setDeviceStatusNotify(Boolean deviceStatusNotify) {
         this.deviceStatusNotify = deviceStatusNotify;
     }
+
+    public String getCivilCodeFile() {
+        return civilCodeFile;
+    }
+
+    public void setCivilCodeFile(String civilCodeFile) {
+        this.civilCodeFile = civilCodeFile;
+    }
 }

+ 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.getStatus() == 0 ? "OFF" : "ON") + "</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.getStatus() == 1?"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.getStatus() == 1?"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

@@ -191,6 +191,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")
@@ -403,7 +407,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) {

+ 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(1);
-            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(1);
-            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(1);
+                    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(1);
+                    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(1);
+                    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(1);
-            }
-            if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
-                deviceChannel.setStatus(0);
-            }
-        }else {
-            deviceChannel.setStatus(1);
-        }
-        // 识别自带的目录标识
-        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(1);
+                        }
+                        if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
+                            deviceChannel.setStatus(0);
+                        }
+                    }else {
+                        deviceChannel.setStatus(1);
+                    }
+
+                    // 经度
+                    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

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

+ 22 - 142
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java

@@ -376,63 +376,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
@@ -441,42 +389,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) {
@@ -496,63 +413,26 @@ public class DeviceServiceImpl implements IDeviceService {
             node.setPid(parentId);
             node.setBasicData(channel);
             node.setParent(false);
-            if (channel.getChannelId().length() > 8) {
-                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.getChannelWithoutCiviCode(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

+ 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()?1:0);
 
         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 )?1:0);
 
         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;

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

@@ -124,18 +124,12 @@ public class PlatformServiceImpl implements IPlatformService {
     @Override
     public boolean update(ParentPlatform parentPlatform) {
         logger.info("[国标级联]更新平台 {}", parentPlatform.getDeviceGBId());
+        // TODO 后续版本去除
+        parentPlatform.setTreeType("");
         parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
         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();

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

@@ -447,7 +447,7 @@ public interface DeviceChannelMapper {
     List<DeviceChannel> getBusinessGroups(String deviceId, String typeCode);
 
     @Select("select dc.id, dc.channelId, dc.deviceId, dc.name, dc.manufacture,dc.model,dc.owner, pc.civilCode,dc.block, " +
-            " dc.address, '0' as parental,'0' as channelType, pc.id as parentId, dc.safetyWay, dc.registerWay,dc.certNum, dc.certifiable,  " +
+            " dc.address, '0' as parental,'0' as channelType, pc.id as parentId, pc.businessGroupId as businessGroupId, dc.safetyWay, dc.registerWay,dc.certNum, dc.certifiable,  " +
             " dc.errCode,dc.endTime, dc.secrecy,   dc.ipAddress,  dc.port,  dc.PTZType,  dc.password, dc.status, " +
             " dc.longitudeWgs84 as longitude, dc.latitudeWgs84 as latitude,  pc.businessGroupId " +
             " from device_channel dc" +
@@ -501,4 +501,14 @@ public interface DeviceChannelMapper {
             "</foreach>" +
             "</script>"})
     int batchOffline(List<DeviceChannel> channels);
+
+    @Select(value = {" <script>" +
+            "select * " +
+            "from device_channel " +
+            "where deviceId=#{deviceId}" +
+            " <if test='parentId != null '> and parentId = #{parentId} </if>" +
+            " <if test='parentId == null '> and parentId is null </if>" +
+            " <if test='onlyCatalog == true '> and parental = 1 </if>" +
+            " </script>"})
+    List<DeviceChannel> getSubChannelsByDeviceId(String deviceId, String parentId, boolean onlyCatalog);
 }

+ 77 - 55
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java

@@ -125,47 +125,50 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		List<DeviceChannel> channels = 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());
-					if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
-						deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
-						deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
-						if (allChannelMap.get(deviceChannel.getChannelId()).getStatus() !=deviceChannel.getStatus()){
-							List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
-							if (!CollectionUtils.isEmpty(strings)){
-								strings.forEach(platformId->{
-									eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF);
-								});
-							}
 
-						}
-					}
-					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()).getStatus() !=deviceChannel.getStatus()){
+					List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
+					if (!CollectionUtils.isEmpty(strings)){
+						strings.forEach(platformId->{
+							eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF);
+						});
 					}
+
+				}
+			}
+			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);
 		}
@@ -773,25 +776,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);
@@ -915,19 +942,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(1);
 		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);

Разница между файлами не показана из-за своего большого размера
+ 3220 - 0
src/main/resources/civilCode.csv


Разница между файлами не показана из-за своего большого размера
+ 4812 - 15999
web_src/package-lock.json


+ 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>