mrjackwang
2022-07-20 8d87741dea3d174f098269073429a0f6b982baa1
Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0
77个文件已修改
17个文件已添加
1 文件已重命名
4133 ■■■■ 已修改文件
sql/mysql.sql 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/update.sql 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 158 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookParam.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/OnPlayHookParam.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/OnPublishHookParam.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IMediaService.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IUserService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGpsMsgListener.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisPushStreamStatusMsgListener.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisStreamMsgListener.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 121 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 325 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/8042900_www.wvp-pro.cn.jks 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/all-application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/Login.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/ParentPlatformList.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/PushVideoList.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/UserManager.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/addUser.vue 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/catalogEdit.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePasswordForAdmin.vue 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePushKey.vue 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannel.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForCatalog.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForStream.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/platformEdit.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/layout/UiHeader.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/router/index.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/static/file/推流通道导入.zip 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql.sql
@@ -50,7 +50,7 @@
                          `treeType` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
                          PRIMARY KEY (`id`) USING BTREE,
                          UNIQUE KEY `device_deviceId_uindex` (`deviceId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -142,7 +142,7 @@
                                  PRIMARY KEY (`id`) USING BTREE,
                                  UNIQUE KEY `device_channel_id_uindex` (`id`) USING BTREE,
                                  UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=19324 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=19336 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -179,7 +179,7 @@
                                          `latitudeWgs84` double DEFAULT NULL,
                                          `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                          PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5649 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=6751 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -208,13 +208,12 @@
                             `latitude` double DEFAULT NULL,
                             `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                             `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                             `status` int DEFAULT NULL,
                             `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                             `gpsTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                             PRIMARY KEY (`gbStreamId`) USING BTREE,
                             UNIQUE KEY `app` (`app`,`stream`) USING BTREE,
                             UNIQUE KEY `gbId` (`gbId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=301681 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=301740 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -244,7 +243,7 @@
                       `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                       `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                       PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=29943 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=37760 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -329,16 +328,16 @@
                                   `ptz` int DEFAULT NULL,
                                   `rtcp` int DEFAULT NULL,
                                   `status` bit(1) DEFAULT NULL,
                                   `shareAllLiveStream` int DEFAULT NULL,
                                   `startOfflinePush` int DEFAULT '0',
                                   `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                   `catalogGroup` int DEFAULT '1',
                                   `createTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                   `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                   `treeType` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
                                   PRIMARY KEY (`id`) USING BTREE,
                                   UNIQUE KEY `parent_platform_id_uindex` (`id`) USING BTREE,
                                   UNIQUE KEY `parent_platform_pk` (`serverGBId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -362,6 +361,8 @@
                                    `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                    `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                                    `civilCode` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                    `businessGroupId` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                    PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -388,7 +389,7 @@
                                       `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                       `deviceChannelId` int NOT NULL,
                                       PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4889 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=4912 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -414,7 +415,7 @@
                                      `id` int NOT NULL AUTO_INCREMENT,
                                      PRIMARY KEY (`id`) USING BTREE,
                                      UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=302077 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=302134 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -455,7 +456,7 @@
                                `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                                PRIMARY KEY (`id`) USING BTREE,
                                UNIQUE KEY `stream_proxy_pk` (`app`,`stream`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -487,9 +488,10 @@
                               `serverId` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
                               `pushTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                               `updateTime` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                               `status` int DEFAULT NULL,
                               PRIMARY KEY (`id`) USING BTREE,
                               UNIQUE KEY `stream_push_pk` (`app`,`stream`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=305304 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
) ENGINE=InnoDB AUTO_INCREMENT=305390 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -515,6 +517,7 @@
                        `roleId` int NOT NULL,
                        `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                        `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                        `pushKey` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                        PRIMARY KEY (`id`) USING BTREE,
                        UNIQUE KEY `user_username_uindex` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
@@ -526,7 +529,7 @@
LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021 - 04 - 13 14:14:57','2021 - 04 - 13 14:14:57');
INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021 - 04 - 13 14:14:57','2021 - 04 - 13 14:14:57','453df297a57a5a7438934sda801fc3');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
@@ -566,4 +569,4 @@
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2022-07-06  9:43:54
-- Dump completed on 2022-07-17 23:15:09
sql/update.sql
@@ -52,9 +52,30 @@
alter table stream_push
    add pushTime varchar(50) default null;
alter table stream_push
    add status int DEFAULT NULL;
alter table stream_push
    add updateTime varchar(50) default null;
alter table stream_push
    add pushIng int DEFAULT NULL;
alter table stream_push
    change createStamp createTime varchar(50) default null;
alter table gb_stream
    drop column status;
alter table user
    add pushKey varchar(50) default null;
update user set pushKey='453df297a57a5a7438934sda801fc3' where id=1;
alter table parent_platform
    add treeType varchar(50) not null;
update parent_platform set parent_platform.treeType='BusinessGroup';
alter table parent_platform drop shareAllLiveStream;
alter table platform_catalog
    add civilCode varchar(50) default null;
alter table platform_catalog
    add businessGroupId varchar(50) default null;
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
@@ -11,7 +11,7 @@
import springfox.documentation.oas.annotations.EnableOpenApi;
/**
 *
 * å¯åŠ¨ç±»
 */
@ServletComponentScan("com.genersoft.iot.vmp.conf")
@SpringBootApplication
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -9,6 +9,9 @@
    private String deviceID;
    private String channelId;
    private String flv;
    private String ip;
    private String https_flv;
    private String ws_flv;
    private String wss_flv;
@@ -292,4 +295,12 @@
    public void setProgress(double progress) {
        this.progress = progress;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
}
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -58,6 +58,8 @@
    public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
    public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_";
    public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
    public static final String SIP_SN_PREFIX = "VMP_SIP_SN_";
@@ -71,6 +73,8 @@
    public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
    //************************** redis æ¶ˆæ¯*********************************
    // æµå˜åŒ–的通知
@@ -79,8 +83,14 @@
    // æŽ¥æ”¶æŽ¨æµè®¾å¤‡çš„GPS变化通知
    public static final String VM_MSG_GPS = "VM_MSG_GPS";
    // æŽ¥æ”¶æŽ¨æµè®¾å¤‡çš„GPS变化通知
    public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE";
    // redis æ¶ˆæ¯é€šçŸ¥è®¾å¤‡æŽ¨æµåˆ°å¹³å°
    public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED";
    // redis æ¶ˆæ¯è¯·æ±‚所有的在线通道
    public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
    // ç§»åŠ¨ä½ç½®è®¢é˜…é€šçŸ¥
    public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition";
@@ -94,6 +104,10 @@
    // è®¾å¤‡çŠ¶æ€è®¢é˜…çš„é€šçŸ¥
    public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device";
    //**************************    ç¬¬ä¸‰æ–¹  ****************************************
    public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
    public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
@@ -5,6 +5,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
@@ -103,12 +104,9 @@
    public void stop(String key) {
        if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) {
//            Runnable runnable = runnableMap.get(key);
//            if (runnable instanceof ISubscribeTask) {
//                ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
//                subscribeTask.stop();
//            }
            futureMap.get(key).cancel(false);
            futureMap.remove(key);
            runnableMap.remove(key);
        }
    }
@@ -123,4 +121,19 @@
    public Runnable get(String key) {
        return runnableMap.get(key);
    }
    /**
     * æ¯äº”分钟检查失效的任务,并移除
     */
    @Scheduled(cron="0 0/5 * * * ?")
    public void execute(){
        if (futureMap.size() > 0) {
            for (String key : futureMap.keySet()) {
                if (futureMap.get(key).isDone()) {
                    futureMap.remove(key);
                    runnableMap.remove(key);
                }
            }
        }
    }
}
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
@@ -1,10 +1,7 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.service.impl.RedisAlarmMsgListener;
import com.genersoft.iot.vmp.service.impl.RedisGpsMsgListener;
import com.genersoft.iot.vmp.service.impl.RedisGbPlayMsgListener;
import com.genersoft.iot.vmp.service.impl.RedisStreamMsgListener;
import com.genersoft.iot.vmp.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -60,6 +57,9 @@
    @Autowired
    private RedisGbPlayMsgListener redisGbPlayMsgListener;
    @Autowired
    private RedisPushStreamStatusMsgListener redisPushStreamStatusMsgListener;
    @Bean
    public JedisPool jedisPool() {
        if (StringUtils.isBlank(password)) {
@@ -108,6 +108,7 @@
        container.addMessageListener(redisAlarmMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE));
        container.addMessageListener(redisStreamMsgListener, new PatternTopic(VideoManagerConstants.WVP_MSG_STREAM_CHANGE_PREFIX + "PUSH"));
        container.addMessageListener(redisGbPlayMsgListener, new PatternTopic(RedisGbPlayMsgListener.WVP_PUSH_STREAM_KEY));
        container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE));
        return container;
    }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -105,11 +105,6 @@
    private int channelCount;
    /**
     * å…±äº«æ‰€æœ‰çš„直播流
     */
    private boolean shareAllLiveStream;
    /**
     * é»˜è®¤ç›®å½•Id,自动添加的通道多放在这个目录下
     */
    private String catalogId;
@@ -153,6 +148,11 @@
     * åˆ›å»ºæ—¶é—´
     */
    private String createTime;
    /**
     * æ ‘类型 å›½æ ‡è§„定了两种树的展现方式 è¡Œæ”¿åŒºåˆ’ CivilCode å’Œä¸šåŠ¡åˆ†ç»„:BusinessGroup
     */
    private String treeType;
    public Integer getId() {
        return id;
@@ -314,15 +314,6 @@
        this.channelCount = channelCount;
    }
    public boolean isShareAllLiveStream() {
        return shareAllLiveStream;
    }
    public void setShareAllLiveStream(boolean shareAllLiveStream) {
        this.shareAllLiveStream = shareAllLiveStream;
    }
    public String getCatalogId() {
        return catalogId;
    }
@@ -394,4 +385,12 @@
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
    public String getTreeType() {
        return treeType;
    }
    public void setTreeType(String treeType) {
        this.treeType = treeType;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java
@@ -1,12 +1,28 @@
package com.genersoft.iot.vmp.gb28181.bean;
/**
 * å›½æ ‡çº§è”-目录
 * @author lin
 */
public class PlatformCatalog {
    private String id;
    private String name;
    private String platformId;
    private String parentId;
    private int childrenCount; // å­èŠ‚ç‚¹æ•°
    private int type; // 0 ç›®å½•, 1 å›½æ ‡é€šé“, 2 ç›´æ’­æµ
    private String civilCode;
    private String businessGroupId;
    /**
     * å­èŠ‚ç‚¹æ•°
     */
    private int childrenCount;
    /**
     * 0 ç›®å½•, 1 å›½æ ‡é€šé“, 2 ç›´æ’­æµ
     */
    private int type;
    public String getId() {
        return id;
@@ -68,4 +84,19 @@
        this.type = 2;
    }
    public String getCivilCode() {
        return civilCode;
    }
    public void setCivilCode(String civilCode) {
        this.civilCode = civilCode;
    }
    public String getBusinessGroupId() {
        return businessGroupId;
    }
    public void setBusinessGroupId(String businessGroupId) {
        this.businessGroupId = businessGroupId;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java
File was renamed from src/main/java/com/genersoft/iot/vmp/domain/req/PresetQuerySipReq.java
@@ -1,4 +1,4 @@
package com.genersoft.iot.vmp.domain.req;
package com.genersoft.iot.vmp.gb28181.bean;
/**
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java
New file
@@ -0,0 +1,10 @@
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";
}
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
@@ -65,7 +65,6 @@
        }
        // æŸ¥è¯¢æ˜¯å¦æœ‰æŽ¨æµï¼Œ å¦‚果有则都停止
        List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(event.getPlatformGbID());
        logger.info("[ å¹³å°æœªæ³¨å†Œäº‹ä»¶ ] åœæ­¢[ {} ]的所有推流size", sendRtpItems.size());
        if (sendRtpItems != null && sendRtpItems.size() > 0) {
            logger.info("[ å¹³å°æœªæ³¨å†Œäº‹ä»¶ ] åœæ­¢[ {} ]的所有推流", event.getPlatformGbID());
            for (SendRtpItem sendRtpItem : sendRtpItems) {
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java
@@ -11,13 +11,40 @@
        super(source);
    }
    public static final String ON = "ON";         // ä¸Šçº¿
    public static final String OFF = "OFF";       // ç¦»çº¿
    public static final String VLOST = "VLOST";   // è§†é¢‘丢失
    public static final String DEFECT = "DEFECT"; // æ•…éšœ
    public static final String ADD = "ADD";       // å¢žåŠ 
    public static final String DEL = "DEL";       // åˆ é™¤
    public static final String UPDATE = "UPDATE";       // æ›´æ–°
    /**
     * ä¸Šçº¿
     */
    public static final String ON = "ON";
    /**
     * ç¦»çº¿
     */
    public static final String OFF = "OFF";
    /**
     * è§†é¢‘丢失
     */
    public static final String VLOST = "VLOST";
    /**
     * æ•…éšœ
     */
    public static final String DEFECT = "DEFECT";
    /**
     * å¢žåŠ 
     */
    public static final String ADD = "ADD";
    /**
     * åˆ é™¤
     */
    public static final String DEL = "DEL";
    /**
     * æ›´æ–°
     */
    public static final String UPDATE = "UPDATE";
    private List<DeviceChannel> deviceChannels;
    private List<GbStream> gbStreams;
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -58,17 +58,16 @@
        ParentPlatform parentPlatform = null;
        Map<String, List<ParentPlatform>> parentPlatformMap = new HashMap<>();
        if (event.getPlatformId() != null) {
        if (!StringUtils.isEmpty(event.getPlatformId())) {
            subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
            if (subscribe == null) {
                return;
            }
            parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId());
            if (parentPlatform != null && !parentPlatform.isStatus()) {
                return;
            }
            subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
            if (subscribe == null) {
                logger.info("发送订阅消息时发现订阅信息已经不存在: {}", event.getPlatformId());
                return;
            }
        }else {
            // èŽ·å–æ‰€ç”¨è®¢é˜…
            List<String> platforms = subscribeHolder.getAllCatalogSubscribePlatform();
@@ -144,11 +143,8 @@
                     }
                    if (event.getGbStreams() != null && event.getGbStreams().size() > 0){
                        for (GbStream gbStream : event.getGbStreams()) {
                            DeviceChannel deviceChannelByStream = gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform);
                            if (deviceChannelByStream.getParentId().length() <= 10) { // çˆ¶èŠ‚ç‚¹æ˜¯è¡Œæ”¿åŒºåˆ’,则设置CivilCode使用此行政区划
                                deviceChannelByStream.setCivilCode(deviceChannelByStream.getParentId());
                            }
                            deviceChannelList.add(deviceChannelByStream);
                            deviceChannelList.add(
                                    gbStreamService.getDeviceChannelListByStream(gbStream, gbStream.getCatalogId(), parentPlatform));
                        }
                    }
                    if (deviceChannelList.size() > 0) {
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
@@ -57,23 +57,17 @@
        SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId());
        if (subscribe != null) {
//            if (!parentPlatform.isStatus()) {
//                logger.info("发送订阅时发现平台已经离线:{}", platformId);
//                return;
//            }
            // TODO æš‚时只处理视频流的回复,后续增加对国标设备的支持
            List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId());
            List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId());
            if (gbStreams.size() == 0) {
                logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId());
                return;
            }
            for (GbStream gbStream : gbStreams) {
                String gbId = gbStream.getGbId();
            for (DeviceChannel deviceChannel : gbStreams) {
                String gbId = deviceChannel.getChannelId();
                GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
                if (gpsMsgInfo != null) { // æ— æœ€æ–°ä½ç½®ä¸å‘送
                   if (logger.isDebugEnabled()) {
                       logger.debug("无最新位置不发送");
                   }
                // æ— æœ€æ–°ä½ç½®ä¸å‘送
                if (gpsMsgInfo != null) {
                    // ç»çº¬åº¦éƒ½ä¸º0不发送
                    if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
                        continue;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -257,37 +257,37 @@
        catalogXml.append("<DeviceList Num=\"" + channels.size() +"\">\r\n");
        if (channels.size() > 0) {
            for (DeviceChannel channel : channels) {
                if (parentPlatform.getServerGBId().equals(channel.getParentId())) {
                    channel.setParentId(parentPlatform.getDeviceGBId());
                }
                catalogXml.append("<Item>\r\n");
                // è¡Œæ”¿åŒºåˆ’分组只需要这两项就可以
                catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
                catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
                catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
                if (channel.getParentId() != null) {
                    // ä¸šåŠ¡åˆ†ç»„åŠ ä¸Šè¿™ä¸€é¡¹å³å¯ï¼Œæé«˜å…¼å®¹æ€§ï¼Œ
                    catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
                }
                if (channel.getChannelId().length() == 20) {
                    if (Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { // è™šæ‹Ÿç»„织增加BusinessGroupID字段
                        catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
                    }
                if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) {
                    // è™šæ‹Ÿç»„织增加BusinessGroupID字段
                    catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
                }
                catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
                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");
                    catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n");
                    if (channel.getChannelType() != 2) { // ä¸šåŠ¡åˆ†ç»„/虚拟组织/行政区划 ä¸è®¾ç½®ä»¥ä¸‹å­—段
                        catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
                    catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
                    if (channel.getChannelType() != 2) {  // ä¸šåŠ¡åˆ†ç»„/虚拟组织/行政区划 ä¸è®¾ç½®ä»¥ä¸‹å±žæ€§
                        catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
                        catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n");
                        catalogXml.append("<Owner> " + channel.getOwner()+ "</Owner>\r\n");
                        catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
                        catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
                        catalogXml.append("<Longitude>" + channel.getLongitudeWgs84() + "</Longitude>\r\n");
                        catalogXml.append("<Latitude>" + channel.getLatitudeWgs84() + "</Latitude>\r\n");
                        catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
                        catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
                        catalogXml.append("<Info>\r\n");
                        catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
                        catalogXml.append("</Info>\r\n");
                    }
                }
                catalogXml.append("</Item>\r\n");
            }
        }
@@ -592,27 +592,35 @@
                    channel.setParentId(parentPlatform.getDeviceGBId());
                }
                catalogXml.append("<Item>\r\n");
                // è¡Œæ”¿åŒºåˆ’分组只需要这两项就可以
                catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
                catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
                catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
                catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
                if (channel.getParentId() != null) {
                    // ä¸šåŠ¡åˆ†ç»„åŠ ä¸Šè¿™ä¸€é¡¹å³å¯ï¼Œæé«˜å…¼å®¹æ€§ï¼Œ
                    catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
                }
                catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
                catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
                catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
                if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) { // è™šæ‹Ÿç»„织增加BusinessGroupID字段
                if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) {
                    // è™šæ‹Ÿç»„织增加BusinessGroupID字段
                    catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
                }
                if (channel.getChannelType() == 2) {  // ä¸šåŠ¡åˆ†ç»„/虚拟组织/行政区划 ä¸è®¾ç½®ä»¥ä¸‹å±žæ€§
                    catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
                    catalogXml.append("<Owner>0</Owner>\r\n");
                    catalogXml.append("<CivilCode>CivilCode</CivilCode>\r\n");
                    catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
                }
                if (!"presence".equals(subscribeInfo.getEventType())) {
                    catalogXml.append("<Event>" + type + "</Event>\r\n");
                catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
                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");
                    catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
                    if (channel.getChannelType() != 2) {  // ä¸šåŠ¡åˆ†ç»„/虚拟组织/行政区划 ä¸è®¾ç½®ä»¥ä¸‹å±žæ€§
                        catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
                        catalogXml.append("<Owner> " + channel.getOwner()+ "</Owner>\r\n");
                        catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
                        catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
                    }
                    if (!"presence".equals(subscribeInfo.getEventType())) {
                        catalogXml.append("<Event>" + type + "</Event>\r\n");
                    }
                }
                catalogXml.append("</Item>\r\n");
            }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -15,6 +15,7 @@
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
@@ -70,6 +71,9 @@
    @Autowired
    private SIPProcessorObserver sipProcessorObserver;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    private boolean taskQueueHandlerRun = false;
@@ -173,28 +177,7 @@
            logger.info("[收到 ç§»åŠ¨ä½ç½®è®¢é˜…]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
                    mobilePosition.getLongitude(), mobilePosition.getLatitude());
            mobilePosition.setReportSource("Mobile Position");
            // é»˜è®¤æ¥æºåæ ‡ç³»ä¸ºWGS-84处理
            if ("WGS84".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude());
                mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeGcj02(position[0]);
                mobilePosition.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude());
                mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeWgs84(position[0]);
                mobilePosition.setLatitudeWgs84(position[1]);
            }else {
                mobilePosition.setLongitudeGcj02(0.00);
                mobilePosition.setLatitudeGcj02(0.00);
                mobilePosition.setLongitudeWgs84(0.00);
                mobilePosition.setLatitudeWgs84(0.00);
            }
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            // æ›´æ–°device channel çš„经纬度
            DeviceChannel deviceChannel = new DeviceChannel();
@@ -202,11 +185,18 @@
            deviceChannel.setChannelId(channelId);
            deviceChannel.setLongitude(mobilePosition.getLongitude());
            deviceChannel.setLatitude(mobilePosition.getLatitude());
            deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84());
            deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84());
            deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02());
            deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02());
            deviceChannel.setGpsTime(mobilePosition.getTime());
            deviceChannel = deviceChannelService.updateGps(deviceChannel, device);
            mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84());
            mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84());
            mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
            mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            storager.updateChannelPosition(deviceChannel);
            // å‘送redis消息。 é€šçŸ¥ä½ç½®ä¿¡æ¯çš„变化
            JSONObject jsonObject = new JSONObject();
@@ -281,38 +271,28 @@
                mobilePosition.setLongitude(deviceAlarm.getLongitude());
                mobilePosition.setLatitude(deviceAlarm.getLatitude());
                mobilePosition.setReportSource("GPS Alarm");
                if ("WGS84".equals(device.getGeoCoordSys())) {
                    mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude());
                    mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude());
                    Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                    mobilePosition.setLongitudeGcj02(position[0]);
                    mobilePosition.setLatitudeGcj02(position[1]);
                }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                    mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude());
                    mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude());
                    Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                    mobilePosition.setLongitudeWgs84(position[0]);
                    mobilePosition.setLatitudeWgs84(position[1]);
                }else {
                    mobilePosition.setLongitudeGcj02(0.00);
                    mobilePosition.setLatitudeGcj02(0.00);
                    mobilePosition.setLongitudeWgs84(0.00);
                    mobilePosition.setLatitudeWgs84(0.00);
                }
                if (userSetting.getSavePositionHistory()) {
                    storager.insertMobilePosition(mobilePosition);
                }
                // æ›´æ–°device channel çš„经纬度
                DeviceChannel deviceChannel = new DeviceChannel();
                deviceChannel.setDeviceId(device.getDeviceId());
                deviceChannel.setChannelId(channelId);
                deviceChannel.setLongitude(mobilePosition.getLongitude());
                deviceChannel.setLatitude(mobilePosition.getLatitude());
                deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84());
                deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84());
                deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02());
                deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02());
                deviceChannel.setGpsTime(mobilePosition.getTime());
                deviceChannel = deviceChannelService.updateGps(deviceChannel, device);
                mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84());
                mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84());
                mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
                mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
                if (userSetting.getSavePositionHistory()) {
                    storager.insertMobilePosition(mobilePosition);
                }
                storager.updateChannelPosition(deviceChannel);
            }
            // TODO: éœ€è¦å®žçŽ°å­˜å‚¨æŠ¥è­¦ä¿¡æ¯ã€æŠ¥è­¦åˆ†ç±»
