648540858
2022-09-08 2f76fa98bb839ede5b47a3c3e1bb6fe499952203
Merge branch 'wvp-28181-2.0'

# Conflicts:
# src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
# src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
# src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
33个文件已修改
444 ■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 144 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisPushStreamListMsgListener.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/logback-spring-local.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/ParentPlatformList.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannel.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForCatalog.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/getCatalog.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/platformEdit.vue 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/static/file/推流通道导入.zip 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -53,7 +53,7 @@
    /**
     * è®¾å¤‡å›½æ ‡ç¼–号
     */
    @Schema(description = "11111")
    @Schema(description = "设备国标编号")
    private String deviceGBId;
    /**
@@ -113,7 +113,6 @@
    /**
     * RTCP流保活
     * TODO é¢„ç•™, æš‚不实现
     */
    @Schema(description = "RTCP流保活")
    private boolean rtcp;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -108,7 +108,7 @@
     * @param startTime å¼€å§‹æ—¶é—´,格式要求:yyyy-MM-dd HH:mm:ss
     * @param endTime ç»“束时间,格式要求:yyyy-MM-dd HH:mm:ss
     */
    void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
    void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
    /**
     * è¯·æ±‚历史媒体下载
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -358,7 +358,7 @@
//            String streamMode = device.getStreamMode().toUpperCase();
            logger.info("{} åˆ†é…çš„ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId());
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
            subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
                if (event != null) {
                    event.response(mediaServerItemInUse, json);
@@ -458,7 +458,7 @@
    @Override
    public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
                                  String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
                                  SipSubscribe.Event errorEvent) {
                                  SipSubscribe.Event okEvent,SipSubscribe.Event errorEvent) {
        try {
            logger.info("{} åˆ†é…çš„ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
@@ -526,7 +526,7 @@
            CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
                    : udpSipProvider.getNewCallId();
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtmp", mediaServerItem.getId());
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
            // æ·»åŠ è®¢é˜…
            subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
                        if (hookEvent != null) {
@@ -537,10 +537,11 @@
                    });
            Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
            transmitRequest(device, request, errorEvent, okEvent -> {
                ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
            transmitRequest(device, request, errorEvent, event -> {
                ResponseEvent responseEvent = (ResponseEvent) event.event;
                streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
                streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
                streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), event.dialog);
                okEvent.response(event);
            });
            if (inviteStreamCallback != null) {
                inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -121,6 +121,10 @@
            param.put("pt", sendRtpItem.getPt());
            param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
            param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
            if (!sendRtpItem.isTcp() && parentPlatform.isRtcp()) {
                // å¼€å¯rtcp保活
                param.put("udp_rtcp_timeout", "1");
            }
            JSONObject jsonObject;
            if (sendRtpItem.isTcpActive()) {
                jsonObject = zlmrtpServerFactory.startSendRtpPassive(mediaInfo, param);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -104,6 +104,8 @@
                    MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
                    zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
                    redisCatchStorage.deleteSendRTPServer(platformGbId, sendRtpItem.getChannelId(), callIdHeader.getCallId(), null);
                    redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null);
                    zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
                    int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
                    if (totalReaderCount <= 0) {
                        logger.info("收到bye: {} æ— å…¶å®ƒè§‚看者,通知设备停止推流", streamId);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -111,6 +111,9 @@
    private ZLMRESTfulUtils zlmresTfulUtils;
    @Autowired
    private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
    @Autowired
    private SIPProcessorObserver sipProcessorObserver;
    @Autowired
@@ -430,7 +433,14 @@
                        if (playTransaction != null) {
                            Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, "rtp", playTransaction.getStream());
                            if (!streamReady) {
                                playTransaction = null;
                                boolean hasRtpServer = mediaServerService.checkRtpServer(mediaServerItem, "rtp", playTransaction.getStream());
                                if (hasRtpServer) {
                                    logger.info("[上级点播]已经开启rtpServer但是尚未收到流,开启监听流的到来");
                                    HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", playTransaction.getStream(), true, "rtsp", mediaServerItem.getId());
                                    zlmHttpHookSubscribe.addSubscribe(hookSubscribe, hookEvent);
                                }else {
                                    playTransaction = null;
                                }
                            }
                        }
                        if (playTransaction == null) {
@@ -593,7 +603,8 @@
            responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
        } else if ("push".equals(gbStream.getStreamType())) {
            if (!platform.isStartOfflinePush()) {
                responseAck(evt, Response.TEMPORARILY_UNAVAILABLE, "channel unavailable");
                // å¹³å°è®¾ç½®ä¸­å…³é—­äº†æ‹‰èµ·ç¦»çº¿çš„æŽ¨æµåˆ™ç›´æŽ¥å›žå¤
                responseAck(evt, Response.TEMPORARILY_UNAVAILABLE, "channel stream not pushing");
                return;
            }
            // å‘送redis消息以使设备上线
@@ -629,7 +640,7 @@
                            app, stream, channelId, mediaTransmissionTCP);
                    if (sendRtpItem == null) {
                        logger.warn("服务器端口资源不足");
                        logger.warn("上级点时创建sendRTPItem失败,可能是服务器端口资源不足");
                        try {
                            responseAck(evt, Response.BUSY_HERE);
                        } catch (SipException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -211,7 +211,6 @@
        }else if (subscribeInfo.getExpires() == 0) {
            subscribeHolder.removeCatalogSubscribe(platformId);
        }
        try {
            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
            responseXmlAck(evt, resultXml.toString(), parentPlatform);
@@ -219,5 +218,4 @@
            e.printStackTrace();
        }
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -203,6 +203,12 @@
            return null;
        }
        deviceChannel.setChannelId(channelId);
        int channelTypeCode = Integer.parseInt(channelId.substring(10, 13));
        if (channelTypeCode == 136 || channelTypeCode == 137 || channelTypeCode == 138) {
            deviceChannel.setHasAudio(true);
        }else {
            deviceChannel.setHasAudio(false);
        }
        if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) {
            // é™¤äº†ADD和update情况下需要识别全部内容,
            return deviceChannel;
@@ -396,7 +402,6 @@
        } else {
            deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
        }
        deviceChannel.setHasAudio(true); // é»˜è®¤å«æœ‰éŸ³é¢‘,播放时再检查是否有音频及是否AAC
        return deviceChannel;
    }
}
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
@@ -50,7 +50,7 @@
        if (mediaServerItem == null) {
            return null;
        }
        if (mediaServerItem.getRecordAssistPort() > 0) {
        if (mediaServerItem.getRecordAssistPort() <= 0) {
            logger.warn("未启用Assist服务");
            return null;
        }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -19,8 +19,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
@@ -544,6 +542,8 @@
                        for (SendRtpItem sendRtpItem : sendRtpItems) {
                            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
                            commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
                            redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
                                    sendRtpItem.getCallId(), sendRtpItem.getStreamId());
                        }
                    }
                }
@@ -573,13 +573,19 @@
            return ret;
        }else {
            StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
            if (streamProxyItem != null && streamProxyItem.isEnable_remove_none_reader()) {
                ret.put("close", true);
                streamProxyService.del(app, streamId);
                String url = streamProxyItem.getUrl() != null?streamProxyItem.getUrl():streamProxyItem.getSrc_url();
                logger.info("[{}/{}]<-[{}] æ‹‰æµä»£ç†æ— äººè§‚看已经移除",  app, streamId, url);
            }else {
                ret.put("close", false);
            if (streamProxyItem != null ) {
                if (streamProxyItem.isEnable_remove_none_reader()) {
                    // æ— äººè§‚看自动移除
                    ret.put("close", true);
                    streamProxyService.del(app, streamId);
                    String url = streamProxyItem.getUrl() != null?streamProxyItem.getUrl():streamProxyItem.getSrc_url();
                    logger.info("[{}/{}]<-[{}] æ‹‰æµä»£ç†æ— äººè§‚看已经移除",  app, streamId, url);
                }else if (streamProxyItem.isEnable_disable_none_reader()) {
                    // æ— äººè§‚看停用
                    ret.put("close", true);
                }else {
                    ret.put("close", false);
                }
            }
            return ret;
        }
@@ -626,7 +632,7 @@
    @ResponseBody
    @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
    public JSONObject onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){
        if (logger.isDebugEnabled()) {
            logger.debug("[ ZLM HOOK ]on_server_started API调用,参数:" + jsonObject.toString());
        }
@@ -649,6 +655,39 @@
        return ret;
    }
    /**
     * å‘送rtp(startSendRtp)被动关闭时回调
     */
    @ResponseBody
    @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
    public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody JSONObject jsonObject){
        logger.info("[ ZLM HOOK ]on_send_rtp_stopped API调用,参数:" + jsonObject);
        JSONObject ret = new JSONObject();
        ret.put("code", 0);
        ret.put("msg", "success");
        // æŸ¥æ‰¾å¯¹åº”的上级推流,发送停止
        String app = jsonObject.getString("app");
        if (!"rtp".equals(app)) {
            return ret;
        }
        String stream = jsonObject.getString("stream");
        List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(stream);
        if (sendRtpItems.size() > 0) {
            for (SendRtpItem sendRtpItem : sendRtpItems) {
                ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
                commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
                redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
                        sendRtpItem.getCallId(), sendRtpItem.getStreamId());
            }
        }
        return ret;
    }
    private Map<String, String> urlParamToMap(String params) {
        HashMap<String, String> map = new HashMap<>();
        if (ObjectUtils.isEmpty(params)) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -96,6 +96,10 @@
        if(rtpInfo.getInteger("code") == 0){
            if (rtpInfo.getBoolean("exist")) {
                result = rtpInfo.getInteger("local_port");
                if (result == 0) {
                    // æ­¤æ—¶è¯´æ˜ŽrtpServer已经创建但是流还没有推上来
                }
                return result;
            }
        }else if(rtpInfo.getInteger("code") == -2){
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -37,6 +37,9 @@
    private boolean enable_mp4;
    @Schema(description = "是否 æ— äººè§‚看时删除")
    private boolean enable_remove_none_reader;
    @Schema(description = "是否 æ— äººè§‚看时不启用")
    private boolean enable_disable_none_reader;
    @Schema(description = "上级平台国标ID")
    private String platformGbId;
    @Schema(description = "创建时间")
@@ -177,4 +180,11 @@
        this.enable_remove_none_reader = enable_remove_none_reader;
    }
    public boolean isEnable_disable_none_reader() {
        return enable_disable_none_reader;
    }
    public void setEnable_disable_none_reader(boolean enable_disable_none_reader) {
        this.enable_disable_none_reader = enable_disable_none_reader;
    }
}
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -82,4 +82,6 @@
    MediaServerItem getDefaultMediaServer();
    void updateMediaServerKeepalive(String mediaServerId, JSONObject data);
    boolean checkRtpServer(MediaServerItem mediaServerItem, String rtp, String stream);
}
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -152,9 +152,11 @@
            if (streamId == null) {
                streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
            }
            int rtpServerPort = mediaServerItem.getRtpProxyPort();
            int rtpServerPort;
            if (mediaServerItem.isRtpEnable()) {
                rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port);
            } else {
                rtpServerPort = mediaServerItem.getRtpProxyPort();
            }
            RedisUtil.set(key, mediaServerItem);
            return new SSRCInfo(rtpServerPort, ssrc, streamId);
