648540858
2022-08-22 042b28b2d62860db912b254420fb4172880aafab
支持全局异常和统一返回结果
30个文件已修改
1个文件已添加
647 ■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/CloudRecordDetail.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/ParentPlatformList.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/PushVideoList.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/StreamProxyList.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/UserManager.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/common/ h265web.vue 327 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/control.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/StreamProxyEdit.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/SyncChannelProgress.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/addUser.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/catalogEdit.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePassword.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePasswordForAdmin.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePushKey.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannel.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForCatalog.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForStream.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/deviceEdit.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/devicePlayer.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/onvifEdit.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/pushStreamEdit.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/recordDownload.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/live.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/map.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/service/DeviceService.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java
@@ -3,6 +3,7 @@
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
@@ -13,20 +14,21 @@
/**
 * 全局统一返回结果
 * @author lin
 */
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    public boolean supports(@NotNull MethodParameter returnType, @NotNull Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType, @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
        // 排除api文档的接口,这个接口不需要统一
        String[] excludePath = {"/v3/api-docs","/api/v1"};
        String[] excludePath = {"/v3/api-docs","/api/v1","/index/hook"};
        for (String path : excludePath) {
            if (request.getURI().getPath().startsWith(path)) {
                return body;
@@ -43,7 +45,7 @@
        }
        if (body instanceof String) {
            return JSON.toJSON(WVPResult.success(body));
            return JSON.toJSONString(WVPResult.success(body));
        }
        return WVPResult.success(body);
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
@@ -4,14 +4,18 @@
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import javax.sip.RequestEvent;
import java.util.EventObject;
/**
 * @author lin
 */
public class PlayBackResult<T> {
    private int code;
    private T data;
    private MediaServerItem mediaServerItem;
    private JSONObject response;
    private SipSubscribe.EventResult event;
    private SipSubscribe.EventResult<EventObject> event;
    public int getCode() {
        return code;
@@ -45,11 +49,11 @@
        this.response = response;
    }
    public SipSubscribe.EventResult getEvent() {
    public SipSubscribe.EventResult<EventObject> getEvent() {
        return event;
    }
    public void setEvent(SipSubscribe.EventResult event) {
    public void setEvent(SipSubscribe.EventResult<EventObject> event) {
        this.event = event;
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -12,8 +12,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.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
@@ -362,7 +360,7 @@
            resultHolder.invokeAllResult(msg);
        } else {
            logger.warn("设备预览API调用失败!");
            msg.setData("设备预览API调用失败!");
            msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));
            resultHolder.invokeAllResult(msg);
        }
    }
@@ -415,16 +413,15 @@
        }
        DeferredResult<String> result = new DeferredResult<>(30000L);
        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid, result);
        RequestMessage msg = new RequestMessage();
        msg.setId(uuid);
        msg.setKey(key);
        RequestMessage requestMessage = new RequestMessage();
        requestMessage.setId(uuid);
        requestMessage.setKey(key);
        PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
        String  playBackTimeOutTaskKey = UUID.randomUUID().toString();
        String playBackTimeOutTaskKey = UUID.randomUUID().toString();
        dynamicTask.startDelay(playBackTimeOutTaskKey, ()->{
            logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
            playBackResult.setCode(-1);
            playBackResult.setData(msg);
            playBackCallback.call(playBackResult);
            playBackResult.setData(requestMessage);
            SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
            // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
            if (dialog != null) {
@@ -447,24 +444,23 @@
                    StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
                    if (streamInfo == null) {
                        logger.warn("设备回放API调用失败!");
                        msg.setData("设备回放API调用失败!");
                        playBackResult.setCode(-1);
                        playBackResult.setData(msg);
                        playBackCallback.call(playBackResult);
                        return;
                    }
                    redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
                    msg.setData(JSON.toJSONString(streamInfo));
                    WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
                    requestMessage.setData(success);
                    playBackResult.setCode(0);
                    playBackResult.setData(msg);
                    playBackResult.setData(requestMessage);
                    playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
                    playBackResult.setResponse(inviteStreamInfo.getResponse());
                    playBackCallback.call(playBackResult);
                }, event -> {
                    dynamicTask.stop(playBackTimeOutTaskKey);
                    msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
                    requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)));
                    playBackResult.setCode(-1);
                    playBackResult.setData(msg);
                    playBackResult.setData(requestMessage);
                    playBackResult.setEvent(event);
                    playBackCallback.call(playBackResult);
                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