@@ -364,7 +344,7 @@
                    }else {
                        event = eventElement.getText().toUpperCase();
                    }
                    DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device);
                    DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
                    channel.setDeviceId(device.getDeviceId());
                    logger.info("[收到 ç›®å½•订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
                    switch (event) {
@@ -389,7 +369,7 @@
                        case CatalogEvent.ADD:
                            // å¢žåŠ 
                            logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId());
                            storager.updateChannel(deviceId, channel);
                            deviceChannelService.updateChannel(deviceId, channel);
                            break;
                        case CatalogEvent.DEL:
                            // åˆ é™¤
@@ -399,7 +379,7 @@
                        case CatalogEvent.UPDATE:
                            // æ›´æ–°
                            logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId());
                            storager.updateChannel(deviceId, channel);
                            deviceChannelService.updateChannel(deviceId, channel);
                            break;
                        default:
                            logger.warn("[ NotifyCatalog ] event not found ï¼š {}", event );
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -11,6 +11,7 @@
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
@@ -57,6 +58,9 @@
    @Autowired
    private IDeviceAlarmService deviceAlarmService;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    @Override
    public void afterPropertiesSet() throws Exception {
@@ -119,38 +123,26 @@
                mobilePosition.setLongitude(deviceAlarm.getLongitude());
                mobilePosition.setLatitude(deviceAlarm.getLatitude());
                mobilePosition.setReportSource("GPS Alarm");
                if ("WGS84".equals(device.getGeoCoordSys())) {
                    mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude());
                    mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude());
                    Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                    mobilePosition.setLongitudeGcj02(position[0]);
                    mobilePosition.setLatitudeGcj02(position[1]);
                }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                    mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude());
                    mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude());
                    Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                    mobilePosition.setLongitudeWgs84(position[0]);
                    mobilePosition.setLatitudeWgs84(position[1]);
                }else {
                    mobilePosition.setLongitudeGcj02(0.00);
                    mobilePosition.setLatitudeGcj02(0.00);
                    mobilePosition.setLongitudeWgs84(0.00);
                    mobilePosition.setLatitudeWgs84(0.00);
                }
                if (userSetting.getSavePositionHistory()) {
                    storager.insertMobilePosition(mobilePosition);
                }
                // æ›´æ–°device channel çš„经纬度
                DeviceChannel deviceChannel = new DeviceChannel();
                deviceChannel.setDeviceId(device.getDeviceId());
                deviceChannel.setChannelId(channelId);
                deviceChannel.setLongitude(mobilePosition.getLongitude());
                deviceChannel.setLatitude(mobilePosition.getLatitude());
                deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84());
                deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84());
                deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02());
                deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02());
                deviceChannel.setGpsTime(mobilePosition.getTime());
                deviceChannel = deviceChannelService.updateGps(deviceChannel, device);
                mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84());
                mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84());
                mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
                mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
                if (userSetting.getSavePositionHistory()) {
                    storager.insertMobilePosition(mobilePosition);
                }
                storager.updateChannelPosition(deviceChannel);
            }
        }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
@@ -58,85 +58,21 @@
            // å‡†å¤‡å›žå¤é€šé“信息
            List<DeviceChannelInPlatform> deviceChannels = storage.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
            // æŸ¥è¯¢å…³è”的直播通道
            List<GbStream> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
            // å›žå¤ç›®å½•信息
            List<DeviceChannel> catalogs =  storage.queryCatalogInPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> allChannels = new ArrayList<>();
            // å›žå¤ç›®å½•信息
            List<PlatformCatalog> catalogs =  storage.queryCatalogInPlatform(parentPlatform.getServerGBId());
            if (catalogs.size() > 0) {
                for (PlatformCatalog catalog : catalogs) {
                    if (catalog.getParentId().equals(catalog.getPlatformId())) {
                        catalog.setParentId(parentPlatform.getDeviceGBId());
                    }
                    DeviceChannel deviceChannel = new DeviceChannel();
                    deviceChannel.setChannelId(catalog.getId());
                    deviceChannel.setName(catalog.getName());
                    deviceChannel.setLongitude(0.0);
                    deviceChannel.setLatitude(0.0);
                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                    deviceChannel.setManufacture("wvp-pro");
                    deviceChannel.setStatus(1);
                    deviceChannel.setParental(1);
                    deviceChannel.setParentId(catalog.getParentId());
                    deviceChannel.setRegisterWay(1);
                    if (catalog.getParentId() != null && catalog.getParentId().length() <= 10) {
                        deviceChannel.setCivilCode(catalog.getParentId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    deviceChannel.setModel("live");
                    deviceChannel.setOwner("wvp-pro");
                    deviceChannel.setSecrecy("0");
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(catalogs);
            }
            // å›žå¤çº§è”的通道
            if (deviceChannels.size() > 0) {
                for (DeviceChannelInPlatform channel : deviceChannels) {
                    if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) {
                        channel.setCatalogId(parentPlatform.getDeviceGBId());
                    }
                    DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId());
                    deviceChannel.setParental(0);
                    deviceChannel.setParentId(channel.getCatalogId());
                    if (channel.getCatalogId() != null &&  channel.getCatalogId().length() <= 10) {
                        channel.setCivilCode(channel.getCatalogId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(deviceChannels);
            }
            // å›žå¤ç›´æ’­çš„通道
            if (gbStreams.size() > 0) {
                for (GbStream gbStream : gbStreams) {
                    if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) {
                        gbStream.setCatalogId(null);
                    }
                    DeviceChannel deviceChannel = new DeviceChannel();
                    deviceChannel.setChannelId(gbStream.getGbId());
                    deviceChannel.setName(gbStream.getName());
                    deviceChannel.setLongitude(gbStream.getLongitude());
                    deviceChannel.setLatitude(gbStream.getLatitude());
                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                    deviceChannel.setManufacture("wvp-pro");
//                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
                    deviceChannel.setStatus(1);
                    deviceChannel.setParentId(gbStream.getCatalogId());
                    deviceChannel.setRegisterWay(1);
                    if (gbStream.getCatalogId() != null && gbStream.getCatalogId().length() <= 10) {
                        deviceChannel.setCivilCode(gbStream.getCatalogId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    deviceChannel.setModel("live");
                    deviceChannel.setOwner("wvp-pro");
                    deviceChannel.setParental(0);
                    deviceChannel.setSecrecy("0");
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(gbStreams);
            }
            if (allChannels.size() > 0) {
                cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
@@ -7,6 +7,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.GpsUtil;
@@ -41,6 +42,9 @@
    @Autowired
    private IVideoManagerStorage storager;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    @Override
    public void afterPropertiesSet() throws Exception {
@@ -79,38 +83,26 @@
                mobilePosition.setAltitude(0.0);
            }
            mobilePosition.setReportSource("Mobile Position");
            if ("WGS84".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude());
                mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeGcj02(position[0]);
                mobilePosition.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude());
                mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeWgs84(position[0]);
                mobilePosition.setLatitudeWgs84(position[1]);
            }else {
                mobilePosition.setLongitudeGcj02(0.00);
                mobilePosition.setLatitudeGcj02(0.00);
                mobilePosition.setLongitudeWgs84(0.00);
                mobilePosition.setLatitudeWgs84(0.00);
            }
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            // æ›´æ–°device channel çš„经纬度
            DeviceChannel deviceChannel = new DeviceChannel();
            deviceChannel.setDeviceId(device.getDeviceId());
            deviceChannel.setChannelId(mobilePosition.getChannelId());
            deviceChannel.setLongitude(mobilePosition.getLongitude());
            deviceChannel.setLatitude(mobilePosition.getLatitude());
            deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84());
            deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84());
            deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02());
            deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02());
            deviceChannel.setGpsTime(mobilePosition.getTime());
            deviceChannel = deviceChannelService.updateGps(deviceChannel, device);
            mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84());
            mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84());
            mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
            mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            storager.updateChannelPosition(deviceChannel);
            //回复 200 OK
            responseAck(evt, Response.OK);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