@@ -537,6 +539,7 @@
        param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
        param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
        param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex));
        param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrex));
        if (mediaServerItem.getRecordAssistPort() > 0) {
            param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort()));
        }else {
@@ -686,4 +689,13 @@
            }
        }
    }
    @Override
    public boolean checkRtpServer(MediaServerItem mediaServerItem, String app, String stream) {
        JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, stream);
        if(rtpInfo.getInteger("code") == 0){
            return rtpInfo.getBoolean("exist");
        }
        return false;
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -73,7 +73,6 @@
                }else {
                    streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null, true);
                }
            }
        }
        return streamInfo;
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -193,17 +193,30 @@
            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
            if(rtpInfo.getInteger("code") == 0){
                if (rtpInfo.getBoolean("exist")) {
                    int localPort = rtpInfo.getInteger("local_port");
                    if (localPort == 0) {
                        logger.warn("[点播],点播时发现rtpServerC存在,但是尚未开始推流");
                        // æ­¤æ—¶è¯´æ˜ŽrtpServer已经创建但是流还没有推上来
                        WVPResult wvpResult = new WVPResult();
                        wvpResult.setCode(ErrorCode.ERROR100.getCode());
                        wvpResult.setMsg("点播已经在进行中,请稍候重试");
                        msg.setData(wvpResult);
                    WVPResult wvpResult = new WVPResult();
                    wvpResult.setCode(ErrorCode.SUCCESS.getCode());
                    wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
                    wvpResult.setData(streamInfo);
                    msg.setData(wvpResult);
                        resultHolder.invokeAllResult(msg);
                        return playResult;
                    }else {
                        WVPResult wvpResult = new WVPResult();
                        wvpResult.setCode(ErrorCode.SUCCESS.getCode());
                        wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
                        wvpResult.setData(streamInfo);
                        msg.setData(wvpResult);
                    resultHolder.invokeAllResult(msg);
                    if (hookEvent != null) {
                        hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
                        resultHolder.invokeAllResult(msg);
                        if (hookEvent != null) {
                            hookEvent.response(mediaServerItem, JSONObject.parseObject(JSON.toJSONString(streamInfo)));
                        }
                    }
                }else {
                    redisCatchStorage.stopPlay(streamInfo);
                    storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
@@ -318,7 +331,7 @@
                }
                logger.info("[点播消息] æ”¶åˆ°invite 200, å‘现下级自定义了ssrc: {}", ssrcInResponse );
                if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
                    logger.info("[SIP æ¶ˆæ¯] SSRC修正 {}->{}", ssrc, ssrcInResponse);
                    logger.info("[点播消息] SSRC修正 {}->{}", ssrc, ssrcInResponse);
                    if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                        // ssrc ä¸å¯ç”¨
@@ -468,37 +481,92 @@
            resultHolder.exist(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid);
        }, userSetting.getPlayTimeout());
        SipSubscribe.Event errorEvent = event -> {
            dynamicTask.stop(playBackTimeOutTaskKey);
            requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("回放失败, é”™è¯¯ç ï¼š %s, %s", event.statusCode, event.msg)));
            playBackResult.setCode(ErrorCode.ERROR100.getCode());
            playBackResult.setMsg(String.format("回放失败, é”™è¯¯ç ï¼š %s, %s", event.statusCode, event.msg));
            playBackResult.setData(requestMessage);
            playBackResult.setEvent(event);
            playBackCallback.call(playBackResult);
            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
        };
        InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
            logger.info("收到回放订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
            dynamicTask.stop(playBackTimeOutTaskKey);
            StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
            if (streamInfo == null) {
                logger.warn("设备回放API调用失败!");
                playBackResult.setCode(ErrorCode.ERROR100.getCode());
                playBackResult.setMsg("设备回放API调用失败!");
                playBackCallback.call(playBackResult);
                return;
            }
            redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
            WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
            requestMessage.setData(success);
            playBackResult.setCode(ErrorCode.SUCCESS.getCode());
            playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
            playBackResult.setData(requestMessage);
            playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
            playBackResult.setResponse(inviteStreamInfo.getResponse());
            playBackCallback.call(playBackResult);
        };
        cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
                (InviteStreamInfo inviteStreamInfo) -> {
                    logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
                    dynamicTask.stop(playBackTimeOutTaskKey);
                    StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
                    if (streamInfo == null) {
                        logger.warn("设备回放API调用失败!");
                        playBackResult.setCode(ErrorCode.ERROR100.getCode());
                        playBackResult.setMsg("设备回放API调用失败!");
                        playBackCallback.call(playBackResult);
                        return;
                hookEvent, eventResult -> {
                    if (eventResult.type == SipSubscribe.EventResultType.response) {
                        ResponseEvent responseEvent = (ResponseEvent)eventResult.event;
                        String contentString = new String(responseEvent.getResponse().getRawContent());
                        // èŽ·å–ssrc
                        int ssrcIndex = contentString.indexOf("y=");
                        // æ£€æŸ¥æ˜¯å¦æœ‰y字段
                        if (ssrcIndex >= 0) {
                            //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO åŽç»­å¯¹ä¸è§„范的非10位ssrc兼容
                            String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
                            // æŸ¥è¯¢åˆ°ssrc不一致且开启了ssrc校验则需要针对处理
                            if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
                                return;
                            }
                            logger.info("[回放消息] æ”¶åˆ°invite 200, å‘现下级自定义了ssrc: {}", ssrcInResponse );
                            if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
                                logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
                                if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                                    // ssrc ä¸å¯ç”¨
                                    // é‡Šæ”¾ssrc
                                    mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
                                    eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";
                                    eventResult.statusCode = 400;
                                    errorEvent.response(eventResult);
                                    return;
                                }
                                // å•端口模式streamId也有变化,需要重新设置监听
                                if (!mediaServerItem.isRtpEnable()) {
                                    // æ·»åŠ è®¢é˜…
                                    HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
                                    subscribe.removeSubscribe(hookSubscribe);
                                    hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
                                    subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{
                                        logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
                                        dynamicTask.stop(playBackTimeOutTaskKey);
                                        // hook响应
                                        onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);
                                        hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
                                    });
                                }
                                // å…³é—­rtp server
                                mediaServerService.closeRTPServer(device.getDeviceId(), channelId, ssrcInfo.getStream());
                                // é‡æ–°å¼€å¯ssrc server
                                mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
                            }
                        }
                    }
                    redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
                    WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
                    requestMessage.setData(success);
                    playBackResult.setCode(ErrorCode.SUCCESS.getCode());
                    playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
                    playBackResult.setData(requestMessage);
                    playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
                    playBackResult.setResponse(inviteStreamInfo.getResponse());
                    playBackCallback.call(playBackResult);
                }, event -> {
                    dynamicTask.stop(playBackTimeOutTaskKey);
                    requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("回放失败, é”™è¯¯ç ï¼š %s, %s", event.statusCode, event.msg)));
                    playBackResult.setCode(ErrorCode.ERROR100.getCode());
                    playBackResult.setMsg(String.format("回放失败, é”™è¯¯ç ï¼š %s, %s", event.statusCode, event.msg));
                    playBackResult.setData(requestMessage);
                    playBackResult.setEvent(event);
                    playBackCallback.call(playBackResult);
                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
                });
                }, errorEvent);
        return result;
    }