@@ -498,13 +494,13 @@
        }
        resultHolder.put(key, uuid, result);
        RequestMessage msg = new RequestMessage();
        msg.setId(uuid);
        msg.setKey(key);
        RequestMessage requestMessage = new RequestMessage();
        requestMessage.setId(uuid);
        requestMessage.setKey(key);
        WVPResult<StreamInfo> wvpResult = new WVPResult<>();
        msg.setData(wvpResult);
        requestMessage.setData(wvpResult);
        PlayBackResult<RequestMessage> downloadResult = new PlayBackResult<>();
        downloadResult.setData(msg);
        downloadResult.setData(requestMessage);
        String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
        dynamicTask.startDelay(downLoadTimeOutTaskKey, ()->{
@@ -606,7 +602,7 @@
            resultHolder.invokeResult(msg);
        } else {
            logger.warn("设备预览API调用失败!");
            msg.setData("设备预览API调用失败!");
            msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "设备预览API调用失败!"));
            resultHolder.invokeResult(msg);
        }
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -24,8 +24,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -80,7 +78,7 @@
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/start/{deviceId}/{channelId}")
    public DeferredResult<String> play(@PathVariable String deviceId,
    public DeferredResult<WVPResult<String>> play(@PathVariable String deviceId,
                                                       @PathVariable String channelId) {
        // 获取可用的zlm
@@ -96,72 +94,33 @@
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/stop/{deviceId}/{channelId}")
    public DeferredResult<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) {
    public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId) {
        logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId ));
        String uuid = UUID.randomUUID().toString();
        DeferredResult<String> result = new DeferredResult<>();
        if (deviceId == null || channelId == null) {
            throw new ControllerException(ErrorCode.ERROR400);
        }
        // 录像查询以channelId作为deviceId查询
        String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId;
        resultHolder.put(key, uuid, result);
        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
        if (streamInfo == null) {
            RequestMessage msg = new RequestMessage();
            msg.setId(uuid);
            msg.setKey(key);
            msg.setData("点播未找到");
            resultHolder.invokeAllResult(msg);
            storager.stopPlay(deviceId, channelId);
            return result;
        }
        cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, eventResult -> {
            redisCatchStorage.stopPlay(streamInfo);
            storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
            RequestMessage msgForSuccess = new RequestMessage();
            msgForSuccess.setId(uuid);
            msgForSuccess.setKey(key);
            msgForSuccess.setData(String.format("success"));
            resultHolder.invokeAllResult(msgForSuccess);
        });
        if (deviceId != null || channelId != null) {
            JSONObject json = new JSONObject();
            json.put("deviceId", deviceId);
            json.put("channelId", channelId);
            RequestMessage msg = new RequestMessage();
            msg.setId(uuid);
            msg.setKey(key);
            msg.setData(json.toString());
            resultHolder.invokeAllResult(msg);
        } else {
            logger.warn("设备预览/回放停止API调用失败!");
            RequestMessage msg = new RequestMessage();
            msg.setId(uuid);
            msg.setKey(key);
            msg.setData("streamId null");
            resultHolder.invokeAllResult(msg);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到");
        }
        // 超时处理
        result.onTimeout(()->{
            logger.warn(String.format("设备预览/回放停止超时,deviceId/channelId:%s_%s ", deviceId, channelId));
            redisCatchStorage.stopPlay(streamInfo);
            storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
            RequestMessage msg = new RequestMessage();
            msg.setId(uuid);
            msg.setKey(key);
            msg.setData("Timeout");
            resultHolder.invokeAllResult(msg);
        });
        return result;
        cmder.streamByeCmd(deviceId, channelId, streamInfo.getStream(), null, null);
        redisCatchStorage.stopPlay(streamInfo);
        storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
        JSONObject json = new JSONObject();
        json.put("deviceId", deviceId);
        json.put("channelId", channelId);
        return json;
    }
    /**
     * 将不是h264的视频通过ffmpeg 转码为h264 + aac
     * @param streamId 流ID
     * @return
     */
    @Operation(summary = "将不是h264的视频通过ffmpeg 转码为h264 + aac")
    @Parameter(name = "streamId", description = "视频流ID", required = true)