@@ -70,86 +70,24 @@
            Element snElement = rootElement.element("SN");
            String sn = snElement.getText();
            // å‡†å¤‡å›žå¤é€šé“信息
            List<DeviceChannelInPlatform> deviceChannelInPlatforms = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> deviceChannelInPlatforms = storager.queryChannelWithCatalog(parentPlatform.getServerGBId());
            // æŸ¥è¯¢å…³è”的直播通道
            List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
            // å›žå¤ç›®å½•信息
            List<PlatformCatalog> catalogs =  storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> catalogs =  storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
            List<DeviceChannel> allChannels = new ArrayList<>();
            if (catalogs.size() > 0) {
                for (PlatformCatalog catalog : catalogs) {
                    if (catalog.getParentId().equals(catalog.getPlatformId())) {
                        catalog.setParentId(parentPlatform.getDeviceGBId());
                    }
                    DeviceChannel deviceChannel = new DeviceChannel();
                    // é€šé“的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划
                    deviceChannel.setChannelType(2);
                    deviceChannel.setChannelId(catalog.getId());
                    deviceChannel.setName(catalog.getName());
                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                    deviceChannel.setManufacture("wvp-pro");
                    deviceChannel.setStatus(1);
                    deviceChannel.setParental(1);
                    deviceChannel.setParentId(catalog.getParentId());
                    deviceChannel.setRegisterWay(1);
                    if (catalog.getParentId() != null &&  catalog.getParentId().length() < 10) {
                        deviceChannel.setCivilCode(catalog.getParentId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(catalogs);
            }
            // å›žå¤çº§è”的通道
            if (deviceChannelInPlatforms.size() > 0) {
                for (DeviceChannelInPlatform channel : deviceChannelInPlatforms) {
                    if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) {
                        channel.setCatalogId(parentPlatform.getDeviceGBId());
                    }
                    DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId());
                    // é€šé“的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划
                    deviceChannel.setChannelType(0);
                    deviceChannel.setParental(0);
                    deviceChannel.setParentId(channel.getCatalogId());
                    if (channel.getCatalogId() != null && channel.getCatalogId().length() < 10) {
                        deviceChannel.setCivilCode(channel.getCatalogId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(deviceChannelInPlatforms);
            }
            // å›žå¤ç›´æ’­çš„通道
            if (gbStreams.size() > 0) {
                for (GbStream gbStream : gbStreams) {
                    if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) {
                        gbStream.setCatalogId(null);
                    }
                    DeviceChannel deviceChannel = new DeviceChannel();
                    // é€šé“的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划
                    deviceChannel.setChannelType(1);
                    deviceChannel.setChannelId(gbStream.getGbId());
                    deviceChannel.setName(gbStream.getName());
                    deviceChannel.setLongitude(gbStream.getLongitude());
                    deviceChannel.setLatitude(gbStream.getLatitude());
                    deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
                    deviceChannel.setManufacture("wvp-pro");
//                    deviceChannel.setStatus(gbStream.isStatus()?1:0);
                    deviceChannel.setStatus(1);
                    deviceChannel.setParentId(gbStream.getCatalogId());
                    deviceChannel.setRegisterWay(1);
                    if (gbStream.getCatalogId() != null && gbStream.getCatalogId().length() < 10) {
                        deviceChannel.setCivilCode(gbStream.getCatalogId());
                    }else {
                        deviceChannel.setCivilCode(parentPlatform.getAdministrativeDivision());
                    }
                    deviceChannel.setModel("live");
                    deviceChannel.setOwner("wvp-pro");
                    deviceChannel.setParental(0);
                    deviceChannel.setSecrecy("0");
                    allChannels.add(deviceChannel);
                }
                allChannels.addAll(gbStreams);
            }
            if (allChannels.size() > 0) {
                cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -125,11 +125,7 @@
                                    if (channelDeviceElement == null) {
                                        continue;
                                    }
                                    //by brewswang
    //                        if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置
    //                            processNotifyMobilePosition(evt, itemDevice);
    //                        }
                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device);
                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
                                    deviceChannel.setDeviceId(take.getDevice().getDeviceId());
                                    channelList.add(deviceChannel);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
@@ -87,7 +87,6 @@
                device.setStreamMode("UDP");
            }
            deviceService.updateDevice(device);
//            storager.updateDevice(device);
            RequestMessage msg = new RequestMessage();
            msg.setKey(key);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
@@ -7,6 +7,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.utils.GpsUtil;
@@ -41,6 +42,9 @@
    @Autowired
    private IVideoManagerStorage storager;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    @Override
    public void afterPropertiesSet() throws Exception {
@@ -79,38 +83,25 @@
                mobilePosition.setAltitude(0.0);
            }
            mobilePosition.setReportSource("Mobile Position");
            if ("WGS84".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeWgs84(mobilePosition.getLongitude());
                mobilePosition.setLatitudeWgs84(mobilePosition.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeGcj02(position[0]);
                mobilePosition.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                mobilePosition.setLongitudeGcj02(mobilePosition.getLongitude());
                mobilePosition.setLatitudeGcj02(mobilePosition.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(mobilePosition.getLongitude(), mobilePosition.getLatitude());
                mobilePosition.setLongitudeWgs84(position[0]);
                mobilePosition.setLatitudeWgs84(position[1]);
            }else {
                mobilePosition.setLongitudeGcj02(0.00);
                mobilePosition.setLatitudeGcj02(0.00);
                mobilePosition.setLongitudeWgs84(0.00);
                mobilePosition.setLatitudeWgs84(0.00);
            }
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            // æ›´æ–°device channel çš„经纬度
            DeviceChannel deviceChannel = new DeviceChannel();
            deviceChannel.setDeviceId(device.getDeviceId());
            deviceChannel.setChannelId(mobilePosition.getChannelId());
            deviceChannel.setLongitude(mobilePosition.getLongitude());
            deviceChannel.setLatitude(mobilePosition.getLatitude());
            deviceChannel.setLongitudeWgs84(mobilePosition.getLongitudeWgs84());
            deviceChannel.setLatitudeWgs84(mobilePosition.getLatitudeWgs84());
            deviceChannel.setLongitudeGcj02(mobilePosition.getLongitudeGcj02());
            deviceChannel.setLatitudeGcj02(mobilePosition.getLatitudeGcj02());
            deviceChannel.setGpsTime(mobilePosition.getTime());
            deviceChannel = deviceChannelService.updateGps(deviceChannel, device);
            mobilePosition.setLongitudeWgs84(deviceChannel.getLongitudeWgs84());
            mobilePosition.setLatitudeWgs84(deviceChannel.getLatitudeWgs84());
            mobilePosition.setLongitudeGcj02(deviceChannel.getLongitudeGcj02());
            mobilePosition.setLatitudeGcj02(deviceChannel.getLatitudeGcj02());
            if (userSetting.getSavePositionHistory()) {
                storager.insertMobilePosition(mobilePosition);
            }
            storager.updateChannelPosition(deviceChannel);
            //回复 200 OK
            responseAck(evt, Response.OK);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java
@@ -1,6 +1,6 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.domain.req.PresetQuerySipReq;
import com.genersoft.iot.vmp.gb28181.bean.PresetQuerySipReq;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -4,6 +4,8 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.dom4j.Attribute;
import org.dom4j.Document;
@@ -29,7 +31,7 @@
    /**
     * æ—¥å¿—服务
     */
    private static Logger LOG = LoggerFactory.getLogger(XmlUtil.class);
    private static Logger logger = LoggerFactory.getLogger(XmlUtil.class);
    /**
     * è§£æžXML为Document对象
@@ -46,7 +48,7 @@
        try {
            document = saxReader.read(sr);
        } catch (DocumentException e) {
            LOG.error("解析失败", e);
            logger.error("解析失败", e);
        }
        return null == document ? null : document.getRootElement();
    }
@@ -182,47 +184,69 @@
        return xml.getRootElement();
    }
    public static DeviceChannel channelContentHander(Element itemDevice, Device device){
        Element channdelNameElement = itemDevice.element("Name");
        String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
        Element statusElement = itemDevice.element("Status");
        String status = statusElement != null ? statusElement.getTextTrim().toString() : "ON";
    private enum ChannelType{
        CivilCode, BusinessGroup,VirtualOrganization,Other
    }
    public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){
        DeviceChannel deviceChannel = new DeviceChannel();
        deviceChannel.setName(channelName);
        deviceChannel.setDeviceId(device.getDeviceId());
        Element channdelIdElement = itemDevice.element("DeviceID");
        String channelId = channdelIdElement != null ? channdelIdElement.getTextTrim().toString() : "";
        deviceChannel.setChannelId(channelId);
        // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
        if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
            deviceChannel.setStatus(1);
        if (channdelIdElement == null) {
            logger.warn("解析Catalog消息时发现缺少 DeviceID");
            return null;
        }
        if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
            deviceChannel.setStatus(0);
        String channelId = channdelIdElement.getTextTrim();
        if (StringUtils.isEmpty(channelId)) {
            logger.warn("解析Catalog消息时发现缺少 DeviceID");
            return null;
        }
        deviceChannel.setChannelId(channelId);
        if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) {
            // é™¤äº†ADD和update情况下需要识别全部内容,
            return deviceChannel;
        }
        deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
        deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
        deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
        deviceChannel.setCivilCode(XmlUtil.getText(itemDevice, "CivilCode"));
        deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
        deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
        String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID");
        if (XmlUtil.getText(itemDevice, "Parental") == null
                || XmlUtil.getText(itemDevice, "Parental").equals("")) {
            if (deviceChannel.getChannelId().length() <= 10
                    || (deviceChannel.getChannelId().length() == 20 && (
                            Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 215
                                    || Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216
                            )
                        )
            ) {
                deviceChannel.setParental(1);
            }else {
                deviceChannel.setParental(0);
        ChannelType channelType = ChannelType.Other;
        if (channelId.length() <= 8) {
            channelType = ChannelType.CivilCode;
        }else {
            if (channelId.length() == 20) {
                int code = Integer.parseInt(channelId.substring(10, 13));
                switch (code){
                    case 215:
                        channelType = ChannelType.BusinessGroup;
                        break;
                    case 216:
                        channelType = ChannelType.VirtualOrganization;
                        break;
                    default:
                        break;
                }
            }
        } else {
            // ç”±äºŽæµ·åº·ä¼šé”™è¯¯çš„发送65535作为这里的取值,所以这里除非是0否则认为是1
            deviceChannel.setParental(Integer.parseInt(XmlUtil.getText(itemDevice, "Parental")) == 1?1:0);
        }
        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 (channelType.equals(ChannelType.CivilCode)) {
            // è¡Œæ”¿åŒºåˆ’其他字段没必要识别了,默认在线即可
            deviceChannel.setStatus(1);
            deviceChannel.setParental(1);
            deviceChannel.setCreateTime(DateUtil.getNow());
            deviceChannel.setUpdateTime(DateUtil.getNow());
            return deviceChannel;
        }
        /**
         * è¡Œæ”¿åŒºåˆ’展示设备树与业务分组展示设备树是两种不同的模式
@@ -230,7 +254,17 @@
         * æ²³åŒ—省
         *    --> çŸ³å®¶åº„市
         *          --> æ‘„像头
         *          --> æ­£å®šåŽ¿
         *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          --> æ­£å®šåŽ¿
         *                  --> æ‘„像头
         *                  --> æ‘„像头
         *
@@ -243,59 +277,88 @@
         *             --> æ‘„像头
         */
        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 {
                deviceChannel.setParentId(parentId);
            }
        }
        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;
        }
//        else {
//            if (deviceChannel.getChannelId().length() <= 10) { // æ­¤æ—¶ä¸ºè¡Œæ”¿åŒºåˆ’, ä¸Šä¸‹çº§è¡Œæ”¿åŒºåˆ’使用DeviceId关联
//                deviceChannel.setParentId(deviceChannel.getChannelId().substring(0, deviceChannel.getChannelId().length() - 2));
//            }else if (deviceChannel.getChannelId().length() == 20) {
//                if (Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216) { // è™šæ‹Ÿç»„织
//                    deviceChannel.setBusinessGroupId(businessGroupID);
//                }else if (Integer.parseInt(device.getDeviceId().substring(10, 13) )== 118) {//NVR å¦‚果上级设备编号是NVR则直接将NVR的编号设置给通道的上级编号
//                    deviceChannel.setParentId(device.getDeviceId());
//                }else if (deviceChannel.getCivilCode() != null) {
//                    // è®¾å¤‡ï¼Œ æ— parentId的20位是使用CivilCode表示上级的设备,
//                    // æ³¨ï¼š215 ä¸šåŠ¡åˆ†ç»„æ˜¯éœ€è¦æœ‰parentId的
//                    deviceChannel.setParentId(deviceChannel.getCivilCode());
//                }
//            }else {
//                deviceChannel.setParentId(deviceChannel.getDeviceId());
//            }
//        }
        Element statusElement = itemDevice.element("Status");
        if (XmlUtil.getText(itemDevice, "SafetyWay") == null
                || XmlUtil.getText(itemDevice, "SafetyWay") == "") {
        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 (!StringUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
            deviceChannel.setParental(0);
        }else {
            deviceChannel.setParental(1);
        }
        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"));
        String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay");
        if (StringUtils.isEmpty(safetyWay)) {
            deviceChannel.setSafetyWay(0);
        } else {
            deviceChannel.setSafetyWay(Integer.parseInt(XmlUtil.getText(itemDevice, "SafetyWay")));
            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
        }
        if (XmlUtil.getText(itemDevice, "RegisterWay") == null
                || XmlUtil.getText(itemDevice, "RegisterWay") == "") {
        String registerWay = XmlUtil.getText(itemDevice, "RegisterWay");
        if (StringUtils.isEmpty(registerWay)) {
            deviceChannel.setRegisterWay(1);
        } else {
            deviceChannel.setRegisterWay(Integer.parseInt(XmlUtil.getText(itemDevice, "RegisterWay")));
            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
        }
        deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
        if (XmlUtil.getText(itemDevice, "Certifiable") == null
                || XmlUtil.getText(itemDevice, "Certifiable") == "") {
            deviceChannel.setCertifiable(0);
        } else {
            deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
        }
        if (XmlUtil.getText(itemDevice, "ErrCode") == null
                || XmlUtil.getText(itemDevice, "ErrCode") == "") {
            deviceChannel.setErrCode(0);
        } else {
            deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
        }
        deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
        deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
        deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
@@ -304,43 +367,23 @@
        } else {
            deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
        }
        deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
        if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {
            deviceChannel.setLongitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Longitude")));
        String longitude = XmlUtil.getText(itemDevice, "Longitude");
        if (NumericUtil.isDouble(longitude)) {
            deviceChannel.setLongitude(Double.parseDouble(longitude));
        } else {
            deviceChannel.setLongitude(0.00);
        }
        if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Latitude"))) {
            deviceChannel.setLatitude(Double.parseDouble(XmlUtil.getText(itemDevice, "Latitude")));
        String latitude = XmlUtil.getText(itemDevice, "Latitude");
        if (NumericUtil.isDouble(latitude)) {
            deviceChannel.setLatitude(Double.parseDouble(latitude));
        } else {
            deviceChannel.setLatitude(0.00);
        }
        deviceChannel.setGpsTime(DateUtil.getNow());
        if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) {
            if ("WGS84".equals(device.getGeoCoordSys())) {
                deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeGcj02(position[0]);
                deviceChannel.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
                deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeWgs84(position[0]);
                deviceChannel.setLatitudeWgs84(position[1]);
            }else {
                deviceChannel.setLongitudeGcj02(0.00);
                deviceChannel.setLatitudeGcj02(0.00);
                deviceChannel.setLongitudeWgs84(0.00);
                deviceChannel.setLatitudeWgs84(0.00);
            }
        }else {
            deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
            deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
            deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
            deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
        }
        if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) {
            //兼容INFO中的信息
            Element info = itemDevice.element("Info");
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
@@ -136,4 +136,12 @@
        return sendGet(mediaServerItem, "api/record/file/duration",param, callback);
    }
    public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){
        Map<String, Object> param = new HashMap<>();
        param.put("app",app);
        param.put("stream",stream);
        param.put("callId",callId);
        return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback);
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -1,7 +1,8 @@
package com.genersoft.iot.vmp.media.zlm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.common.StreamInfo;
@@ -21,6 +22,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -80,7 +82,13 @@
    private UserSetting userSetting;
    @Autowired
    private IUserService userService;
    @Autowired
    private VideoStreamSessionManager sessionManager;
    @Autowired
    private AssistRESTfulUtils assistRESTfulUtils;
    /**
     * æœåŠ¡å™¨å®šæ—¶ä¸ŠæŠ¥æ—¶é—´ï¼Œä¸ŠæŠ¥é—´éš”å¯é…ç½®ï¼Œé»˜è®¤10s上报一次
@@ -151,12 +159,14 @@
     */
    @ResponseBody
    @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
    public ResponseEntity<String> onPlay(@RequestBody JSONObject json){
    public ResponseEntity<String> onPlay(@RequestBody OnPlayHookParam param){
        JSONObject json = (JSONObject)JSON.toJSON(param);
        if (logger.isDebugEnabled()) {
            logger.debug("[ ZLM HOOK ]on_play API调用,参数:" + json.toString());
            logger.debug("[ ZLM HOOK ]on_play API调用,参数:" + JSON.toJSONString(param));
        }
        String mediaServerId = json.getString("mediaServerId");
        String mediaServerId = param.getMediaServerId();
        ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_play, json);
        if (subscribe != null ) {
            MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
@@ -165,9 +175,20 @@
            }
        }
        JSONObject ret = new JSONObject();
        if (!"rtp".equals(param.getApp())) {
            Map<String, String> paramMap = urlParamToMap(param.getParams());
            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
            if (streamAuthorityInfo == null
                    || (streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId")))) {
                ret.put("code", 401);
                ret.put("msg", "Unauthorized");
                return new ResponseEntity<>(ret.toString(),HttpStatus.OK);
            }
        }
        ret.put("code", 0);
        ret.put("msg", "success");
        return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
        return new ResponseEntity<>(ret.toString(),HttpStatus.OK);
    }
    
    /**
@@ -176,23 +197,61 @@
     */
    @ResponseBody
    @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
    public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
    public ResponseEntity<String> onPublish(@RequestBody OnPublishHookParam param) {
        JSONObject json = (JSONObject) JSON.toJSON(param);
        logger.info("[ ZLM HOOK ]on_publish API调用,参数:" + json.toString());
        JSONObject ret = new JSONObject();
        String mediaServerId = json.getString("mediaServerId");
        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
        if (!"rtp".equals(param.getApp())) {
            // æŽ¨æµé‰´æƒ
            if (param.getParams() == null) {
                logger.info("推流鉴权失败: ç¼ºå°‘不要参数:sign=md5(user表的pushKey)");
                ret.put("code", 401);
                ret.put("msg", "Unauthorized");
                return new ResponseEntity<>(ret.toString(), HttpStatus.OK);
            }
            Map<String, String> paramMap = urlParamToMap(param.getParams());
            String sign = paramMap.get("sign");
            if (sign == null) {
                logger.info("推流鉴权失败: ç¼ºå°‘不要参数:sign=md5(user表的pushKey)");
                ret.put("code", 401);
                ret.put("msg", "Unauthorized");
                return new ResponseEntity<>(ret.toString(), HttpStatus.OK);
            }
            // æŽ¨æµè‡ªå®šä¹‰æ’­æ”¾é‰´æƒç 
            String callId = paramMap.get("callId");
            // é‰´æƒé…ç½®
            boolean hasAuthority = userService.checkPushAuthority(callId, sign);
            if (!hasAuthority) {
                logger.info("推流鉴权失败: sign æ— æƒé™: callId={}. sign={}", callId, sign);
                ret.put("code", 401);
                ret.put("msg", "Unauthorized");
                return new ResponseEntity<>(ret.toString(), HttpStatus.OK);
            }
            StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
            streamAuthorityInfo.setCallId(callId);
            streamAuthorityInfo.setSign(sign);
            // é‰´æƒé€šè¿‡
            redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
            // é€šçŸ¥assist新的callId
            if (mediaInfo != null) {
                assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
            }
        }
        ret.put("code", 0);
        ret.put("msg", "success");
        ret.put("enable_hls", true);
        if (json.getInteger("originType") == 1
                || json.getInteger("originType") == 2
                || json.getInteger("originType") == 3) {
        if (!"rtp".equals(param.getApp())) {
            ret.put("enable_audio", true);
        }
        String mediaServerId = json.getString("mediaServerId");
        ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
        if (subscribe != null) {
            MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
            if (mediaInfo != null) {
                subscribe.response(mediaInfo, json);
            }else {
@@ -200,14 +259,13 @@
                ret.put("msg", "zlm not register");
            }
        }
         String app = json.getString("app");
         String stream = json.getString("stream");
        if ("rtp".equals(app)) {
        if ("rtp".equals(param.getApp())) {
            ret.put("enable_mp4", userSetting.getRecordSip());
        }else {
            ret.put("enable_mp4", userSetting.isRecordPushLive());
        }
        List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, stream);
        List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());
        if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
            String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
            String channelId = ssrcTransactionForAll.get(0).getChannelId();
@@ -220,14 +278,17 @@
                ret.put("mp4_max_second", 10);
                ret.put("enable_mp4", true);
                ret.put("enable_audio", true);
            }
            }
        }
        return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
    }
    /**
     * å½•制mp4完成后通知事件;此事件对回复不敏感。
     *  
@@ -312,9 +373,6 @@
        if (logger.isDebugEnabled()) {
            logger.debug("[ ZLM HOOK ]on_shell_login API调用,参数:" + json.toString());
        }
        // TODO å¦‚果是带有rtpstream则开启按需拉流
        // String app = json.getString("app");
        // String stream = json.getString("stream");
        String mediaServerId = json.getString("mediaServerId");
        ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_shell_login, json);
        if (subscribe != null ) {
@@ -351,12 +409,24 @@
        }
        // æµæ¶ˆå¤±ç§»é™¤redis play
        String app = item.getApp();
        String streamId = item.getStream();
        String stream = item.getStream();
        String schema = item.getSchema();
        List<MediaItem.MediaTrack> tracks = item.getTracks();
        boolean regist = item.isRegist();
        if (regist) {
            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
            if (streamAuthorityInfo == null) {
                streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(item);
            }else {
                streamAuthorityInfo.setOriginType(item.getOriginType());
                streamAuthorityInfo.setOriginTypeStr(item.getOriginTypeStr());
            }
            redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
        }else {
            redisCatchStorage.removeStreamAuthorityInfo(app, stream);
        }
        if ("rtmp".equals(schema)){
            logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, streamId);
            logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, stream);
            if (regist) {
                mediaServerService.addCount(mediaServerId);
            }else {
@@ -365,15 +435,15 @@
            if (item.getOriginType() == OriginType.PULL.ordinal()
                    || item.getOriginType() == OriginType.FFMPEG_PULL.ordinal()) {
                // è®¾ç½®æ‹‰æµä»£ç†ä¸Šçº¿/离线
                streamProxyService.updateStatus(regist, app, streamId);
                streamProxyService.updateStatus(regist, app, stream);
            }
            if ("rtp".equals(app) && !regist ) {
                StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
                StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(stream);
                if (streamInfo!=null){
                    redisCatchStorage.stopPlay(streamInfo);
                    storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
                }else{
                    streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
                    streamInfo = redisCatchStorage.queryPlayback(null, null, stream, null);
                    if (streamInfo != null) {
                        redisCatchStorage.stopPlayback(streamInfo.getDeviceID(), streamInfo.getChannelId(),
                                streamInfo.getStream(), null);
@@ -387,10 +457,12 @@
                    if (mediaServerItem != null){
                        if (regist) {
                            StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, streamId, tracks);
                            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
                            StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem,
                                    app, stream, tracks, streamAuthorityInfo.getCallId());
                            item.setStreamInfo(streamInfoByAppAndStream);
                            redisCatchStorage.addStream(mediaServerItem, type, app, streamId, item);
                            item.setSeverId(userSetting.getServerId());
                            redisCatchStorage.addStream(mediaServerItem, type, app, stream, item);
                            if (item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
                                    || item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
                                    || item.getOriginType() == OriginType.RTC_PUSH.ordinal() ) {
@@ -413,23 +485,23 @@
                        }else {
                            // å…¼å®¹æµæ³¨é”€æ—¶ç±»åž‹ä»Žredis记录获取
                            MediaItem mediaItem = redisCatchStorage.getStreamInfo(app, streamId, mediaServerId);
                            MediaItem mediaItem = redisCatchStorage.getStreamInfo(app, stream, mediaServerId);
                            if (mediaItem != null) {
                                type = OriginType.values()[mediaItem.getOriginType()].getType();
                                redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, streamId);
                                redisCatchStorage.removeStream(mediaServerItem.getId(), type, app, stream);
                            }
                            GbStream gbStream = storager.getGbStream(app, streamId);
                            GbStream gbStream = storager.getGbStream(app, stream);
                            if (gbStream != null) {
//                                eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
                            }
                            zlmMediaListManager.removeMedia(app, streamId);
                            zlmMediaListManager.removeMedia(app, stream);
                        }
                        if (type != null) {
                            // å‘送流变化redis消息
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("serverId", userSetting.getServerId());
                            jsonObject.put("app", app);
                            jsonObject.put("stream", streamId);
                            jsonObject.put("stream", stream);
                            jsonObject.put("register", regist);
                            jsonObject.put("mediaServerId", mediaServerId);
                            redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
@@ -565,4 +637,22 @@
        ret.put("msg", "success");
        return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
    }
    private Map<String, String> urlParamToMap(String params) {
        HashMap<String, String> map = new HashMap<>();
        if (StringUtils.isEmpty(params)) {
            return map;
        }
        String[] paramsArray = params.split("&");
        if (paramsArray.length == 0) {
            return map;
        }
        for (String param : paramsArray) {
            String[] paramArray = param.split("=");
            if (paramArray.length == 2){
                map.put(paramArray[0], paramArray[1]);
            }
        }
        return map;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -115,64 +115,16 @@
    public StreamPushItem addPush(MediaItem mediaItem) {
        // æŸ¥æ‰¾æ­¤ç›´æ’­æµæ˜¯å¦å­˜åœ¨redis预设gbId
        StreamPushItem transform = streamPushService.transform(mediaItem);
        // ä»ŽstreamId取出查询关键值
        Pattern pattern = Pattern.compile(userSetting.getThirdPartyGBIdReg());
        Matcher matcher = pattern.matcher(mediaItem.getStream());// æŒ‡å®šè¦åŒ¹é…çš„字符串
        String queryKey = null;
        if (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
            queryKey = matcher.group();
        StreamPushItem pushInDb = streamPushService.getPush(mediaItem.getApp(), mediaItem.getStream());
        transform.setPushIng(true);
        transform.setUpdateTime(DateUtil.getNow());
        transform.setPushTime(DateUtil.getNow());
        if (pushInDb == null) {
            transform.setCreateTime(DateUtil.getNow());
            streamPushMapper.add(transform);
        }else {
            streamPushMapper.update(transform);
        }
        if (queryKey != null) {
            ThirdPartyGB thirdPartyGB = redisCatchStorage.queryMemberNoGBId(queryKey);
            if (thirdPartyGB != null && !StringUtils.isEmpty(thirdPartyGB.getNationalStandardNo())) {
                transform.setGbId(thirdPartyGB.getNationalStandardNo());
                transform.setName(thirdPartyGB.getName());
            }
        }
        if (!StringUtils.isEmpty(transform.getGbId())) {
            // å¦‚果这个国标ID已经给了其他推流且流已离线,则移除其他推流
            List<GbStream> gbStreams = gbStreamMapper.selectByGBId(transform.getGbId());
            if (gbStreams.size() > 0) {
                for (GbStream gbStream : gbStreams) {
                    // å‡ºçŽ°ä½¿ç”¨ç›¸åŒå›½æ ‡Id的视频流时,使用新流替换旧流,
                    if (queryKey != null && gbStream.getApp().equals(mediaItem.getApp())) {
                        Matcher matcherForStream = pattern.matcher(gbStream.getStream());
                        String queryKeyForStream = null;
                        if (matcherForStream.find()) { //此处find()每次被调用后,会偏移到下一个匹配
                            queryKeyForStream = matcherForStream.group();
                        }
                        if (queryKeyForStream == null || !queryKeyForStream.equals(queryKey)) {
                            // æ­¤æ—¶ä¸æ˜¯åŒä¸€ä¸ªæµ
                            gbStreamMapper.del(gbStream.getApp(), gbStream.getStream());
                            if (!gbStream.isStatus()) {
                                streamPushMapper.del(gbStream.getApp(), gbStream.getStream());
                            }
                        }
                    }
                }
            }
            List<GbStream> gbStreamList = gbStreamMapper.selectByGBId(transform.getGbId());
            if (gbStreamList != null && gbStreamList.size() == 1) {
                transform.setGbStreamId(gbStreamList.get(0).getGbStreamId());
                transform.setPlatformId(gbStreamList.get(0).getPlatformId());
                transform.setCatalogId(gbStreamList.get(0).getCatalogId());
                transform.setGbId(gbStreamList.get(0).getGbId());
                gbStreamMapper.update(transform);
                streamPushMapper.del(gbStreamList.get(0).getApp(), gbStreamList.get(0).getStream());
            }else {
                transform.setCreateTime(DateUtil.getNow());
                transform.setUpdateTime(DateUtil.getNow());
                gbStreamMapper.add(transform);
            }
            if (transform != null) {
                if (channelOnlineEvents.get(transform.getGbId()) != null)  {
                    channelOnlineEvents.get(transform.getGbId()).run(transform.getApp(), transform.getStream(), transform.getServerId());
                    channelOnlineEvents.remove(transform.getGbId());
                }
            }
        }
        storager.updateMedia(transform);
        return transform;
    }
@@ -206,13 +158,13 @@
    public int removeMedia(String app, String streamId) {
        // æŸ¥æ‰¾æ˜¯å¦å…³è”了国标, å…³è”了不删除, ç½®ä¸ºç¦»çº¿
        StreamProxyItem streamProxyItem = gbStreamMapper.selectOne(app, streamId);
        int result = 0;
        if (streamProxyItem == null) {
        GbStream gbStream = gbStreamMapper.selectOne(app, streamId);
        int result;
        if (gbStream == null) {
            result = storager.removeMedia(app, streamId);
        }else {
            // TODO æš‚不设置为离线
            result =storager.mediaOutline(app, streamId);
            result =storager.mediaOffline(app, streamId);
        }
        return result;
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -66,7 +66,7 @@
        String stream = UUID.randomUUID().toString();
        param.put("enable_tcp", 1);
        param.put("stream_id", stream);
        param.put("port", 0);
//        param.put("port", 0);
        JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
        if (openRtpServerResultJson != null) {
@@ -101,9 +101,10 @@
        }
        Map<String, Object> param = new HashMap<>();
        // æŽ¨æµç«¯å£è®¾ç½®0则使用随机端口
        param.put("enable_tcp", 1);
        param.put("stream_id", streamId);
        // æŽ¨æµç«¯å£è®¾ç½®0则使用随机端口
        param.put("port", 0);
        param.put("ssrc", ssrc);
        JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
@@ -291,7 +292,7 @@
            logger.warn("查询流({}/{})是否有其它观看者时得到: {}", app, streamId, mediaInfo.getString("msg"));
            return -1;
        }
        if ( code == 0 && ! mediaInfo.getBoolean("online")) {
        if ( code == 0 && mediaInfo.getBoolean("online") != null && !mediaInfo.getBoolean("online")) {
            logger.warn("查询流({}/{})是否有其它观看者时得到: {}", app, streamId, mediaInfo.getString("msg"));
            return -1;
        }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookParam.java
New file
@@ -0,0 +1,17 @@
package com.genersoft.iot.vmp.media.zlm.dto;
/**
 * zlm hook事件的参数
 * @author lin
 */
public class HookParam {
    private String mediaServerId;
    public String getMediaServerId() {
        return mediaServerId;
    }
    public void setMediaServerId(String mediaServerId) {
        this.mediaServerId = mediaServerId;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaItem.java
@@ -4,6 +4,9 @@
import java.util.List;
/**
 * @author lin
 */
public class MediaItem {
    /**
@@ -20,6 +23,11 @@
     * æµid
     */
    private String stream;
    /**
     * æŽ¨æµé‰´æƒId
     */
    private String callId;
    /**
     * è§‚看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv
@@ -427,4 +435,12 @@
    public void setSeverId(String severId) {
        this.severId = severId;
    }
    public String getCallId() {
        return callId;
    }
    public void setCallId(String callId) {
        this.callId = callId;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/OnPlayHookParam.java
New file
@@ -0,0 +1,82 @@
package com.genersoft.iot.vmp.media.zlm.dto;
/**
 * zlm hook事件中的on_play事件的参数
 * @author lin
 */
public class OnPlayHookParam extends HookParam{
    private String id;
    private String app;
    private String stream;
    private String ip;
    private String params;
    private int port;
    private String schema;
    private String vhost;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getApp() {
        return app;
    }
    public void setApp(String app) {
        this.app = app;
    }
    public String getStream() {
        return stream;
    }
    public void setStream(String stream) {
        this.stream = stream;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public String getParams() {
        return params;
    }
    public void setParams(String params) {
        this.params = params;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public String getSchema() {
        return schema;
    }
    public void setSchema(String schema) {
        this.schema = schema;
    }
    public String getVhost() {
        return vhost;
    }
    public void setVhost(String vhost) {
        this.vhost = vhost;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/OnPublishHookParam.java
New file
@@ -0,0 +1,82 @@
package com.genersoft.iot.vmp.media.zlm.dto;
/**
 * zlm hook事件中的on_publish事件的参数
 * @author lin
 */
public class OnPublishHookParam extends HookParam{
    private String id;
    private String app;
    private String stream;
    private String ip;
    private String params;
    private int port;
    private String schema;
    private String vhost;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getApp() {
        return app;
    }
    public void setApp(String app) {
        this.app = app;
    }
    public String getStream() {
        return stream;
    }
    public void setStream(String stream) {
        this.stream = stream;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
    public String getParams() {
        return params;
    }
    public void setParams(String params) {
        this.params = params;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public String getSchema() {
        return schema;
    }
    public void setSchema(String schema) {
        this.schema = schema;
    }
    public String getVhost() {
        return vhost;
    }
    public void setVhost(String vhost) {
        this.vhost = vhost;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java
New file
@@ -0,0 +1,114 @@
package com.genersoft.iot.vmp.media.zlm.dto;
/**
 * æµçš„鉴权信息
 * @author lin
 */
public class StreamAuthorityInfo {
    private String id;
    private String app;
    private String stream;
    /**
     * äº§ç”Ÿæºç±»åž‹ï¼Œ
     * unknown = 0,
     * rtmp_push=1,
     * rtsp_push=2,
     * rtp_push=3,
     * pull=4,
     * ffmpeg_pull=5,
     * mp4_vod=6,
     * device_chn=7
     */
    private int originType;
    /**
     * äº§ç”Ÿæºç±»åž‹çš„字符串描述
     */
    private String originTypeStr;
    /**
     * æŽ¨æµæ—¶è‡ªå®šä¹‰çš„æ’­æ”¾é‰´æƒID
     */
    private String callId;
    /**
     * æŽ¨æµçš„鉴权签名
     */
    private String sign;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getApp() {
        return app;
    }
    public void setApp(String app) {
        this.app = app;
    }
    public String getStream() {
        return stream;
    }
    public void setStream(String stream) {
        this.stream = stream;
    }
    public int getOriginType() {
        return originType;
    }
    public void setOriginType(int originType) {
        this.originType = originType;
    }
    public String getOriginTypeStr() {
        return originTypeStr;
    }
    public void setOriginTypeStr(String originTypeStr) {
        this.originTypeStr = originTypeStr;
    }
    public String getCallId() {
        return callId;
    }
    public void setCallId(String callId) {
        this.callId = callId;
    }
    public String getSign() {
        return sign;
    }
    public void setSign(String sign) {
        this.sign = sign;
    }
    public static StreamAuthorityInfo getInstanceByHook(OnPublishHookParam hookParam) {
        StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
        streamAuthorityInfo.setApp(hookParam.getApp());
        streamAuthorityInfo.setStream(hookParam.getStream());
        streamAuthorityInfo.setId(hookParam.getId());
        return streamAuthorityInfo;
    }
    public static StreamAuthorityInfo getInstanceByHook(MediaItem mediaItem) {
        StreamAuthorityInfo streamAuthorityInfo = new StreamAuthorityInfo();
        streamAuthorityInfo.setApp(mediaItem.getApp());
        streamAuthorityInfo.setStream(mediaItem.getStream());
        streamAuthorityInfo.setId(mediaItem.getMediaServerId());
        streamAuthorityInfo.setOriginType(mediaItem.getOriginType());
        streamAuthorityInfo.setOriginTypeStr(mediaItem.getOriginTypeStr());
        return streamAuthorityInfo;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
@@ -103,6 +103,11 @@
     */
    private String createTime;
    /**
     * æ˜¯å¦æ­£åœ¨æŽ¨æµ
     */
    private boolean pushIng;
    public String getVhost() {
        return vhost;
    }
@@ -277,5 +282,13 @@
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
    public boolean isPushIng() {
        return pushIng;
    }
    public void setPushIng(boolean pushIng) {
        this.pushIng = pushIng;
    }
}
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
New file
@@ -0,0 +1,35 @@
package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import java.util.List;
/**
 * å›½æ ‡é€šé“业务类
 * @author lin
 */
public interface IDeviceChannelService {
    /**
     * æ›´æ–°gps信息
     */
    DeviceChannel updateGps(DeviceChannel deviceChannel, Device device);
    /**
     * æ·»åŠ è®¾å¤‡é€šé“
     *
     * @param deviceId è®¾å¤‡id
     * @param channel é€šé“
     */
    void updateChannel(String deviceId, DeviceChannel channel);
    /**
     * æ‰¹é‡æ·»åŠ è®¾å¤‡é€šé“
     *
     * @param deviceId è®¾å¤‡id
     * @param channels å¤šä¸ªé€šé“
     */
    int updateChannels(String deviceId, List<DeviceChannel> channels);
}
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java
@@ -18,7 +18,7 @@
     * @param count
     * @return
     */
    PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId,String query,Boolean pushing,String mediaServerId);
    PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId,String query,String mediaServerId);
    /**
src/main/java/com/genersoft/iot/vmp/service/IMediaService.java
@@ -15,7 +15,7 @@
     * @param stream
     * @return
     */
    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr);
    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId,String addr, boolean authority);
    /**
@@ -24,7 +24,7 @@
     * @param stream
     * @return
     */
    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId);
    StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority);
    /**
     * æ ¹æ®åº”用名和流ID获取播放地址, åªæ˜¯åœ°å€æ‹¼æŽ¥
@@ -32,7 +32,7 @@
     * @param stream
     * @return
     */
    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaServerItem, String app, String stream, Object tracks);
    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaServerItem, String app, String stream, Object tracks, String callId);
    /**
     * æ ¹æ®åº”用名和流ID获取播放地址, åªæ˜¯åœ°å€æ‹¼æŽ¥ï¼Œè¿”回的ip使用远程访问ip,适用与zlm与wvp在一台主机的情况
@@ -40,5 +40,5 @@
     * @param stream
     * @return
     */
    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr);
    StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr, String callId);
}
src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java
New file
@@ -0,0 +1,22 @@
package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import java.util.List;
/**
 * å¹³å°å…³è”通道管理
 * @author lin
 */
public interface IPlatformChannelService {
    /**
     * æ›´æ–°ç›®å½•下的通道
     * @param platformId å¹³å°ç¼–号
     * @param channelReduces é€šé“信息
     * @param catalogId ç›®å½•编号
     * @return
     */
    int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId);
}
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
@@ -101,4 +101,9 @@
    void zlmServerOffline(String mediaServerId);
    void clean();
    /**
     * æ›´æ–°ä»£ç†æµ
     */
    boolean updateStreamProxy(StreamProxyItem streamProxyItem);
}
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
@@ -5,6 +5,7 @@
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.github.pagehelper.PageInfo;
@@ -44,31 +45,55 @@
     * åœæ­¢ä¸€è·¯æŽ¨æµ
     * @param app åº”用名
     * @param streamId æµID
     * @return
     */
    boolean stop(String app, String streamId);
    /**
     * æ–°çš„节点加入
     * @param mediaServerId
     * @return
     */
    void zlmServerOnline(String mediaServerId);
    /**
     * èŠ‚ç‚¹ç¦»çº¿
     * @param mediaServerId
     * @return
     */
    void zlmServerOffline(String mediaServerId);
    /**
     * æ¸…空
     */
    void clean();
    boolean saveToRandomGB();
    /**
     * æ‰¹é‡æ·»åŠ 
     */
    void batchAdd(List<StreamPushItem> streamPushExcelDtoList);
    /**
     * ä¸­æ­¢å¤šä¸ªæŽ¨æµ
     */
    boolean batchStop(List<GbStream> streamPushItems);
    /**
     * å¯¼å…¥æ—¶æ‰¹é‡å¢žåŠ 
     */
    void batchAddForUpload(List<StreamPushItem> streamPushItems, Map<String, List<String[]>> streamPushItemsForAll);
    /**
     * å…¨éƒ¨ç¦»çº¿
     */
    void allStreamOffline();
    /**
     * æŽ¨æµç¦»çº¿
     */
    void offline(List<StreamPushItemFromRedis> offlineStreams);
    /**
     * æŽ¨æµä¸Šçº¿
     */
    void online(List<StreamPushItemFromRedis> onlineStreams);
}
src/main/java/com/genersoft/iot/vmp/service/IUserService.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.service;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import com.github.pagehelper.PageInfo;
import java.util.List;
@@ -19,4 +20,10 @@
    List<User> getAllUsers();
    int updateUsers(User user);
    boolean checkPushAuthority(String callId, String sign);
    PageInfo<User> getUsers(int page, int count);
    int changePushKey(int id, String pushKey);
}
src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java
New file
@@ -0,0 +1,41 @@
package com.genersoft.iot.vmp.service.bean;
import java.util.List;
/**
 * æ”¶åˆ°redis通知修改推流通道状态
 * @author lin
 */