src/main/java/com/genersoft/iot/vmp/service/impl/RedisPushStreamListMsgListener.java
@@ -53,7 +53,6 @@
            boolean contains = allAppAndStream.contains(app + stream);
            //不存在就添加
            if (!contains) {
                streamPushItem.setStatus(false);
                streamPushItem.setStreamType("push");
                streamPushItem.setCreateTime(DateUtil.getNow());
                streamPushItem.setMediaServerId(mediaServerService.getDefaultMediaServer().getId());
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
@@ -116,7 +116,7 @@
        streamPushItem.setApp(streamPushExcelDto.getApp());
        streamPushItem.setStream(streamPushExcelDto.getStream());
        streamPushItem.setGbId(streamPushExcelDto.getGbId());
        streamPushItem.setStatus(false);
        streamPushItem.setStatus(streamPushExcelDto.getStatus());
        streamPushItem.setStreamType("push");
        streamPushItem.setCreateTime(DateUtil.getNow());
        streamPushItem.setMediaServerId(defaultMediaServerId);
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -236,4 +236,6 @@
    void sendStreamPushRequestedMsgForStatus();
    List<SendRtpItem> querySendRTPServerByChnnelId(String channelId);
    List<SendRtpItem> querySendRTPServerByStream(String stream);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -143,15 +143,12 @@
    @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"})
    void offlineByDeviceId(String deviceId);
    @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
    void online(String deviceId,  String channelId);
    @Insert("<script> " +
            "insert into device_channel " +
            "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
            "  address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
            "  ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
            "  longitudeWgs84, latitudeWgs84, createTime, updateTime, businessGroupId, gpsTime) " +
            "  longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
            "values " +
            "<foreach collection='addChannels' index='index' item='item' separator=','> " +
            "('${item.channelId}', '${item.deviceId}', '${item.name}', '${item.manufacture}', '${item.model}', " +
@@ -160,7 +157,7 @@
            "'${item.certNum}', ${item.certifiable}, ${item.errCode}, '${item.secrecy}', " +
            "'${item.ipAddress}', ${item.port}, '${item.password}', ${item.PTZType}, ${item.status}, " +
            "'${item.streamId}', ${item.longitude}, ${item.latitude},${item.longitudeGcj02}, " +
            "${item.latitudeGcj02},${item.longitudeWgs84}, ${item.latitudeWgs84},'${item.createTime}', '${item.updateTime}', " +
            "${item.latitudeGcj02},${item.longitudeWgs84}, ${item.latitudeWgs84}, ${item.hasAudio},'${item.createTime}', '${item.updateTime}', " +
            "'${item.businessGroupId}', '${item.gpsTime}') " +
            "</foreach> " +
            "ON DUPLICATE KEY UPDATE " +
@@ -193,10 +190,14 @@
            "latitudeGcj02=VALUES(latitudeGcj02), " +
            "longitudeWgs84=VALUES(longitudeWgs84), " +
            "latitudeWgs84=VALUES(latitudeWgs84), " +
            "hasAudio=VALUES(hasAudio), " +
            "businessGroupId=VALUES(businessGroupId), " +
            "gpsTime=VALUES(gpsTime)" +
            "</script>")
    int batchAdd(List<DeviceChannel> addChannels);
    @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
    void online(String deviceId,  String channelId);
    @Update({"<script>" +
            "<foreach collection='updateChannels' item='item' separator=';'>" +
@@ -341,4 +342,7 @@
            " left join platform_catalog pc on pgc.catalogId = pc.id and pgc.platformId = pc.platformId" +
            " where pgc.platformId=#{serverGBId}")
    List<DeviceChannel> queryChannelWithCatalog(String serverGBId);
    @Select("select * from device_channel where deviceId = #{deviceId}")
    List<DeviceChannel> queryAllChannels(String deviceId);
}
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
@@ -23,10 +23,10 @@
    @Insert("<script> " +
            "INSERT into platform_gb_stream " +
            "(gbStreamId, platformId, catalogId) " +
            "(gbStreamId, platformId, catalogId,status) " +
            "values " +
            "<foreach collection='streamPushItems' index='index' item='item' separator=','> " +
            "(${item.gbStreamId}, '${item.platformId}', '${item.catalogId}')" +
            "(${item.gbStreamId}, '${item.platformId}', '${item.catalogId}'), '${item.status}')" +
            "</foreach> " +
            "</script>")
    int batchAdd(List<StreamPushItem> streamPushItems);
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
@@ -77,7 +77,7 @@
            "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 st.pushIng=1)</if>" +
            " <if test='pushing == false' > AND st.pushIng=0</if>" +
            " <if test='pushing == false' > AND (gs.pushIng is null OR st.pushIng=0) </if>" +
            " <if test='mediaServerId != null' > AND st.mediaServerId=#{mediaServerId} </if>" +
            "order by st.createTime desc" +
            " </script>"})
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -388,6 +388,24 @@
    }
    @Override
    public List<SendRtpItem> querySendRTPServerByStream(String stream) {
        if (stream == null) {
            return null;
        }
        String platformGbId = "*";
        String callId = "*";
        String channelId = "*";
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
                + "_" + channelId + "_" + stream + "_" + callId;
        List<Object> scan = RedisUtil.scan(key);
        List<SendRtpItem> result = new ArrayList<>();
        for (Object o : scan) {
            result.add((SendRtpItem) RedisUtil.get((String) o));
        }
        return result;
    }
    @Override
    public List<SendRtpItem> querySendRTPServer(String platformGbId) {
        if (platformGbId == null) {
            platformGbId = "*";
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -111,11 +111,11 @@
        if (CollectionUtils.isEmpty(deviceChannelList)) {
            return false;
        }
        List<DeviceChannel> allChannelInPlay = deviceChannelMapper.getAllChannelInPlay();
        Map<String,DeviceChannel> allChannelMapInPlay = new ConcurrentHashMap<>();
        if (allChannelInPlay.size() > 0) {
            for (DeviceChannel deviceChannel : allChannelInPlay) {
                allChannelMapInPlay.put(deviceChannel.getChannelId(), deviceChannel);
        List<DeviceChannel> allChannels = deviceChannelMapper.queryAllChannels(deviceId);
        Map<String,DeviceChannel> allChannelMap = new ConcurrentHashMap<>();
        if (allChannels.size() > 0) {
            for (DeviceChannel deviceChannel : allChannels) {
                allChannelMap.put(deviceChannel.getChannelId(), deviceChannel);
            }
        }
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
@@ -123,15 +123,17 @@
        List<DeviceChannel> channels = new ArrayList<>();
        StringBuilder stringBuilder = new StringBuilder();
        Map<String, Integer> subContMap = new HashMap<>();
        if (deviceChannelList.size() > 1) {
        if (deviceChannelList.size() > 0) {
            // æ•°æ®åŽ»é‡
            Set<String> gbIdSet = new HashSet<>();
            for (DeviceChannel deviceChannel : deviceChannelList) {
                if (!gbIdSet.contains(deviceChannel.getChannelId())) {
                    gbIdSet.add(deviceChannel.getChannelId());
                    if (allChannelMapInPlay.containsKey(deviceChannel.getChannelId())) {
                        deviceChannel.setStreamId(allChannelMapInPlay.get(deviceChannel.getChannelId()).getStreamId());
                    if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
                        deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
                        deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
                    }
                    channels.add(deviceChannel);
                    if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
                        if (subContMap.get(deviceChannel.getParentId()) == null) {
@@ -153,8 +155,6 @@
                }
            }
        }else {
            channels = deviceChannelList;
        }
        if (stringBuilder.length() > 0) {
            logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder);
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java
@@ -22,6 +22,9 @@
    @ExcelProperty("目录ID")
    private String catalogId;
    @ExcelProperty("在线状态")
    private boolean status;
    public String getName() {
        return name;
    }
@@ -70,4 +73,16 @@
    public void setCatalogId(String catalogId) {
        this.catalogId = catalogId;
    }
    public boolean isStatus() {
        return status;
    }
    public boolean getStatus() {
        return status;
    }
    public void setStatus(boolean status) {
        this.status = status;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -43,6 +43,7 @@
    private IRoleService roleService;
    @GetMapping("/login")
    @PostMapping("/login")
    @Operation(summary = "登录")
    @Parameter(name = "username", description = "用户名", required = true)
    @Parameter(name = "password", description = "密码(32位md5加密)", required = true)
src/main/resources/logback-spring-local.xml
@@ -98,6 +98,11 @@
        <appender-ref ref="STDOUT" />
    </root>
    <logger name="wvp" level="debug" additivity="true">
        <appender-ref ref="RollingFileError"/>
        <appender-ref ref="RollingFile"/>
    </logger>
    <logger name="GB28181_SIP" level="debug" additivity="true">
        <appender-ref ref="RollingFileError"/>
        <appender-ref ref="sipRollingFile"/>
web_src/src/components/ParentPlatformList.vue
@@ -143,7 +143,8 @@
        });
    },
    chooseChannel: function(platform) {
       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, platform.name, platform.catalogId, platform.treeType, this.initData)
        console.log("platform.name: " + platform.name)
       this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, platform.treeType, this.initData)
    },
    initData: function() {
      this.getPlatformList();
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" :treeType=treeType ></chooseChannelForCatalog>
                  <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog>
                </el-main>
              </el-container>
            </el-tab-pane>
@@ -60,6 +60,7 @@
            tabActiveName: "gbChannel",
            catalogTabActiveName: "catalog",
            platformId: "",
            platformDeviceId: "",
            catalogId: "",
            catalogName: "",
            currentCatalogId: "",
@@ -73,8 +74,10 @@
        };
    },
    methods: {
        openDialog(platformId, platformName, defaultCatalogId, treeType, closeCallback) {
        openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, treeType, closeCallback) {
            console.log("defaultCatalogId: " + defaultCatalogId)
            this.platformId = platformId
            this.platformDeviceId = platformDeviceId
            this.platformName = platformName
            this.defaultCatalogId = defaultCatalogId
            this.showDialog = true
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', 'treeType'],
    props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'],
    created() {
        this.chooseId = this.defaultCatalogId;
        this.defaultCatalogIdSign = this.defaultCatalogId;
@@ -171,6 +171,7 @@
            });
        },
        loadNode: function(node, resolve){
          console.log("this.platformDeviceId: " + this.platformDeviceId)
          if (node.level === 0) {
            resolve([
              {
@@ -179,7 +180,7 @@
              type:  -1
              },{
                name: this.platformName,
                id:  this.platformId,
                id:   this.platformDeviceId,
                type:  0
              }
            ]);
@@ -298,6 +299,8 @@
        return false;
      },
      nodeClickHandler: function (data, node, tree){
          console.log(data)
          console.log(node)
       this.chooseId = data.id;
       this.chooseName = data.name;
       if (this.catalogIdChange)this.catalogIdChange(this.chooseId, this.chooseName);
web_src/src/components/dialog/getCatalog.vue
@@ -77,6 +77,7 @@
    },
    methods: {
        openDialog(catalogIdResult) {
          console.log(this.chooseId)
          this.showDialog = true
          this.catalogIdResult = catalogIdResult
        },
@@ -107,9 +108,6 @@
        },
        loadNode: function(node, resolve){
          if (node.level === 0) {
            this.$axios({
              method:"get",
@@ -124,7 +122,7 @@
                  resolve([
                   {
                      name: this.platformName,
                      id:  this.platformId,
                      id:   res.data.data.deviceGBId,
                      type:  0
                    }
                  ]);
@@ -142,9 +140,19 @@
         this.chooseId = data.id;
        },
        close: function() {
          this.chooseId = null;
          this.showDialog = false;
        },
        submit: function() {
          console.log(this.chooseId)
          if (this.chooseId === null) {
            this.$message({
              showClose: true,
              message: '未选择任何节点,',
              type: 'warning'
            });
            return;
          }
          if (this.catalogIdResult)this.catalogIdResult(this.chooseId)
          this.showDialog = false;
        },
web_src/src/components/dialog/platformEdit.vue
@@ -37,13 +37,13 @@
              <el-form-item label="本地端口" prop="devicePort">
                <el-input v-model="platform.devicePort" :disabled="true" type="number"></el-input>
              </el-form-item>
              <el-form-item label="SIP认证用户名" prop="username">
                <el-input v-model="platform.username"></el-input>
              </el-form-item>
            </el-form>
          </el-col>
          <el-col :span="12">
            <el-form ref="platform2" :rules="rules" :model="platform" label-width="160px">
              <el-form-item label="SIP认证用户名" prop="username">
                <el-input v-model="platform.username"></el-input>
              </el-form-item>
              <el-form-item label="行政区划" prop="administrativeDivision">
                <el-input v-model="platform.administrativeDivision" clearable></el-input>
              </el-form-item>
@@ -79,7 +79,7 @@
                </el-select>
              </el-form-item>
              <el-form-item label="目录结构" prop="treeType" >
                <el-select v-model="platform.treeType" style="width: 100%" >
                <el-select v-model="platform.treeType" style="width: 100%" @change="treeTypeChange">
                  <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option>
                  <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option>
                </el-select>
@@ -98,6 +98,7 @@
                <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.startOfflinePush"></el-checkbox>
                <el-checkbox label="RTCP保活" v-model="platform.rtcp" @change="rtcpCheckBoxChange"></el-checkbox>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="onSubmit">{{
@@ -251,21 +252,7 @@
    },
    onSubmit: function () {
      if (this.onSubmit_text === "保存") {
        this.$confirm("修改目录结构会导致关联目录与通道数据被清空", '提示', {
          dangerouslyUseHTMLString: true,
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          center: true,
          type: 'warning'
        }).then(() => {
          this.saveForm()
        }).catch(() => {
        });
      }else {
        this.saveForm()
      }
      this.saveForm()
    },
    saveForm: function (){
      this.$axios({
@@ -343,6 +330,22 @@
      if (this.platform.enable && this.platform.expires == "0") {
        this.platform.expires = "300";
      }
    },
    rtcpCheckBoxChange: function (result){
      if (result) {
        this.$message({
          showClose: true,
          message: "开启RTCP保活需要上级平台支持,可以避免无效推流",
          type: "warning",
        });
      }
    },
    treeTypeChange: function (){
      this.$message({
        showClose: true,
        message: "修改目录结构会导致关联目录与通道数据被清空,保存后生效",
        type: "warning",
      });
    }
  },
};
web_src/static/file/ÍÆÁ÷ͨµÀµ¼Èë.zip
Binary files differ