@@ -205,8 +164,6 @@
    /**
     * 结束转码
     * @param key
     * @return
     */
    @Operation(summary = "结束转码")
    @Parameter(name = "key", description = "视频流key", required = true)
@@ -278,7 +235,7 @@
        });
        result.onTimeout(() -> {
            logger.warn(String.format("语音广播操作超时, 设备未返回应答指令"));
            logger.warn("语音广播操作超时, 设备未返回应答指令");
            RequestMessage msg = new RequestMessage();
            msg.setKey(key);
            msg.setId(uuid);
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -3,7 +3,6 @@
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -13,10 +12,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -29,6 +25,9 @@
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.springframework.web.context.request.async.DeferredResult;
/**
 * @author lin
 */
@Tag(name = "视频回放")
@CrossOrigin
@RestController
@@ -65,11 +64,9 @@
            logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
        }
        DeferredResult<String> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{
            resultHolder.invokeResult(wvpResult.getData());
        });
        return result;
        return playService.playBack(deviceId, channelId, startTime, endTime, null,
                playBackResult->resultHolder.invokeResult(playBackResult.getData()));
    }
@@ -109,10 +106,8 @@
    @GetMapping("/resume/{streamId}")
    public void playResume(@PathVariable String streamId) {
        logger.info("playResume: "+streamId);
        JSONObject json = new JSONObject();
        StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        if (null == streamInfo) {
            json.put("msg", "streamId不存在");
            logger.warn("streamId不存在!");
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
        }
web_src/src/components/CloudRecordDetail.vue
@@ -15,7 +15,6 @@
                  <i class="el-icon-video-camera"  ></i>
                  {{ item.substring(0,17)}}
                </el-tag>
<!--                <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${basePath}/${mediaServerId}/record/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" download />-->
                <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${basePath}/download.html?url=record/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" target="_blank" />
              </li>
            </ul>
@@ -392,7 +391,7 @@
            endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'),
          }
        }).then(function (res) {
          if (res.data.code === 0 && res.data.msg === "success") {
          if (res.data.code === 0 ) {
            that.showTaskBox = false
            that.getTaskList(false);
          }else {
@@ -414,7 +413,7 @@
            isEnd: isEnd,
          }
        }).then(function (res) {
          if (res.data.code == 0) {
          if (res.data.code === 0) {
            if (isEnd){
              that.taskListEnded = res.data.data;
            }else {
web_src/src/components/ParentPlatformList.vue
@@ -127,8 +127,8 @@
    deletePlatformCommit: function(platform) {
        var that = this;
        that.$axios({
        method: 'delete',
        url:`/api/platform/delete/${platform.serverGBId}`
          method: 'delete',
          url:`/api/platform/delete/${platform.serverGBId}`
        }).then(function (res) {
            if (res.data.code === 0) {
                that.$message({
web_src/src/components/PushVideoList.vue
@@ -229,7 +229,7 @@
          streamId: row.stream
        }
      }).then((res) => {
        if (res.data == "success") {
        if (res.data.code === 0) {
          that.initData()
        }
      }).catch(function (error) {
@@ -250,7 +250,7 @@
        url: "/api/push/remove_form_gb",
        data: row
      }).then((res) => {
        if (res.data == "success") {
        if (res.data.code === 0) {
          that.initData()
        }
      }).catch(function (error) {
web_src/src/components/StreamProxyList.vue
@@ -168,12 +168,14 @@
                        count: that.count
                    }
                }).then(function (res) {
                    that.total = res.data.total;
          for (let i = 0; i < res.data.list.length; i++) {
            res.data.list[i]["startBtnLoading"] = false;
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            for (let i = 0; i < res.data.data.list.length; i++) {
              res.data.data.list[i]["startBtnLoading"] = false;
            }
            that.streamProxyList = res.data.data.list;
          }
          that.streamProxyList = res.data.list;
                    that.getListLoading = false;
          that.getListLoading = false;
                }).catch(function (error) {
                    console.log(error);
                    that.getListLoading = false;
@@ -190,7 +192,7 @@
          url:`/api/onvif/search?timeout=3000`,
        }).then((res) =>{
          this.getListLoading = false;
          if (res.data.code == 0 ){
          if (res.data.code === 0 ){
            if (res.data.data.length > 0) {
              this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
                  if (url != null) {
@@ -277,7 +279,7 @@
                }).then(function (res) {
          that.getListLoading = false;
          that.$set(row, 'startBtnLoading', false)
                  if (res.data == "success"){
                  if (res.data.code === 0){
            that.initData()
          }else {
            that.$message({
web_src/src/components/UserManager.vue
@@ -105,8 +105,10 @@
          count: that.count
        }
      }).then(function (res) {
        that.total = res.data.total;
        that.userList = res.data.list;
        if (res.data.code === 0) {
          that.total = res.data.data.total;
          that.userList = res.data.data.list;
        }
        that.getUserListLoading = false;
      }).catch(function (error) {
        that.getUserListLoading = false;
web_src/src/components/channelList.vue
@@ -342,12 +342,15 @@
            channelType: this.channelType
          }
        }).then( (res) =>{
          this.total = res.data.total;
          this.deviceChannelList = res.data.list;
          // 防止出现表格错位
          this.$nextTick(() => {
            this.$refs.channelListTable.doLayout();
          })
          if (res.data.code === 0) {
            this.total = res.data.data.total;
            this.deviceChannelList = res.data.data.list;
            // 防止出现表格错位
            this.$nextTick(() => {
              this.$refs.channelListTable.doLayout();
            })
          }
        }).catch(function (error) {
          console.log(error);
        });
@@ -361,12 +364,14 @@
            count: this.count,
          }
        }).then((res)=> {
          this.total = res.data.total;
          this.deviceChannelList = res.data.list;
          // 防止出现表格错位
          this.$nextTick(() => {
            this.$refs.channelListTable.doLayout();
          })
          if (res.data.code === 0) {
            this.total = res.data.total;
            this.deviceChannelList = res.data.list;
            // 防止出现表格错位
            this.$nextTick(() => {
              this.$refs.channelListTable.doLayout();
            })
          }
        }).catch(function (error) {
          console.log(error);
        });
web_src/src/components/common/ h265web.vue
New file
@@ -0,0 +1,327 @@
<template>
  <div ref="container" @dblclick="fullscreenSwich" style="width:100%;height:100%;background-color: #000000;margin:0 auto;">
    <div class="buttons-box" id="buttonsBox">
      <div class="buttons-box-left">
        <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
        <i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
        <i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i>
        <i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="mute()"></i>
        <i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="cancelMute()"></i>
      </div>
      <div class="buttons-box-right">
        <span class="jessibuca-btn">{{ kBps }} kb/s</span>
        <!--          <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
        <!--          <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
        <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="jessibuca.screenshot('截图','png',0.5)"
           style="font-size: 1rem !important"></i>
        <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
        <i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
        <i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
      </div>
    </div>
  </div>
</template>
<script>
let jessibucaPlayer = {};
export default {
  name: 'jessibuca',
  data() {
    return {
      playing: false,
      isNotMute: false,
      quieting: false,
      fullscreen: false,
      loaded: false, // mute
      speed: 0,
      performance: "", // 工作情况
      kBps: 0,
      btnDom: null,
      videoInfo: null,
      volume: 1,
      rotate: 0,
      vod: true, // 点播
      forceNoOffscreen: false,
    };
  },
  props: ['videoUrl', 'error', 'hasAudio', 'height'],
  mounted() {
    window.onerror = (msg) => {
      // console.error(msg)
    };
    console.log(this._uid)
    let paramUrl = decodeURIComponent(this.$route.params.url)
    this.$nextTick(() => {
      this.updatePlayerDomSize()
      window.onresize = () => {
        this.updatePlayerDomSize()
      }
      if (typeof (this.videoUrl) == "undefined") {
        this.videoUrl = paramUrl;
      }
      this.btnDom = document.getElementById("buttonsBox");
      console.log("初始化时的地址为: " + this.videoUrl)
      this.play(this.videoUrl)
    })
  },
  watch: {
    videoUrl(newData, oldData) {
      this.play(newData)
    },
    immediate: true
  },
  methods: {
    updatePlayerDomSize() {
      let dom = this.$refs.container;
      let width = dom.parentNode.clientWidth
      let height = (9 / 16) * width
      const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
      if (height > clientHeight) {
        height = clientHeight
        width = (16 / 9) * height
      }
      dom.style.width = width + 'px';
      dom.style.height = height + "px";
    },
    create() {
      let options = {};
      console.log("hasAudio  " + this.hasAudio)
      jessibucaPlayer[this._uid] = new window.Jessibuca(Object.assign(
        {
          container: this.$refs.container,
          videoBuffer: 0.2, // 最大缓冲时长,单位秒
          isResize: true,
          decoder: "static/js/jessibuca/decoder.js",
          useMSE: false,
          showBandwidth: false,
          isFlv: true,
          // text: "WVP-PRO",
          // background: "static/images/zlm-logo.png",
          loadingText: "加载中",
          hasAudio: typeof (this.hasAudio) == "undefined" ? true : this.hasAudio,
          debug: false,
          supportDblclickFullscreen: false, // 是否支持屏幕的双击事件,触发全屏,取消全屏事件。
          operateBtns: {
            fullscreen: false,
            screenshot: false,
            play: false,
            audio: false,
            recorder: false,
          },
          record: "record",
          vod: this.vod,
          forceNoOffscreen: this.forceNoOffscreen,
          isNotMute: this.isNotMute,
        },
        options
      ));
      let jessibuca = jessibucaPlayer[this._uid];
      let _this = this;
      jessibuca.on("load", function () {
        console.log("on load init");
      });
      jessibuca.on("log", function (msg) {
        console.log("on log", msg);
      });
      jessibuca.on("record", function (msg) {
        console.log("on record:", msg);
      });
      jessibuca.on("pause", function () {
        _this.playing = false;
      });
      jessibuca.on("play", function () {
        _this.playing = true;
      });
      jessibuca.on("fullscreen", function (msg) {
        console.log("on fullscreen", msg);
        _this.fullscreen = msg
      });
      jessibuca.on("mute", function (msg) {
        console.log("on mute", msg);
        _this.isNotMute = !msg;
      });
      jessibuca.on("audioInfo", function (msg) {
        // console.log("audioInfo", msg);
      });
      jessibuca.on("videoInfo", function (msg) {
        // this.videoInfo = msg;
        console.log("videoInfo", msg);
      });
      jessibuca.on("bps", function (bps) {
        // console.log('bps', bps);
      });
      let _ts = 0;
      jessibuca.on("timeUpdate", function (ts) {
        // console.log('timeUpdate,old,new,timestamp', _ts, ts, ts - _ts);
        _ts = ts;
      });
      jessibuca.on("videoInfo", function (info) {
        console.log("videoInfo", info);
      });
      jessibuca.on("error", function (error) {
        console.log("error", error);
      });
      jessibuca.on("timeout", function () {
        console.log("timeout");
      });
      jessibuca.on('start', function () {
        console.log('start');
      })
      jessibuca.on("performance", function (performance) {
        let show = "卡顿";
        if (performance === 2) {
          show = "非常流畅";
        } else if (performance === 1) {
          show = "流畅";
        }
        _this.performance = show;
      });
      jessibuca.on('buffer', function (buffer) {
        // console.log('buffer', buffer);
      })
      jessibuca.on('stats', function (stats) {
        // console.log('stats', stats);
      })
      jessibuca.on('kBps', function (kBps) {
        _this.kBps = Math.round(kBps);
      });
      // 显示时间戳 PTS
      jessibuca.on('videoFrame', function () {
      })
      //
      jessibuca.on('metadata', function () {
      });
    },
    playBtnClick: function (event) {
      this.play(this.videoUrl)
    },
    play: function (url) {
      console.log(url)
      if (jessibucaPlayer[this._uid]) {
        this.destroy();
      }
      this.create();
      jessibucaPlayer[this._uid].on("play", () => {
        this.playing = true;
        this.loaded = true;
        this.quieting = jessibuca.quieting;
      });
      if (jessibucaPlayer[this._uid].hasLoaded()) {
        jessibucaPlayer[this._uid].play(url);
      } else {
        jessibucaPlayer[this._uid].on("load", () => {
          console.log("load 播放")
          jessibucaPlayer[this._uid].play(url);
        });
      }
    },
    pause: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].pause();
      }
      this.playing = false;
      this.err = "";
      this.performance = "";
    },
    mute: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].mute();
      }
    },
    cancelMute: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].cancelMute();
      }
    },
    destroy: function () {
      if (jessibucaPlayer[this._uid]) {
        jessibucaPlayer[this._uid].destroy();
      }
      if (document.getElementById("buttonsBox") == null) {
        this.$refs.container.appendChild(this.btnDom)
      }
      jessibucaPlayer[this._uid] = null;
      this.playing = false;
      this.err = "";
      this.performance = "";
    },
    eventcallbacK: function (type, message) {
      // console.log("player 事件回调")
      // console.log(type)
      // console.log(message)
    },
    fullscreenSwich: function () {
      let isFull = this.isFullscreen()
      jessibucaPlayer[this._uid].setFullscreen(!isFull)
      this.fullscreen = !isFull;
    },
    isFullscreen: function () {
      return document.fullscreenElement ||
        document.msFullscreenElement ||
        document.mozFullScreenElement ||
        document.webkitFullscreenElement || false;
    }
  },
  destroyed() {
    if (jessibucaPlayer[this._uid]) {
      jessibucaPlayer[this._uid].destroy();
    }
    this.playing = false;
    this.loaded = false;
    this.performance = "";
  },
}
</script>
<style>
.buttons-box {
  width: 100%;
  height: 28px;
  background-color: rgba(43, 51, 63, 0.7);
  position: absolute;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  left: 0;
  bottom: 0;
  user-select: none;
  z-index: 10;
}
.jessibuca-btn {
  width: 20px;
  color: rgb(255, 255, 255);
  line-height: 27px;
  margin: 0px 10px;
  padding: 0px 2px;
  cursor: pointer;
  text-align: center;
  font-size: 0.8rem !important;
}
.buttons-box-right {
  position: absolute;
  right: 0;
}
</style>
web_src/src/components/control.vue
@@ -329,7 +329,7 @@
          method: 'get',
          url: '/zlm/' + that.mediaServerChoose + '/index/api/getThreadsLoad'
        }).then(function (res) {
          if (res.data.code == 0) {
          if (res.data.code === 0) {
            that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
              hour12: false
            }));
@@ -554,7 +554,7 @@
          url: '/zlm/' + that.mediaServerChoose + '/index/api/restartServer'
        }).then(function (res) {
          that.getAllSession();
          if (res.data.code == 0) {
          if (res.data.code === 0) {
            that.$message({
              type: 'success',
              message: '操作完成'
web_src/src/components/dialog/StreamProxyEdit.vue
@@ -200,7 +200,7 @@
        method: 'get',
        url:`/api/platform/query/10000/1`
      }).then(function (res) {
        that.platformList = res.data.list;
        that.platformList = res.data.data.list;
      }).catch(function (error) {
        console.log(error);
      });
web_src/src/components/dialog/SyncChannelProgress.vue
@@ -57,7 +57,7 @@
        method: 'get',
        url:`/api/device/query/${this.deviceId}/sync_status/`,
      }).then((res) => {
        if (res.data.code == 0) {
        if (res.data.code === 0) {
          if (!this.syncFlag) {
            this.syncFlag = true;
          }
web_src/src/components/dialog/addUser.vue
@@ -142,13 +142,8 @@
        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)
web_src/src/components/dialog/catalogEdit.vue
@@ -118,8 +118,7 @@
        method:"post",
        url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
        data: this.form
      })
        .then((res)=> {
      }).then((res)=> {
          if (res.data.code === 0) {
            if (this.submitCallback)this.submitCallback(this.form)
          }else {
web_src/src/components/dialog/changePassword.vue
@@ -96,7 +96,7 @@
          password: this.newPassword
        }
      }).then((res)=> {
        if (res.data === "success"){
        if (res.data.code === 0) {
          this.$message({
            showClose: true,
            message: '修改成功,请重新登录',
web_src/src/components/dialog/changePasswordForAdmin.vue
@@ -91,7 +91,7 @@
          userId: this.form.id,
        }
      }).then((res)=> {
        if (res.data === "success"){
        if (res.data.code === 0) {
          this.$message({
            showClose: true,
            message: '修改成功',
web_src/src/components/dialog/changePushKey.vue
@@ -71,8 +71,7 @@
          userId: this.form.id,
        }
      }).then((res)=> {
        console.log(res.data)
        if (res.data.msg === "success"){
        if (res.data.code === 0) {
          this.$message({
            showClose: true,
            message: '修改成功',
web_src/src/components/dialog/chooseChannel.vue
@@ -101,7 +101,7 @@
                    channelReduces:  that.chooseData
                }
            }).then((res)=>{
                if (res.data == true) {
              if (res.data.code === 0) {
                    that.$message({
                        showClose: true,
                        message: '保存成功,',
web_src/src/components/dialog/chooseChannelForCatalog.vue
@@ -87,8 +87,7 @@
                        platformId: that.platformId,
                        parentId: parentId
                    }
                })
                .then((res)=> {
                }).then((res)=> {
                  if (res.data.code === 0) {
                    if (typeof(callback) === 'function') {
                      callback(res.data.data)
@@ -140,8 +139,7 @@
              id: id,
              platformId: this.platformId,
            }
          })
            .then((res) => {
          }).then((res) => {
              if (res.data.code === 0) {
                console.log("移除成功")
                node.parent.loaded = false
@@ -163,8 +161,7 @@
              platformId: this.platformId,
              catalogId: id,
            }
          })
            .then((res)=> {
          }).then((res)=> {
              if (res.data.code === 0) {
                this.defaultCatalogIdSign = id;
              }
web_src/src/components/dialog/chooseChannelForStream.vue
@@ -180,15 +180,17 @@
                }
                })
                .then(function (res) {
                    that.total = res.data.total;
                    that.gbStreams = res.data.list;
                    that.gbChoosechannel = {};
                    // 防止出现表格错位
                    that.$nextTick(() => {
                    if (res.data.code === 0) {
                      that.total = res.data.data.total;
                      that.gbStreams = res.data.data.list;
                      that.gbChoosechannel = {};
                      // 防止出现表格错位
                      that.$nextTick(() => {
                        that.$refs.gbStreamsTable.doLayout();
                        // 默认选中
                         that.eventEnable = true;
                    })
                        that.eventEnable = true;
                      })
                    }
                })
                .catch(function (error) {
                    console.log(error);
web_src/src/components/dialog/deviceEdit.vue
@@ -122,7 +122,7 @@
        params: this.form
      }).then((res) => {
        console.log(res.data)
        if (res.data.code == 0) {
        if (res.data.code === 0) {
          this.listChangeCallback()
        }else {
          this.$message({
web_src/src/components/dialog/devicePlayer.vue
@@ -438,6 +438,7 @@
            this.playFromStreamInfo(false, streamInfo)
        },
        getUrlByStreamInfo(){
            console.log(this.streamInfo)
            if (location.protocol === "https:") {
              this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]]
            }else {
@@ -452,9 +453,9 @@
            this.$refs[this.activePlayer].pause()
            that.$axios({
                method: 'post',
                url: '/api/gb_record/convert/' + that.streamId
                url: '/api/play/convert/' + that.streamId
                }).then(function (res) {
                    if (res.data.code == 0) {
                    if (res.data.code === 0) {
                        that.convertKey = res.data.key;
                        setTimeout(()=>{
                            that.isLoging = false;
web_src/src/components/dialog/onvifEdit.vue
@@ -90,7 +90,7 @@
        }
      }).then((res) => {
        console.log(res.data)
        if (res.data.code == 0) {
        if (res.data.code === 0) {
          if (res.data.data != null) {
            this.listChangeCallback(res.data.data)
          }else {
web_src/src/components/dialog/pushStreamEdit.vue
@@ -112,7 +112,7 @@
          url:`/api/push/save_to_gb`,
          data: this.proxyParam
        }).then( (res) => {
          if (res.data == "success") {
          if (res.data.code === 0) {
            this.$message({
              showClose: true,
              message: "保存成功",
web_src/src/components/dialog/recordDownload.vue
@@ -84,15 +84,16 @@
            method: 'get',
            url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}`
          }).then((res)=> {
              console.log(res)
              console.log(res.data.progress)
              this.streamInfo = res.data;
              if (parseFloat(res.data.progress) == 1) {
                this.percentage = 100;
              }else {
                this.percentage = (res.data.progress*100).toFixed(1);
              if (res.data.code === 0) {
                this.streamInfo = res.data.data;
                if (parseFloat(res.data.progress) == 1) {
                  this.percentage = 100;
                }else {
                  this.percentage = (res.data.progress*100).toFixed(1);
                }
                if (callback)callback();
              }
              if (callback)callback();
          }).catch((e) =>{
          });
@@ -140,7 +141,7 @@
              endTime: null,
            }
          }).then((res) =>{
            if (res.data.code === 0 && res.data.msg === "success") {
            if (res.data.code === 0 ) {
              // 查询进度
              this.title = "录像文件处理中..."
              this.taskId = res.data.data;
@@ -173,7 +174,7 @@
            }
          }).then((res) => {
            console.log(res)
            if (res.data.code == 0) {
            if (res.data.code === 0) {
                this.percentage = parseFloat(res.data.data.percentage)*100
                 if (res.data.data[0].percentage === '1') {
                   this.getProgressForFileRun = false;
web_src/src/components/live.vue
@@ -137,9 +137,6 @@
        method: 'get',
        url: '/api/play/start/' + deviceId + '/' + channelId
      }).then(function (res) {
        // that.isLoging = false;
        console.log('=====----=====')
        console.log(res)
        if (res.data.code === 0 && res.data.data) {
          itemData.playUrl = res.data.data.httpsFlv
          that.setPlayUrl(res.data.data.ws_flv, idxTmp)
web_src/src/components/map.vue
@@ -302,7 +302,6 @@
      }).then(function (res) {
        that.isLoging = false;
        if (res.data.code === 0) {
          that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
            streamInfo: res.data.data,
            hasAudio: channel.hasAudio
web_src/src/components/service/DeviceService.js
@@ -43,10 +43,10 @@
  getAllDeviceListIteration(deviceList, currentPage, count, callback, endCallback, errorCallback) {
    this.getDeviceList(currentPage, count, (data) => {
      if (data.list) {
        if (typeof (callback) == "function") callback(data.list)
        deviceList = deviceList.concat(data.list);
        if (deviceList.length < data.total) {
      if (data.code === 0 && data.data.list) {
        if (typeof (callback) == "function") callback(data.data.list)
        deviceList = deviceList.concat(data.data.list);
        if (deviceList.length < data.data.total) {
          currentPage ++
          this.getAllDeviceListIteration(deviceList, currentPage, count, callback,  endCallback, errorCallback)
        }else {
@@ -134,10 +134,6 @@
    }).catch(errorCallback);
  }
  getTree(deviceId, id, param3, param4) {
  }
  getTree(deviceId, parentId, onlyCatalog, callback, endCallback, errorCallback) {
    let currentPage = 1;
    let count = 100;
@@ -147,10 +143,10 @@
  getTreeIteration(deviceId, parentId, onlyCatalog, catalogList, currentPage, count, callback, endCallback, errorCallback) {
    this.getTreeInfo(deviceId, parentId, onlyCatalog, currentPage, count, (data) => {
      if (data.list) {
        if (typeof (callback) == "function") callback(data.list)
        catalogList = catalogList.concat(data.list);
        if (catalogList.length < data.total) {
      if (data.code === 0 && data.data.list) {
        if (typeof (callback) == "function") callback(data.data.list)
        catalogList = catalogList.concat(data.data.list);
        if (catalogList.length < data.data.total) {
          currentPage ++
          this.getTreeIteration(deviceId, parentId, onlyCatalog, catalogList, currentPage, count, callback, endCallback, errorCallback)
        }else {