public class PushStreamStatusChangeFromRedisDto {
    private boolean setAllOffline;
    private List<StreamPushItemFromRedis> onlineStreams;
    private List<StreamPushItemFromRedis> offlineStreams;
    public boolean isSetAllOffline() {
        return setAllOffline;
    }
    public void setSetAllOffline(boolean setAllOffline) {
        this.setAllOffline = setAllOffline;
    }
    public List<StreamPushItemFromRedis> getOnlineStreams() {
        return onlineStreams;
    }
    public void setOnlineStreams(List<StreamPushItemFromRedis> onlineStreams) {
        this.onlineStreams = onlineStreams;
    }
    public List<StreamPushItemFromRedis> getOfflineStreams() {
        return offlineStreams;
    }
    public void setOfflineStreams(List<StreamPushItemFromRedis> offlineStreams) {
        this.offlineStreams = offlineStreams;
    }
}
src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java
New file
@@ -0,0 +1,34 @@
package com.genersoft.iot.vmp.service.bean;
public class StreamPushItemFromRedis {
    private String app;
    private String stream;
    private long timeStamp;
    public String getApp() {
        return app;
    }
    public void setApp(String app) {
        this.app = app;
    }
    public String getStream() {
        return stream;
    }
    public void setStream(String stream) {
        this.stream = stream;
    }
    public long getTimeStamp() {
        return timeStamp;
    }
    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java
@@ -17,7 +17,6 @@
    @Autowired
    private DeviceAlarmMapper deviceAlarmMapper;
    @Override
    public PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String alarmPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
        PageHelper.startPage(page, count);
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
New file
@@ -0,0 +1,165 @@
package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
 * @author lin
 */
@Service
public class DeviceChannelServiceImpl implements IDeviceChannelService {
    private final static Logger logger = LoggerFactory.getLogger(DeviceChannelServiceImpl.class);
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private DeviceChannelMapper channelMapper;
    @Autowired
    private DeviceMapper deviceMapper;
    @Override
    public DeviceChannel updateGps(DeviceChannel deviceChannel, Device device) {
        if (deviceChannel.getLongitude()*deviceChannel.getLatitude() > 0) {
            if (device == null) {
                device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
            }
            if ("WGS84".equals(device.getGeoCoordSys())) {
                deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
                Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeGcj02(position[0]);
                deviceChannel.setLatitudeGcj02(position[1]);
            }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
                deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
                Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                deviceChannel.setLongitudeWgs84(position[0]);
                deviceChannel.setLatitudeWgs84(position[1]);
            }else {
                deviceChannel.setLongitudeGcj02(0.00);
                deviceChannel.setLatitudeGcj02(0.00);
                deviceChannel.setLongitudeWgs84(0.00);
                deviceChannel.setLatitudeWgs84(0.00);
            }
        }else {
            deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
            deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
            deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
            deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
        }
        return deviceChannel;
    }
    @Override
    public void updateChannel(String deviceId, DeviceChannel channel) {
        String channelId = channel.getChannelId();
        channel.setDeviceId(deviceId);
        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
        if (streamInfo != null) {
            channel.setStreamId(streamInfo.getStream());
        }
        String now = DateUtil.getNow();
        channel.setUpdateTime(now);
        DeviceChannel deviceChannel = channelMapper.queryChannel(deviceId, channelId);
        channel = updateGps(channel, null);
        if (deviceChannel == null) {
            channel.setCreateTime(now);
            channelMapper.add(channel);
        }else {
            channelMapper.update(channel);
        }
        channelMapper.updateChannelSubCount(deviceId,channel.getParentId());
    }
    @Override
    public int updateChannels(String deviceId, List<DeviceChannel> channels) {
        List<DeviceChannel> addChannels = new ArrayList<>();
        List<DeviceChannel> updateChannels = new ArrayList<>();
        HashMap<String, DeviceChannel> channelsInStore = new HashMap<>();
        Device device = deviceMapper.getDeviceByDeviceId(deviceId);
        if (channels != null && channels.size() > 0) {
            List<DeviceChannel> channelList = channelMapper.queryChannels(deviceId, null, null, null, null);
            if (channelList.size() == 0) {
                for (DeviceChannel channel : channels) {
                    channel.setDeviceId(deviceId);
                    StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
                    if (streamInfo != null) {
                        channel.setStreamId(streamInfo.getStream());
                    }
                    String now = DateUtil.getNow();
                    channel.setUpdateTime(now);
                    channel.setCreateTime(now);
                    channel = updateGps(channel, device);
                    addChannels.add(channel);
                }
            }else {
                for (DeviceChannel deviceChannel : channelList) {
                    channelsInStore.put(deviceChannel.getChannelId(), deviceChannel);
                }
                for (DeviceChannel channel : channels) {
                    channel.setDeviceId(deviceId);
                    StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
                    if (streamInfo != null) {
                        channel.setStreamId(streamInfo.getStream());
                    }
                    String now = DateUtil.getNow();
                    channel.setUpdateTime(now);
                    channel = updateGps(channel, device);
                    if (channelsInStore.get(channel.getChannelId()) != null) {
                        updateChannels.add(channel);
                    }else {
                        addChannels.add(channel);
                        channel.setCreateTime(now);
                    }
                }
            }
            int limitCount = 300;
            if (addChannels.size() > 0) {
                if (addChannels.size() > limitCount) {
                    for (int i = 0; i < addChannels.size(); i += limitCount) {
                        int toIndex = i + limitCount;
                        if (i + limitCount > addChannels.size()) {
                            toIndex = addChannels.size();
                        }
                        channelMapper.batchAdd(addChannels.subList(i, toIndex));
                    }
                }else {
                    channelMapper.batchAdd(addChannels);
                }
            }
            if (updateChannels.size() > 0) {
                if (updateChannels.size() > limitCount) {
                    for (int i = 0; i < updateChannels.size(); i += limitCount) {
                        int toIndex = i + limitCount;
                        if (i + limitCount > updateChannels.size()) {
                            toIndex = updateChannels.size();
                        }
                        channelMapper.batchUpdate(updateChannels.subList(i, toIndex));
                    }
                }else {
                    channelMapper.batchUpdate(updateChannels);
                }
            }
        }
        return addChannels.size() + updateChannels.size();
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -7,6 +7,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
@@ -54,6 +55,9 @@
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    @Autowired
    private DeviceChannelMapper deviceChannelMapper;
@@ -324,23 +328,12 @@
    private void updateDeviceChannelGeoCoordSys(Device device) {
       List<DeviceChannel> deviceChannels =  deviceChannelMapper.getAllChannelWithCoordinate(device.getDeviceId());
       if (deviceChannels.size() > 0) {
           List<DeviceChannel> deviceChannelsForStore = new ArrayList<>();
           for (DeviceChannel deviceChannel : deviceChannels) {
               if ("WGS84".equals(device.getGeoCoordSys())) {
                   deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                   deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
                   Double[] position = Coordtransform.WGS84ToGCJ02(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                   deviceChannel.setLongitudeGcj02(position[0]);
                   deviceChannel.setLatitudeGcj02(position[1]);
               }else if ("GCJ02".equals(device.getGeoCoordSys())) {
                   deviceChannel.setLongitudeGcj02(deviceChannel.getLongitude());
                   deviceChannel.setLatitudeGcj02(deviceChannel.getLatitude());
                   Double[] position = Coordtransform.GCJ02ToWGS84(deviceChannel.getLongitude(), deviceChannel.getLatitude());
                   deviceChannel.setLongitudeWgs84(position[0]);
                   deviceChannel.setLatitudeWgs84(position[1]);
               }
               deviceChannelsForStore.add(deviceChannelService.updateGps(deviceChannel, device));
           }
           deviceChannelService.updateChannels(device.getDeviceId(), deviceChannelsForStore);
       }
        storage.updateChannels(device.getDeviceId(), deviceChannels);
    }
@@ -352,11 +345,11 @@
        }
        if (parentId == null || parentId.equals(deviceId)) {
            // å­—根节点开始查询
            List<DeviceChannel> rootNodes = getRootNodes(deviceId, "CivilCode".equals(device.getTreeType()), true, !onlyCatalog);
            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog);
            return transportChannelsToTree(rootNodes, "");
        }
        if ("CivilCode".equals(device.getTreeType())) {
        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
            if (parentId.length()%2 != 0) {
                return null;
            }
@@ -386,7 +379,7 @@
        }
        // ä½¿ç”¨ä¸šåŠ¡åˆ†ç»„å±•ç¤ºæ ‘
        if ("BusinessGroup".equals(device.getTreeType())) {
        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
            if (parentId.length() < 14 ) {
                return null;
            }
@@ -406,11 +399,11 @@
        }
        if (parentId == null || parentId.equals(deviceId)) {
            // å­—根节点开始查询
            List<DeviceChannel> rootNodes = getRootNodes(deviceId, "CivilCode".equals(device.getTreeType()), false, true);
            List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true);
            return rootNodes;
        }
        if ("CivilCode".equals(device.getTreeType())) {
        if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
            if (parentId.length()%2 != 0) {
                return null;
            }
@@ -431,7 +424,7 @@
        }
        // ä½¿ç”¨ä¸šåŠ¡åˆ†ç»„å±•ç¤ºæ ‘
        if ("BusinessGroup".equals(device.getTreeType())) {
        if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
            if (parentId.length() < 14 ) {
                return null;
            }
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
@@ -1,14 +1,13 @@
package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformCatalogMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.github.pagehelper.PageHelper;
@@ -46,15 +45,15 @@
    private ParentPlatformMapper platformMapper;
    @Autowired
    private SipConfig sipConfig;
    private PlatformCatalogMapper catalogMapper;
    @Autowired
    private EventPublisher eventPublisher;
    @Override
    public PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId, String query, Boolean pushing, String mediaServerId) {
    public PageInfo<GbStream> getAll(Integer page, Integer count, String platFormId, String catalogId, String query, String mediaServerId) {
        PageHelper.startPage(page, count);
        List<GbStream> all = gbStreamMapper.selectAll(platFormId, catalogId, query, pushing, mediaServerId);
        List<GbStream> all = gbStreamMapper.selectAll(platFormId, catalogId, query, mediaServerId);
        return new PageInfo<>(all);
    }
@@ -102,16 +101,25 @@
        deviceChannel.setLatitude(gbStream.getLatitude());
        deviceChannel.setDeviceId(platform.getDeviceGBId());
        deviceChannel.setManufacture("wvp-pro");
//        deviceChannel.setStatus(gbStream.isStatus()?1:0);
        deviceChannel.setStatus(1);
        deviceChannel.setParentId(catalogId ==null?gbStream.getCatalogId():catalogId);
        deviceChannel.setStatus(gbStream.isStatus()?1:0);
        deviceChannel.setRegisterWay(1);
        if (catalogId.length() > 0 && catalogId.length() <= 10) {
            // çˆ¶èŠ‚ç‚¹æ˜¯è¡Œæ”¿åŒºåˆ’,则设置CivilCode使用此行政区划
        deviceChannel.setCivilCode(platform.getAdministrativeDivision());
        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
            deviceChannel.setCivilCode(catalogId);
        }else {
            deviceChannel.setCivilCode(platform.getAdministrativeDivision());
        }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());
            }
        }
        deviceChannel.setModel("live");
        deviceChannel.setOwner("wvp-pro");
        deviceChannel.setParental(0);
@@ -149,9 +157,9 @@
        if (gbStream.getGbId() != null) {
            gbStreams.add(gbStream);
        }else {
            StreamProxyItem streamProxyItem = gbStreamMapper.selectOne(gbStream.getApp(), gbStream.getStream());
            if (streamProxyItem != null && streamProxyItem.getGbId() != null){
                gbStreams.add(streamProxyItem);
            GbStream gbStreamIndb  = gbStreamMapper.selectOne(gbStream.getApp(), gbStream.getStream());
            if (gbStreamIndb != null && gbStreamIndb.getGbId() != null){
                gbStreams.add(gbStreamIndb);
            }
        }
        sendCatalogMsgs(gbStreams, type);
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -7,12 +7,15 @@
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.OnPublishHookParam;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.service.IMediaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
public class MediaServiceImpl implements IMediaService {
@@ -36,18 +39,22 @@
    @Override
    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks) {
        return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String callId) {
        return getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null, callId);
    }
    @Override
    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr) {
    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, String addr, boolean authority) {
        StreamInfo streamInfo = null;
        if (mediaServerId == null) {
            mediaServerId = mediaConfig.getId();
        }
        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);;
        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
        if (mediaInfo == null) {
            return null;
        }
        StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
        if (streamAuthorityInfo == null) {
            return null;
        }
        JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaInfo, app, stream);
@@ -59,7 +66,12 @@
                }
                JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
                JSONArray tracks = mediaJSON.getJSONArray("tracks");
                streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks);
                if (authority) {
                    streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, streamAuthorityInfo.getCallId());
                }else {
                    streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, null);
                }
            }
        }
        return streamInfo;
@@ -68,46 +80,48 @@
    @Override
    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId) {
        return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null);
    public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream, String mediaServerId, boolean authority) {
        return getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, null, authority);
    }
    @Override
    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr) {
    public StreamInfo getStreamInfoByAppAndStream(MediaServerItem mediaInfo, String app, String stream, Object tracks, String addr, String callId) {
        StreamInfo streamInfoResult = new StreamInfo();
        streamInfoResult.setStream(stream);
        streamInfoResult.setApp(app);
        if (addr == null) {
            addr = mediaInfo.getStreamIp();
        }
        streamInfoResult.setIp(addr);
        streamInfoResult.setMediaServerId(mediaInfo.getId());
        streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", addr, mediaInfo.getRtmpPort(), app,  stream));
        String callIdParam = StringUtils.isEmpty(callId)?"":"?callId=" + callId;
        streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s%s", addr, mediaInfo.getRtmpPort(), app,  stream, callIdParam));
        if (mediaInfo.getRtmpSSlPort() != 0) {
            streamInfoResult.setRtmps(String.format("rtmps://%s:%s/%s/%s", addr, mediaInfo.getRtmpSSlPort(), app,  stream));
            streamInfoResult.setRtmps(String.format("rtmps://%s:%s/%s/%s%s", addr, mediaInfo.getRtmpSSlPort(), app,  stream, callIdParam));
        }
        streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", addr, mediaInfo.getRtspPort(), app,  stream));
        streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s%s", addr, mediaInfo.getRtspPort(), app,  stream, callIdParam));
        if (mediaInfo.getRtspSSLPort() != 0) {
            streamInfoResult.setRtsps(String.format("rtsps://%s:%s/%s/%s", addr, mediaInfo.getRtspSSLPort(), app,  stream));
            streamInfoResult.setRtsps(String.format("rtsps://%s:%s/%s/%s%s", addr, mediaInfo.getRtspSSLPort(), app,  stream, callIdParam));
        }
        streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.live.flv", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setWs_flv(String.format("ws://%s:%s/%s/%s.live.flv", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setHls(String.format("http://%s:%s/%s/%s/hls.m3u8", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setWs_hls(String.format("ws://%s:%s/%s/%s/hls.m3u8", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setFmp4(String.format("http://%s:%s/%s/%s.live.mp4", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts", addr, mediaInfo.getHttpPort(), app,  stream));
        streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setWs_flv(String.format("ws://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setHls(String.format("http://%s:%s/%s/%s/hls.m3u8%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setWs_hls(String.format("ws://%s:%s/%s/%s/hls.m3u8%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setFmp4(String.format("http://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        if (mediaInfo.getHttpSSlPort() != 0) {
            streamInfoResult.setHttps_flv(String.format("https://%s:%s/%s/%s.live.flv", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setWss_flv(String.format("wss://%s:%s/%s/%s.live.flv", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setHttps_hls(String.format("https://%s:%s/%s/%s/hls.m3u8", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setWss_hls(String.format("wss://%s:%s/%s/%s/hls.m3u8", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setHttps_fmp4(String.format("https://%s:%s/%s/%s.live.mp4", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setWss_fmp4(String.format("wss://%s:%s/%s/%s.live.mp4", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setHttps_ts(String.format("https://%s:%s/%s/%s.live.ts", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts", addr, mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setRtc(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app,  stream));
            streamInfoResult.setHttps_flv(String.format("https://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_flv(String.format("wss://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setHttps_hls(String.format("https://%s:%s/%s/%s/hls.m3u8%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_hls(String.format("wss://%s:%s/%s/%s/hls.m3u8%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setHttps_fmp4(String.format("https://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_fmp4(String.format("wss://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setHttps_ts(String.format("https://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setRtc(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app,  stream, StringUtils.isEmpty(callId)?"":"&callId=" + callId));
        }
        streamInfoResult.setTracks(tracks);
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
New file
@@ -0,0 +1,106 @@
package com.genersoft.iot.vmp.service.impl;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.service.IPlatformChannelService;
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformCatalogMapper;
import com.genersoft.iot.vmp.storager.dao.PlatformChannelMapper;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author lin
 */
@Service
public class PlatformChannelServiceImpl implements IPlatformChannelService {
    private final static Logger logger = LoggerFactory.getLogger(PlatformChannelServiceImpl.class);
    @Autowired
    private PlatformChannelMapper platformChannelMapper;
    @Autowired
    private DeviceChannelMapper deviceChannelMapper;
    @Autowired
    private PlatformCatalogMapper catalogManager;
    @Autowired
    private ParentPlatformMapper platformMapper;
    @Autowired
    EventPublisher eventPublisher;
    @Override
    public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) {
        ParentPlatform platform = platformMapper.getParentPlatByServerGBId(platformId);
        if (platform == null) {
            logger.warn("更新级联通道信息时未找到平台{}的信息", platformId);
            return 0;
        }
        Map<Integer, ChannelReduce> deviceAndChannels = new HashMap<>();
        for (ChannelReduce channelReduce : channelReduces) {
            channelReduce.setCatalogId(catalogId);
            deviceAndChannels.put(channelReduce.getId(), channelReduce);
        }
        List<Integer> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
        // æŸ¥è¯¢å½“前已经存在的
        List<Integer> channelIds = platformChannelMapper.findChannelRelatedPlatform(platformId, channelReduces);
        if (deviceAndChannelList != null) {
            deviceAndChannelList.removeAll(channelIds);
        }
        for (Integer channelId : channelIds) {
            deviceAndChannels.remove(channelId);
        }
        List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values());
        // å¯¹å‰©ä¸‹çš„æ•°æ®è¿›è¡Œå­˜å‚¨
        int result = 0;
        if (channelReducesToAdd.size() > 0) {
            result = platformChannelMapper.addChannels(platformId, channelReducesToAdd);
            // TODO åŽç»­ç»™å¹³å°å¢žåŠ æŽ§åˆ¶å¼€å…³ä»¥æŽ§åˆ¶æ˜¯å¦å“åº”ç›®å½•è®¢é˜…
            List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId, platform);
            eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
        }
        return result;
    }
    private List<DeviceChannel> getDeviceChannelListByChannelReduceList(List<ChannelReduce> channelReduces, String catalogId, ParentPlatform platform) {
        List<DeviceChannel> deviceChannelList = new ArrayList<>();
        if (channelReduces.size() > 0){
            PlatformCatalog catalog = catalogManager.select(catalogId);
            if (catalog == null && !catalogId.equals(platform.getServerGBId())) {
                logger.warn("未查询到目录{}的信息", catalogId);
                return null;
            }
            for (ChannelReduce channelReduce : channelReduces) {
                DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
                deviceChannel.setParental(0);
                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;
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -620,7 +620,7 @@
    public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) {
        String streamId = resonse.getString("stream");
        JSONArray tracks = resonse.getJSONArray("tracks");
        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks);
        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem,"rtp", streamId, tracks, null);
        streamInfo.setDeviceID(deviceId);
        streamInfo.setChannelId(channelId);
        return streamInfo;
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGpsMsgListener.java
@@ -25,9 +25,7 @@
    @Override
    public void onMessage(@NotNull Message message, byte[] bytes) {
        if (logger.isDebugEnabled()) {
            logger.debug("收到来自REDIS的GPS通知: {}", new String(message.getBody()));
        }
        // TODO åŠ æ¶ˆæ¯é˜Ÿåˆ—
        GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class);
        redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
    }
src/main/java/com/genersoft/iot/vmp/service/impl/RedisPushStreamStatusMsgListener.java
New file
@@ -0,0 +1,92 @@
package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.bean.PushStreamStatusChangeFromRedisDto;
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
 * æŽ¥æ”¶redis发送的推流设备上线下线通知
 * @author lin
 */
@Component
public class RedisPushStreamStatusMsgListener implements MessageListener, ApplicationRunner {
    private final static Logger logger = LoggerFactory.getLogger(RedisPushStreamStatusMsgListener.class);
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private IStreamPushService streamPushService;
    @Autowired
    private EventPublisher eventPublisher;
    @Autowired
    private UserSetting userSetting;
    @Autowired
    private DynamicTask dynamicTask;
    @Override
    public void onMessage(Message message, byte[] bytes) {
        PushStreamStatusChangeFromRedisDto statusChangeFromPushStream = JSON.parseObject(message.getBody(), PushStreamStatusChangeFromRedisDto.class);
        if (statusChangeFromPushStream == null) {
            logger.warn("[REDIS æ¶ˆæ¯]推流设备状态变化消息解析失败");
            return;
        }
        if (statusChangeFromPushStream.isSetAllOffline()) {
            // æ‰€æœ‰è®¾å¤‡ç¦»çº¿
            streamPushService.allStreamOffline();
        }
        if (statusChangeFromPushStream.getOfflineStreams() != null
                && statusChangeFromPushStream.getOfflineStreams().size() > 0) {
            // æ›´æ–°éƒ¨åˆ†è®¾å¤‡ç¦»çº¿
            streamPushService.offline(statusChangeFromPushStream.getOfflineStreams());
        }
        if (statusChangeFromPushStream.getOnlineStreams() != null &&
                statusChangeFromPushStream.getOnlineStreams().size() > 0) {
            // æ›´æ–°éƒ¨åˆ†è®¾å¤‡ä¸Šçº¿
            streamPushService.online(statusChangeFromPushStream.getOnlineStreams());
        }
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //  å¯åŠ¨æ—¶è®¾ç½®æ‰€æœ‰æŽ¨æµé€šé“ç¦»çº¿ï¼Œå‘èµ·æŸ¥è¯¢è¯·æ±‚
        redisCatchStorage.sendStreamPushRequestedMsgForStatus();
        dynamicTask.startDelay(VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED, ()->{
            logger.info("[REDIS æ¶ˆæ¯]未收到redis回复推流设备状态,执行推流设备离线");
            // äº”秒收不到请求就设置通道离线,然后通知上级离线
            streamPushService.allStreamOffline();
        }, 5000);
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/RedisStreamMsgListener.java
@@ -3,16 +3,12 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +18,7 @@
/**
 * æŽ¥æ”¶å…¶ä»–wvp发送流变化通知
 * @author lin
 */
@Component
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -3,10 +3,10 @@
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
@@ -23,14 +23,19 @@
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
import java.util.*;
/**
@@ -48,7 +53,7 @@
    private IMediaService mediaService;
    @Autowired
    private ZLMRESTfulUtils zlmresTfulUtils;;
    private ZLMRESTfulUtils zlmresTfulUtils;
    @Autowired
    private StreamProxyMapper streamProxyMapper;
@@ -61,9 +66,6 @@
    @Autowired
    private UserSetting userSetting;
    @Autowired
    private SipConfig sipConfig;
    @Autowired
    private GbStreamMapper gbStreamMapper;
@@ -83,6 +85,12 @@
    @Autowired
    private IMediaServerService mediaServerService;
    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    TransactionDefinition transactionDefinition;
    @Override
    public WVPResult<StreamInfo> save(StreamProxyItem param) {
@@ -99,6 +107,7 @@
            wvpResult.setMsg("保存失败");
            return wvpResult;
        }
        String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
                param.getStream() );
        param.setDst_url(dstUrl);
@@ -108,9 +117,9 @@
        boolean saveResult;
        // æ›´æ–°
        if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) {
            saveResult = videoManagerStorager.updateStreamProxy(param);
            saveResult = updateStreamProxy(param);
        }else { // æ–°å¢ž
            saveResult = videoManagerStorager.addStreamProxy(param);
            saveResult = addStreamProxy(param);
        }
        if (saveResult) {
            result.append("保存成功");
@@ -124,7 +133,7 @@
                    if (param.isEnable_remove_none_reader()) {
                        del(param.getApp(), param.getStream());
                    }else {
                        videoManagerStorager.updateStreamProxy(param);
                        updateStreamProxy(param);
                    }
                }else {
@@ -147,25 +156,79 @@
                result.append(",  å…³è”国标平台[ " + param.getPlatformGbId() + " ]失败");
            }
        }
        if (!StringUtils.isEmpty(param.getGbId())) {
            // æŸ¥æ‰¾å¼€å¯äº†å…¨éƒ¨ç›´æ’­æµå…±äº«çš„上级平台
            List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
            if (parentPlatforms.size() > 0) {
                for (ParentPlatform parentPlatform : parentPlatforms) {
                    param.setPlatformId(parentPlatform.getServerGBId());
                    param.setCatalogId(parentPlatform.getCatalogId());
                    String stream = param.getStream();
                    StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId());
                    if (streamProxyItems == null) {
                        platformGbStreamMapper.add(param);
                        eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), param, CatalogEvent.ADD);
                    }
                }
            }
        }
        wvpResult.setMsg(result.toString());
        return wvpResult;
    }
    /**
     * æ–°å¢žä»£ç†æµ
     * @param streamProxyItem
     * @return
     */
    private boolean addStreamProxy(StreamProxyItem streamProxyItem) {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        boolean result = false;
        streamProxyItem.setStreamType("proxy");
        streamProxyItem.setStatus(true);
        String now = DateUtil.getNow();
        streamProxyItem.setCreateTime(now);
        try {
            if (streamProxyMapper.add(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.add(streamProxyItem) < 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
                        return false;
                    }
                }
            }else {
                //事务回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return false;
            }
            result = true;
            dataSourceTransactionManager.commit(transactionStatus);     //手动提交
        }catch (Exception e) {
            logger.error("向数据库添加流代理失败:", e);
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return result;
    }
    /**
     * æ›´æ–°ä»£ç†æµ
     * @param streamProxyItem
     * @return
     */
    @Override
    public boolean updateStreamProxy(StreamProxyItem streamProxyItem) {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        boolean result = false;
        streamProxyItem.setStreamType("proxy");
        try {
            if (streamProxyMapper.update(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
                        return false;
                    }
                }
            } else {
                //事务回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return false;
            }
            dataSourceTransactionManager.commit(transactionStatus);     //手动提交
            result = true;
        }catch (Exception e) {
            e.printStackTrace();
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return result;
    }
    @Override
@@ -239,7 +302,7 @@
            if (jsonObject.getInteger("code") == 0) {
                result = true;
                streamProxy.setEnable(true);
                videoManagerStorager.updateStreamProxy(streamProxy);
                updateStreamProxy(streamProxy);
            }
        }
        return result;
@@ -253,7 +316,7 @@
            JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto);
            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
                streamProxyDto.setEnable(false);
                result = videoManagerStorager.updateStreamProxy(streamProxyDto);
                result = updateStreamProxy(streamProxyDto);
            }
        }
        return result;
@@ -319,7 +382,7 @@
        }
        streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId);
        // å…¶ä»–的流设置离线
        streamProxyMapper.updateStatusByMediaServerId(false, mediaServerId);
        streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false);
        String type = "PULL";
        // å‘送redis消息
@@ -346,7 +409,7 @@
    @Override
    public int updateStatus(boolean status, String app, String stream) {
        return streamProxyMapper.updateStatus(status, app, stream);
        return streamProxyMapper.updateStatus(app, stream, status);
    }
    private void syncPullStream(String mediaServerId){
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -13,6 +13,7 @@
import com.genersoft.iot.vmp.service.IGbStreamService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.*;
import com.genersoft.iot.vmp.utils.DateUtil;
@@ -37,6 +38,9 @@
    @Autowired
    private StreamPushMapper streamPushMapper;
    @Autowired
    private StreamProxyMapper streamProxyMapper;
    @Autowired
    private ParentPlatformMapper parentPlatformMapper;
@@ -130,29 +134,6 @@
        stream.setStatus(true);
        stream.setCreateTime(DateUtil.getNow());
        int add = gbStreamMapper.add(stream);
        // æŸ¥æ‰¾å¼€å¯äº†å…¨éƒ¨ç›´æ’­æµå…±äº«çš„上级平台
        List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
        if (parentPlatforms.size() > 0) {
            for (ParentPlatform parentPlatform : parentPlatforms) {
                stream.setCatalogId(parentPlatform.getCatalogId());
                stream.setPlatformId(parentPlatform.getServerGBId());
                String streamId = stream.getStream();
                StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());
                if (streamProxyItem == null) {
                    platformGbStreamMapper.add(stream);
                    eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
                }else {
                    if (!streamProxyItem.getGbId().equals(stream.getGbId())) {
                        // æ­¤æµä½¿ç”¨å¦ä¸€ä¸ªå›½æ ‡Id已经与该平台关联,移除此记录
                        platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId());
                        platformGbStreamMapper.add(stream);
                        eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
                    }
                }
            }
        }
        return add > 0;
    }
@@ -178,7 +159,6 @@
    @Override
    public StreamPushItem getPush(String app, String streamId) {
        return streamPushMapper.selectOne(app, streamId);
    }
@@ -285,7 +265,8 @@
        streamPushMapper.deleteWithoutGBId(mediaServerId);
        gbStreamMapper.deleteWithoutGBId("push", mediaServerId);
        // å…¶ä»–的流设置未启用
        gbStreamMapper.updateStatusByMediaServerId(mediaServerId, false);
        streamPushMapper.updateStatusByMediaServerId(mediaServerId, false);
        streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false);
        // å‘送流停止消息
        String type = "PUSH";
        // å‘送redis消息
@@ -341,31 +322,6 @@
    public void batchAdd(List<StreamPushItem> streamPushItems) {
        streamPushMapper.addAll(streamPushItems);
        gbStreamMapper.batchAdd(streamPushItems);
        // æŸ¥æ‰¾å¼€å¯äº†å…¨éƒ¨ç›´æ’­æµå…±äº«çš„上级平台
        List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
        if (parentPlatforms.size() > 0) {
            for (StreamPushItem stream : streamPushItems) {
                for (ParentPlatform parentPlatform : parentPlatforms) {
                    stream.setCatalogId(parentPlatform.getCatalogId());
                    stream.setPlatformId(parentPlatform.getServerGBId());
                    String streamId = stream.getStream();
                    StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId());
                    if (streamProxyItem == null) {
                        platformGbStreamMapper.add(stream);
                        eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
                    }else {
                        if (!streamProxyItem.getGbId().equals(stream.getGbId())) {
                            // æ­¤æµä½¿ç”¨å¦ä¸€ä¸ªå›½æ ‡Id已经与该平台关联,移除此记录
                            platformGbStreamMapper.delByAppAndStreamAndPlatform(stream.getApp(), streamId, parentPlatform.getServerGBId());
                            platformGbStreamMapper.add(stream);
                            eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.ADD);
                            stream.setGbId(streamProxyItem.getGbId());
                            eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), stream, CatalogEvent.DEL);
                        }
                    }
                }
            }
        }
    }
    @Override
@@ -477,4 +433,34 @@
        }
        return true;
    }
    @Override
    public void allStreamOffline() {
        List<GbStream> onlinePushers = streamPushMapper.getOnlinePusherForGb();
        if (onlinePushers.size() == 0) {
            return;
        }
        streamPushMapper.setAllStreamOffline();
        // å‘送通知
        eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.OFF);
    }
    @Override
    public void offline(List<StreamPushItemFromRedis> offlineStreams) {
        // æ›´æ–°éƒ¨åˆ†è®¾å¤‡ç¦»çº¿
        List<GbStream> onlinePushers = streamPushMapper.getOnlinePusherForGbInList(offlineStreams);
        streamPushMapper.offline(offlineStreams);
        // å‘送通知
        eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.OFF);
    }
    @Override
    public void online(List<StreamPushItemFromRedis> onlineStreams) {
        // æ›´æ–°éƒ¨åˆ†è®¾å¤‡ä¸Šçº¿streamPushService
        List<GbStream> onlinePushers = streamPushMapper.getOfflinePusherForGbInList(onlineStreams);
        streamPushMapper.online(onlineStreams);
        // å‘送通知
        eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.ON);
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
@@ -14,38 +14,60 @@
public class StreamPushUploadFileHandler extends AnalysisEventListener<StreamPushExcelDto> {
    // é”™è¯¯æ•°æ®çš„回调,用于将错误数据发送给页面
    /**
     * é”™è¯¯æ•°æ®çš„回调,用于将错误数据发送给页面
     */
    private ErrorDataHandler errorDataHandler;
    // æŽ¨æµçš„业务类用于存储数据
    /**
     * æŽ¨æµçš„业务类用于存储数据
     */
    private IStreamPushService pushService;
    // é»˜è®¤æµåª’体节点ID
    /**
     * é»˜è®¤æµåª’体节点ID
     */
    private String defaultMediaServerId;
    // ç”¨äºŽå­˜å‚¨ä¸åŠ è¿‡æ»¤çš„æ‰€æœ‰æ•°æ®
    /**
     * ç”¨äºŽå­˜å‚¨ä¸åŠ è¿‡æ»¤çš„æ‰€æœ‰æ•°æ®
     */
    private List<StreamPushItem> streamPushItems = new ArrayList<>();
    // ç”¨äºŽå­˜å‚¨æ›´å…·APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表
    /**
     * ç”¨äºŽå­˜å‚¨æ›´å…·APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表
     */
    private Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>();
    // ç”¨äºŽå­˜å‚¨æŒ‰ç…§APP+Stream为KEY, å¹³å°ID+目录Id ä¸ºvalue的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表
    /**
     * ç”¨äºŽå­˜å‚¨æŒ‰ç…§APP+Stream为KEY, å¹³å°ID+目录Id ä¸ºvalue的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表
     */
    private Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>();
    // ç”¨äºŽåˆ¤æ–­æ–‡ä»¶æ˜¯å¦å­˜åœ¨é‡å¤çš„app+Stream+平台ID
    /**
     * ç”¨äºŽåˆ¤æ–­æ–‡ä»¶æ˜¯å¦å­˜åœ¨é‡å¤çš„app+Stream+平台ID
     */
    private Set<String> streamPushStreamSet = new HashSet<>();
    // ç”¨äºŽå­˜å‚¨APP+Stream->国标ID çš„æ•°æ®ç»“æž„, æ•°æ®ä¸€ä¸€å¯¹åº”,全局判断APP+Stream->国标ID是否存在不对应
    /**
     * ç”¨äºŽå­˜å‚¨APP+Stream->国标ID çš„æ•°æ®ç»“æž„, æ•°æ®ä¸€ä¸€å¯¹åº”,全局判断APP+Stream->国标ID是否存在不对应
     */
    private BiMap<String,String> gBMap = HashBiMap.create();
    // è®°å½•错误的APP+Stream
    /**
     * è®°å½•错误的APP+Stream
     */
    private List<String> errorStreamList = new ArrayList<>();
    // è®°å½•错误的国标ID
    /**
     * è®°å½•错误的国标ID
     */
    private List<String> errorGBList = new ArrayList<>();
    // è¯»å–数量计数器
    /**
     * è¯»å–数量计数器
     */
    private int loadedSize = 0;
    public StreamPushUploadFileHandler(IStreamPushService pushService, String defaultMediaServerId, ErrorDataHandler errorDataHandler) {
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
@@ -3,14 +3,17 @@
import com.genersoft.iot.vmp.service.IUserService;
import com.genersoft.iot.vmp.storager.dao.UserMapper;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
@@ -55,4 +58,24 @@
    }
    @Override
    public boolean checkPushAuthority(String callId, String sign) {
        if (StringUtils.isEmpty(callId)) {
            return userMapper.checkPushAuthorityByCallId(sign).size() > 0;
        }else {
            return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0;
        }
    }
    @Override
    public PageInfo<User> getUsers(int page, int count) {
        PageHelper.startPage(page, count);
        List<User> users = userMapper.getUsers();
        return new PageInfo<>(users);
    }
    @Override
    public int changePushKey(int id, String pushKey) {
        return userMapper.changePushKey(id,pushKey);
    }
}
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -3,9 +3,7 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
@@ -213,4 +211,31 @@
     */
    public boolean deviceIsOnline(String deviceId);
    /**
     * å­˜å‚¨æŽ¨æµçš„鉴权信息
     * @param app åº”用名
     * @param stream æµ
     * @param streamAuthorityInfo é‰´æƒä¿¡æ¯
     */
    void updateStreamAuthorityInfo(String app, String stream, StreamAuthorityInfo streamAuthorityInfo);
    /**
     * ç§»é™¤æŽ¨æµçš„鉴权信息
     * @param app åº”用名
     * @param streamId æµ
     */
    void removeStreamAuthorityInfo(String app, String streamId);
    /**
     * èŽ·å–æŽ¨æµçš„é‰´æƒä¿¡æ¯
     * @param app åº”用名
     * @param stream æµ
     * @return
     */
    StreamAuthorityInfo getStreamAuthorityInfo(String app, String stream);
    /**
     * å‘送redis消息 æŸ¥è¯¢æ‰€æœ‰æŽ¨æµè®¾å¤‡çš„状态
     */
    void sendStreamPushRequestedMsgForStatus();
}
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
@@ -27,22 +27,6 @@
    public boolean exists(String deviceId);
    /**
     * æ·»åŠ è®¾å¤‡é€šé“
     *
     * @param deviceId è®¾å¤‡id
     * @param channel é€šé“
     */
    public void updateChannel(String deviceId, DeviceChannel channel);
    /**
     * æ‰¹é‡æ·»åŠ è®¾å¤‡é€šé“
     *
     * @param deviceId è®¾å¤‡id
     * @param channels å¤šä¸ªé€šé“
     */
    public int updateChannels(String deviceId, List<DeviceChannel> channels);
    /**
     * å¼€å§‹æ’­æ”¾
     * @param deviceId è®¾å¤‡id
     * @param channelId é€šé“ID
@@ -224,13 +208,6 @@
    List<DeviceChannelInPlatform> queryChannelListInParentPlatform(String platformId);
    /**
     * æ›´æ–°ä¸Šçº§å¹³å°çš„通道信息
     * @param platformId
     * @param channelReduces
     * @return
     */
    int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId);
    /**
     *  ç§»é™¤ä¸Šçº§å¹³å°çš„通道信息
@@ -277,20 +254,6 @@
    public int clearMobilePositionsByDeviceId(String deviceId);
    /**
     * æ–°å¢žä»£ç†æµ
     * @param streamProxyDto
     * @return
     */
    public boolean addStreamProxy(StreamProxyItem streamProxyDto);
    /**
     * æ›´æ–°ä»£ç†æµ
     * @param streamProxyDto
     * @return
     */
    public boolean updateStreamProxy(StreamProxyItem streamProxyDto);
    /**
     * ç§»é™¤ä»£ç†æµ
     * @param app
     * @param stream
@@ -334,7 +297,7 @@
     * @param platformId
     * @return
     */
    List<GbStream> queryGbStreamListInPlatform(String platformId);
    List<DeviceChannel> queryGbStreamListInPlatform(String platformId);
    /**
     * æ‰¹é‡æ›´æ–°æŽ¨æµåˆ—表
@@ -372,14 +335,16 @@
    /**
     * è®¾ç½®æµç¦»çº¿
     * @param app
     * @param streamId
     */
    int mediaOutline(String app, String streamId);
    int mediaOffline(String app, String streamId);
    /**
     * è®¾ç½®æµä¸Šçº¿
     */
    int mediaOnline(String app, String streamId);
    /**
     * è®¾ç½®å¹³å°åœ¨çº¿/离线
     * @param online
     */
    void updateParentPlatformStatus(String platformGbID, boolean online);
@@ -443,7 +408,7 @@
    int setDefaultCatalog(String platformId, String catalogId);
    List<PlatformCatalog> queryCatalogInPlatform(String serverGBId);
    List<DeviceChannel> queryCatalogInPlatform(String serverGBId);
    int delRelation(PlatformCatalog platformCatalog);
@@ -464,4 +429,8 @@
    List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
    void updateChannelPosition(DeviceChannel deviceChannel);
    void cleanContentForPlatform(String serverGBId);
    List<DeviceChannel> queryChannelWithCatalog(String serverGBId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -329,5 +329,13 @@
    @Select("select * from device_channel where deviceId=#{deviceId} and SUBSTRING(channelId, 11, 3)=#{typeCode}")
    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.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" +
            " left join platform_gb_channel pgc on  dc.id = pgc.deviceChannelId" +
            " left join platform_catalog pc on pgc.catalogId = pc.id and pgc.platformId = pc.platformId" +
            " where pgc.platformId=#{serverGBId}")
    List<DeviceChannel> queryChannelWithCatalog(String serverGBId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
@@ -15,10 +16,10 @@
public interface GbStreamMapper {
    @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " +
            "longitude, latitude, streamType, mediaServerId, status, createTime) VALUES" +
            "longitude, latitude, streamType, mediaServerId, createTime) VALUES" +
            "('${app}', '${stream}', '${gbId}', '${name}', " +
            "'${longitude}', '${latitude}', '${streamType}', " +
            "'${mediaServerId}', ${status}, '${createTime}')")
            "'${mediaServerId}', '${createTime}')")
    @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
    int add(GbStream gbStream);
@@ -30,8 +31,7 @@
            "streamType=#{streamType}," +
            "longitude=#{longitude}, " +
            "latitude=#{latitude}," +
            "mediaServerId=#{mediaServerId}," +
            "status=${status} " +
            "mediaServerId=#{mediaServerId}" +
            "WHERE app=#{app} AND stream=#{stream}")
    int updateByAppAndStream(GbStream gbStream);
@@ -43,8 +43,7 @@
            "streamType=#{streamType}," +
            "longitude=#{longitude}, " +
            "latitude=#{latitude}," +
            "mediaServerId=#{mediaServerId}," +
            "status=${status} " +
            "mediaServerId=#{mediaServerId}" +
            "WHERE gbStreamId=#{gbStreamId}")
    int update(GbStream gbStream);
@@ -60,15 +59,13 @@
            " <if test='catalogId == null'> AND gs.gbStreamId not in" +
            "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId}) </if> " +
            " <if test='query != null'> AND (gs.app LIKE '%${query}%' OR gs.stream LIKE '%${query}%' OR gs.gbId LIKE '%${query}%' OR gs.name LIKE '%${query}%')</if> " +
            " <if test='pushing == true' > AND gs.status=1</if>" +
            " <if test='pushing == false' > AND gs.status=0</if>" +
            " <if test='mediaServerId != null' > AND gs.mediaServerId=#{mediaServerId} </if>" +
            " order by gs.gbStreamId asc " +
            "</script>")
    List<GbStream> selectAll(String platformId, String catalogId, String query, Boolean pushing, String mediaServerId);
    List<GbStream> selectAll(String platformId, String catalogId, String query, String mediaServerId);
    @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
    StreamProxyItem selectOne(String app, String stream);
    GbStream selectOne(String app, String stream);
    @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
    List<GbStream> selectByGBId(String gbId);
@@ -78,25 +75,23 @@
            "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
    GbStream queryStreamInPlatform(String platformId, String gbId);
    @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
            "LEFT JOIN platform_gb_stream pgs ON gs.gbStreamId = pgs.gbStreamId " +
            "WHERE pgs.platformId = #{platformId}")
    List<GbStream> queryGbStreamListInPlatform(String platformId);
    @Select("select gt.gbId as channelId, gt.name, 'wvp-pro' as manufacture,  st.status, gt.longitude, gt.latitude, pc.id as parentId," +
            "       '1' as registerWay, pc.civilCode, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" +
            " from gb_stream gt " +
            " left join (" +
            "    select sp.status, sp.app, sp.stream from stream_push sp" +
            "    union all" +
            "    select spxy.status, spxy.app, spxy.stream from stream_proxy spxy" +
            " ) st on st.app = gt.app and st.stream = gt.stream" +
            " left join platform_gb_stream pgs on  gt.gbStreamId = pgs.gbStreamId" +
            " left join platform_catalog pc on pgs.catalogId = pc.id and pgs.platformId = pc.platformId" +
            " where pgs.platformId=#{platformId}")
    List<DeviceChannel> queryGbStreamListInPlatform(String platformId);
    @Select("SELECT gs.* FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " +
            "ON gs.gbStreamId = pgs.gbStreamId WHERE pgs.gbStreamId is NULL")
    List<GbStream> queryStreamNotInPlatform();
    @Update("UPDATE gb_stream " +
            "SET status=${status} " +
            "WHERE app=#{app} AND stream=#{stream}")
    int setStatus(String app, String stream, boolean status);
    @Update("UPDATE gb_stream " +
            "SET status=${status} " +
            "WHERE mediaServerId=#{mediaServerId} ")
    void updateStatusByMediaServerId(String mediaServerId, boolean status);
    @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}")
    void deleteWithoutGBId(String type, String mediaServerId);
@@ -120,12 +115,12 @@
    @Insert("<script> " +
            "INSERT IGNORE into gb_stream " +
            "(app, stream, gbId, name, " +
            "longitude, latitude, streamType, mediaServerId, status, createTime)" +
            "longitude, latitude, streamType, mediaServerId, createTime)" +
            "values " +
            "<foreach collection='subList' index='index' item='item' separator=','> " +
            "('${item.app}', '${item.stream}', '${item.gbId}', '${item.name}', " +
            "'${item.longitude}', '${item.latitude}', '${item.streamType}', " +
            "'${item.mediaServerId}', ${item.status}, '${item.createTime}') "+
            "'${item.mediaServerId}', '${item.createTime}') "+
            "</foreach> " +
            "</script>")
    @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
@@ -16,10 +16,10 @@
    @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
            "            devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
            "            status, shareAllLiveStream, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime) " +
            "            status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " +
            "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
            "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
            "            ${status}, ${shareAllLiveStream},  ${startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})")
            "            ${status},  ${startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
    int addParentPlatform(ParentPlatform parentPlatform);
    @Update("UPDATE parent_platform " +
@@ -41,12 +41,12 @@
            "ptz=#{ptz}, " +
            "rtcp=#{rtcp}, " +
            "status=#{status}, " +
            "shareAllLiveStream=#{shareAllLiveStream}, " +
            "startOfflinePush=${startOfflinePush}, " +
            "catalogGroup=#{catalogGroup}, " +
            "administrativeDivision=#{administrativeDivision}, " +
            "createTime=#{createTime}, " +
            "updateTime=#{updateTime}, " +
            "treeType=#{treeType}, " +
            "catalogId=#{catalogId} " +
            "WHERE id=#{id}")
    int updateParentPlatform(ParentPlatform parentPlatform);
@@ -82,9 +82,6 @@
    @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" )
    int updateParentPlatformStatus(String platformGbID, boolean online);
    @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true")
    List<ParentPlatform> selectAllAhareAllLiveStream();
    @Update(value = {" <script>" +
            "UPDATE parent_platform " +
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
@@ -14,8 +15,8 @@
@Repository
public interface PlatformCatalogMapper {
    @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId) VALUES" +
            "(#{id}, #{name}, #{platformId}, #{parentId})")
    @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId, civilCode, businessGroupId) VALUES" +
            "(#{id}, #{name}, #{platformId}, #{parentId}, #{civilCode}, #{businessGroupId})")
    int add(PlatformCatalog platformCatalog);
    @Delete("DELETE FROM platform_catalog WHERE id=#{id}")
@@ -44,4 +45,12 @@
    @Select("SELECT pc.* FROM  platform_catalog pc WHERE  pc.id = (SELECT pp.catalogId from parent_platform pp WHERE pp.serverGBId=#{platformId})")
    PlatformCatalog selectDefaultByPlatFormId(String platformId);
    @Select("SELECT pc.* FROM  platform_catalog pc WHERE  pc.id = #{id}")
    PlatformCatalog selectParentCatalog(String id);
    @Select("SELECT pc.id as channelId, pc.name, pc.civilCode, pc.businessGroupId,'0' as parental, pc.parentId  " +
            " FROM platform_catalog pc WHERE pc.platformId=#{platformId}")
    List<DeviceChannel> queryCatalogInPlatform(String platformId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -62,12 +62,12 @@
    @Update("UPDATE stream_proxy " +
            "SET status=#{status} " +
            "WHERE mediaServerId=#{mediaServerId}")
    void updateStatusByMediaServerId(boolean status, String mediaServerId);
    void updateStatusByMediaServerId(String mediaServerId, boolean status);
    @Update("UPDATE stream_proxy " +
            "SET status=${status} " +
            "WHERE app=#{app} AND stream=#{stream}")
    int updateStatus(boolean status, String app, String stream);
    int updateStatus(String app, String stream, boolean status);
    @Delete("DELETE FROM stream_proxy WHERE enable_remove_none_reader=true AND mediaServerId=#{mediaServerId}")
    void deleteAutoRemoveItemByMediaServerId(String mediaServerId);
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
@@ -2,6 +2,7 @@
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
import org.apache.ibatis.annotations.*;
// import org.omg.PortableInterceptor.INACTIVE;
import org.springframework.stereotype.Repository;
@@ -14,21 +15,24 @@
public interface StreamPushMapper {
    @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
            "createStamp, aliveSecond, mediaServerId, serverId) VALUES" +
            "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime, pushIng) VALUES" +
            "('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
            "'${createStamp}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' )")
            "'${pushTime}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' , '${updateTime}' , '${createTime}', ${pushIng} )")
    int add(StreamPushItem streamPushItem);
    @Update("UPDATE stream_push " +
            "SET app=#{app}," +
            "stream=#{stream}," +
            "mediaServerId=#{mediaServerId}," +
            "totalReaderCount=#{totalReaderCount}, " +
            "originType=#{originType}," +
            "originTypeStr=#{originTypeStr}, " +
            "createStamp=#{createStamp}, " +
            "aliveSecond=#{aliveSecond} " +
            "WHERE app=#{app} AND stream=#{stream}")
    @Update(value = {" <script>" +
            "UPDATE stream_push " +
            "SET updateTime='${updateTime}'" +
            "<if test=\"mediaServerId != null\">, mediaServerId='${mediaServerId}'</if>" +
            "<if test=\"totalReaderCount != null\">, totalReaderCount='${totalReaderCount}'</if>" +
            "<if test=\"originType != null\">, originType=${originType}</if>" +
            "<if test=\"originTypeStr != null\">, originTypeStr='${originTypeStr}'</if>" +
            "<if test=\"pushTime != null\">, pushTime='${pushTime}'</if>" +
            "<if test=\"aliveSecond != null\">, aliveSecond='${aliveSecond}'</if>" +
            "<if test=\"pushIng != null\">, pushIng=${pushIng}</if>" +
            "WHERE app=#{app} AND stream=#{stream}"+
            " </script>"})
    int update(StreamPushItem streamPushItem);
    @Delete("DELETE FROM stream_push WHERE app=#{app} AND stream=#{stream}")
@@ -62,7 +66,7 @@
    @Select(value = {" <script>" +
            "SELECT " +
            "st.*, " +
            "gs.gbId, gs.status, gs.name, gs.longitude, gs.latitude, gs.gbStreamId " +
            "gs.gbId, gs.name, gs.longitude, gs.latitude, gs.gbStreamId " +
            "from " +
            "stream_push st " +
            "LEFT JOIN gb_stream gs " +
@@ -70,25 +74,26 @@
            "WHERE " +
            "1=1 " +
            " <if test='query != null'> AND (st.app LIKE '%${query}%' OR st.stream LIKE '%${query}%' OR gs.gbId LIKE '%${query}%' OR gs.name LIKE '%${query}%')</if> " +
            " <if test='pushing == true' > AND (gs.gbId is null OR gs.status=1)</if>" +
            " <if test='pushing == false' > AND gs.status=0</if>" +
            " <if test='pushing == true' > AND (gs.gbId is null OR st.status=1)</if>" +
            " <if test='pushing == false' > AND st.status=0</if>" +
            " <if test='mediaServerId != null' > AND st.mediaServerId=#{mediaServerId} </if>" +
            "order by st.createStamp desc" +
            "order by st.createTime desc" +
            " </script>"})
    List<StreamPushItem> selectAllForList(String query, Boolean pushing, String mediaServerId);
    @Select("SELECT st.*, gs.gbId, gs.status, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.createStamp desc")
    @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.createTime desc")
    List<StreamPushItem> selectAll();
    @Select("SELECT st.*, gs.gbId, gs.status, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
    @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
    StreamPushItem selectOne(String app, String stream);
    @Insert("<script>"  +
            "Insert IGNORE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
            "createStamp, aliveSecond, mediaServerId) " +
            "createTime, aliveSecond, mediaServerId, status, pushIng) " +
            "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" +
            "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', #{item.originType}, " +
            "'${item.originTypeStr}',#{item.createStamp}, #{item.aliveSecond}, '${item.mediaServerId}' )" +
            "'${item.originTypeStr}',#{item.createTime}, #{item.aliveSecond}, '${item.mediaServerId}', ${item.status} ," +
            " ${item.pushIng} )" +
            " </foreach>" +
            "</script>")
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@@ -106,4 +111,59 @@
    @Select("SELECT sp.* FROM stream_push sp left join gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.mediaServerId=#{mediaServerId} and gs.gbId is null")
    List<StreamPushItem> selectAllByMediaServerIdWithOutGbID(String mediaServerId);
    @Update("UPDATE stream_push " +
            "SET status=${status} " +
            "WHERE app=#{app} AND stream=#{stream}")
    int updateStatus(String app, String stream, boolean status);
    @Update("UPDATE stream_push " +
            "SET pushIng=${pushIng} " +
            "WHERE app=#{app} AND stream=#{stream}")
    int updatePushStatus(String app, String stream, boolean status);
    @Update("UPDATE stream_push " +
            "SET status=#{status} " +
            "WHERE mediaServerId=#{mediaServerId}")
    void updateStatusByMediaServerId(String mediaServerId, boolean status);
    @Select("<script> "+
            "SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
            "where sp.status = 1 and (gs.app, gs.stream) in (" +
            "<foreach collection='offlineStreams' item='item' separator=','>" +
            "(#{item.app}, #{item.stream}) " +
            "</foreach>" +
            ")</script>")
    List<GbStream> getOnlinePusherForGbInList(List<StreamPushItemFromRedis> offlineStreams);
    @Update("<script> "+
            "UPDATE stream_push SET status=0  where (app, stream) in (" +
            "<foreach collection='offlineStreams' item='item' separator=','>" +
            "(#{item.app}, #{item.stream}) " +
            "</foreach>" +
            ")</script>")
    void offline(List<StreamPushItemFromRedis> offlineStreams);
    @Select("<script> "+
            "SELECT * FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
            "where sp.status = 0 and (gs.app, gs.stream) in (" +
            "<foreach collection='onlineStreams' item='item' separator=','>" +
            "(#{item.app}, #{item.stream}) " +
            "</foreach>" +
            ") </script>")
    List<GbStream> getOfflinePusherForGbInList(List<StreamPushItemFromRedis> onlineStreams);
    @Update("<script> "+
            "UPDATE stream_push SET status=1  where (app, stream) in (" +
            "<foreach collection='onlineStreams' item='item' separator=','>" +
            "(#{item.app}, #{item.stream}) " +
            "</foreach>" +
            ")</script>")
    void online(List<StreamPushItemFromRedis> onlineStreams);
    @Select("SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = 1")
    List<GbStream> getOnlinePusherForGb();
    @Update("UPDATE stream_push SET status=0")
    void setAllStreamOffline();
}
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
@@ -10,13 +10,14 @@
@Repository
public interface UserMapper {
    @Insert("INSERT INTO user (username, password, roleId, createTime, updateTime) VALUES" +
            "('${username}', '${password}', '${role.id}', '${createTime}', '${updateTime}')")
    @Insert("INSERT INTO user (username, password, roleId, pushKey, createTime, updateTime) VALUES" +
            "('${username}', '${password}', '${role.id}', '${pushKey}', '${createTime}', '${updateTime}')")
    int add(User user);
    @Update(value = {" <script>" +
            "UPDATE user " +
            "SET updateTime='${updateTime}' " +
            "<if test=\"pushKey != null\">, pushKey='${pushKey}'</if>" +
            "<if test=\"role != null\">, roleId='${role.id}'</if>" +
            "<if test=\"password != null\">, password='${password}'</if>" +
            "<if test=\"username != null\">, username='${username}'</if>" +
@@ -48,4 +49,17 @@
    @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id")
    @ResultMap(value="roleMap")
    List<User> selectAll();
    @Select("select * from (select user.*, concat('${callId}_', pushKey) as str1 from user) as u where md5(u.str1) = '${sign}'")
    List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign);
    @Select("select * from user where md5(pushKey) = '${sign}'")
    List<User> checkPushAuthorityByCallId(String sign);
    @Select("select u.id, u.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id")
    @ResultMap(value="roleMap")
    List<User> getUsers();
    @Update("update user set pushKey=#{pushKey} where id=#{id}")
    int changePushKey(int id, String pushKey);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java
@@ -7,6 +7,7 @@
    private String password;
    private String createTime;
    private String updateTime;
    private String pushKey;
    private Role role;
    public int getId() {
@@ -56,4 +57,12 @@
    public void setRole(Role role) {
        this.role = role;
    }
    public String getPushKey() {
        return pushKey;
    }
    public void setPushKey(String pushKey) {
        this.pushKey = pushKey;
    }
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -9,6 +9,8 @@
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.OnPublishHookParam;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
@@ -20,6 +22,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -482,7 +485,12 @@
    @Override
    public void addStream(MediaServerItem mediaServerItem, String type, String app, String streamId, MediaItem mediaItem) {
        // æŸ¥æ‰¾æ˜¯å¦ä½¿ç”¨äº†callID
        StreamAuthorityInfo streamAuthorityInfo = getStreamAuthorityInfo(app, streamId);
        String key = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX  + userSetting.getServerId() + "_" + type + "_" + app + "_" + streamId + "_" + mediaServerItem.getId();
        if (streamAuthorityInfo != null) {
            mediaItem.setCallId(streamAuthorityInfo.getCallId());
        }
        redis.set(key, mediaItem);
    }
@@ -599,6 +607,26 @@
    }
    @Override
    public void updateStreamAuthorityInfo(String app, String stream, StreamAuthorityInfo streamAuthorityInfo) {
        String key = VideoManagerConstants.MEDIA_STREAM_AUTHORITY + userSetting.getServerId() + "_" + app+ "_" + stream;
        redis.set(key, streamAuthorityInfo);
    }
    @Override
    public void removeStreamAuthorityInfo(String app, String stream) {
        String key = VideoManagerConstants.MEDIA_STREAM_AUTHORITY + userSetting.getServerId() + "_" + app+ "_" + stream ;
        redis.del(key);
    }
    @Override
    public StreamAuthorityInfo getStreamAuthorityInfo(String app, String stream) {
        String key = VideoManagerConstants.MEDIA_STREAM_AUTHORITY + userSetting.getServerId() + "_" + app+ "_" + stream ;
        return (StreamAuthorityInfo) redis.get(key);
    }
    @Override
    public MediaItem getStreamInfo(String app, String streamId, String mediaServerId) {
        String scanKey = VideoManagerConstants.WVP_SERVER_STREAM_PREFIX  + userSetting.getServerId() + "_*_" + app + "_" + streamId + "_" + mediaServerId;
@@ -682,4 +710,14 @@
    public boolean deviceIsOnline(String deviceId) {
        return getDevice(deviceId).getOnline() == 1;
    }
    @Override
    public void sendStreamPushRequestedMsgForStatus() {
        String key = VideoManagerConstants.VM_MSG_GET_ALL_ONLINE_REQUESTED;
        logger.info("[redis é€šçŸ¥]获取所有推流设备的状态");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(key, key);
        redis.convertAndSend(key, jsonObject);
    }
}
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -48,11 +48,12 @@
    @Autowired
    SipConfig sipConfig;
    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    TransactionDefinition transactionDefinition;
    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    private DeviceMapper deviceMapper;
@@ -102,96 +103,6 @@
    @Override
    public boolean exists(String deviceId) {
        return deviceMapper.getDeviceByDeviceId(deviceId) != null;
    }
    @Override
    public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
        String channelId = channel.getChannelId();
        channel.setDeviceId(deviceId);
        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
        if (streamInfo != null) {
            channel.setStreamId(streamInfo.getStream());
        }
        String now = DateUtil.getNow();
        channel.setUpdateTime(now);
        DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
        if (deviceChannel == null) {
            channel.setCreateTime(now);
            deviceChannelMapper.add(channel);
        }else {
            deviceChannelMapper.update(channel);
        }
        deviceChannelMapper.updateChannelSubCount(deviceId,channel.getParentId());
    }
    @Override
    public int updateChannels(String deviceId, List<DeviceChannel> channels) {
        List<DeviceChannel> addChannels = new ArrayList<>();
        List<DeviceChannel> updateChannels = new ArrayList<>();
        HashMap<String, DeviceChannel> channelsInStore = new HashMap<>();
        if (channels != null && channels.size() > 0) {
            List<DeviceChannel> channelList = deviceChannelMapper.queryChannels(deviceId, null, null, null, null);
            if (channelList.size() == 0) {
                for (DeviceChannel channel : channels) {
                    channel.setDeviceId(deviceId);
                    StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
                    if (streamInfo != null) {
                        channel.setStreamId(streamInfo.getStream());
                    }
                    String now = DateUtil.getNow();
                    channel.setUpdateTime(now);
                    channel.setCreateTime(now);
                    addChannels.add(channel);
                }
            }else {
                for (DeviceChannel deviceChannel : channelList) {
                    channelsInStore.put(deviceChannel.getChannelId(), deviceChannel);
                }
                for (DeviceChannel channel : channels) {
                    channel.setDeviceId(deviceId);
                    StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channel.getChannelId());
                    if (streamInfo != null) {
                        channel.setStreamId(streamInfo.getStream());
                    }
                    String now = DateUtil.getNow();
                    channel.setUpdateTime(now);
                    if (channelsInStore.get(channel.getChannelId()) != null) {
                        updateChannels.add(channel);
                    }else {
                        addChannels.add(channel);
                        channel.setCreateTime(now);
                    }
                }
            }
            int limitCount = 300;
            if (addChannels.size() > 0) {
                if (addChannels.size() > limitCount) {
                    for (int i = 0; i < addChannels.size(); i += limitCount) {
                        int toIndex = i + limitCount;
                        if (i + limitCount > addChannels.size()) {
                            toIndex = addChannels.size();
                        }
                        deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex));
                    }
                }else {
                    deviceChannelMapper.batchAdd(addChannels);
                }
            }
            if (updateChannels.size() > 0) {
                if (updateChannels.size() > limitCount) {
                    for (int i = 0; i < updateChannels.size(); i += limitCount) {
                        int toIndex = i + limitCount;
                        if (i + limitCount > updateChannels.size()) {
                            toIndex = updateChannels.size();
                        }
                        deviceChannelMapper.batchUpdate(updateChannels.subList(i, toIndex));
                    }
                }else {
                    deviceChannelMapper.batchUpdate(updateChannels);
                }
            }
        }
        return addChannels.size() + updateChannels.size();
    }
    @Override
@@ -532,20 +443,6 @@
        // æ›´æ–°ç¼“å­˜
        parentPlatformCatch.setParentPlatform(parentPlatform);
        redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
        if (parentPlatform.isEnable()) {
            // å…±äº«æ‰€æœ‰è§†é¢‘流,需要将现有视频流添加到此平台
            List<GbStream> gbStreams = gbStreamMapper.queryStreamNotInPlatform();
            if (gbStreams.size() > 0) {
                for (GbStream gbStream : gbStreams) {
                    gbStream.setCatalogId(parentPlatform.getCatalogId());
                }
                if (parentPlatform.isShareAllLiveStream()) {
                    gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId());
                }else {
                    gbStreamService.delPlatformInfo(parentPlatform.getServerGBId(), gbStreams);
                }
            }
        }
        return result > 0;
    }
@@ -594,36 +491,6 @@
    public List<DeviceChannelInPlatform> queryChannelListInParentPlatform(String platformId) {
        return deviceChannelMapper.queryChannelByPlatformId(platformId);
    }
    @Override
    public int updateChannelForGB(String platformId, List<ChannelReduce> channelReduces, String catalogId) {
        Map<Integer, ChannelReduce> deviceAndChannels = new HashMap<>();
        for (ChannelReduce channelReduce : channelReduces) {
            channelReduce.setCatalogId(catalogId);
            deviceAndChannels.put(channelReduce.getId(), channelReduce);
        }
        List<Integer> deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet());
        // æŸ¥è¯¢å½“前已经存在的
        List<Integer> channelIds = platformChannelMapper.findChannelRelatedPlatform(platformId, channelReduces);
        if (deviceAndChannelList != null) {
            deviceAndChannelList.removeAll(channelIds);
        }
        for (Integer channelId : channelIds) {
            deviceAndChannels.remove(channelId);
        }
        List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values());
        // å¯¹å‰©ä¸‹çš„æ•°æ®è¿›è¡Œå­˜å‚¨
        int result = 0;
        if (channelReducesToAdd.size() > 0) {
            result = platformChannelMapper.addChannels(platformId, channelReducesToAdd);
            // TODO åŽç»­ç»™å¹³å°å¢žåŠ æŽ§åˆ¶å¼€å…³ä»¥æŽ§åˆ¶æ˜¯å¦å“åº”ç›®å½•è®¢é˜…
            List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId);
            eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
        }
        return result;
    }
@@ -701,77 +568,6 @@
        return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId);
    }
    /**
     * æ–°å¢žä»£ç†æµ
     * @param streamProxyItem
     * @return
     */
    @Override
    public boolean addStreamProxy(StreamProxyItem streamProxyItem) {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        boolean result = false;
        streamProxyItem.setStreamType("proxy");
        streamProxyItem.setStatus(true);
        String now = DateUtil.getNow();
        streamProxyItem.setCreateTime(now);
        try {
            if (streamProxyMapper.add(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.add(streamProxyItem) < 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
                        return false;
                    }
                }
            }else {
                //事务回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return false;
            }
            result = true;
            dataSourceTransactionManager.commit(transactionStatus);     //手动提交
        }catch (Exception e) {
            logger.error("向数据库添加流代理失败:", e);
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return result;
    }
    /**
     * æ›´æ–°ä»£ç†æµ
     * @param streamProxyItem
     * @return
     */
    @Override
    public boolean updateStreamProxy(StreamProxyItem streamProxyItem) {
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        boolean result = false;
        streamProxyItem.setStreamType("proxy");
        try {
            if (streamProxyMapper.update(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
                        return false;
                    }
                }
            } else {
                //事务回滚
                dataSourceTransactionManager.rollback(transactionStatus);
                return false;
            }
            dataSourceTransactionManager.commit(transactionStatus);     //手动提交
            result = true;
        }catch (Exception e) {
            e.printStackTrace();
            dataSourceTransactionManager.rollback(transactionStatus);
        }
        return result;
    }
    /**
     * ç§»é™¤ä»£ç†æµ
@@ -824,7 +620,7 @@
     * @return
     */
    @Override
    public List<GbStream> queryGbStreamListInPlatform(String platformId) {
    public List<DeviceChannel> queryGbStreamListInPlatform(String platformId) {
        return gbStreamMapper.queryGbStreamListInPlatform(platformId);
    }
@@ -848,7 +644,7 @@
        streamPushMapper.addAll(streamPushItems);
        // TODO å¾…优化
        for (int i = 0; i < streamPushItems.size(); i++) {
            int onlineResult = gbStreamMapper.setStatus(streamPushItems.get(i).getApp(), streamPushItems.get(i).getStream(), true);
            int onlineResult = mediaOnline(streamPushItems.get(i).getApp(), streamPushItems.get(i).getStream());
            if (onlineResult > 0) {
                // å‘送上线通知
                eventPublisher.catalogEventPublishForStream(null, streamPushItems.get(i), CatalogEvent.ON);
@@ -856,29 +652,13 @@
        }
    }
    @Override
    public void updateMedia(StreamPushItem streamPushItem) {
        streamPushMapper.del(streamPushItem.getApp(), streamPushItem.getStream());
        streamPushMapper.add(streamPushItem);
        gbStreamMapper.setStatus(streamPushItem.getApp(), streamPushItem.getStream(), true);
        if(!StringUtils.isEmpty(streamPushItem.getGbId() )){
            // æŸ¥æ‰¾å¼€å¯äº†å…¨éƒ¨ç›´æ’­æµå…±äº«çš„上级平台
            List<ParentPlatform> parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream();
            if (parentPlatforms.size() > 0) {
                for (ParentPlatform parentPlatform : parentPlatforms) {
                    StreamProxyItem streamProxyItem = platformGbStreamMapper.selectOne(streamPushItem.getApp(), streamPushItem.getStream(),
                            parentPlatform.getServerGBId());
                    if (streamProxyItem == null) {
                        streamPushItem.setCatalogId(parentPlatform.getCatalogId());
                        streamPushItem.setPlatformId(parentPlatform.getServerGBId());
                        platformGbStreamMapper.add(streamPushItem);
                        eventPublisher.catalogEventPublishForStream(parentPlatform.getServerGBId(), streamPushItem, CatalogEvent.ADD);
                    }
                }
            }
        }
        mediaOffline(streamPushItem.getApp(), streamPushItem.getStream());
    }
    @Override
@@ -897,8 +677,27 @@
    }
    @Override
    public int mediaOutline(String app, String streamId) {
        return gbStreamMapper.setStatus(app, streamId, false);
    public int mediaOffline(String app, String stream) {
        GbStream gbStream = gbStreamMapper.selectOne(app, stream);
        int result;
        if ("proxy".equals(gbStream.getStreamType())) {
            result = streamProxyMapper.updateStatus(app, stream, false);
        }else {
            result = streamPushMapper.updateStatus(app, stream, false);
        }
        return result;
    }
    @Override
    public int mediaOnline(String app, String stream) {
        GbStream gbStream = gbStreamMapper.selectOne(app, stream);
        int result;
        if ("proxy".equals(gbStream.getStreamType())) {
            result = streamProxyMapper.updateStatus(app, stream, true);
        }else {
            result = streamPushMapper.updateStatus(app, stream, true);
        }
        return result;
    }
    @Override
@@ -934,12 +733,39 @@
    @Override
    public int addCatalog(PlatformCatalog platformCatalog) {
        ParentPlatform platform = platformMapper.getParentPlatByServerGBId(platformCatalog.getPlatformId());
        if (platform == null) {
            return 0;
        }
        if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
            if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) {
                // ç¬¬ä¸€å±‚节点
                platformCatalog.setBusinessGroupId(platformCatalog.getId());
            }else {
                // èŽ·å–é¡¶å±‚çš„
                PlatformCatalog topCatalog = getTopCatalog(platformCatalog.getParentId(), platformCatalog.getPlatformId());
                platformCatalog.setBusinessGroupId(topCatalog.getId());
            }
        }
        if (platform.getTreeType().equals(TreeType.CIVIL_CODE)) {
            platformCatalog.setCivilCode(platformCatalog.getId());
        }
        int result = catalogMapper.add(platformCatalog);
        if (result > 0) {
            DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog);
            eventPublisher.catalogEventPublish(platformCatalog.getPlatformId(), deviceChannel, CatalogEvent.ADD);
        }
        return result;
    }
    private PlatformCatalog getTopCatalog(String id, String platformId) {
        PlatformCatalog catalog = catalogMapper.selectParentCatalog(id);
        if (catalog.getParentId().equals(platformId)) {
            return catalog;
        }else {
            return getTopCatalog(catalog.getParentId(), platformId);
        }
    }
    @Override
@@ -1012,8 +838,8 @@
    }
    @Override
    public List<PlatformCatalog> queryCatalogInPlatform(String platformId) {
        return catalogMapper.selectByPlatForm(platformId);
    public List<DeviceChannel> queryCatalogInPlatform(String platformId) {
        return catalogMapper.queryCatalogInPlatform(platformId);
    }
    @Override
@@ -1056,20 +882,24 @@
    }
    private DeviceChannel getDeviceChannelByCatalog(PlatformCatalog catalog) {
        ParentPlatform parentPlatByServerGBId = platformMapper.getParentPlatByServerGBId(catalog.getPlatformId());
        ParentPlatform platform = platformMapper.getParentPlatByServerGBId(catalog.getPlatformId());
        DeviceChannel deviceChannel = new DeviceChannel();
        deviceChannel.setChannelId(catalog.getId());
        deviceChannel.setName(catalog.getName());
        deviceChannel.setLongitude(0.0);
        deviceChannel.setLatitude(0.0);
        deviceChannel.setDeviceId(parentPlatByServerGBId.getDeviceGBId());
        deviceChannel.setDeviceId(platform.getDeviceGBId());
        deviceChannel.setManufacture("wvp-pro");
        deviceChannel.setStatus(1);
        deviceChannel.setParental(1);
        deviceChannel.setParentId(catalog.getParentId());
        deviceChannel.setRegisterWay(1);
        // è¡Œæ”¿åŒºåˆ’应该是Domain的前八位
        deviceChannel.setCivilCode(parentPlatByServerGBId.getAdministrativeDivision());
        if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
            deviceChannel.setParentId(catalog.getParentId());
            deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
        }
        deviceChannel.setModel("live");
        deviceChannel.setOwner("wvp-pro");
        deviceChannel.setSecrecy("0");
@@ -1131,4 +961,27 @@
        deviceChannelMapper.updatePosition(deviceChannel);
    }
    @Override
    public void cleanContentForPlatform(String serverGBId) {
//        List<PlatformCatalog> catalogList = catalogMapper.selectByPlatForm(serverGBId);
//        if (catalogList.size() > 0) {
//            int result = catalogMapper.delByPlatformId(serverGBId);
//            if (result > 0) {
//                List<DeviceChannel> deviceChannels = new ArrayList<>();
//                for (PlatformCatalog catalog : catalogList) {
//                    deviceChannels.add(getDeviceChannelByCatalog(catalog));
//                }
//                eventPublisher.catalogEventPublish(serverGBId, deviceChannels, CatalogEvent.DEL);
//            }
//        }
        catalogMapper.delByPlatformId(serverGBId);
        platformChannelMapper.delByPlatformId(serverGBId);
        platformGbStreamMapper.delByPlatformId(serverGBId);
    }
    @Override
    public List<DeviceChannel> queryChannelWithCatalog(String serverGBId) {
        return deviceChannelMapper.queryChannelWithCatalog(serverGBId);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -12,6 +12,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.service.IDeviceChannelService;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -51,6 +52,9 @@
    
    @Autowired
    private IVideoManagerStorage storager;
    @Autowired
    private IDeviceChannelService deviceChannelService;
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
@@ -280,7 +284,7 @@
    })
    @PostMapping("/channel/update/{deviceId}")
    public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
        storager.updateChannel(deviceId, channel);
        deviceChannelService.updateChannel(deviceId, channel);
        return new ResponseEntity<>(null,HttpStatus.OK);
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
@@ -44,7 +44,6 @@
            @ApiImplicitParam(name = "platformId", value = "平台ID", required = true , dataTypeClass = String.class),
            @ApiImplicitParam(name = "catalogId", value = "目录ID", required = false , dataTypeClass = String.class),
            @ApiImplicitParam(name="query", value = "查询内容", required = false , dataTypeClass = String.class),
            @ApiImplicitParam(name="pushing", value = "是否正在推流", required = false , dataTypeClass = Boolean.class),
            @ApiImplicitParam(name="mediaServerId", value = "流媒体ID", required = false , dataTypeClass = String.class),
    })
@@ -55,7 +54,6 @@
                                   @RequestParam(required = true)String platformId,
                                   @RequestParam(required = false)String catalogId,
                                   @RequestParam(required = false)String query,
                                   @RequestParam(required = false)Boolean pushing,
                                   @RequestParam(required = false)String mediaServerId){
        if (StringUtils.isEmpty(catalogId)) {
            catalogId = null;
@@ -69,7 +67,7 @@
        // catalogId ä¸ºnull æŸ¥è¯¢æœªåœ¨å¹³å°ä¸‹åˆ†é…çš„æ•°æ®
        // catalogId ä¸ä¸ºnull æŸ¥è¯¢å¹³å°ä¸‹è¿™ä¸ªï¼Œç›®å½•下的通道
        return gbStreamService.getAll(page, count, platformId, catalogId, query, pushing, mediaServerId);
        return gbStreamService.getAll(page, count, platformId, catalogId, query, mediaServerId);
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -1,9 +1,14 @@
package com.genersoft.iot.vmp.vmanager.gb28181.media;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.media.zlm.dto.OnPublishHookParam;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.annotations.Api;
@@ -16,6 +21,8 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@Api(tags = "媒体流相关")
@Controller
@@ -26,16 +33,10 @@
    private final static Logger logger = LoggerFactory.getLogger(MediaController.class);
    @Autowired
    private IVideoManagerStorage storager;
    @Autowired
    private IStreamPushService streamPushService;
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private IMediaService mediaService;
    @Autowired
    private IMediaServerService mediaServerService;
    /**
@@ -52,13 +53,47 @@
    })
    @GetMapping(value = "/stream_info_by_app_and_stream")
    @ResponseBody
    public WVPResult<StreamInfo> getStreamInfoByAppAndStream(@RequestParam String app, @RequestParam String stream, @RequestParam(required = false) String mediaServerId){
        StreamInfo streamInfoByAppAndStreamWithCheck = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId);
    public WVPResult<StreamInfo> getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
                                                             @RequestParam String stream,
                                                             @RequestParam(required = false) String mediaServerId,
                                                             @RequestParam(required = false) String callId,
                                                             @RequestParam(required = false) Boolean useSourceIpAsStreamIp){
        boolean authority = false;
        if (callId != null) {
            // æƒé™æ ¡éªŒ
            StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
            if (streamAuthorityInfo.getCallId().equals(callId)) {
                authority = true;
            }else {
                WVPResult<StreamInfo> result = new WVPResult<>();
                result.setCode(401);
                result.setMsg("fail");
                return result;
            }
        }else {
            // æ˜¯å¦ç™»é™†ç”¨æˆ·, ç™»é™†ç”¨æˆ·è¿”回完整信息
            LoginUser userInfo = SecurityUtils.getUserInfo();
            if (userInfo!= null) {
                authority = true;
            }
        }
        StreamInfo streamInfo;
        if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
            String host = request.getHeader("Host");
            String localAddr = host.split(":")[0];
            logger.info("使用{}作为返回流的ip", localAddr);
            streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
        }else {
            streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
        }
        WVPResult<StreamInfo> result = new WVPResult<>();
        if (streamInfoByAppAndStreamWithCheck != null){
        if (streamInfo != null){
            result.setCode(0);
            result.setMsg("scccess");
            result.setData(streamInfoByAppAndStreamWithCheck);
            result.setData(streamInfo);
        }else {
            result.setCode(-1);
            result.setMsg("fail");
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -9,6 +9,7 @@
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.IPlatformChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
@@ -47,6 +48,9 @@
    @Autowired
    private IVideoManagerStorage storager;
    @Autowired
    private IPlatformChannelService platformChannelService;
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
@@ -236,6 +240,12 @@
        parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
        ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
        parentPlatform.setUpdateTime(DateUtil.getNow());
        if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
             // ç›®å½•结构发生变化,清空之前的关联关系
             logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());
             storager.cleanContentForPlatform(parentPlatform.getServerGBId());
        }
        boolean updateResult = storager.updateParentPlatform(parentPlatform);
        if (updateResult) {
@@ -256,6 +266,8 @@
                }
            } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // å…³é—­å¯ç”¨æ—¶æ³¨é”€
                commanderForPlatform.unregister(parentPlatformOld, null, null);
                // åœæ­¢è®¢é˜…相关的定时任务
                subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
            }
            wvpResult.setCode(0);
            wvpResult.setMsg("success");
@@ -405,7 +417,7 @@
        if (logger.isDebugEnabled()) {
            logger.debug("给上级平台添加国标通道API调用");
        }
        int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
        int result = platformChannelService.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
        return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
    }
@@ -484,7 +496,6 @@
        }
        PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
        if (platformCatalogInStore != null) {
            result.setCode(-1);
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -193,7 +193,7 @@
                JSONObject data = jsonObject.getJSONObject("data");
                if (data != null) {
                       result.put("key", data.getString("key"));
                    StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId());
                    StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId(), false);
                    result.put("data", streamInfoResult);
                }
            }else {
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -3,11 +3,16 @@
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
import com.genersoft.iot.vmp.vmanager.bean.BatchGBStreamParam;
@@ -30,6 +35,7 @@
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
@@ -53,6 +59,9 @@
    @Autowired
    private DeferredResultHolder resultHolder;
    @Autowired
    private IMediaService mediaService;
    @ApiOperation("推流列表查询")
    @ApiImplicitParams({
@@ -237,5 +246,43 @@
        return result;
    }
    /**
     * èŽ·å–æŽ¨æµæ’­æ”¾åœ°å€
     * @param app åº”用名
     * @param stream æµid
     * @return
     */
    @ApiOperation("获取推流播放地址")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "app", value = "应用名", dataTypeClass = String.class),
            @ApiImplicitParam(name = "stream", value = "流id", dataTypeClass = String.class),
            @ApiImplicitParam(name = "mediaServerId", value = "媒体服务器id", dataTypeClass = String.class, required = false),
    })
    @GetMapping(value = "/getPlayUrl")
    @ResponseBody
    public WVPResult<StreamInfo> getPlayUrl(HttpServletRequest request, @RequestParam String app,
                                                             @RequestParam String stream,
                                                             @RequestParam(required = false) String mediaServerId){
        boolean authority = false;
        // æ˜¯å¦ç™»é™†ç”¨æˆ·, ç™»é™†ç”¨æˆ·è¿”回完整信息
        LoginUser userInfo = SecurityUtils.getUserInfo();
        if (userInfo!= null) {
            authority = true;
        }
        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
        WVPResult<StreamInfo> result = new WVPResult<>();
        if (streamInfo != null){
            result.setCode(0);
            result.setMsg("scccess");
            result.setData(streamInfo);
        }else {
            result.setCode(-1);
            result.setMsg("fail");
        }
        return result;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -8,6 +8,7 @@
import com.genersoft.iot.vmp.storager.dao.dto.User;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -123,7 +124,8 @@
        User user = new User();
        user.setUsername(username);
        user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
        //新增用户的pushKey的生成规则为md5(时间戳+用户名)
        user.setPushKey(DigestUtils.md5DigestAsHex((System.currentTimeMillis()+password).getBytes()));
        Role role = roleService.getRoleById(roleId);
        if (role == null) {
@@ -136,6 +138,7 @@
        user.setCreateTime(DateUtil.getNow());
        user.setUpdateTime(DateUtil.getNow());
        int addResult = userService.addUser(user);
        result.setCode(addResult > 0 ? 0 : -1);
        result.setMsg(addResult > 0 ? "success" : "fail");
@@ -177,4 +180,68 @@
        result.setData(allUsers);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }
    /**
     * åˆ†é¡µæŸ¥è¯¢ç”¨æˆ·
     *
     * @param page  å½“前页
     * @param count æ¯é¡µæŸ¥è¯¢æ•°é‡
     * @return åˆ†é¡µç”¨æˆ·åˆ—表
     */
    @ApiOperation("分页查询用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页", required = true, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "count", value = "每页查询数量", required = true, dataTypeClass = Integer.class),
    })
    @GetMapping("/users")
    public PageInfo<User> users(int page, int count) {
        return userService.getUsers(page, count);
    }
    @ApiOperation("修改pushkey")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", required = true, value = "用户Id", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pushKey", required = true, value = "新的pushKey", dataTypeClass = String.class),
    })
    @RequestMapping("/changePushKey")
    public ResponseEntity<WVPResult<String>> changePushKey(@RequestParam Integer userId,@RequestParam String pushKey) {
        // èŽ·å–å½“å‰ç™»å½•ç”¨æˆ·id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        WVPResult<String> result = new WVPResult<>();
        if (currenRoleId != 1) {
            // åªç”¨è§’色id为0才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
        }
        int resetPushKeyResult = userService.changePushKey(userId,pushKey);
        result.setCode(resetPushKeyResult > 0 ? 0 : -1);
        result.setMsg(resetPushKeyResult > 0 ? "success" : "fail");
        return new ResponseEntity<>(result, HttpStatus.OK);
    }
    @ApiOperation("管理员修改普通用户密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "adminId", required = true, value = "管理员id", dataTypeClass = String.class),
            @ApiImplicitParam(name = "userId", required = true, value = "用户id", dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", required = true, value = "新密码(未md5加密的密码)", dataTypeClass = String.class),
    })
    @PostMapping("/changePasswordForAdmin")
    public String changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) {
        // èŽ·å–å½“å‰ç™»å½•ç”¨æˆ·id
        LoginUser userInfo = SecurityUtils.getUserInfo();
        if (userInfo == null) {
            return "fail";
        }
        Role role = userInfo.getRole();
        if (role != null && role.getId() == 1) {
            boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
            if (result) {
                return "success";
            }
        }
        return "fail";
    }
}
src/main/resources/8042900_www.wvp-pro.cn.jks
Binary files differ
src/main/resources/all-application.yml
@@ -185,8 +185,6 @@
    record-sip: true
    # æ˜¯å¦å°†æ—¥å¿—存储进数据库
    logInDatebase: true
    # ç¬¬ä¸‰æ–¹åŒ¹é…ï¼Œç”¨äºŽä»Žstream钟获取有效信息
    thirdPartyGBIdReg: "[\\s\\S]*"
# åœ¨çº¿æ–‡æ¡£ï¼š swagger-ui(生产环境建议关闭)
swagger-ui:
web_src/src/components/Login.vue
@@ -86,7 +86,7 @@
      }).then(function (res) {
        console.log(JSON.stringify(res));
          if (res.data.code == 0 && res.data.msg == "success") {
            that.$cookies.set("session", {"username": that.username}) ;
            that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ;
            //登录成功后
            that.cancelEnterkeyDefaultAction();
            that.$router.push('/');
web_src/src/components/ParentPlatformList.vue
@@ -143,7 +143,7 @@
        });
    },
    chooseChannel: function(platform) {
       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, this.initData)
       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, platform.treeType, this.initData)
    },
    initData: function() {
      this.getPlatformList();
web_src/src/components/PushVideoList.vue
@@ -56,13 +56,18 @@
      <el-table-column label="开始时间"  min-width="200">
        <template slot-scope="scope">
          <el-button-group>
            {{ dateFormat(parseInt(scope.row.createStamp)) }}
            {{ scope.row.pushTime == null? "-":scope.row.pushTime }}
          </el-button-group>
        </template>
      </el-table-column>
      <el-table-column label="正在推流"  min-width="100">
        <template slot-scope="scope">
          {{ (scope.row.status == false && scope.row.gbId == null) || scope.row.status ? '是' : '否' }}
          {{scope.row.pushIng ? '是' : '否' }}
        </template>
      </el-table-column>
      <el-table-column label="本平台推流"  min-width="100">
        <template slot-scope="scope">
          {{scope.row.pushIng && !!!scope.row.serverId ? '是' : '否' }}
        </template>
      </el-table-column>
@@ -187,7 +192,7 @@
      this.getListLoading = true;
      this.$axios({
        method: 'get',
        url: '/api/media/stream_info_by_app_and_stream',
        url: '/api/push/getPlayUrl',
        params: {
          app: row.app,
          stream: row.stream,
@@ -241,19 +246,6 @@
      }).catch(function (error) {
        console.error(error);
      });
    },
    dateFormat: function (/** timestamp=0 **/) {
      let ts = arguments[0] || 0;
      let t, y, m, d, h, i, s;
      t = ts ? new Date(ts) : new Date();
      y = t.getFullYear();
      m = t.getMonth() + 1;
      d = t.getDate();
      h = t.getHours();
      i = t.getMinutes();
      s = t.getSeconds();
      // å¯æ ¹æ®éœ€è¦åœ¨è¿™é‡Œå®šä¹‰æ—¶é—´æ ¼å¼
      return y + '-' + (m < 10 ? '0' + m : m) + '-' + (d < 10 ? '0' + d : d) + ' ' + (h < 10 ? '0' + h : h) + ':' + (i < 10 ? '0' + i : i) + ':' + (s < 10 ? '0' + s : s);
    },
    importChannel: function () {
      this.$refs.importChannel.openDialog(() => {
web_src/src/components/UserManager.vue
New file
@@ -0,0 +1,236 @@
<template>
  <div id="app" style="width: 100%">
    <div class="page-header">
      <div class="page-title">用户列表</div>
      <div class="page-header-btn">
        <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addUser">
          æ·»åŠ ç”¨æˆ·
        </el-button>
      </div>
    </div>
    <!--用户列表-->
    <el-table :data="userList" style="width: 100%;font-size: 12px;" :height="winHeight"
              header-row-class-name="table-header">
      <el-table-column prop="username" label="用户名" min-width="160"/>
      <el-table-column prop="pushKey" label="pushkey" min-width="160"/>
      <el-table-column prop="role.name" label="类型" min-width="160"/>
      <el-table-column label="操作" min-width="450" fixed="right">
        <template slot-scope="scope">
          <el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">修改密码</el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button size="medium" icon="el-icon-edit" type="text" @click="changePushKey(scope.row)">修改pushkey</el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button size="medium" icon="el-icon-delete" type="text" @click="deleteUser(scope.row)"
                     style="color: #f56c6c">删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <changePasswordForAdmin ref="changePasswordForAdmin"></changePasswordForAdmin>
    <changePushKey ref="changePushKey"></changePushKey>
    <addUser ref="addUser"></addUser>
    <el-pagination
      style="float: right"
      @size-change="handleSizeChange"
      @current-change="currentChange"
      :current-page="currentPage"
      :page-size="count"
      :page-sizes="[15, 25, 35, 50]"
      layout="total, sizes, prev, pager, next"
      :total="total">
    </el-pagination>
  </div>
</template>
<script>
import uiHeader from '../layout/UiHeader.vue'
import changePasswordForAdmin from './dialog/changePasswordForAdmin.vue'
import changePushKey from './dialog/changePushKey.vue'
import addUser from '../components/dialog/addUser.vue'
export default {
  name: 'userManager',
  components: {
    uiHeader,
    changePasswordForAdmin,
    changePushKey,
    addUser
  },
  data() {
    return {
      userList: [], //设备列表
      currentUser: {}, //当前操作设备对象
      videoComponentList: [],
      updateLooper: 0, //数据刷新轮训标志
      currentUserLenth: 0,
      winHeight: window.innerHeight - 200,
      currentPage: 1,
      count: 15,
      total: 0,
      getUserListLoading: false
    };
  },
  mounted() {
    this.initData();
    this.updateLooper = setInterval(this.initData, 10000);
  },
  destroyed() {
    this.$destroy('videojs');
    clearTimeout(this.updateLooper);
  },
  methods: {
    initData: function () {
      this.getUserList();
    },
    currentChange: function (val) {
      this.currentPage = val;
      this.getUserList();
    },
    handleSizeChange: function (val) {
      this.count = val;
      this.getUserList();
    },
    getUserList: function () {
      let that = this;
      this.getUserListLoading = true;
      this.$axios({
        method: 'get',
        url: `/api/user/users`,
        params: {
          page: that.currentPage,
          count: that.count
        }
      }).then(function (res) {
        that.total = res.data.total;
        that.userList = res.data.list;
        that.getUserListLoading = false;
      }).catch(function (error) {
        that.getUserListLoading = false;
      });
    },
    edit: function (row) {
      this.$refs.changePasswordForAdmin.openDialog(row, () => {
        this.$refs.changePasswordForAdmin.close();
        this.$message({
          showClose: true,
          message: "密码修改成功",
          type: "success",
        });
        setTimeout(this.getUserList, 200)
      })
    },
    deleteUser: function (row) {
      let msg = "确定删除此用户?"
      if (row.online !== 0) {
        msg = "<strong>确定删除此用户?</strong>"
      }
      this.$confirm(msg, '提示', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        center: true,
        type: 'warning'
      }).then(() => {
        this.$axios({
          method: 'delete',
          url: `/api/user/delete?id=${row.id}`
        }).then((res) => {
          this.getUserList();
        }).catch((error) => {
          console.error(error);
        });
      }).catch(() => {
      });
    },
    changePushKey: function (row) {
      this.$refs.changePushKey.openDialog(row, () => {
        this.$refs.changePushKey.close();
        this.$message({
          showClose: true,
          message: "pushKey修改成功",
          type: "success",
        });
        setTimeout(this.getUserList, 200)
      })
    },
    addUser: function () {
      // this.$refs.addUser.openDialog()
      this.$refs.addUser.openDialog( () => {
        this.$refs.addUser.close();
        this.$message({
          showClose: true,
          message: "用户添加成功",
          type: "success",
        });
        setTimeout(this.getUserList, 200)
      })
    }
  }
}
</script>
<style>
.videoList {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
}
.video-item {
  position: relative;
  width: 15rem;
  height: 10rem;
  margin-right: 1rem;
  background-color: #000000;
}
.video-item-img {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  width: 100%;
  height: 100%;
}
.video-item-img:after {
  content: "";
  display: inline-block;
  position: absolute;
  z-index: 2;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  width: 3rem;
  height: 3rem;
  background-image: url("../assets/loading.png");
  background-size: cover;
  background-color: #000000;
}
.video-item-title {
  position: absolute;
  bottom: 0;
  color: #000000;
  background-color: #ffffff;
  line-height: 1.5rem;
  padding: 0.3rem;
  width: 14.4rem;
}
</style>
web_src/src/components/dialog/addUser.vue
New file
@@ -0,0 +1,159 @@
<template>
  <div id="addUser" v-loading="isLoging">
    <el-dialog
      title="添加用户"
      width="40%"
      top="2rem"
      :close-on-click-modal="false"
      :visible.sync="showDialog"
      :destroy-on-close="true"
      @close="close()"
    >
      <div id="shared" style="margin-right: 20px;">
        <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="username" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="用户类型" prop="roleId">
            <el-select v-model="roleId"   placeholder="请选择">
              <el-option
                v-for="item in options"
                :key="item.id"
                :label="item.name"
                :value="item.id">
              </el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="password" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="确认密码" prop="confirmPassword">
            <el-input v-model="confirmPassword" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item>
            <div style="float: right;">
              <el-button type="primary" @click="onSubmit">保存</el-button>
              <el-button @click="close">取消</el-button>
            </div>
          </el-form-item>
        </el-form>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: "addUser",
  props: {},
  computed: {},
  created() {
    this.getAllRole();
  },
  data() {
    let validatePass1 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入新密码'));
      } else {
        if (this.confirmPassword !== '') {
          this.$refs.passwordForm.validateField('confirmPassword');
        }
        callback();
      }
    };
    let validatePass2 = (rule, value, callback) => {
      if (this.confirmPassword === '') {
        callback(new Error('请再次输入密码'));
      } else if (this.confirmPassword !== this.password) {
        callback(new Error('两次输入密码不一致!'));
      } else {
        callback();
      }
    };
    return {
      value:"",
      options: [],
      loading: false,
      username: null,
      password: null,
      roleId: null,
      confirmPassword: null,
      listChangeCallback: null,
      showDialog: false,
      isLoging: false,
      rules: {
        newPassword: [{required: true, validator: validatePass1, trigger: "blur"}, {
          pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
          message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
        },],
        confirmPassword: [{required: true, validator: validatePass2, trigger: "blur"}],
      },
    };
  },
  methods: {
    openDialog: function (callback) {
      this.listChangeCallback = callback;
      this.showDialog = true;
    },
    onSubmit: function () {
      this.$axios({
        method: 'post',
        url: "/api/user/add",
        params: {
          username: this.username,
          password: this.password,
          roleId: this.roleId
        }
      }).then((res) => {
        if (res.data.code === 0) {
          this.$message({
            showClose: true,
            message: '添加成功',
            type: 'success',
          });
          this.showDialog = false;
          this.listChangeCallback()
        } else {
          this.$message({
            showClose: true,
            message: res.data.msg,
            type: 'error'
          });
        }
      }).catch((error) => {
        console.error(error)
      });
    },
    close: function () {
      this.showDialog = false;
      this.password = null;
      this.confirmPassword = null;
      this.username = null;
      this.roleId = null;
    },
    getAllRole:function () {
      this.$axios({
        method: 'get',
        url: "/api/role/all"
      }).then((res) => {
        this.loading = true;
        console.info(res)
        res.data
        console.info(res.data.code)
        if (res.data.code === 0) {
          console.info(res.data.data)
          this.options=res.data.data
        }
      }).catch((error) => {
        console.error(error)
      });
    }
  },
};
</script>
web_src/src/components/dialog/catalogEdit.vue
@@ -49,11 +49,43 @@
  props: ['platformId'],
  created() {},
  data() {
    let checkId = (rule, value, callback) => {
      console.log("checkId")
      console.log(this.treeType)
      console.log(rule)
      console.log(value)
      console.log(value.length)
      console.log(this.level)
      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") {
        let catalogType = value.substring(10, 13);
        console.log(catalogType)
        // 216 ä¸ºè™šæ‹Ÿç»„织 215 ä¸ºä¸šåŠ¡åˆ†ç»„ï¼›ç›®å½•ç¬¬ä¸€çº§å¿…é¡»ä¸ºä¸šåŠ¡åˆ†ç»„ï¼Œ ä¸šåŠ¡åˆ†ç»„ä¸‹ä¸ºè™šæ‹Ÿç»„ç»‡ï¼Œè™šæ‹Ÿç»„ç»‡ä¸‹å¯ä»¥æœ‰å…¶ä»–è™šæ‹Ÿç»„ç»‡
        if (this.level === 1 && catalogType !== "215") {
          return callback(new Error('业务分组模式下第一层目录的编号10到13位必须为215'));
        }
        if (this.level > 1 && catalogType !== "216") {
          return callback(new Error('业务分组模式下第一层以下目录的编号10到13位必须为216'));
        }
      }
      callback();
    }
    return {
      submitCallback: null,
      showDialog: false,
      isLoging: false,
      isEdit: false,
      treeType: null,
      level: 0,
      form: {
        id: null,
        name: null,
@@ -62,12 +94,12 @@
      },
      rules: {
        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
        id: [{ required: true, message: "请输入ID", trigger: "blur" }]
        id: [{ trigger: "blur",validator: checkId  }]
      },
    };
  },
  methods: {
    openDialog: function (isEdit, id, name, parentId, callback) {
    openDialog: function (isEdit, id, name, parentId, treeType, level, callback) {
      console.log("parentId: " + parentId)
      console.log(this.form)
      this.isEdit = isEdit;
@@ -77,6 +109,8 @@
      this.form.parentId = parentId;
      this.showDialog = true;
      this.submitCallback = callback;
      this.treeType = treeType;
      this.level = level;
    },
    onSubmit: function () {
      console.log("onSubmit");
web_src/src/components/dialog/changePasswordForAdmin.vue
New file
@@ -0,0 +1,121 @@
<template>
  <div id="changePassword" v-loading="isLoging">
    <el-dialog
      title="修改密码"
      width="40%"
      top="2rem"
      :close-on-click-modal="false"
      :visible.sync="showDialog"
      :destroy-on-close="true"
      @close="close()"
    >
      <div id="shared" style="margin-right: 20px;">
        <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
              <el-form-item label="新密码" prop="newPassword" >
                <el-input v-model="newPassword" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="确认密码" prop="confirmPassword">
                <el-input v-model="confirmPassword" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item>
                <div style="float: right;">
                  <el-button type="primary" @click="onSubmit">保存</el-button>
                  <el-button @click="close">取消</el-button>
                </div>
              </el-form-item>
            </el-form>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: "changePasswordForAdmin",
  props: {},
  computed: {},
  created() {},
  data() {
    let validatePass1 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入新密码'));
      } else {
        if (this.confirmPassword !== '') {
          this.$refs.passwordForm.validateField('confirmPassword');
        }
        callback();
      }
    };
    let validatePass2 = (rule, value, callback) => {
      if (this.confirmPassword === '') {
        callback(new Error('请再次输入密码'));
      } else if (this.confirmPassword !== this.newPassword) {
        callback(new Error('两次输入密码不一致!'));
      } else {
        callback();
      }
    };
    return {
      newPassword: null,
      confirmPassword: null,
      userId: null,
      showDialog: false,
      isLoging: false,
      listChangeCallback: null,
      form: {},
      rules: {
        newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, {
            pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
            message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
          },],
        confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }],
      },
    };
  },
  methods: {
    openDialog: function (row, callback) {
      console.log(row)
      this.showDialog = true;
      this.listChangeCallback = callback;
      if (row != null) {
        this.form = row;
      }
    },
    onSubmit: function () {
      this.$axios({
        method: 'post',
        url:"/api/user/changePasswordForAdmin",
        params: {
          password: this.newPassword,
          userId: this.form.id,
        }
      }).then((res)=> {
        if (res.data === "success"){
          this.$message({
            showClose: true,
            message: '修改成功',
            type: 'success'
          });
          this.showDialog = false;
        }else {
          this.$message({
            showClose: true,
            message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)',
            type: 'error'
          });
        }
      }).catch((error)=> {
        console.error(error)
      });
    },
    close: function () {
      this.showDialog = false;
      this.newPassword = null;
      this.confirmPassword = null;
      this.userId=null;
      this.adminId=null;
    },
  },
};
</script>
web_src/src/components/dialog/changePushKey.vue
New file
@@ -0,0 +1,102 @@
<template>
  <div id="changepushKey" v-loading="isLoging">
    <el-dialog
      title="修改密码"
      width="42%"
      top="2rem"
      :close-on-click-modal="false"
      :visible.sync="showDialog"
      :destroy-on-close="true"
      @close="close()"
    >
      <div id="shared" style="margin-right: 18px;">
        <el-form ref="pushKeyForm" :rules="rules" status-icon label-width="86px">
              <el-form-item label="新pushKey" prop="newPushKey" >
                <el-input v-model="newPushKey" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item>
                <div style="float: right;">
                  <el-button type="primary" @click="onSubmit">保存</el-button>
                  <el-button @click="close">取消</el-button>
                </div>
              </el-form-item>
            </el-form>
      </div>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: "changePushKey",
  props: {},
  computed: {},
  created() {},
  data() {
    let validatePass1 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入新pushKey'));
      } else {
        callback();
      }
    };
    return {
      newPushKey: null,
      confirmpushKey: null,
      userId: null,
      showDialog: false,
      isLoging: false,
      listChangeCallback: null,
      form: {},
      rules: {
        newpushKey: [{ required: true, validator: validatePass1, trigger: "blur" }],
      },
    };
  },
  methods: {
    openDialog: function (row, callback) {
      console.log(row)
      this.showDialog = true;
      this.listChangeCallback = callback;
      if (row != null) {
        this.form = row;
      }
    },
    onSubmit: function () {
      this.$axios({
        method: 'post',
        url:"/api/user/changePushKey",
        params: {
          pushKey: this.newPushKey,
          userId: this.form.id,
        }
      }).then((res)=> {
        console.log(res.data)
        if (res.data.msg === "success"){
          this.$message({
            showClose: true,
            message: '修改成功',
            type: 'success'
          });
          this.showDialog = false;
          this.listChangeCallback();
        }else {
          this.$message({
            showClose: true,
            message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)',
            type: 'error'
          });
        }
      }).catch((error)=> {
        console.error(error)
      });
    },
    close: function () {
      this.showDialog = false;
      this.newpushKey = null;
      this.userId=null;
      this.adminId=null;
    },
  },
};
</script>
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 :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" ></chooseChannelForCatalog>
                  <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog>
                </el-main>
              </el-container>
            </el-tab-pane>
@@ -66,18 +66,20 @@
            platformName: "",
            defaultCatalogId: "",
            showDialog: false,
            treeType: null,
            chooseData: {},
            winHeight: window.innerHeight - 250,
        };
    },
    methods: {
        openDialog(platformId, platformName, defaultCatalogId, closeCallback) {
        openDialog(platformId, platformName, defaultCatalogId, treeType, closeCallback) {
            this.platformId = platformId
            this.platformName = platformName
            this.defaultCatalogId = defaultCatalogId
            this.showDialog = true
            this.closeCallback = closeCallback
            this.treeType = treeType
        },
        tabClick (tab, event){
web_src/src/components/dialog/chooseChannelForCatalog.vue
@@ -38,7 +38,7 @@
import catalogEdit from './catalogEdit.vue'
export default {
    name: 'chooseChannelForCatalog',
    props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange'],
    props: ['platformId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'],
    created() {
        this.chooseId = this.defaultCatalogId;
        this.defaultCatalogIdSign = this.defaultCatalogId;
@@ -102,8 +102,9 @@
        },
        addCatalog: function (parentId, node){
          let that = this;
          console.log(this.treeType)
          // æ‰“开添加弹窗
          that.$refs.catalogEdit.openDialog(false, null, null, parentId, ()=>{
          that.$refs.catalogEdit.openDialog(false, null, null, parentId, this.treeType, node.level, ()=>{
            node.loaded = false
            node.expand();
          });
web_src/src/components/dialog/chooseChannelForStream.vue
@@ -174,7 +174,6 @@
                    page: that.currentPage,
                    count: that.count,
                    query: that.searchSrt,
                    pushing: that.pushing,
                    platformId: that.platformId,
                    catalogId: that.catalogId,
                    mediaServerId: that.mediaServerId
web_src/src/components/dialog/platformEdit.vue
@@ -78,6 +78,12 @@
                  <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%" >
                  <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"
@@ -91,7 +97,6 @@
              <el-form-item label="其他选项">
                <el-checkbox label="启用" v-model="platform.enable" @change="checkExpires"></el-checkbox>
                <el-checkbox label="云台控制" v-model="platform.ptz"></el-checkbox>
                <el-checkbox label="共享所有直播流" v-model="platform.shareAllLiveStream"></el-checkbox>
                <el-checkbox label="拉起离线推流" v-model="platform.startOfflinePush"></el-checkbox>
              </el-form-item>
              <el-form-item>
@@ -153,10 +158,10 @@
        keepTimeout: 60,
        transport: "UDP",
        characterSet: "GB2312",
        shareAllLiveStream: false,
        startOfflinePush: false,
        catalogGroup: 1,
        administrativeDivision: null,
        treeType: "BusinessGroup",
      },
      rules: {
        name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
@@ -194,6 +199,7 @@
          that.platform.devicePort = res.data.devicePort;
          that.platform.username = res.data.username;
          that.platform.password = res.data.password;
          that.platform.treeType = "BusinessGroup";
          that.platform.administrativeDivision = res.data.username.substr(0, 6);
        }).catch(function (error) {
          console.log(error);
@@ -217,11 +223,11 @@
        this.platform.keepTimeout = platform.keepTimeout;
        this.platform.transport = platform.transport;
        this.platform.characterSet = platform.characterSet;
        this.platform.shareAllLiveStream = platform.shareAllLiveStream;
        this.platform.catalogId = platform.catalogId;
        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";
      }
@@ -242,32 +248,49 @@
    },
    onSubmit: function () {
      if (this.onSubmit_text === "保存") {
        this.$confirm("修改目录结构会导致关联目录与通道数据被清空", '提示', {
          dangerouslyUseHTMLString: true,
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          center: true,
          type: 'warning'
        }).then(() => {
          this.saveForm()
        }).catch(() => {
        });
      }else {
        this.saveForm()
      }
    },
    saveForm: function (){
      var that = this;
      that.$axios({
        method: 'post',
        url: this.saveUrl,
        data: that.platform
      }).then(function (res) {
          if (res.data.code === 0) {
            that.$message({
              showClose: true,
              message: "保存成功",
              type: "success",
            });
            that.showDialog = false;
            if (that.listChangeCallback != null) {
              that.listChangeCallback();
            }
          }else {
            that.$message({
              showClose: true,
              message: res.data.msg,
              type: "error",
            });
        if (res.data.code === 0) {
          that.$message({
            showClose: true,
            message: "保存成功",
            type: "success",
          });
          that.showDialog = false;
          if (that.listChangeCallback != null) {
            that.listChangeCallback();
          }
        }).catch(function (error) {
          console.log(error);
        });
        }else {
          that.$message({
            showClose: true,
            message: res.data.msg,
            type: "error",
          });
        }
      }).catch(function (error) {
        console.log(error);
      });
    },
    close: function () {
      this.showDialog = false;
@@ -293,7 +316,7 @@
        keepTimeout: 60,
        transport: "UDP",
        characterSet: "GB2312",
        shareAllLiveStream: false,
        treeType: "BusinessGroup",
        startOfflinePush: false,
        catalogGroup: 1,
      }
web_src/src/layout/UiHeader.vue
@@ -13,6 +13,7 @@
      <el-menu-item index="/cloudRecord">云端录像</el-menu-item>
      <el-menu-item index="/mediaServerManger">节点管理</el-menu-item>
      <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item>
      <el-menu-item v-if="editUser" index="/userManager">用户管理</el-menu-item>
      <!--            <el-submenu index="/setting">-->
      <!--              <template slot="title">系统设置</template>-->
@@ -23,12 +24,12 @@
      <!--            <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>-->
      <el-submenu index="" style="float: right;">
        <template slot="title">欢迎,{{ this.$cookies.get("session").username }}</template>
        <el-menu-item @click="changePassword">修改密码</el-menu-item>
        <el-menu-item @click="loginout">注销</el-menu-item>
        <el-menu-item @click="openDoc">在线文档</el-menu-item>
        <el-menu-item >
          <el-switch v-model="alarmNotify" inactive-text="报警信息推送" @change="alarmNotifyChannge"></el-switch>
        </el-menu-item>
        <el-menu-item @click="changePassword">修改密码</el-menu-item>
        <el-menu-item @click="loginout">注销</el-menu-item>
      </el-submenu>
    </el-menu>
    <changePasswordDialog ref="changePasswordDialog"></changePasswordDialog>
@@ -47,9 +48,11 @@
      alarmNotify: false,
      sseSource: null,
      activeIndex: this.$route.path,
      editUser: this.$cookies.get("session").roleId==1
    };
  },
  created() {
    console.log(this.$cookies.get("session"))
    if (this.$route.path.startsWith("/channelList")) {
      this.activeIndex = "/deviceList"
    }
web_src/src/router/index.js
@@ -17,6 +17,7 @@
import media from '../components/setting/Media.vue'
import live from '../components/live.vue'
import deviceTree from '../components/common/DeviceTree.vue'
import userManager from '../components/UserManager.vue'
import wasmPlayer from '../components/common/jessibuca.vue'
import rtcPlayer from '../components/dialog/rtcPlayer.vue'
@@ -103,6 +104,11 @@
          name: 'map',
          component: map,
        },
        {
          path: '/userManager',
          name: 'userManager',
          component: userManager,
        }
        ]
    },
    {
web_src/static/file/ÍÆÁ÷ͨµÀµ¼Èë.zip
Binary files differ