Merge branch 'master' into 重构/1078
# Conflicts: # web/src/router/index.js # web/src/views/common/channelPlayer/chooseChannelForJt.vue # web/src/views/common/channelPlayer/jtDeviceEdit.vue # web/src/views/common/channelPlayer/jtDevicePlayer.vue # web_src/src/layout/UiHeader.vue # web_src/src/main.js # web_src/src/router/index.js
23
README.md
@ -27,12 +27,6 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网
|
||||
wvp使用文档 [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn)
|
||||
ZLM使用文档 [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
|
||||
|
||||
# 付费社群
|
||||
[](https://t.zsxq.com/0d8VAD3Dm)
|
||||
> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接自行推出,星球会直接退款给大家。
|
||||
|
||||
> 星球还提供了包括闭源的全功能试用包, 会随时更新。
|
||||
|
||||
# gitee仓库
|
||||
https://gitee.com/pan648540858/wvp-GB28181-pro.git
|
||||
|
||||
@ -133,6 +127,12 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
|
||||
- [X] 支持部标1078+808协议,支持点播,云台控制,录像回放,位置上报,自动点播等。
|
||||
- [X] 支持国标28181-2022协议,支持巡航轨迹查询,PTZ精准控制,存储卡格式化,设备软件升级,OSD配置,h265+aac,支持辅码流,录像倒放等。
|
||||
- [X] 支持国网B接口协议。支持注册,获取资源,预览, 云台控制,预置位控制等,可免费定制支持语音对讲、录像回放和抓拍图像。
|
||||
- [X] 功能加强版本
|
||||
- [X] 支持按权限分配可以使用的通道
|
||||
- [X] 支持电子地图。支持展示通道位置,支持在地图上修改通道位置。可扩展接入高德地图API,支持搜索位置,附近设备。
|
||||
- [X] 支持表格导出
|
||||
- [X] 拉流代理支持按照品牌拼接url。
|
||||
- [X] 功能持续扩展,可根据用户需要增加支持。
|
||||
|
||||
|
||||
# 授权协议
|
||||
@ -140,6 +140,17 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
|
||||
|
||||
# 技术支持
|
||||
|
||||
# 付费社群
|
||||
<img src="doc/_media/shequ.png" width="50%" height="50%">
|
||||
|
||||
> 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。
|
||||
> 加入三天内不满意可以直接自行推出,星球会直接退款给大家。需要发票可以在星球app中直接咨询星球客服获取。
|
||||
|
||||
> 星球还提供了包括闭源的全功能试用包, 会随时更新。
|
||||
|
||||
> 付费社群即可以对作者提供支持,也可以为大家更加快速的解决问题。如果暂时无法加入,给项目点个星也是极大的鼓励。
|
||||
|
||||
|
||||
[知识星球](https://t.zsxq.com/0d8VAD3Dm)专栏列表:,
|
||||
- [使用入门系列一:WVP-PRO能做什么](https://t.zsxq.com/0dLguVoSp)
|
||||
|
||||
|
||||
@ -39,9 +39,9 @@ public class SpringDocConfig {
|
||||
.info(new Info().title("WVP-PRO 接口文档")
|
||||
.contact(contact)
|
||||
.description("开箱即用的28181协议视频平台。 <br/>" +
|
||||
"1. 打开http://127.0.0.1:18080/doc.html#/1.%20全部/用户管理/login_1" +
|
||||
"1. 打开<a href='/doc.html#/1.%20全部/用户管理/login_1'>登录</a>接口" +
|
||||
" 登录成功后返回AccessToken。 <br/>" +
|
||||
"2. 填写到AccessToken到参数值 http://127.0.0.1:18080/doc.html#/Authorize/1.%20全部 <br/>" +
|
||||
"2. 填写到AccessToken到参数值 <a href='/doc.html#/Authorize/1.%20全部'>Token配置</a> <br/>" +
|
||||
"后续接口就可以直接测试了")
|
||||
.version("v3.1.0")
|
||||
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
|
||||
|
||||
@ -204,6 +204,9 @@ public class UserSetting {
|
||||
*/
|
||||
private boolean sipCacheServerConnections = true;
|
||||
|
||||
|
||||
/**
|
||||
* 禁用date头,变相禁用了校时
|
||||
*/
|
||||
private boolean disableDateHeader = false;
|
||||
|
||||
}
|
||||
|
||||
@ -21,6 +21,12 @@ public class DeviceChannel extends CommonGBChannel {
|
||||
@Schema(description = "数据库自增ID")
|
||||
private int id;
|
||||
|
||||
@Schema(description = "父设备编码")
|
||||
private String parentDeviceId;
|
||||
|
||||
@Schema(description = "父设备名称")
|
||||
private String parentName;
|
||||
|
||||
@MessageElementForCatalog("DeviceID")
|
||||
@Schema(description = "编码")
|
||||
private String deviceId;
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
package com.genersoft.iot.vmp.gb28181.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.dom4j.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MessageResponseTask<T> implements Delayed {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Element element;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private List<T> data;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String key;
|
||||
|
||||
|
||||
/**
|
||||
* 超时时间(单位: 毫秒)
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private long delayTime;
|
||||
|
||||
@Override
|
||||
public long getDelay(@NotNull TimeUnit unit) {
|
||||
return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Delayed o) {
|
||||
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
@ -148,6 +148,7 @@ public class AlarmController {
|
||||
@Parameter(name = "page",description = "当前页",required = true)
|
||||
@Parameter(name = "count",description = "每页查询数量",required = true)
|
||||
@Parameter(name = "deviceId",description = "设备id")
|
||||
@Parameter(name = "channelId",description = "通道id")
|
||||
@Parameter(name = "alarmPriority",description = "查询内容")
|
||||
@Parameter(name = "alarmMethod",description = "查询内容")
|
||||
@Parameter(name = "alarmType",description = "每页查询数量")
|
||||
@ -157,7 +158,8 @@ public class AlarmController {
|
||||
public PageInfo<DeviceAlarm> getAll(
|
||||
@RequestParam int page,
|
||||
@RequestParam int count,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
@RequestParam(required = false) String deviceId,
|
||||
@RequestParam(required = false) String channelId,
|
||||
@RequestParam(required = false) String alarmPriority,
|
||||
@RequestParam(required = false) String alarmMethod,
|
||||
@RequestParam(required = false) String alarmType,
|
||||
@ -186,7 +188,7 @@ public class AlarmController {
|
||||
throw new ControllerException(ErrorCode.ERROR400.getCode(), "endTime格式为" + DateUtil.PATTERN);
|
||||
}
|
||||
|
||||
return deviceAlarmService.getAllAlarm(page, count, deviceId, alarmPriority, alarmMethod,
|
||||
return deviceAlarmService.getAllAlarm(page, count, deviceId, channelId, alarmPriority, alarmMethod,
|
||||
alarmType, startTime, endTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,6 +113,19 @@ public class DeviceQuery {
|
||||
return deviceChannelService.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
|
||||
}
|
||||
|
||||
@GetMapping("/streams")
|
||||
@Operation(summary = "分页查询存在流的通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Parameter(name = "page", description = "当前页", required = true)
|
||||
@Parameter(name = "count", description = "每页查询数量", required = true)
|
||||
@Parameter(name = "query", description = "查询内容")
|
||||
public PageInfo<DeviceChannel> streamChannels(int page, int count,
|
||||
@RequestParam(required = false) String query) {
|
||||
if (ObjectUtils.isEmpty(query)) {
|
||||
query = null;
|
||||
}
|
||||
|
||||
return deviceChannelService.queryChannels(query, true, null, null, true, page, count);
|
||||
}
|
||||
|
||||
@Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
|
||||
|
||||
@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Group;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GroupTree;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IGroupService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@ -33,7 +34,7 @@ public class GroupController {
|
||||
groupService.add(group);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询分组")
|
||||
@Operation(summary = "查询分组节点")
|
||||
@Parameter(name = "query", description = "要搜索的内容", required = true)
|
||||
@Parameter(name = "parent", description = "所属分组编号", required = true)
|
||||
@ResponseBody
|
||||
@ -49,6 +50,17 @@ public class GroupController {
|
||||
return groupService.queryForTree(query, parent, hasChannel);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询分组")
|
||||
@Parameter(name = "query", description = "要搜索的内容", required = true)
|
||||
@Parameter(name = "channel", description = "true为查询通道,false为查询节点", required = true)
|
||||
@ResponseBody
|
||||
@GetMapping("/tree/query")
|
||||
public PageInfo<Group> queryTree(Integer page, Integer count,
|
||||
@RequestParam(required = true) String query
|
||||
){
|
||||
return groupService.queryList(page, count, query);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新分组")
|
||||
@Parameter(name = "group", description = "Group", required = true)
|
||||
@ResponseBody
|
||||
|
||||
@ -7,19 +7,26 @@ import com.genersoft.iot.vmp.conf.security.SecurityUtils;
|
||||
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
@Tag(name = "媒体流相关")
|
||||
@ -52,11 +59,12 @@ public class MediaController {
|
||||
@Parameter(name = "useSourceIpAsStreamIp", description = "是否使用请求IP作为返回的地址IP")
|
||||
@GetMapping(value = "/stream_info_by_app_and_stream")
|
||||
@ResponseBody
|
||||
public StreamContent getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
|
||||
@RequestParam String stream,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) Boolean useSourceIpAsStreamIp){
|
||||
public DeferredResult<WVPResult<StreamContent>> getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
|
||||
@RequestParam String stream,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) Boolean useSourceIpAsStreamIp){
|
||||
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>();
|
||||
boolean authority = false;
|
||||
if (callId != null) {
|
||||
// 权限校验
|
||||
@ -75,9 +83,7 @@ public class MediaController {
|
||||
authority = true;
|
||||
}
|
||||
}
|
||||
|
||||
StreamInfo streamInfo;
|
||||
|
||||
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
|
||||
String host = request.getHeader("Host");
|
||||
String localAddr = host.split(":")[0];
|
||||
@ -88,30 +94,37 @@ public class MediaController {
|
||||
}
|
||||
|
||||
if (streamInfo != null){
|
||||
return new StreamContent(streamInfo);
|
||||
WVPResult<StreamContent> wvpResult = WVPResult.success();
|
||||
wvpResult.setData(new StreamContent(streamInfo));
|
||||
result.setResult(wvpResult);
|
||||
}else {
|
||||
ErrorCallback<StreamInfo> callback = (code, msg, streamInfoStoStart) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
WVPResult<StreamContent> wvpResult = WVPResult.success();
|
||||
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
|
||||
String host;
|
||||
try {
|
||||
URL url=new URL(request.getRequestURL().toString());
|
||||
host=url.getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host=request.getLocalAddr();
|
||||
}
|
||||
streamInfoStoStart.changeStreamIp(host);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(streamInfoStoStart.getMediaServer().getTranscodeSuffix())
|
||||
&& !"null".equalsIgnoreCase(streamInfoStoStart.getMediaServer().getTranscodeSuffix())) {
|
||||
streamInfoStoStart.setStream(streamInfoStoStart.getStream() + "_" + streamInfoStoStart.getMediaServer().getTranscodeSuffix());
|
||||
}
|
||||
wvpResult.setData(new StreamContent(streamInfoStoStart));
|
||||
result.setResult(wvpResult);
|
||||
}else {
|
||||
result.setResult(WVPResult.fail(code, msg));
|
||||
}
|
||||
};
|
||||
//获取流失败,重启拉流后重试一次
|
||||
streamProxyService.stopByAppAndStream(app,stream);
|
||||
boolean start = streamProxyService.startByAppAndStream(app, stream);
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("[线程休眠失败], {}", e.getMessage());
|
||||
}
|
||||
if (useSourceIpAsStreamIp != null && useSourceIpAsStreamIp) {
|
||||
String host = request.getHeader("Host");
|
||||
String localAddr = host.split(":")[0];
|
||||
log.info("使用{}作为返回流的ip", localAddr);
|
||||
streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, localAddr, authority);
|
||||
}else {
|
||||
streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
|
||||
}
|
||||
if (streamInfo != null){
|
||||
return new StreamContent(streamInfo);
|
||||
}else {
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
streamProxyService.startByAppAndStream(app, stream, callback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 获取推流播放地址
|
||||
|
||||
@ -50,20 +50,29 @@ public class RegionController {
|
||||
return regionService.query(query, page, count);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询区域")
|
||||
@Operation(summary = "查询区域节点")
|
||||
@Parameter(name = "query", description = "要搜索的内容", required = true)
|
||||
@Parameter(name = "parent", description = "所属行政区划编号", required = true)
|
||||
@Parameter(name = "hasChannel", description = "是否查询通道", required = true)
|
||||
@ResponseBody
|
||||
@GetMapping("/tree/list")
|
||||
public List<RegionTree> queryForTree(
|
||||
@RequestParam(required = false) String query,
|
||||
@RequestParam(required = false) Integer parent,
|
||||
@RequestParam(required = false) Boolean hasChannel
|
||||
){
|
||||
if (ObjectUtils.isEmpty(query)) {
|
||||
query = null;
|
||||
}
|
||||
return regionService.queryForTree(query, parent, hasChannel);
|
||||
return regionService.queryForTree(parent, hasChannel);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "查询区域")
|
||||
@Parameter(name = "query", description = "要搜索的内容", required = true)
|
||||
@Parameter(name = "channel", description = "true为查询通道,false为查询节点", required = true)
|
||||
@ResponseBody
|
||||
@GetMapping("/tree/query")
|
||||
public PageInfo<Region> queryTree(Integer page, Integer count,
|
||||
@RequestParam(required = true) String query
|
||||
){
|
||||
return regionService.queryList(page, count, query);
|
||||
}
|
||||
|
||||
@Operation(summary = "更新区域")
|
||||
|
||||
@ -275,10 +275,8 @@ public interface CommonGBChannelMapper {
|
||||
" true as is_leaf " +
|
||||
" from wvp_device_channel " +
|
||||
" where coalesce(gb_civil_code, civil_code) = #{parentDeviceId} " +
|
||||
" <if test='query != null'> AND (coalesce(gb_device_id, device_id) LIKE concat('%',#{query},'%') " +
|
||||
" OR coalesce(gb_name, name) LIKE concat('%',#{query},'%'))</if> " +
|
||||
" </script>")
|
||||
List<RegionTree> queryForRegionTreeByCivilCode(@Param("query") String query, @Param("parentDeviceId") String parentDeviceId);
|
||||
List<RegionTree> queryForRegionTreeByCivilCode(@Param("parentDeviceId") String parentDeviceId);
|
||||
|
||||
@Update(value = {" <script>" +
|
||||
" UPDATE wvp_device_channel " +
|
||||
|
||||
@ -26,6 +26,7 @@ public interface DeviceAlarmMapper {
|
||||
" SELECT * FROM wvp_device_alarm " +
|
||||
" WHERE 1=1 " +
|
||||
" <if test=\"deviceId != null\" > AND device_id = #{deviceId}</if>" +
|
||||
" <if test=\"channelId != null\" > AND channel_id = #{channelId}</if>" +
|
||||
" <if test=\"alarmPriority != null\" > AND alarm_priority = #{alarmPriority} </if>" +
|
||||
" <if test=\"alarmMethod != null\" > AND alarm_method = #{alarmMethod} </if>" +
|
||||
" <if test=\"alarmType != null\" > AND alarm_type = #{alarmType} </if>" +
|
||||
@ -33,7 +34,7 @@ public interface DeviceAlarmMapper {
|
||||
" <if test=\"endTime != null\" > AND alarm_time <= #{endTime} </if>" +
|
||||
" ORDER BY alarm_time ASC " +
|
||||
" </script>"})
|
||||
List<DeviceAlarm> query(@Param("deviceId") String deviceId, @Param("alarmPriority") String alarmPriority, @Param("alarmMethod") String alarmMethod,
|
||||
List<DeviceAlarm> query(@Param("deviceId") String deviceId, @Param("channelId") String channelId, @Param("alarmPriority") String alarmPriority, @Param("alarmMethod") String alarmMethod,
|
||||
@Param("alarmType") String alarmType, @Param("startTime") String startTime, @Param("endTime") String endTime);
|
||||
|
||||
|
||||
|
||||
@ -86,10 +86,11 @@ public interface DeviceChannelMapper {
|
||||
int update(DeviceChannel channel);
|
||||
|
||||
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannels")
|
||||
List<DeviceChannel> queryChannels(@Param("dataDeviceId") int dataDeviceId, @Param("civilCode") String civilCode,
|
||||
List<DeviceChannel> queryChannels(@Param("dataDeviceId") Integer dataDeviceId, @Param("civilCode") String civilCode,
|
||||
@Param("businessGroupId") String businessGroupId, @Param("parentChannelId") String parentChannelId,
|
||||
@Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel,
|
||||
@Param("online") Boolean online, @Param("channelIds") List<String> channelIds);
|
||||
@Param("query") String query, @Param("queryParent") Boolean queryParent,
|
||||
@Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online,
|
||||
@Param("channelIds") List<String> channelIds, @Param("hasStream") Boolean hasStream);
|
||||
|
||||
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannelsByDeviceDbId")
|
||||
List<DeviceChannel> queryChannelsByDeviceDbId(@Param("dataDeviceId") int dataDeviceId);
|
||||
|
||||
@ -346,38 +346,41 @@ public interface DeviceMapper {
|
||||
|
||||
@Select(" <script>" +
|
||||
"SELECT " +
|
||||
"id, " +
|
||||
"device_id, " +
|
||||
"coalesce(custom_name, name) as name, " +
|
||||
"password, " +
|
||||
"manufacturer, " +
|
||||
"model, " +
|
||||
"firmware, " +
|
||||
"transport," +
|
||||
"stream_mode," +
|
||||
"ip,"+
|
||||
"sdp_ip,"+
|
||||
"local_ip,"+
|
||||
"port,"+
|
||||
"host_address,"+
|
||||
"expires,"+
|
||||
"register_time,"+
|
||||
"keepalive_time,"+
|
||||
"create_time,"+
|
||||
"update_time,"+
|
||||
"charset,"+
|
||||
"subscribe_cycle_for_catalog,"+
|
||||
"subscribe_cycle_for_mobile_position,"+
|
||||
"mobile_position_submission_interval,"+
|
||||
"subscribe_cycle_for_alarm,"+
|
||||
"ssrc_check,"+
|
||||
"as_message_channel,"+
|
||||
"broadcast_push_after_ack,"+
|
||||
"geo_coord_sys,"+
|
||||
"on_line,"+
|
||||
"media_server_id,"+
|
||||
"server_id,"+
|
||||
"(SELECT count(0) FROM wvp_device_channel dc WHERE dc.data_type = #{dataType} and dc.data_device_id= de.id) as channel_count " +
|
||||
"id" +
|
||||
",device_id" +
|
||||
",manufacturer" +
|
||||
",model" +
|
||||
",firmware" +
|
||||
",transport" +
|
||||
",stream_mode" +
|
||||
",on_line" +
|
||||
",register_time" +
|
||||
",keepalive_time" +
|
||||
",ip" +
|
||||
",create_time" +
|
||||
",update_time" +
|
||||
",port" +
|
||||
",expires" +
|
||||
",subscribe_cycle_for_catalog" +
|
||||
",subscribe_cycle_for_mobile_position" +
|
||||
",mobile_position_submission_interval" +
|
||||
",subscribe_cycle_for_alarm" +
|
||||
",host_address" +
|
||||
",charset" +
|
||||
",ssrc_check" +
|
||||
",geo_coord_sys" +
|
||||
",media_server_id" +
|
||||
",sdp_ip" +
|
||||
",local_ip" +
|
||||
",password" +
|
||||
",as_message_channel" +
|
||||
",heart_beat_interval" +
|
||||
",heart_beat_count" +
|
||||
",position_capability" +
|
||||
",broadcast_push_after_ack" +
|
||||
",server_id" +
|
||||
",(SELECT count(0) FROM wvp_device_channel dc WHERE dc.data_type = #{dataType} and dc.data_device_id= de.id) as channel_count " +
|
||||
" FROM wvp_device de" +
|
||||
" where 1 = 1 "+
|
||||
" <if test='status != null'> AND de.on_line=${status}</if>"+
|
||||
@ -423,4 +426,36 @@ public interface DeviceMapper {
|
||||
"<foreach collection='offlineDevices' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
|
||||
" </script>"})
|
||||
void offlineByList(List<Device> offlineDevices);
|
||||
|
||||
|
||||
@Update({"<script>" +
|
||||
"<foreach collection='devices' item='item' separator=';'>" +
|
||||
" UPDATE" +
|
||||
" wvp_device" +
|
||||
" SET update_time=#{item.updateTime}" +
|
||||
", name=#{item.name}" +
|
||||
", manufacturer=#{item.manufacturer}" +
|
||||
", model=#{item.model}" +
|
||||
", firmware=#{item.firmware}" +
|
||||
", transport=#{item.transport}" +
|
||||
", ip=#{item.ip}" +
|
||||
", local_ip=#{item.localIp}" +
|
||||
", port=#{item.port}" +
|
||||
", host_address=#{item.hostAddress}" +
|
||||
", on_line=#{item.onLine}" +
|
||||
", register_time=#{item.registerTime}" +
|
||||
", keepalive_time=#{item.keepaliveTime}" +
|
||||
", heart_beat_interval=#{item.heartBeatInterval}" +
|
||||
", position_capability=#{item.positionCapability}" +
|
||||
", heart_beat_count=#{item.heartBeatCount}" +
|
||||
", subscribe_cycle_for_catalog=#{item.subscribeCycleForCatalog}" +
|
||||
", subscribe_cycle_for_mobile_position=#{item.subscribeCycleForMobilePosition}" +
|
||||
", mobile_position_submission_interval=#{item.mobilePositionSubmissionInterval}" +
|
||||
", subscribe_cycle_for_alarm=#{item.subscribeCycleForAlarm}" +
|
||||
", expires=#{item.expires}" +
|
||||
", server_id=#{item.serverId}" +
|
||||
" WHERE device_id=#{item.deviceId}"+
|
||||
"</foreach>" +
|
||||
"</script>"})
|
||||
void batchUpdate(List<Device> devices);
|
||||
}
|
||||
|
||||
@ -80,9 +80,8 @@ public interface RegionMapper {
|
||||
" where " +
|
||||
" <if test='parentId != null'> parent_id = #{parentId} </if> " +
|
||||
" <if test='parentId == null'> parent_id is null </if> " +
|
||||
" <if test='query != null'> AND (device_id LIKE concat('%',#{query},'%') escape '/' OR name LIKE concat('%',#{query},'%') escape '/')</if> " +
|
||||
" </script>")
|
||||
List<RegionTree> queryForTree(@Param("query") String query, @Param("parentId") Integer parentId);
|
||||
List<RegionTree> queryForTree(@Param("parentId") Integer parentId);
|
||||
|
||||
@Delete("<script>" +
|
||||
" DELETE FROM wvp_common_region WHERE id in " +
|
||||
|
||||
@ -20,6 +20,8 @@ public class DeviceChannelProvider {
|
||||
" dc.gps_time,\n" +
|
||||
" dc.stream_identification,\n" +
|
||||
" dc.channel_type,\n" +
|
||||
" d.device_id as parent_device_id,\n" +
|
||||
" coalesce(d.custom_name, d.name) as parent_name,\n" +
|
||||
" coalesce(dc.gb_device_id, dc.device_id) as device_id,\n" +
|
||||
" coalesce(dc.gb_name, dc.name) as name,\n" +
|
||||
" coalesce(dc.gb_manufacturer, dc.manufacturer) as manufacturer,\n" +
|
||||
@ -55,13 +57,17 @@ public class DeviceChannelProvider {
|
||||
" coalesce(dc.gb_svc_space_support_mod, dc.svc_space_support_mod) as svc_space_support_mod,\n" +
|
||||
" coalesce(dc.gb_svc_time_support_mode,dc.svc_time_support_mode) as svc_time_support_mode\n" +
|
||||
" from " +
|
||||
" wvp_device_channel dc "
|
||||
" wvp_device_channel dc " +
|
||||
" left join wvp_device d on d.id = dc.data_device_id "
|
||||
;
|
||||
}
|
||||
public String queryChannels(Map<String, Object> params ){
|
||||
StringBuilder sqlBuild = new StringBuilder();
|
||||
sqlBuild.append(getBaseSelectSql());
|
||||
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId} ");
|
||||
sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value);
|
||||
if (params.get("dataDeviceId") != null) {
|
||||
sqlBuild.append(" AND dc.data_device_id = #{dataDeviceId} ");
|
||||
}
|
||||
if (params.get("businessGroupId") != null ) {
|
||||
sqlBuild.append(" AND coalesce(dc.gb_business_group_id, dc.business_group_id)=#{businessGroupId} AND coalesce(dc.gb_parent_id, dc.parent_id) is null");
|
||||
}else if (params.get("parentChannelId") != null ) {
|
||||
@ -73,8 +79,15 @@ public class DeviceChannelProvider {
|
||||
}
|
||||
if (params.get("query") != null && !ObjectUtils.isEmpty(params.get("query"))) {
|
||||
sqlBuild.append(" AND (coalesce(dc.gb_device_id, dc.device_id) LIKE concat('%',#{query},'%') escape '/'" +
|
||||
" OR coalesce(dc.gb_name, dc.name) LIKE concat('%',#{query},'%') escape '/')")
|
||||
;
|
||||
" OR coalesce(dc.gb_name, dc.name) LIKE concat('%',#{query},'%') escape '/'");
|
||||
if (params.get("queryParent") != null && (Boolean) params.get("queryParent")) {
|
||||
sqlBuild.append(" OR d.device_id LIKE concat('%',#{query},'%') escape '/'");
|
||||
sqlBuild.append(" OR coalesce(d.custom_name, d.name) LIKE concat('%',#{query},'%') escape '/'");
|
||||
}
|
||||
sqlBuild.append(")");
|
||||
}
|
||||
if (params.get("hasStream") != null && (Boolean) params.get("hasStream")) {
|
||||
sqlBuild.append(" AND dc.stream_id IS NOT NULL");
|
||||
}
|
||||
if (params.get("online") != null && (Boolean)params.get("online")) {
|
||||
sqlBuild.append(" AND coalesce(gb_status, status) = 'ON'");
|
||||
@ -101,7 +114,7 @@ public class DeviceChannelProvider {
|
||||
}
|
||||
sqlBuild.append(" )");
|
||||
}
|
||||
sqlBuild.append(" ORDER BY device_id");
|
||||
sqlBuild.append(" ORDER BY d.device_id, dc.device_id");
|
||||
return sqlBuild.toString();
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ public interface IDeviceAlarmService {
|
||||
* @param endTime 结束时间
|
||||
* @return 报警列表
|
||||
*/
|
||||
PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String alarmPriority, String alarmMethod,
|
||||
PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String channelId, String alarmPriority, String alarmMethod,
|
||||
String alarmType, String startTime, String endTime);
|
||||
|
||||
/**
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
package com.genersoft.iot.vmp.gb28181.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.common.enums.DeviceControlType;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||
@ -104,6 +101,7 @@ public interface IDeviceChannelService {
|
||||
|
||||
PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean channelType, Boolean online, int page, int count);
|
||||
|
||||
PageInfo<DeviceChannel> queryChannels(String query, Boolean queryParent, Boolean channelType, Boolean online, Boolean hasStream, int page, int count);
|
||||
|
||||
List<Device> queryDeviceWithAsMessageChannel();
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -117,6 +118,9 @@ public interface IDeviceService {
|
||||
*/
|
||||
void updateDevice(Device device);
|
||||
|
||||
@Transactional
|
||||
void updateDeviceList(List<Device> deviceList);
|
||||
|
||||
/**
|
||||
* 检查设备编号是否已经存在
|
||||
* @param deviceId 设备编号
|
||||
|
||||
@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Group;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GroupTree;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -23,4 +24,6 @@ public interface IGroupService {
|
||||
boolean batchAdd(List<Group> groupList);
|
||||
|
||||
List<Group> getPath(String deviceId, String businessGroup);
|
||||
|
||||
PageInfo<Group> queryList(Integer page, Integer count, String query);
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ public interface IRegionService {
|
||||
|
||||
Region queryRegionByDeviceId(String regionDeviceId);
|
||||
|
||||
List<RegionTree> queryForTree(String query, Integer parent, Boolean hasChannel);
|
||||
List<RegionTree> queryForTree(Integer parent, Boolean hasChannel);
|
||||
|
||||
void syncFromChannel();
|
||||
|
||||
@ -40,4 +40,6 @@ public interface IRegionService {
|
||||
String getDescription(String civilCode);
|
||||
|
||||
void addByCivilCode(String civilCode);
|
||||
|
||||
PageInfo<Region> queryList(int page, int count, String query);
|
||||
}
|
||||
|
||||
@ -17,9 +17,9 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
|
||||
private DeviceAlarmMapper deviceAlarmMapper;
|
||||
|
||||
@Override
|
||||
public PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String alarmPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
|
||||
public PageInfo<DeviceAlarm> getAllAlarm(int page, int count, String deviceId, String channelId, String alarmPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
|
||||
PageHelper.startPage(page, count);
|
||||
List<DeviceAlarm> all = deviceAlarmMapper.query(deviceId, alarmPriority, alarmMethod, alarmType, startTime, endTime);
|
||||
List<DeviceAlarm> all = deviceAlarmMapper.query(deviceId, channelId, alarmPriority, alarmMethod, alarmType, startTime, endTime);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
|
||||
@ -696,7 +696,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
|
||||
.replaceAll("%", "/%")
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
List<DeviceChannel> all = channelMapper.queryChannels(deviceDbId, civilCode, businessGroupId, parentId, query, channelType, online,null);
|
||||
List<DeviceChannel> all = channelMapper.queryChannels(deviceDbId, civilCode, businessGroupId, parentId, query, false, channelType, online, null, null);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@ -717,7 +717,19 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
PageHelper.startPage(page, count);
|
||||
List<DeviceChannel> all = channelMapper.queryChannels(device.getId(), null,null, null, query, hasSubChannel, online,null);
|
||||
List<DeviceChannel> all = channelMapper.queryChannels(device.getId(), null, null, null, query, false, hasSubChannel, online, null, null);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<DeviceChannel> queryChannels(String query, Boolean queryParent, Boolean hasSubChannel, Boolean online, Boolean hasStream, int page, int count) {
|
||||
PageHelper.startPage(page, count);
|
||||
if (query != null) {
|
||||
query = query.replaceAll("/", "//")
|
||||
.replaceAll("%", "/%")
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
List<DeviceChannel> all = channelMapper.queryChannels(null, null, null, null, query, queryParent, hasSubChannel, online, null, hasStream);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
|
||||
@ -506,7 +506,11 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
if (device == null || device.getSubscribeCycleForCatalog() < 0) {
|
||||
return false;
|
||||
}
|
||||
log.info("[添加目录订阅] 设备 {}", device.getDeviceId());
|
||||
if (transactionInfo == null) {
|
||||
log.info("[添加目录订阅] 设备 {}", device.getDeviceId());
|
||||
}else {
|
||||
log.info("[目录订阅续期] 设备 {}", device.getDeviceId());
|
||||
}
|
||||
try {
|
||||
sipCommander.catalogSubscribe(device, transactionInfo, eventResult -> {
|
||||
ResponseEvent event = (ResponseEvent) eventResult.event;
|
||||
@ -514,8 +518,8 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
log.info("[目录订阅]成功: {}", device.getDeviceId());
|
||||
if (!subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) {
|
||||
SIPResponse response = (SIPResponse) event.getResponse();
|
||||
SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse);
|
||||
SipTransactionInfo transactionInfoForResponse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResponse);
|
||||
if (subscribeTask != null) {
|
||||
subscribeTaskRunner.addSubscribe(subscribeTask);
|
||||
}
|
||||
@ -566,7 +570,11 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public boolean addMobilePositionSubscribe(@NotNull Device device, SipTransactionInfo transactionInfo) {
|
||||
log.info("[添加移动位置订阅] 设备 {}", device.getDeviceId());
|
||||
if (transactionInfo == null) {
|
||||
log.info("[添加移动位置订阅] 设备 {}", device.getDeviceId());
|
||||
}else {
|
||||
log.info("[移动位置订阅续期] 设备 {}", device.getDeviceId());
|
||||
}
|
||||
try {
|
||||
sipCommander.mobilePositionSubscribe(device, transactionInfo, eventResult -> {
|
||||
ResponseEvent event = (ResponseEvent) eventResult.event;
|
||||
@ -574,13 +582,13 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
log.info("[移动位置订阅]成功: {}", device.getDeviceId());
|
||||
if (!subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) {
|
||||
SIPResponse response = (SIPResponse) event.getResponse();
|
||||
SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse);
|
||||
SipTransactionInfo transactionInfoForResponse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::mobilPositionSubscribeExpire, transactionInfoForResponse);
|
||||
if (subscribeTask != null) {
|
||||
subscribeTaskRunner.addSubscribe(subscribeTask);
|
||||
}
|
||||
}else {
|
||||
subscribeTaskRunner.updateDelay(SubscribeTaskForMobilPosition.getKey(device), (device.getSubscribeCycleForCatalog() * 1000L - 500L) + System.currentTimeMillis());
|
||||
subscribeTaskRunner.updateDelay(SubscribeTaskForMobilPosition.getKey(device), (device.getSubscribeCycleForMobilePosition() * 1000L - 500L) + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
},eventResult -> {
|
||||
@ -721,8 +729,6 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
@Override
|
||||
public void updateDevice(Device device) {
|
||||
|
||||
String now = DateUtil.getNow();
|
||||
device.setUpdateTime(now);
|
||||
device.setCharset(device.getCharset() == null ? "" : device.getCharset().toUpperCase());
|
||||
device.setUpdateTime(DateUtil.getNow());
|
||||
if (deviceMapper.update(device) > 0) {
|
||||
@ -730,6 +736,40 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void updateDeviceList(List<Device> deviceList) {
|
||||
if (deviceList.isEmpty()){
|
||||
log.info("[批量更新设备] 列表为空,更细失败");
|
||||
return;
|
||||
}
|
||||
if (deviceList.size() == 1) {
|
||||
updateDevice(deviceList.get(0));
|
||||
}else {
|
||||
for (Device device : deviceList) {
|
||||
device.setCharset(device.getCharset() == null ? "" : device.getCharset().toUpperCase());
|
||||
device.setUpdateTime(DateUtil.getNow());
|
||||
}
|
||||
int limitCount = 300;
|
||||
if (!deviceList.isEmpty()) {
|
||||
if (deviceList.size() > limitCount) {
|
||||
for (int i = 0; i < deviceList.size(); i += limitCount) {
|
||||
int toIndex = i + limitCount;
|
||||
if (i + limitCount > deviceList.size()) {
|
||||
toIndex = deviceList.size();
|
||||
}
|
||||
deviceMapper.batchUpdate(deviceList.subList(i, toIndex));
|
||||
}
|
||||
}else {
|
||||
deviceMapper.batchUpdate(deviceList);
|
||||
}
|
||||
for (Device device : deviceList) {
|
||||
redisCatchStorage.updateDevice(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExist(String deviceId) {
|
||||
return getDeviceByDeviceIdFromDb(deviceId) != null;
|
||||
@ -866,7 +906,16 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
public void subscribeMobilePosition(int id, int cycle, int interval) {
|
||||
Device device = deviceMapper.query(id);
|
||||
Assert.notNull(device, "未找到设备");
|
||||
Assert.isTrue(device.isOnLine(), "设备已离线");
|
||||
if (!device.isOnLine()) {
|
||||
// 开启订阅
|
||||
device.setSubscribeCycleForMobilePosition(cycle);
|
||||
device.setMobilePositionSubmissionInterval(interval);
|
||||
updateDevice(device);
|
||||
if (subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) {
|
||||
subscribeTaskRunner.removeSubscribe(SubscribeTaskForMobilPosition.getKey(device));
|
||||
}
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备已离线");
|
||||
}
|
||||
|
||||
if (device.getSubscribeCycleForMobilePosition() == cycle) {
|
||||
return;
|
||||
@ -882,6 +931,7 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
// 开启订阅
|
||||
device.setSubscribeCycleForMobilePosition(cycle);
|
||||
device.setMobilePositionSubmissionInterval(interval);
|
||||
updateDevice(device);
|
||||
if (cycle > 0) {
|
||||
addMobilePositionSubscribe(device, null);
|
||||
}
|
||||
|
||||
@ -118,6 +118,7 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
|
||||
|
||||
@Override
|
||||
public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback) {
|
||||
log.info("[通用通道] 播放, 类型: {}, 编号:{}", channel.getDataType(), channel.getGbDeviceId());
|
||||
if (channel.getDataType() == ChannelDataType.GB28181.value) {
|
||||
// 国标通道
|
||||
playGbDeviceChannel(channel, record, callback);
|
||||
|
||||
@ -10,6 +10,8 @@ import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IGroupService;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -293,4 +295,16 @@ public class GroupServiceImpl implements IGroupService {
|
||||
allParent.add(parent);
|
||||
return allParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<Group> queryList(Integer page, Integer count, String query) {
|
||||
PageHelper.startPage(page, count);
|
||||
if (query != null) {
|
||||
query = query.replaceAll("/", "//")
|
||||
.replaceAll("%", "/%")
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
List<Group> all = groupManager.query(query, null, null);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,17 +144,12 @@ public class RegionServiceImpl implements IRegionService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RegionTree> queryForTree(String query, Integer parent, Boolean hasChannel) {
|
||||
if (query != null) {
|
||||
query = query.replaceAll("/", "//")
|
||||
.replaceAll("%", "/%")
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
List<RegionTree> regionList = regionMapper.queryForTree(query, parent);
|
||||
public List<RegionTree> queryForTree(Integer parent, Boolean hasChannel) {
|
||||
List<RegionTree> regionList = regionMapper.queryForTree(parent);
|
||||
if (parent != null && hasChannel != null && hasChannel) {
|
||||
Region parentRegion = regionMapper.queryOne(parent);
|
||||
if (parentRegion != null) {
|
||||
List<RegionTree> channelList = commonGBChannelMapper.queryForRegionTreeByCivilCode(query, parentRegion.getDeviceId());
|
||||
List<RegionTree> channelList = commonGBChannelMapper.queryForRegionTreeByCivilCode(parentRegion.getDeviceId());
|
||||
regionList.addAll(channelList);
|
||||
}
|
||||
}
|
||||
@ -324,4 +319,16 @@ public class RegionServiceImpl implements IRegionService {
|
||||
parentId = region.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<Region> queryList(int page, int count, String query) {
|
||||
PageHelper.startPage(page, count);
|
||||
if (query != null) {
|
||||
query = query.replaceAll("/", "//")
|
||||
.replaceAll("%", "/%")
|
||||
.replaceAll("_", "/_");
|
||||
}
|
||||
List<Region> all = regionMapper.query(query, null);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,14 +94,7 @@ public class DeviceStatusTaskRunner {
|
||||
return false;
|
||||
}
|
||||
log.debug("[更新状态任务时间] 编号: {}", key);
|
||||
if (delayQueue.contains(task)) {
|
||||
boolean remove = delayQueue.remove(task);
|
||||
if (!remove) {
|
||||
log.info("[更新状态任务时间] 从延时队列内移除失败: {}", key);
|
||||
}
|
||||
}
|
||||
task.setDelayTime(expirationTime);
|
||||
delayQueue.offer(task);
|
||||
String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getDeviceId());
|
||||
Duration duration = Duration.ofSeconds((expirationTime - System.currentTimeMillis())/1000);
|
||||
redisTemplate.expire(redisKey, duration);
|
||||
|
||||
@ -94,14 +94,7 @@ public class SubscribeTaskRunner{
|
||||
return false;
|
||||
}
|
||||
log.info("[更新订阅任务时间] {}, 编号: {}", task.getName(), key);
|
||||
if (delayQueue.contains(task)) {
|
||||
boolean remove = delayQueue.remove(task);
|
||||
if (!remove) {
|
||||
log.info("[更新订阅任务时间] 从延时队列内移除失败: {}", key);
|
||||
}
|
||||
}
|
||||
task.setDelayTime(expirationTime);
|
||||
delayQueue.offer(task);
|
||||
String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), task.getKey());
|
||||
Duration duration = Duration.ofSeconds((expirationTime - System.currentTimeMillis())/1000);
|
||||
redisTemplate.expire(redisKey, duration);
|
||||
|
||||
@ -12,7 +12,7 @@ public class SubscribeTaskForMobilPosition extends SubscribeTask {
|
||||
public static final String name = "mobilPosition";
|
||||
|
||||
public static SubscribeTask getInstance(Device device, SubscribeCallback callback, SipTransactionInfo transactionInfo) {
|
||||
if (device.getSubscribeCycleForCatalog() <= 0) {
|
||||
if (device.getSubscribeCycleForMobilePosition() <= 0) {
|
||||
return null;
|
||||
}
|
||||
SubscribeTaskForMobilPosition subscribeTaskForMobilPosition = new SubscribeTaskForMobilPosition();
|
||||
|
||||
@ -114,14 +114,7 @@ public class PlatformStatusTaskRunner {
|
||||
return false;
|
||||
}
|
||||
log.info("[更新平台注册任务时间] 平台上级编号: {}", platformServerId);
|
||||
if (registerDelayQueue.contains(task)) {
|
||||
boolean remove = registerDelayQueue.remove(task);
|
||||
if (!remove) {
|
||||
log.info("[更新平台注册任务时间] 从延时队列内移除失败: {}", platformServerId);
|
||||
}
|
||||
}
|
||||
task.setDelayTime(expirationTime);
|
||||
registerDelayQueue.offer(task);
|
||||
String redisKey = String.format("%s_%s_%s", prefix, userSetting.getServerId(), platformServerId);
|
||||
Duration duration = Duration.ofSeconds((expirationTime - System.currentTimeMillis())/1000);
|
||||
redisTemplate.expire(redisKey, duration);
|
||||
@ -165,14 +158,7 @@ public class PlatformStatusTaskRunner {
|
||||
return false;
|
||||
}
|
||||
log.info("[更新平台心跳任务时间] 平台上级编号: {}", platformServerId);
|
||||
if (keepaliveTaskDelayQueue.contains(task)) {
|
||||
boolean remove = keepaliveTaskDelayQueue.remove(task);
|
||||
if (!remove) {
|
||||
log.info("[更新平台心跳任务时间] 从延时队列内移除失败: {}", platformServerId);
|
||||
}
|
||||
}
|
||||
task.setDelayTime(expirationTime);
|
||||
keepaliveTaskDelayQueue.offer(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1136,9 +1136,9 @@ public class SIPCommander implements ISIPCommander {
|
||||
}
|
||||
cmdXml.append("</Query>\r\n");
|
||||
|
||||
MessageEvent<Object> messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback);
|
||||
MessageEvent<Object> messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 4000L, callback);
|
||||
messageSubscribe.addSubscribe(messageEvent);
|
||||
|
||||
log.info("[预置位查询] 设备编号: {}, 通道编号: {}, SN: {}", device.getDeviceId(), channelId, sn);
|
||||
Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
|
||||
sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> {
|
||||
messageSubscribe.removeSubscribe(messageEvent.getKey());
|
||||
|
||||
@ -144,12 +144,15 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
|
||||
|
||||
// 携带授权头并且密码正确
|
||||
response = getMessageFactory().createResponse(Response.OK, request);
|
||||
// 添加date头
|
||||
SIPDateHeader dateHeader = new SIPDateHeader();
|
||||
// 使用自己修改的
|
||||
GbSipDate gbSipDate = new GbSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
|
||||
dateHeader.setDate(gbSipDate);
|
||||
response.addHeader(dateHeader);
|
||||
// 如果主动禁用了Date头,则不添加
|
||||
if (!userSetting.isDisableDateHeader()) {
|
||||
// 添加date头
|
||||
SIPDateHeader dateHeader = new SIPDateHeader();
|
||||
// 使用自己修改的
|
||||
GbSipDate gbSipDate = new GbSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
|
||||
dateHeader.setDate(gbSipDate);
|
||||
response.addHeader(dateHeader);
|
||||
}
|
||||
|
||||
if (request.getExpires() == null) {
|
||||
response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
|
||||
@ -218,12 +221,15 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
|
||||
private Response getRegisterOkResponse(Request request) throws ParseException {
|
||||
// 携带授权头并且密码正确
|
||||
Response response = getMessageFactory().createResponse(Response.OK, request);
|
||||
// 添加date头
|
||||
SIPDateHeader dateHeader = new SIPDateHeader();
|
||||
// 使用自己修改的
|
||||
GbSipDate gbSipDate = new GbSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
|
||||
dateHeader.setDate(gbSipDate);
|
||||
response.addHeader(dateHeader);
|
||||
// 如果主动禁用了Date头,则不添加
|
||||
if (!userSetting.isDisableDateHeader()) {
|
||||
// 添加date头
|
||||
SIPDateHeader dateHeader = new SIPDateHeader();
|
||||
// 使用自己修改的
|
||||
GbSipDate gbSipDate = new GbSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
|
||||
dateHeader.setDate(gbSipDate);
|
||||
response.addHeader(dateHeader);
|
||||
}
|
||||
|
||||
// 添加Contact头
|
||||
response.addHeader(request.getHeader(ContactHeader.NAME));
|
||||
|
||||
@ -69,6 +69,12 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
|
||||
responseAck(request, Response.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
ExpiresHeader expires = request.getExpires();
|
||||
if (expires == null) {
|
||||
log.error("处理SUBSCRIBE请求 未获取到ExpiresHeader{}", evt.getRequest());
|
||||
responseAck(request, Response.BAD_REQUEST, "missing expires");
|
||||
return;
|
||||
}
|
||||
String platformId = SipUtils.getUserIdFromFromHeader(request);
|
||||
String cmd = XmlUtil.getText(rootElement, "CmdType");
|
||||
log.info("[收到订阅请求] 类型: {}, 来自: {}", cmd, platformId);
|
||||
@ -181,7 +187,6 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
|
||||
.append("<Result>OK</Result>\r\n")
|
||||
.append("</Response>\r\n");
|
||||
|
||||
|
||||
try {
|
||||
int expires = request.getExpires().getExpires();
|
||||
Platform parentPlatform = platformService.queryPlatformByServerGBId(platformId);
|
||||
|
||||
@ -2,9 +2,12 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Platform;
|
||||
import com.genersoft.iot.vmp.gb28181.event.MessageSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.event.sip.MessageEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.service.IPlatformService;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd.CatalogQueryMessageHandler;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dom4j.Element;
|
||||
@ -28,6 +31,9 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
|
||||
@Autowired
|
||||
private IPlatformService platformService;
|
||||
|
||||
@Autowired
|
||||
private MessageSubscribe messageSubscribe;
|
||||
|
||||
public void addHandler(String cmdType, IMessageHandler messageHandler) {
|
||||
messageHandlerMap.put(cmdType, messageHandler);
|
||||
}
|
||||
@ -54,6 +60,8 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
|
||||
return;
|
||||
}
|
||||
messageHandler.handForDevice(evt, device, element);
|
||||
}else {
|
||||
handMessageEvent(element, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,4 +73,21 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
|
||||
messageHandler.handForPlatform(evt, parentPlatform, element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handMessageEvent(Element element, Object data) {
|
||||
|
||||
String cmd = getText(element, "CmdType");
|
||||
String sn = getText(element, "SN");
|
||||
MessageEvent<Object> subscribe = (MessageEvent<Object>)messageSubscribe.getSubscribe(cmd + sn);
|
||||
if (subscribe != null && subscribe.getCallback() != null) {
|
||||
String result = getText(element, "Result");
|
||||
if (result == null || "OK".equalsIgnoreCase(result) || data != null) {
|
||||
subscribe.getCallback().run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data);
|
||||
}else {
|
||||
subscribe.getCallback().run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), result);
|
||||
}
|
||||
messageSubscribe.removeSubscribe(cmd + sn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +87,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
||||
if (handlerCatchDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Device> deviceListForUpdate = new ArrayList<>();
|
||||
for (SipMsgInfo sipMsgInfo : handlerCatchDataList) {
|
||||
if (sipMsgInfo == null) {
|
||||
continue;
|
||||
@ -113,7 +114,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
||||
device.setKeepaliveTime(DateUtil.getNow());
|
||||
|
||||
if (device.isOnLine()) {
|
||||
deviceService.updateDevice(device);
|
||||
deviceListForUpdate.add(device);
|
||||
long expiresTime = Math.min(device.getExpires(), device.getHeartBeatInterval() * device.getHeartBeatCount()) * 1000L;
|
||||
if (statusTaskRunner.containsKey(device.getDeviceId())) {
|
||||
statusTaskRunner.updateDelay(device.getDeviceId(), expiresTime + System.currentTimeMillis());
|
||||
@ -125,6 +126,9 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!deviceListForUpdate.isEmpty()) {
|
||||
deviceService.updateDeviceList(deviceListForUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.event.MessageSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.event.sip.MessageEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -13,8 +10,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.RequestEvent;
|
||||
|
||||
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
|
||||
|
||||
/**
|
||||
* 命令类型: 请求动作的应答
|
||||
* 命令类型: 设备控制, 报警通知, 设备目录信息查询, 目录信息查询, 目录收到, 设备信息查询, 设备状态信息查询 ......
|
||||
@ -27,8 +22,7 @@ public class ResponseMessageHandler extends MessageHandlerAbstract implements In
|
||||
@Autowired
|
||||
private MessageRequestProcessor messageRequestProcessor;
|
||||
|
||||
@Autowired
|
||||
private MessageSubscribe messageSubscribe;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
@ -38,21 +32,5 @@ public class ResponseMessageHandler extends MessageHandlerAbstract implements In
|
||||
@Override
|
||||
public void handForDevice(RequestEvent evt, Device device, Element element) {
|
||||
super.handForDevice(evt, device, element);
|
||||
handMessageEvent(element, null);
|
||||
}
|
||||
|
||||
public void handMessageEvent(Element element, Object data) {
|
||||
String cmd = getText(element, "CmdType");
|
||||
String sn = getText(element, "SN");
|
||||
MessageEvent<Object> subscribe = (MessageEvent<Object>)messageSubscribe.getSubscribe(cmd + sn);
|
||||
if (subscribe != null && subscribe.getCallback() != null) {
|
||||
String result = getText(element, "Result");
|
||||
if (result == null || "OK".equalsIgnoreCase(result) || data != null) {
|
||||
subscribe.getCallback().run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data);
|
||||
}else {
|
||||
subscribe.getCallback().run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), result);
|
||||
}
|
||||
messageSubscribe.removeSubscribe(cmd + sn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.MessageResponseTask;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Platform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Preset;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
|
||||
@ -13,6 +13,7 @@ import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
@ -23,6 +24,12 @@ import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.DelayQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
|
||||
|
||||
/**
|
||||
* 设备预置位查询应答
|
||||
@ -36,8 +43,9 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
|
||||
@Autowired
|
||||
private ResponseMessageHandler responseMessageHandler;
|
||||
|
||||
@Autowired
|
||||
private DeferredResultHolder deferredResultHolder;
|
||||
private final Map<String, MessageResponseTask<Preset>> mesageMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final DelayQueue<MessageResponseTask<Preset>> delayQueue = new DelayQueue<>();
|
||||
|
||||
|
||||
@Override
|
||||
@ -93,7 +101,14 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
|
||||
presetQuerySipReqList.add(presetQuerySipReq);
|
||||
}
|
||||
}
|
||||
responseMessageHandler.handMessageEvent(rootElement, presetQuerySipReqList);
|
||||
// if (presetQuerySipReqList.size() == sumNum) {
|
||||
// responseMessageHandler.handMessageEvent(rootElement, presetQuerySipReqList);
|
||||
// }else {
|
||||
// String sn = getText(element, "SN");
|
||||
// addCatch(cmdType + "_" + sn, rootElement, presetQuerySipReqList);
|
||||
// }
|
||||
String sn = getText(element, "SN");
|
||||
addCatch(cmdType + "_" + sn, sumNum, rootElement, presetQuerySipReqList);
|
||||
try {
|
||||
responseAck(request, Response.OK);
|
||||
} catch (InvalidArgumentException | ParseException | SipException e) {
|
||||
@ -104,6 +119,63 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
|
||||
}
|
||||
}
|
||||
|
||||
private void addCatch(String key, int sumNum, Element rootElement, List<Preset> presetQuerySipReqList) {
|
||||
if (presetQuerySipReqList.size() == sumNum) {
|
||||
responseMessageHandler.handMessageEvent(rootElement, presetQuerySipReqList);
|
||||
if (mesageMap.containsKey(key)) {
|
||||
MessageResponseTask<Preset> messageResponseTask = mesageMap.get(key);
|
||||
mesageMap.remove(key);
|
||||
boolean remove = delayQueue.remove(messageResponseTask);
|
||||
if (!remove) {
|
||||
log.info("[移除预置位查询任务] 从延时队列内移除失败: {}", key);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (mesageMap.containsKey(key)) {
|
||||
MessageResponseTask<Preset> messageResponseTask = mesageMap.get(key);
|
||||
List<Preset> data = messageResponseTask.getData();
|
||||
data.addAll(presetQuerySipReqList);
|
||||
if (data.size() == sumNum) {
|
||||
responseMessageHandler.handMessageEvent(rootElement, presetQuerySipReqList);
|
||||
mesageMap.remove(key);
|
||||
boolean remove = delayQueue.remove(messageResponseTask);
|
||||
if (!remove) {
|
||||
log.info("[移除预置位查询任务] 从延时队列内移除失败: {}", key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
messageResponseTask.setDelayTime(System.currentTimeMillis() + 1000);
|
||||
}else {
|
||||
MessageResponseTask<Preset> messageResponseTask = new MessageResponseTask<>();
|
||||
messageResponseTask.setElement(rootElement);
|
||||
messageResponseTask.setData(presetQuerySipReqList);
|
||||
messageResponseTask.setDelayTime(System.currentTimeMillis() + 1000);
|
||||
messageResponseTask.setKey(key);
|
||||
mesageMap.put(key, messageResponseTask);
|
||||
delayQueue.offer(messageResponseTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理过期的缓存
|
||||
@Scheduled(fixedDelay = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
public void expirationCheck(){
|
||||
while (!delayQueue.isEmpty()) {
|
||||
MessageResponseTask<Preset> take = null;
|
||||
try {
|
||||
take = delayQueue.take();
|
||||
try {
|
||||
responseMessageHandler.handMessageEvent(take.getElement(), take.getData());
|
||||
mesageMap.remove(take.getKey());
|
||||
}catch (Exception e) {
|
||||
log.error("[预置位查询到期] {} 到期处理时出现异常", take.getKey());
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("[设备订阅任务] ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handForPlatform(RequestEvent evt, Platform parentPlatform, Element rootElement) {
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ public interface IMediaNodeServerService {
|
||||
|
||||
Long updateDownloadProcess(MediaServer mediaServer, String app, String stream);
|
||||
|
||||
StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy);
|
||||
void startProxy(MediaServer mediaServer, StreamProxy streamProxy);
|
||||
|
||||
void stopProxy(MediaServer mediaServer, String streamKey);
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ public interface IMediaServerService {
|
||||
|
||||
Long updateDownloadProcess(MediaServer mediaServerItem, String app, String stream);
|
||||
|
||||
StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy);
|
||||
void startProxy(MediaServer mediaServer, StreamProxy streamProxy);
|
||||
|
||||
void stopProxy(MediaServer mediaServer, String streamKey);
|
||||
|
||||
|
||||
@ -952,13 +952,13 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy) {
|
||||
public void startProxy(MediaServer mediaServer, StreamProxy streamProxy) {
|
||||
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||
if (mediaNodeServerService == null) {
|
||||
log.info("[startProxy] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
||||
}
|
||||
return mediaNodeServerService.startProxy(mediaServer, streamProxy);
|
||||
mediaNodeServerService.startProxy(mediaServer, streamProxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -425,7 +425,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy) {
|
||||
public void startProxy(MediaServer mediaServer, StreamProxy streamProxy) {
|
||||
String dstUrl;
|
||||
if ("ffmpeg".equalsIgnoreCase(streamProxy.getType())) {
|
||||
|
||||
@ -463,10 +463,6 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
MediaInfo mediaInfo = getMediaInfo(mediaServer, streamProxy.getApp(), streamProxy.getStream());
|
||||
|
||||
if (mediaInfo != null) {
|
||||
if (mediaInfo.getOriginUrl() != null && mediaInfo.getOriginUrl().equals(streamProxy.getSrcUrl())) {
|
||||
log.info("[启动拉流代理] 已存在, 直接返回, app: {}, stream: {}", mediaInfo.getApp(), streamProxy.getStream());
|
||||
return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), mediaInfo, null, true);
|
||||
}
|
||||
closeStreams(mediaServer, streamProxy.getApp(), streamProxy.getStream());
|
||||
}
|
||||
|
||||
@ -490,15 +486,6 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
||||
JSONObject data = jsonObject.getJSONObject("data");
|
||||
if (data == null) {
|
||||
throw new ControllerException(jsonObject.getInteger("code"), "代理结果异常: " + jsonObject);
|
||||
}else {
|
||||
streamProxy.setStreamKey(data.getString("key"));
|
||||
// 由于此时流未注册,手动拼装流信息
|
||||
mediaInfo = new MediaInfo();
|
||||
mediaInfo.setApp(streamProxy.getApp());
|
||||
mediaInfo.setStream(streamProxy.getStream());
|
||||
mediaInfo.setOriginType(4);
|
||||
mediaInfo.setOriginTypeStr("pull");
|
||||
return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), mediaInfo, null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,6 +378,7 @@ public class ZLMRESTfulUtils {
|
||||
param.put("url", streamUrl);
|
||||
param.put("timeout_sec", timeout_sec);
|
||||
param.put("expire_sec", expire_sec);
|
||||
param.put("async", 1);
|
||||
sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName);
|
||||
}
|
||||
|
||||
@ -446,7 +447,6 @@ public class ZLMRESTfulUtils {
|
||||
BigDecimal bigDecimal = new BigDecimal(stamp);
|
||||
param.put("stamp", bigDecimal);
|
||||
param.put("schema", schema);
|
||||
System.out.println(bigDecimal);
|
||||
return sendPost(mediaServer, "seekRecordStamp",param, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ public interface IRedisRpcPlayService {
|
||||
|
||||
void playPush(String serverId, Integer id, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
StreamInfo playProxy(String serverId, int id);
|
||||
void playProxy(String serverId, int id, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
void stopProxy(String serverId, int id);
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.genersoft.iot.vmp.service.redisMsg.control;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig;
|
||||
import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage;
|
||||
@ -63,10 +62,13 @@ public class RedisRpcStreamProxyController extends RpcController {
|
||||
response.setBody("param error");
|
||||
return response;
|
||||
}
|
||||
StreamInfo streamInfo = streamProxyPlayService.startProxy(streamProxy);
|
||||
response.setStatusCode(ErrorCode.SUCCESS.getCode());
|
||||
response.setBody(JSONObject.toJSONString(streamInfo));
|
||||
return response;
|
||||
streamProxyPlayService.startProxy(streamProxy, (code, msg, streamInfo) -> {
|
||||
response.setStatusCode(code);
|
||||
response.setBody(JSONObject.toJSONString(streamInfo));
|
||||
sendResponse(response);
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -212,13 +212,20 @@ public class RedisRpcPlayServiceImpl implements IRedisRpcPlayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo playProxy(String serverId, int id) {
|
||||
public void playProxy(String serverId, int id, ErrorCallback<StreamInfo> callback) {
|
||||
RedisRpcRequest request = buildRequest("streamProxy/play", id);
|
||||
request.setToId(serverId);
|
||||
RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS);
|
||||
if (response != null && response.getStatusCode() == ErrorCode.SUCCESS.getCode()) {
|
||||
return JSON.parseObject(response.getBody().toString(), StreamInfo.class);
|
||||
if (response == null) {
|
||||
callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null);
|
||||
}else {
|
||||
if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) {
|
||||
StreamInfo streamInfo = JSON.parseObject(response.getBody().toString(), StreamInfo.class);
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
}else {
|
||||
callback.run(response.getStatusCode(), response.getBody().toString(), null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -7,12 +7,15 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.conf.security.JwtUtils;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxyParam;
|
||||
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService;
|
||||
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -20,8 +23,10 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.MalformedURLException;
|
||||
@ -89,7 +94,7 @@ public class StreamProxyController {
|
||||
})
|
||||
@PostMapping(value = "/save")
|
||||
@ResponseBody
|
||||
public StreamContent save(@RequestBody StreamProxyParam param){
|
||||
public DeferredResult<WVPResult<StreamContent>> save(HttpServletRequest request, @RequestBody StreamProxyParam param){
|
||||
log.info("添加代理: " + JSONObject.toJSONString(param));
|
||||
if (ObjectUtils.isEmpty(param.getMediaServerId())) {
|
||||
param.setMediaServerId("auto");
|
||||
@ -97,18 +102,39 @@ public class StreamProxyController {
|
||||
if (ObjectUtils.isEmpty(param.getType())) {
|
||||
param.setType("default");
|
||||
}
|
||||
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
|
||||
ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
WVPResult<StreamContent> wvpResult = WVPResult.success();
|
||||
if (streamInfo != null) {
|
||||
if (userSetting.getUseSourceIpAsStreamIp()) {
|
||||
streamInfo=streamInfo.clone();//深拷贝
|
||||
String host;
|
||||
try {
|
||||
URL url=new URL(request.getRequestURL().toString());
|
||||
host=url.getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host=request.getLocalAddr();
|
||||
}
|
||||
streamInfo.changeStreamIp(host);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
|
||||
&& !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
|
||||
streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
|
||||
}
|
||||
wvpResult.setData(new StreamContent(streamInfo));
|
||||
}else {
|
||||
wvpResult.setCode(code);
|
||||
wvpResult.setMsg(msg);
|
||||
}
|
||||
|
||||
StreamInfo streamInfo = streamProxyService.save(param);
|
||||
if (param.isEnable()) {
|
||||
if (streamInfo == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg());
|
||||
result.setResult(wvpResult);
|
||||
}else {
|
||||
return new StreamContent(streamInfo);
|
||||
result.setResult(WVPResult.fail(code, msg));
|
||||
}
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
streamProxyService.save(param, callback);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Operation(summary = "新增代理", security = @SecurityRequirement(name = JwtUtils.HEADER), parameters = {
|
||||
@ -193,25 +219,46 @@ public class StreamProxyController {
|
||||
@ResponseBody
|
||||
@Operation(summary = "启用代理", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Parameter(name = "id", description = "代理Id", required = true)
|
||||
public StreamContent start(HttpServletRequest request, int id){
|
||||
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, int id){
|
||||
log.info("播放代理: {}", id);
|
||||
StreamInfo streamInfo = streamProxyPlayService.start(id, null, null);
|
||||
if (streamInfo == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg());
|
||||
}else {
|
||||
if (userSetting.getUseSourceIpAsStreamIp()) {
|
||||
streamInfo=streamInfo.clone();//深拷贝
|
||||
String host;
|
||||
try {
|
||||
URL url=new URL(request.getRequestURL().toString());
|
||||
host=url.getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host=request.getLocalAddr();
|
||||
StreamProxy streamProxy = streamProxyService.getStreamProxy(id);
|
||||
Assert.notNull(streamProxy, "代理信息不存在");
|
||||
|
||||
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
|
||||
|
||||
ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
|
||||
if (code == InviteErrorCode.SUCCESS.getCode()) {
|
||||
WVPResult<StreamContent> wvpResult = WVPResult.success();
|
||||
if (streamInfo != null) {
|
||||
if (userSetting.getUseSourceIpAsStreamIp()) {
|
||||
streamInfo=streamInfo.clone();//深拷贝
|
||||
String host;
|
||||
try {
|
||||
URL url=new URL(request.getRequestURL().toString());
|
||||
host=url.getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host=request.getLocalAddr();
|
||||
}
|
||||
streamInfo.changeStreamIp(host);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
|
||||
&& !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
|
||||
streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
|
||||
}
|
||||
wvpResult.setData(new StreamContent(streamInfo));
|
||||
}else {
|
||||
wvpResult.setCode(code);
|
||||
wvpResult.setMsg(msg);
|
||||
}
|
||||
streamInfo.changeStreamIp(host);
|
||||
|
||||
result.setResult(wvpResult);
|
||||
}else {
|
||||
result.setResult(WVPResult.fail(code, msg));
|
||||
}
|
||||
return new StreamContent(streamInfo);
|
||||
}
|
||||
};
|
||||
|
||||
streamProxyPlayService.start(id, null, callback);
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/stop")
|
||||
|
||||
@ -92,5 +92,5 @@ public interface StreamProxyMapper {
|
||||
" SET pulling=#{pulling}, media_server_id = #{mediaServerId}, " +
|
||||
" stream_key = #{streamKey} " +
|
||||
" WHERE id=#{id}")
|
||||
void addStream(StreamProxy streamProxy);
|
||||
void updateStream(StreamProxy streamProxy);
|
||||
}
|
||||
|
||||
@ -4,13 +4,13 @@ import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public interface IStreamProxyPlayService {
|
||||
|
||||
StreamInfo start(int id, Boolean record, ErrorCallback<StreamInfo> callback);
|
||||
void start(int id, Boolean record, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
void start(int id, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
StreamInfo startProxy(StreamProxy streamProxy);
|
||||
void startProxy(@NotNull StreamProxy streamProxy, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
void stop(int id);
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.streamProxy.service;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxyParam;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
|
||||
@ -15,7 +16,7 @@ public interface IStreamProxyService {
|
||||
* 保存视频代理
|
||||
* @param param
|
||||
*/
|
||||
StreamInfo save(StreamProxyParam param);
|
||||
void save(StreamProxyParam param, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
@ -38,7 +39,7 @@ public interface IStreamProxyService {
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
boolean startByAppAndStream(String app, String stream);
|
||||
void startByAppAndStream(String app, String stream, ErrorCallback<StreamInfo> callback);
|
||||
|
||||
/**
|
||||
* 停用用视频代理
|
||||
|
||||
@ -1,36 +1,29 @@
|
||||
package com.genersoft.iot.vmp.streamProxy.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaInfo;
|
||||
import com.genersoft.iot.vmp.media.bean.MediaServer;
|
||||
import com.genersoft.iot.vmp.media.event.hook.Hook;
|
||||
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.event.hook.HookType;
|
||||
import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
import com.genersoft.iot.vmp.streamProxy.dao.StreamProxyMapper;
|
||||
import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sip.message.Response;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 视频代理业务
|
||||
@ -57,96 +50,42 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService {
|
||||
@Autowired
|
||||
private IRedisRpcPlayService redisRpcPlayService;
|
||||
|
||||
private ConcurrentHashMap<Integer, ErrorCallback<StreamInfo>> callbackMap = new ConcurrentHashMap<>();
|
||||
|
||||
private ConcurrentHashMap<Integer, StreamInfo> streamInfoMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 流到来的处理
|
||||
*/
|
||||
@Async("taskExecutor")
|
||||
@Transactional
|
||||
@EventListener
|
||||
public void onApplicationEvent(MediaArrivalEvent event) {
|
||||
if ("rtsp".equals(event.getSchema())) {
|
||||
StreamProxy streamProxy = streamProxyMapper.selectOneByAppAndStream(event.getApp(), event.getStream());
|
||||
if (streamProxy != null) {
|
||||
ErrorCallback<StreamInfo> callback = callbackMap.remove(streamProxy.getId());
|
||||
StreamInfo streamInfo = streamInfoMap.remove(streamProxy.getId());
|
||||
if (callback != null && streamInfo != null) {
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(int id, ErrorCallback<StreamInfo> callback) {
|
||||
StreamProxy streamProxy = streamProxyMapper.select(id);
|
||||
if (streamProxy == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到");
|
||||
}
|
||||
StreamInfo streamInfo = startProxy(streamProxy);
|
||||
if (streamInfo == null) {
|
||||
callback.run(Response.BUSY_HERE, "busy here", null);
|
||||
return;
|
||||
}
|
||||
callbackMap.put(id, callback);
|
||||
streamInfoMap.put(id, streamInfo);
|
||||
|
||||
MediaServer mediaServer = mediaServerService.getOne(streamProxy.getMediaServerId());
|
||||
if (mediaServer != null) {
|
||||
MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, streamProxy.getApp(), streamProxy.getStream());
|
||||
if (mediaInfo != null) {
|
||||
callbackMap.remove(id);
|
||||
streamInfoMap.remove(id);
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo start(int id, Boolean record, ErrorCallback<StreamInfo> callback) {
|
||||
public void start(int id, Boolean record, ErrorCallback<StreamInfo> callback) {
|
||||
log.info("[拉流代理], 开始拉流,ID:{}", id);
|
||||
StreamProxy streamProxy = streamProxyMapper.select(id);
|
||||
if (streamProxy == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到");
|
||||
}
|
||||
log.info("[拉流代理] 类型: {}, app:{}, stream: {}, 流地址: {}", streamProxy.getType(), streamProxy.getApp(), streamProxy.getStream(), streamProxy.getSrcUrl());
|
||||
if (record != null) {
|
||||
streamProxy.setEnableMp4(record);
|
||||
}
|
||||
|
||||
StreamInfo streamInfo = startProxy(streamProxy);
|
||||
if (callback != null) {
|
||||
// 设置流超时的定时任务
|
||||
String timeOutTaskKey = UUID.randomUUID().toString();
|
||||
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, streamProxy.getApp(), streamProxy.getStream(), streamInfo.getMediaServer().getId());
|
||||
dynamicTask.startDelay(timeOutTaskKey, () -> {
|
||||
// 收流超时
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), streamInfo);
|
||||
}, userSetting.getPlayTimeout());
|
||||
|
||||
// 开启流到来的监听
|
||||
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||
dynamicTask.stop(timeOutTaskKey);
|
||||
// hook响应
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
});
|
||||
}
|
||||
return streamInfo;
|
||||
startProxy(streamProxy, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamInfo startProxy(StreamProxy streamProxy){
|
||||
public void startProxy(@NotNull StreamProxy streamProxy, ErrorCallback<StreamInfo> callback){
|
||||
if (!streamProxy.isEnable()) {
|
||||
return null;
|
||||
callback.run(ErrorCode.ERROR100.getCode(), "代理未启用", null);
|
||||
return;
|
||||
}
|
||||
if (streamProxy.getServerId() == null) {
|
||||
streamProxy.setServerId(userSetting.getServerId());
|
||||
}
|
||||
if (!userSetting.getServerId().equals(streamProxy.getServerId())) {
|
||||
return redisRpcPlayService.playProxy(streamProxy.getServerId(), streamProxy.getId());
|
||||
log.info("[拉流代理] 由其他服务{}管理", streamProxy.getServerId());
|
||||
redisRpcPlayService.playProxy(streamProxy.getServerId(), streamProxy.getId(), callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (streamProxy.getMediaServerId() != null) {
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStreamWithCheck(streamProxy.getApp(), streamProxy.getStream(), streamProxy.getMediaServerId(), null, false);
|
||||
if (streamInfo != null) {
|
||||
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MediaServer mediaServer;
|
||||
@ -159,12 +98,32 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService {
|
||||
if (mediaServer == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), mediaServerId == null?"未找到可用的媒体节点":"未找到节点" + mediaServerId);
|
||||
}
|
||||
StreamInfo streamInfo = mediaServerService.startProxy(mediaServer, streamProxy);
|
||||
|
||||
// 设置流超时的定时任务
|
||||
String timeOutTaskKey = UUID.randomUUID().toString();
|
||||
Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, streamProxy.getApp(), streamProxy.getStream(), mediaServer.getId());
|
||||
dynamicTask.startDelay(timeOutTaskKey, () -> {
|
||||
log.info("[拉流代理] 收流超时,app:{},stream: {}", streamProxy.getApp(), streamProxy.getStream());
|
||||
// 收流超时
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
|
||||
}, userSetting.getPlayTimeout());
|
||||
|
||||
// 开启流到来的监听
|
||||
subscribe.addSubscribe(rtpHook, (hookData) -> {
|
||||
log.info("[拉流代理] 收流成功,app:{},stream: {}", hookData.getApp(), hookData.getStream());
|
||||
dynamicTask.stop(timeOutTaskKey);
|
||||
StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServer, hookData.getApp(), hookData.getStream(), hookData.getMediaInfo(), null);
|
||||
// hook响应
|
||||
callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||
subscribe.removeSubscribe(rtpHook);
|
||||
});
|
||||
|
||||
mediaServerService.startProxy(mediaServer, streamProxy);
|
||||
if (mediaServerId == null || !mediaServerId.equals(mediaServer.getId())) {
|
||||
streamProxy.setMediaServerId(mediaServer.getId());
|
||||
streamProxyMapper.addStream(streamProxy);
|
||||
streamProxyMapper.updateStream(streamProxy);
|
||||
}
|
||||
return streamInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent;
|
||||
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent;
|
||||
import com.genersoft.iot.vmp.media.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
||||
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxyParam;
|
||||
@ -109,7 +110,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
// 拉流代理
|
||||
StreamProxy streamProxyByAppAndStream = getStreamProxyByAppAndStream(event.getApp(), event.getStream());
|
||||
if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
|
||||
startByAppAndStream(event.getApp(), event.getStream());
|
||||
startByAppAndStream(event.getApp(), event.getStream(), ((code, msg, data) -> {
|
||||
log.info("[拉流代理] 自动点播成功, app: {}, stream: {}", event.getApp(), event.getStream());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +139,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public StreamInfo save(StreamProxyParam param) {
|
||||
public void save(StreamProxyParam param, ErrorCallback<StreamInfo> callback) {
|
||||
// 兼容旧接口
|
||||
StreamProxy streamProxyInDb = getStreamProxyByAppAndStream(param.getApp(), param.getStream());
|
||||
if (streamProxyInDb != null && streamProxyInDb.getPulling() != null && streamProxyInDb.getPulling()) {
|
||||
@ -159,9 +162,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
}
|
||||
|
||||
if (param.isEnable()) {
|
||||
return playService.startProxy(streamProxy);
|
||||
} else {
|
||||
return null;
|
||||
playService.startProxy(streamProxy, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,13 +248,12 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean startByAppAndStream(String app, String stream) {
|
||||
public void startByAppAndStream(String app, String stream, ErrorCallback<StreamInfo> callback) {
|
||||
StreamProxy streamProxy = streamProxyMapper.selectOneByAppAndStream(app, stream);
|
||||
if (streamProxy == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到");
|
||||
}
|
||||
StreamInfo streamInfo = playService.startProxy(streamProxy);
|
||||
return streamInfo != null;
|
||||
playService.startProxy(streamProxy, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -406,7 +406,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
streamProxy.setPulling(status);
|
||||
streamProxy.setMediaServerId(mediaServerId);
|
||||
streamProxy.setUpdateTime(DateUtil.getNow());
|
||||
streamProxyMapper.addStream(streamProxy);
|
||||
streamProxyMapper.updateStream(streamProxy);
|
||||
|
||||
streamProxy.setGbStatus(status ? "ON" : "OFF");
|
||||
if (streamProxy.getGbId() > 0) {
|
||||
|
||||
@ -15,7 +15,7 @@ import java.time.temporal.TemporalAccessor;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
/**
|
||||
* 全局时间工具类
|
||||
* @author lin
|
||||
*/
|
||||
@ -74,7 +74,7 @@ public class DateUtil {
|
||||
public static String yyyy_MM_dd_HH_mm_ssToISO8601(@NotNull String formatTime) {
|
||||
return formatterISO8601.format(formatter.parse(formatTime));
|
||||
}
|
||||
|
||||
|
||||
public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) {
|
||||
// 三种日期格式都尝试,为了兼容不同厂家的日期格式
|
||||
if (verification(formatTime, formatterCompatibleISO8601)) {
|
||||
@ -211,11 +211,4 @@ public class DateUtil {
|
||||
return ChronoUnit.MILLIS.between(startInstant, endInstant);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
long difference = getDifference("2025-05-21 13:00:00", "2025-05-21 13:30:00")/1000;
|
||||
System.out.println(difference);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ public class RecordPlanController {
|
||||
return recordPlanService.query(page, count, query);
|
||||
}
|
||||
|
||||
@Operation(summary = "分页查询级联平台的所有所有通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Operation(summary = "分页查询录制计划关联的所有通道", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Parameter(name = "page", description = "当前页", required = true)
|
||||
@Parameter(name = "count", description = "每页条数", required = true)
|
||||
@Parameter(name = "planId", description = "录制计划ID")
|
||||
|
||||
@ -90,4 +90,6 @@ user-settings:
|
||||
record-sip: true
|
||||
# 国标点播 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
|
||||
stream-on-demand: true
|
||||
# 是否返回Date属性,true:不返回,避免摄像头通过该参数自动校时,false:返回,摄像头可能会根据该时间校时
|
||||
disable-date-header: false
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ module.exports = {
|
||||
"comma-dangle": ["warn", "never"],
|
||||
"space-in-parens": "warn",
|
||||
"comma-spacing": "warn",
|
||||
"object-curly-spacing": "warn",
|
||||
"object-curly-spacing": ["warn", "always"],
|
||||
"arrow-spacing": "warn",
|
||||
semi: ["warn", "never"],
|
||||
"no-multi-spaces": "warn",
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 876 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
BIN
web/public/static/images/bg19.webp
Normal file
|
After Width: | Height: | Size: 35 KiB |
@ -2,32 +2,6 @@ import request from '@/utils/request'
|
||||
|
||||
// 通用通道API
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/add',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function reset(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/reset',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryOne(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
@ -38,180 +12,6 @@ export function queryOne(id) {
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToGroup(params) {
|
||||
const { parentId, businessGroup, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addToGroup(params) {
|
||||
const { parentId, businessGroup, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromGroup(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFromGroup(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToRegion(params) {
|
||||
const { civilCode, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
export function addToRegion(params) {
|
||||
const { civilCode, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromRegion(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
export function deleteFromRegion(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online, civilCode } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilcode/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
civilCode: civilCode
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getParentList(params) {
|
||||
const { page, count, channelType, query, online, groupDeviceId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
groupDeviceId: groupDeviceId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualParentList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualParentList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/parent/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilCode/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualCivilCodeList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/civilCode/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getIndustryList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
@ -233,6 +33,224 @@ export function getNetworkIdentificationList() {
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function reset(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/reset',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/add',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getList(params) {
|
||||
const { page, count, query, online, hasRecordPlan, channelType } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
hasRecordPlan: hasRecordPlan
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online, civilCode } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilcode/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
civilCode: civilCode
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilCode/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualParentList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualCivilCodeList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/civilCode/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualParentList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/parent/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getParentList(params) {
|
||||
const { page, count, channelType, query, online, groupDeviceId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
groupDeviceId: groupDeviceId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addToRegion(params) {
|
||||
const { civilCode, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFromRegion(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToRegion(params) {
|
||||
const { civilCode, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromRegion(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addToGroup(params) {
|
||||
const { parentId, businessGroup, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFromGroup(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToGroup(params) {
|
||||
const { parentId, businessGroup, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromGroup(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function playChannel(channelId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
|
||||
@ -118,6 +118,19 @@ export function queryChannels(deviceId, params) {
|
||||
})
|
||||
}
|
||||
|
||||
export function queryHasStreamChannels(params) {
|
||||
const {page, count, query} = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/streams`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deviceRecord(params) {
|
||||
const { deviceId, channelId, recordCmdStr } = params
|
||||
return request({
|
||||
|
||||
@ -48,3 +48,15 @@ export function getPath(params) {
|
||||
}
|
||||
})
|
||||
}
|
||||
export function queryTree(params) {
|
||||
const { page, count, query } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/group/tree/query`,
|
||||
params: {
|
||||
query: query,
|
||||
page: page,
|
||||
count: count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -81,4 +81,16 @@ export function queryPath(deviceId) {
|
||||
}
|
||||
})
|
||||
}
|
||||
export function queryTree(params) {
|
||||
const { page, count, query } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/region/tree/query`,
|
||||
params: {
|
||||
query: query,
|
||||
page: page,
|
||||
count: count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
1
web/src/icons/svg/devices.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751337772774" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="19666" id="mx_n_1751337772775" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M793.6 128a38.4 38.4 0 0 1 38.4 38.4v46.912h110.912a38.4 38.4 0 0 1 38.4 38.4V806.4a38.4 38.4 0 0 1-38.4 38.4L832 844.736v46.976a38.4 38.4 0 0 1-38.4 38.4H238.912a38.4 38.4 0 0 1-38.4-38.4V844.8L89.6 844.8a38.4 38.4 0 0 1-38.4-38.4V251.712a38.4 38.4 0 0 1 38.4-38.4h110.912V166.4a38.4 38.4 0 0 1 38.4-38.4H793.6z m-38.4 76.8H277.248v648.512H755.2V204.8zM200.448 290.112H128V768h72.512V290.112z m704 0H832V768h72.512V290.112z m-443.392 103.04l192 128a35.2 35.2 0 0 1 0 58.56l-192 128a35.2 35.2 0 0 1-54.72-29.312v-256c0-28.16 31.36-44.864 54.72-29.312z m15.68 94.976v124.48L570.112 550.4 476.8 488.128z" p-id="19667"></path></svg>
|
||||
|
After Width: | Height: | Size: 964 B |
1
web/src/icons/svg/devices1.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751336642026" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4525" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M185.6 723.2v89.6h652.8v-89.6H185.6z m-6.4-64h665.6c31.7952 0 57.6 25.8048 57.6 57.6v102.4c0 31.7952-25.8048 57.6-57.6 57.6h-665.6A57.6 57.6 0 0 1 121.6 819.2v-102.4c0-31.7952 25.8048-57.6 57.6-57.6zM185.6 211.2v294.4h448v-294.4h-448zM179.2 147.2h460.8c31.7952 0 57.6 25.8048 57.6 57.6v307.2c0 31.7952-25.8048 57.6-57.6 57.6h-460.8A57.6 57.6 0 0 1 121.6 512V204.8c0-31.7952 25.8048-57.6 57.6-57.6z" p-id="4526"></path><path d="M697.6 415.4368l140.8 70.4V230.912l-140.8 70.4v114.0736z m121.4464-246.3232a57.6 57.6 0 0 1 83.3536 51.5072v275.5584a57.6 57.6 0 0 1-83.3536 51.5072l-185.4464-92.672V261.7856l185.4464-92.7232z" fill="#5A5A68" p-id="4527"></path></svg>
|
||||
|
After Width: | Height: | Size: 971 B |
@ -17,10 +17,10 @@
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
|
||||
<li @click="refreshSelectedTag(selectedTag)">Refresh</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
|
||||
<li @click="closeOthersTags">Close Others</li>
|
||||
<li @click="closeAllTags(selectedTag)">Close All</li>
|
||||
<li @click="refreshSelectedTag(selectedTag)">刷新</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭</li>
|
||||
<li @click="closeOthersTags">关闭其他</li>
|
||||
<li @click="closeAllTags(selectedTag)">关闭所有</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -66,14 +66,25 @@ export const constantRoutes = [
|
||||
meta: { title: '分屏监控', icon: 'live' }
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/channel',
|
||||
component: Layout,
|
||||
redirect: '/channel',
|
||||
children: [{
|
||||
path: '',
|
||||
name: 'Channel',
|
||||
component: () => import('@/views/channel/index'),
|
||||
meta: {title: '通道列表', icon: 'channelManger'}
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/device',
|
||||
component: Layout,
|
||||
redirect: '/device',
|
||||
onlyIndex: 0,
|
||||
name: '设备接入',
|
||||
meta: { title: '设备接入', icon: 'devices' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
path: '/device',
|
||||
name: 'Device',
|
||||
component: () => import('@/views/device/index'),
|
||||
meta: { title: '国标设备', icon: 'device' }
|
||||
@ -82,50 +93,34 @@ export const constantRoutes = [
|
||||
path: '/device/record/:deviceId/:channelDeviceId',
|
||||
name: 'DeviceRecord',
|
||||
component: () => import('@/views/device/channel/record'),
|
||||
meta: { title: '国标录像' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/jtDevice',
|
||||
component: Layout,
|
||||
redirect: '/jtDevice',
|
||||
onlyIndex: 0,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'JTDevice',
|
||||
component: () => import('@/views/jtDevice/index'),
|
||||
meta: { title: '部标设备', icon: 'jtDevice' }
|
||||
},
|
||||
{
|
||||
path: '/jtDevice/record/:phoneNumber/:channelId',
|
||||
name: 'JTDeviceRecord',
|
||||
component: () => import('@/views/jtDevice/channel/record'),
|
||||
meta: { title: '部标录像' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/push',
|
||||
component: Layout,
|
||||
redirect: '/push',
|
||||
children: [
|
||||
path: '/jtDevice',
|
||||
component: Layout,
|
||||
redirect: '/jtDevice',
|
||||
onlyIndex: 0,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'JTDevice',
|
||||
component: () => import('@/views/jtDevice/index'),
|
||||
meta: { title: '部标设备', icon: 'jtDevice' }
|
||||
},
|
||||
{
|
||||
path: '/jtDevice/record/:phoneNumber/:channelId',
|
||||
name: 'JTDeviceRecord',
|
||||
component: () => import('@/views/jtDevice/channel/record'),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
path: '/push',
|
||||
name: 'PushList',
|
||||
component: () => import('@/views/streamPush/index'),
|
||||
meta: { title: '推流列表', icon: 'streamPush' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/proxy',
|
||||
component: Layout,
|
||||
redirect: '/proxy',
|
||||
children: [
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
path: '/proxy',
|
||||
name: 'Proxy',
|
||||
component: () => import('@/views/streamProxy/index'),
|
||||
meta: { title: '拉流代理', icon: 'streamProxy' }
|
||||
@ -136,8 +131,8 @@ export const constantRoutes = [
|
||||
path: '/commonChannel',
|
||||
component: Layout,
|
||||
redirect: '/commonChannel/region',
|
||||
name: '通道管理',
|
||||
meta: { title: '通道管理', icon: 'channelManger' },
|
||||
name: '组织结构',
|
||||
meta: { title: '组织结构', icon: 'tree' },
|
||||
children: [
|
||||
{
|
||||
path: 'region',
|
||||
|
||||
@ -15,7 +15,22 @@ import {
|
||||
clearUnusualCivilCodeList,
|
||||
getIndustryList,
|
||||
getTypeList,
|
||||
getNetworkIdentificationList, playChannel, addToRegion, deleteFromRegion, addToGroup, deleteFromGroup
|
||||
getNetworkIdentificationList, playChannel, addToRegion, deleteFromRegion, addToGroup, deleteFromGroup, getList,
|
||||
addPointForCruise,
|
||||
addPreset, auxiliary,
|
||||
callPreset,
|
||||
deletePointForCruise,
|
||||
deletePreset, focus, iris, ptz,
|
||||
queryPreset,
|
||||
setCruiseSpeed,
|
||||
setCruiseTime,
|
||||
setLeftForScan,
|
||||
setRightForScan,
|
||||
setSpeedForScan,
|
||||
startCruise,
|
||||
startScan,
|
||||
stopCruise,
|
||||
stopScan, wiper, getAllForMap
|
||||
} from '@/api/commonChannel'
|
||||
|
||||
const actions = {
|
||||
@ -238,6 +253,226 @@ const actions = {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
getList({ commit }, param) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getList(param).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
setSpeedForScan({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setSpeedForScan(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
setLeftForScan({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setLeftForScan(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
setRightForScan({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setRightForScan(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
startScan({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
startScan(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
stopScan({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
stopScan(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
addPointForCruise({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
addPointForCruise(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
deletePointForCruise({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
deletePointForCruise(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
setCruiseSpeed({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setCruiseSpeed(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
setCruiseTime({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setCruiseTime(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
startCruise({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
startCruise(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
stopCruise({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
stopCruise(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
addPreset({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
addPreset(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
queryPreset({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryPreset(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
callPreset({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
callPreset(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
deletePreset({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
deletePreset(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
auxiliary({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
auxiliary(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
wiper({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wiper(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
ptz({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ptz(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
iris({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
iris(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
focus({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
focus(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
getAllForMap({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAllForMap(params).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
import {
|
||||
add, changeChannelAudio,
|
||||
add,
|
||||
changeChannelAudio,
|
||||
deleteDevice,
|
||||
deviceRecord,
|
||||
queryBasicParam,
|
||||
queryChannelOne,
|
||||
queryChannels, queryChannelTree, queryDeviceOne,
|
||||
queryChannels,
|
||||
queryChannelTree,
|
||||
queryDeviceOne,
|
||||
queryDevices,
|
||||
queryDeviceSyncStatus, queryDeviceTree,
|
||||
queryDeviceSyncStatus,
|
||||
queryDeviceTree,
|
||||
queryHasStreamChannels,
|
||||
resetGuard,
|
||||
setGuard,
|
||||
subscribeCatalog,
|
||||
subscribeMobilePosition,
|
||||
sync, update, updateChannelStreamIdentification,
|
||||
sync,
|
||||
update,
|
||||
updateChannelStreamIdentification,
|
||||
updateDeviceTransport
|
||||
} from '@/api/device'
|
||||
|
||||
@ -126,6 +133,16 @@ const actions = {
|
||||
})
|
||||
})
|
||||
},
|
||||
queryHasStreamChannels({commit}, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryHasStreamChannels(params).then(response => {
|
||||
const {data} = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
deviceRecord({ commit }, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
deviceRecord(params).then(response => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
getTreeList,
|
||||
update,
|
||||
add, deleteGroup, getPath
|
||||
add, deleteGroup, getPath, queryTree
|
||||
} from '@/api/group'
|
||||
|
||||
const actions = {
|
||||
@ -54,6 +54,16 @@ const actions = {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
queryTree({ commit }, param) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryTree(param).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
queryChildListInBase,
|
||||
update,
|
||||
add,
|
||||
queryPath
|
||||
queryPath, queryTree
|
||||
} from '@/api/region'
|
||||
|
||||
const actions = {
|
||||
@ -89,6 +89,16 @@ const actions = {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
queryTree({ commit }, param) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryTree(param).then(response => {
|
||||
const { data } = response
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import Cookies from 'js-cookie'
|
||||
const TokenKey = 'wvp_token'
|
||||
const NameKey = 'wvp_username'
|
||||
const serverIdKey = 'wvp_server_id'
|
||||
const expires = 30
|
||||
|
||||
export function getToken() {
|
||||
console.log('Getting token...')
|
||||
@ -10,7 +11,7 @@ export function getToken() {
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token)
|
||||
return Cookies.set(TokenKey, token, {expires: expires})
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
@ -22,7 +23,7 @@ export function getName() {
|
||||
}
|
||||
|
||||
export function setName(name) {
|
||||
return Cookies.set(NameKey, name)
|
||||
return Cookies.set(NameKey, name, {expires: expires})
|
||||
}
|
||||
|
||||
export function removeName() {
|
||||
@ -34,7 +35,7 @@ export function getServerId() {
|
||||
}
|
||||
|
||||
export function setServerId(serverId) {
|
||||
return Cookies.set(serverIdKey, serverId)
|
||||
return Cookies.set(serverIdKey, serverId, {expires: expires})
|
||||
}
|
||||
|
||||
export function removeServerId() {
|
||||
|
||||
30
web/src/views/channel/edit.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div id="ChannelEdit" v-loading="locading" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header content="编辑通道" @back="close" />
|
||||
</div>
|
||||
</div>
|
||||
<CommonChannelEdit :id="id" ref="commonChannelEdit" :save-success="close" :cancel="close" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CommonChannelEdit from '../common/CommonChannelEdit'
|
||||
|
||||
export default {
|
||||
name: 'ChannelEdit',
|
||||
components: {
|
||||
CommonChannelEdit
|
||||
},
|
||||
props: ['id', 'closeEdit'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
close: function() {
|
||||
this.closeEdit()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -4,7 +4,7 @@
|
||||
ref="groupTree"
|
||||
:show-header="true"
|
||||
:edit="true"
|
||||
:click-event="treeNodeClickEvent"
|
||||
@clickEvent="treeNodeClickEvent"
|
||||
:on-channel-change="onChannelChange"
|
||||
:enable-add-channel="true"
|
||||
:add-channel-to-group="addChannelToGroup"
|
||||
@ -20,7 +20,7 @@
|
||||
<div style="float: right;">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: 10rem; "
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -132,7 +132,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
channelList: [],
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
channelType: '',
|
||||
online: '',
|
||||
hasGroup: 'false',
|
||||
@ -170,7 +170,7 @@ export default {
|
||||
this.$store.dispatch('commonChanel/getParentList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType,
|
||||
groupDeviceId: this.groupDeviceId
|
||||
|
||||
439
web/src/views/channel/index.vue
Executable file
@ -0,0 +1,439 @@
|
||||
<template>
|
||||
<div id="channelList" class="app-container" style="height: calc(100vh - 124px);">
|
||||
<div v-if="!editId" style="height: 100%">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@input="search"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="在线状态">
|
||||
<el-select
|
||||
v-model="online"
|
||||
style="width: 8rem; margin-right: 1rem;"
|
||||
placeholder="请选择"
|
||||
default-first-option
|
||||
@change="search"
|
||||
>
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="在线" value="true" />
|
||||
<el-option label="离线" value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select
|
||||
v-model="channelType"
|
||||
style="width: 8rem; margin-right: 1rem;"
|
||||
placeholder="请选择"
|
||||
default-first-option
|
||||
@change="getChannelList"
|
||||
>
|
||||
<el-option label="全部" value="" />
|
||||
<el-option v-for="item in Object.values($channelTypeList)" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item style="float: right;">
|
||||
<el-button icon="el-icon-refresh-right" circle @click="refresh()" title="刷新表格"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
ref="channelListTable"
|
||||
size="small"
|
||||
:data="channelList"
|
||||
height="calc(100% - 64px)"
|
||||
style="width: 100%; font-size: 12px;"
|
||||
header-row-class-name="table-header"
|
||||
>
|
||||
<el-table-column prop="gbName" label="名称" min-width="180" />
|
||||
<el-table-column prop="gbDeviceId" label="编号" min-width="180" />
|
||||
<el-table-column prop="gbManufacturer" label="厂家" min-width="100" />
|
||||
<el-table-column label="类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" effect="plain" type="success" :style="$channelTypeList[scope.row.dataType].style">{{ $channelTypeList[scope.row.dataType].name }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="位置信息" min-width="150">
|
||||
<template v-slot:default="scope">
|
||||
<span v-if="scope.row.gbLongitude && scope.row.gbLatitude">{{ scope.row.gbLongitude }}<br>{{ scope.row.gbLatitude }}</span>
|
||||
<span v-if="!scope.row.gbLongitude || !scope.row.gbLatitude">无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ptzType" label="云台类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div>{{ scope.row.ptzTypeText }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag v-if="scope.row.gbStatus === 'ON'" size="medium">在线</el-tag>
|
||||
<el-tag v-if="scope.row.gbStatus !== 'ON'" size="medium" type="info">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="210" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button
|
||||
size="medium"
|
||||
:disabled="scope.row.gbStatus !== 'ON'"
|
||||
icon="el-icon-video-play"
|
||||
type="text"
|
||||
:loading="scope.row.playLoading"
|
||||
@click="sendDevicePush(scope.row)"
|
||||
>播放
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!!scope.row.streamId"
|
||||
size="medium"
|
||||
:disabled="device == null || device.online === 0"
|
||||
icon="el-icon-switch-button"
|
||||
type="text"
|
||||
style="color: #f56c6c"
|
||||
@click="stopDevicePush(scope.row)"
|
||||
>停止
|
||||
</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button
|
||||
size="medium"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
v-if="$store.getters.authority !== 2"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<devicePlayer ref="devicePlayer" />
|
||||
<channel-edit v-if="editId" :id="editId" :close-edit="closeEdit" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import devicePlayer from '@/views/common/channelPlayer/index.vue'
|
||||
import Edit from './edit.vue'
|
||||
|
||||
export default {
|
||||
name: 'ChannelList',
|
||||
components: {
|
||||
devicePlayer,
|
||||
ChannelEdit: Edit
|
||||
},
|
||||
props: {
|
||||
defaultPage: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
defaultCount: {
|
||||
type: Number,
|
||||
default: 15
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
excelName(){
|
||||
return '通道列表-' + this.currentPage
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
device: null,
|
||||
channelList: [],
|
||||
excelFields: {
|
||||
名称: 'gbName',
|
||||
编号: 'gbDeviceId',
|
||||
厂家: 'gbManufacturer',
|
||||
类型: {
|
||||
field: 'dataType',
|
||||
callback: (value) => {
|
||||
return this.$channelTypeList[value].name
|
||||
}
|
||||
},
|
||||
经度: 'gbLongitude',
|
||||
纬度: 'gbLatitude',
|
||||
云台类型: 'ptzTypeText',
|
||||
状态: {
|
||||
field: 'gbStatus',
|
||||
callback: (value) => {
|
||||
return value === 'ON' ? '在线' : '离线'
|
||||
}
|
||||
}
|
||||
},
|
||||
videoComponentList: [],
|
||||
currentPlayerInfo: {}, // 当前播放对象
|
||||
updateLooper: 0, // 数据刷新轮训标志
|
||||
searchStr: '',
|
||||
channelType: '',
|
||||
online: '',
|
||||
subStream: '',
|
||||
winHeight: window.innerHeight - 200,
|
||||
currentPage: this.defaultPage | 1,
|
||||
count: this.defaultCount | 15,
|
||||
total: 0,
|
||||
beforeUrl: '/device',
|
||||
editId: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initData()
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('videojs')
|
||||
clearTimeout(this.updateLooper)
|
||||
},
|
||||
methods: {
|
||||
initData: function() {
|
||||
this.getChannelList()
|
||||
},
|
||||
initParam: function() {
|
||||
this.currentPage = 1
|
||||
this.count = 15
|
||||
},
|
||||
currentChange: function(val) {
|
||||
this.currentPage = val
|
||||
this.initData()
|
||||
},
|
||||
handleSizeChange: function(val) {
|
||||
this.count = val
|
||||
this.getChannelList()
|
||||
},
|
||||
getChannelList: function() {
|
||||
this.$store.dispatch('commonChanel/getList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType
|
||||
}).then(data => {
|
||||
this.total = data.total
|
||||
this.channelList = data.list
|
||||
this.channelList.forEach(e => {
|
||||
e.ptzType = e.ptzType + ''
|
||||
this.$set(e, 'playLoading', false)
|
||||
})
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 通知设备上传媒体流
|
||||
sendDevicePush: function(itemData) {
|
||||
itemData.playLoading = true
|
||||
this.$store.dispatch('commonChanel/playChannel', itemData.gbId)
|
||||
.then((data) => {
|
||||
itemData.streamId = data.stream
|
||||
this.$refs.devicePlayer.openDialog('media', itemData.gbId, {
|
||||
streamInfo: data,
|
||||
hasAudio: itemData.hasAudio
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.initData()
|
||||
}, 1000)
|
||||
}).finally(() => {
|
||||
itemData.playLoading = false
|
||||
})
|
||||
},
|
||||
queryRecords: function(itemData) {
|
||||
const deviceId = this.deviceId
|
||||
const channelId = itemData.deviceId
|
||||
|
||||
this.$router.push(`/device/record/${deviceId}/${channelId}`)
|
||||
},
|
||||
queryCloudRecords: function(itemData) {
|
||||
const deviceId = this.deviceId
|
||||
const channelId = itemData.deviceId
|
||||
|
||||
this.$router.push(`/cloudRecord/detail/rtp/${deviceId}_${channelId}`)
|
||||
},
|
||||
startRecord: function(itemData) {
|
||||
this.$store.dispatch('device/deviceRecord', {
|
||||
deviceId: this.deviceId,
|
||||
channelId: itemData.deviceId,
|
||||
recordCmdStr: 'Record'
|
||||
}).then(data => {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '开始录像成功'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
})
|
||||
},
|
||||
stopRecord: function(itemData) {
|
||||
this.$store.dispatch('device/deviceRecord', {
|
||||
deviceId: this.deviceId,
|
||||
channelId: itemData.deviceId,
|
||||
recordCmdStr: 'StopRecord'
|
||||
}).then(data => {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '停止录像成功'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
})
|
||||
},
|
||||
stopDevicePush: function(itemData) {
|
||||
this.$store.dispatch('play/stop', [itemData.deviceId]).then(data => {
|
||||
this.initData()
|
||||
}).catch((error) => {
|
||||
if (error.response.status === 402) { // 已经停止过
|
||||
this.initData()
|
||||
} else {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
getSnap: function(row) {
|
||||
const baseUrl = window.baseUrl ? window.baseUrl : ''
|
||||
return ((process.env.NODE_ENV === 'development') ? process.env.VUE_APP_BASE_API : baseUrl) + '/api/device/query/snap/' + this.deviceId + '/' + row.deviceId
|
||||
},
|
||||
getBigSnap: function(row) {
|
||||
return [this.getSnap(row)]
|
||||
},
|
||||
getSnapErrorEvent: function(deviceId, channelId) {
|
||||
if (typeof (this.loadSnap[deviceId + channelId]) !== 'undefined') {
|
||||
console.log('下载截图' + this.loadSnap[deviceId + channelId])
|
||||
if (this.loadSnap[deviceId + channelId] > 5) {
|
||||
delete this.loadSnap[deviceId + channelId]
|
||||
return
|
||||
}
|
||||
setTimeout(() => {
|
||||
const url = (process.env.NODE_ENV === 'development' ? 'debug' : '') + '/api/device/query/snap/' + deviceId + '/' + channelId
|
||||
this.loadSnap[deviceId + channelId]++
|
||||
document.getElementById(deviceId + channelId).setAttribute('src', url + '?' + new Date().getTime())
|
||||
}, 1000)
|
||||
}
|
||||
},
|
||||
showDevice: function() {
|
||||
// this.$router.push(this.beforeUrl).then(() => {
|
||||
// this.initParam()
|
||||
// this.initData()
|
||||
// })
|
||||
this.$emit('show-device')
|
||||
},
|
||||
changeSubchannel(itemData) {
|
||||
this.beforeUrl = this.$router.currentRoute.path
|
||||
|
||||
var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.deviceId}`
|
||||
this.$router.push(url).then(() => {
|
||||
this.searchStr = ''
|
||||
this.channelType = ''
|
||||
this.online = ''
|
||||
this.initParam()
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
showSubChannels: function() {
|
||||
this.$store.dispatch('device/querySubChannels', [
|
||||
{
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType
|
||||
},
|
||||
this.deviceId,
|
||||
this.parentChannelId
|
||||
])
|
||||
.then(data => {
|
||||
this.total = data.total
|
||||
this.channelList = data.list
|
||||
this.channelList.forEach(e => {
|
||||
e.ptzType = e.ptzType + ''
|
||||
})
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout()
|
||||
})
|
||||
})
|
||||
},
|
||||
search: function() {
|
||||
this.currentPage = 1
|
||||
this.total = 0
|
||||
this.initData()
|
||||
},
|
||||
updateChannel: function(row) {
|
||||
this.$store.dispatch('device/changeChannelAudio', {
|
||||
channelId: row.gbId,
|
||||
audio: row.hasAudio
|
||||
})
|
||||
},
|
||||
subStreamChange: function() {
|
||||
this.$confirm('确定重置所有通道的码流类型?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$store.dispatch('device/updateChannelStreamIdentification', {
|
||||
deviceDbId: this.device.id,
|
||||
streamIdentification: this.subStream
|
||||
})
|
||||
.then(data => {
|
||||
this.initData()
|
||||
})
|
||||
.finally(() => {
|
||||
this.subStream = ''
|
||||
})
|
||||
}).catch(() => {
|
||||
this.subStream = ''
|
||||
})
|
||||
},
|
||||
channelSubStreamChange: function(row) {
|
||||
this.$store.dispatch('device/updateChannelStreamIdentification', {
|
||||
deviceDbId: row.deviceDbId,
|
||||
id: row.id,
|
||||
streamIdentification: row.streamIdentification
|
||||
})
|
||||
.then(data => {
|
||||
this.initData()
|
||||
})
|
||||
.finally(() => {
|
||||
this.subStream = ''
|
||||
})
|
||||
},
|
||||
refresh: function() {
|
||||
this.initData()
|
||||
},
|
||||
// 编辑
|
||||
handleEdit(row) {
|
||||
console.log(row)
|
||||
this.editId = row.gbId
|
||||
},
|
||||
// 结束编辑
|
||||
closeEdit: function() {
|
||||
this.editId = null
|
||||
this.getChannelList()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -4,7 +4,7 @@
|
||||
ref="regionTree"
|
||||
:show-header="true"
|
||||
:edit="true"
|
||||
:click-event="treeNodeClickEvent"
|
||||
@clickEvent="treeNodeClickEvent"
|
||||
:on-channel-change="onChannelChange"
|
||||
:enable-add-channel="true"
|
||||
:add-channel-to-civil-code="addChannelToCivilCode"
|
||||
@ -20,7 +20,7 @@
|
||||
<div style="float: right;">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="width: 10rem; margin-right: 1rem;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -130,7 +130,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
channelList: [],
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
channelType: '',
|
||||
online: '',
|
||||
currentPage: 1,
|
||||
@ -166,7 +166,7 @@ export default {
|
||||
this.$store.dispatch('commonChanel/getCivilCodeList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType,
|
||||
civilCode: this.regionDeviceId
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="DeviceTree" class="device-tree-container">
|
||||
<div id="DeviceTree" class="device-tree-container" style="height: 100%">
|
||||
<div class="device-tree-header">
|
||||
<div class="header-title">通道列表</div>
|
||||
<div class="header-switch">
|
||||
@ -20,7 +20,7 @@
|
||||
:edit="false"
|
||||
:show-header="false"
|
||||
:has-channel="true"
|
||||
:click-event="treeNodeClickEvent"
|
||||
@clickEvent="treeNodeClickEvent"
|
||||
:default-expanded-keys="[]"
|
||||
/>
|
||||
<GroupTree
|
||||
@ -29,7 +29,7 @@
|
||||
:edit="false"
|
||||
:show-header="false"
|
||||
:has-channel="true"
|
||||
:click-event="treeNodeClickEvent"
|
||||
@clickEvent="treeNodeClickEvent"
|
||||
:default-expanded-keys="[]"
|
||||
/>
|
||||
</div>
|
||||
@ -53,10 +53,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clickEvent: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
contextMenuEvent: {
|
||||
type: Function,
|
||||
default: null
|
||||
@ -137,11 +133,7 @@ export default {
|
||||
},
|
||||
treeNodeClickEvent: function(data) {
|
||||
if (data.leaf) {
|
||||
console.log(23111)
|
||||
console.log(data)
|
||||
if (this.clickEvent) {
|
||||
this.clickEvent(data.id)
|
||||
}
|
||||
this.$emit('clickEvent', data.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,14 @@
|
||||
<template>
|
||||
<div id="DeviceTree" style="border-right: 1px solid #EBEEF5; padding: 0 20px">
|
||||
<div v-if="showHeader" class="page-header">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item style="visibility: hidden">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
style="margin-right: 1rem; width: 12rem;"
|
||||
size="mini"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@input="search"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="显示编号">
|
||||
<el-checkbox v-model="showCode" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div id="groupTree" style="border-right: 1px solid #EBEEF5; height: 100%">
|
||||
<div style="padding: 0 20px 0 10px;">
|
||||
<el-input size="small" v-model="searchStr" @input="searchChange" suffix-icon="el-icon-search" placeholder="请输入搜索内容" clearable>
|
||||
<!-- <el-select v-model="searchType" slot="prepend" placeholder="搜索类型" style="width: 80px">-->
|
||||
<!-- <el-option label="目录" :value="0"></el-option>-->
|
||||
<!-- <el-option label="通道" :value="1"></el-option>-->
|
||||
<!-- </el-select>-->
|
||||
</el-input>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="!searchStr">
|
||||
<el-alert
|
||||
v-if="showAlert && edit"
|
||||
title="操作提示"
|
||||
@ -26,6 +16,10 @@
|
||||
type="info"
|
||||
style="text-align: left"
|
||||
/>
|
||||
<div v-if="edit" style="float: right;margin-right: 24px;margin-top: 18px; font-size: 14px" >
|
||||
显示编号: <el-checkbox v-model="showCode" />
|
||||
</div>
|
||||
|
||||
<vue-easy-tree
|
||||
ref="veTree"
|
||||
class="flow-tree"
|
||||
@ -75,6 +69,49 @@
|
||||
</template>
|
||||
</vue-easy-tree>
|
||||
</div>
|
||||
<div v-if="searchStr" style="color: #606266; height: calc(100% - 32px); overflow: auto !important;">
|
||||
<ul v-if="groupList.length > 0" style="list-style: none; margin: 0; padding: 10px">
|
||||
<li v-for="item in groupList" :key="item.id" class="channel-list-li" style="height: 26px; align-items: center;cursor: pointer;" @click="listClickHandler(item)">
|
||||
<span
|
||||
v-if="chooseId !== item.deviceId"
|
||||
style="color: #409EFF; font-size: 20px"
|
||||
class="iconfont icon-bianzubeifen3"
|
||||
/>
|
||||
<span
|
||||
v-if="chooseId === item.deviceId"
|
||||
style="color: #c60135; font-size: 20px"
|
||||
class="iconfont icon-bianzubeifen3"
|
||||
/>
|
||||
<div>
|
||||
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.name}}</div>
|
||||
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.deviceId}}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul v-if="channelList.length > 0" style="list-style: none; margin: 0; padding: 10px; overflow: auto">
|
||||
<li v-for="item in channelList" :key="item.id" class="channel-list-li" @click="channelLstClickHandler(item)">
|
||||
<span
|
||||
v-if="item.gbStatus === 'ON'"
|
||||
style="color: #409EFF; font-size: 20px"
|
||||
class="iconfont icon-shexiangtou2"
|
||||
/>
|
||||
<span
|
||||
v-if="item.gbStatus !== 'ON'"
|
||||
style="color: #808181; font-size: 20px"
|
||||
class="iconfont icon-shexiangtou2"
|
||||
/>
|
||||
<div>
|
||||
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.gbName}}</div>
|
||||
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.gbDeviceId}}</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="this.currentPage * this.count < this.total" style="text-align: center;">
|
||||
<el-button type="text" @click="loadListMore">加载更多</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<groupEdit ref="groupEdit" />
|
||||
<gbDeviceSelect ref="gbDeviceSelect" />
|
||||
<gbChannelSelect ref="gbChannelSelect" data-type="group" />
|
||||
@ -93,7 +130,7 @@ export default {
|
||||
GbChannelSelect,
|
||||
VueEasyTree, groupEdit, gbDeviceSelect
|
||||
},
|
||||
props: ['edit', 'enableAddChannel', 'clickEvent', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToGroup', 'treeHeight'],
|
||||
props: ['edit', 'enableAddChannel', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToGroup', 'treeHeight'],
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
@ -102,9 +139,14 @@ export default {
|
||||
},
|
||||
showCode: false,
|
||||
showAlert: true,
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
chooseId: '',
|
||||
treeData: []
|
||||
treeData: [],
|
||||
currentPage: this.defaultPage | 1,
|
||||
count: this.defaultCount | 15,
|
||||
total: 0,
|
||||
groupList: [],
|
||||
channelList: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -118,8 +160,44 @@ export default {
|
||||
// this.performance = "";
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
|
||||
searchChange() {
|
||||
this.currentPage = 1
|
||||
this.total = 0
|
||||
if (this.edit) {
|
||||
this.groupList = []
|
||||
this.queryGroup()
|
||||
}else {
|
||||
this.channelList = []
|
||||
this.queryChannelList()
|
||||
}
|
||||
},
|
||||
loadListMore: function() {
|
||||
this.currentPage += 1
|
||||
if (this.edit) {
|
||||
this.queryGroup()
|
||||
}else {
|
||||
this.queryChannelList()
|
||||
}
|
||||
},
|
||||
queryGroup: function() {
|
||||
this.$store.dispatch('group/queryTree', {
|
||||
query: this.searchStr,
|
||||
page: this.currentPage,
|
||||
count: this.count
|
||||
}).then(data => {
|
||||
this.total = data.total
|
||||
this.groupList = this.groupList.concat(data.list)
|
||||
})
|
||||
},
|
||||
queryChannelList: function() {
|
||||
this.$store.dispatch('commonChanel/getList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchStr
|
||||
}).then(data => {
|
||||
this.total = data.total
|
||||
this.channelList = this.channelList.concat(data.list)
|
||||
})
|
||||
},
|
||||
loadNode: function(node, resolve) {
|
||||
if (node.level === 0) {
|
||||
@ -136,7 +214,7 @@ export default {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('group/getTreeList', {
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
parent: node.data.id,
|
||||
hasChannel: this.hasChannel
|
||||
}).then(data => {
|
||||
@ -144,6 +222,8 @@ export default {
|
||||
this.showAlert = false
|
||||
}
|
||||
resolve(data)
|
||||
}).finally(() => {
|
||||
this.locading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -348,9 +428,17 @@ export default {
|
||||
},
|
||||
nodeClickHandler: function(data, node, tree) {
|
||||
this.chooseId = data.deviceId
|
||||
if (this.clickEvent) {
|
||||
this.clickEvent(data)
|
||||
}
|
||||
this.$emit('clickEvent', data)
|
||||
},
|
||||
listClickHandler: function(data) {
|
||||
this.chooseId = data.deviceId
|
||||
this.$emit('clickEvent', data)
|
||||
},
|
||||
channelLstClickHandler: function(data) {
|
||||
this.$emit('clickEvent', {
|
||||
leaf: true,
|
||||
id: data.gbId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -375,7 +463,7 @@ export default {
|
||||
|
||||
.flow-tree {
|
||||
overflow: auto;
|
||||
margin: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.flow-tree .vue-recycle-scroller__item-wrapper{
|
||||
height: 100%;
|
||||
|
||||
@ -1,24 +1,14 @@
|
||||
<template>
|
||||
<div id="DeviceTree" style="border-right: 1px solid #EBEEF5; padding: 0 20px">
|
||||
<div v-if="showHeader" class="page-header">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item style="visibility: hidden">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
style="margin-right: 1rem; width: 12rem;"
|
||||
size="mini"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@input="search"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="显示编号">
|
||||
<el-checkbox v-model="showCode" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div id="regionTree" style="border-right: 1px solid #EBEEF5; height: 100%">
|
||||
<div style="padding: 0 20px 0 10px;">
|
||||
<el-input size="small" v-model="searchStr" @input="searchChange" suffix-icon="el-icon-search" placeholder="请输入搜索内容" clearable>
|
||||
<!-- <el-select v-model="searchType" slot="prepend" placeholder="搜索类型" style="width: 80px">-->
|
||||
<!-- <el-option label="目录" :value="0"></el-option>-->
|
||||
<!-- <el-option label="通道" :value="1"></el-option>-->
|
||||
<!-- </el-select>-->
|
||||
</el-input>
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="!searchStr">
|
||||
<el-alert
|
||||
v-if="showAlert && edit"
|
||||
title="操作提示"
|
||||
@ -26,6 +16,10 @@
|
||||
type="info"
|
||||
style="text-align: left"
|
||||
/>
|
||||
<div v-if="edit" style="float: right;margin-right: 24px;margin-top: 18px; font-size: 14px" >
|
||||
显示编号: <el-checkbox v-model="showCode" />
|
||||
</div>
|
||||
|
||||
<vue-easy-tree
|
||||
ref="veTree"
|
||||
class="flow-tree"
|
||||
@ -75,6 +69,49 @@
|
||||
</template>
|
||||
</vue-easy-tree>
|
||||
</div>
|
||||
<div v-if="searchStr" style="color: #606266; height: calc(100% - 32px); overflow: auto !important;">
|
||||
<ul v-if="regionList.length > 0" style="list-style: none; margin: 0; padding: 10px">
|
||||
<li v-for="item in regionList" :key="item.id" class="channel-list-li" style="height: 26px; align-items: center;cursor: pointer;" @click="listClickHandler(item)">
|
||||
<span
|
||||
v-if="chooseId !== item.deviceId"
|
||||
style="color: #409EFF; font-size: 20px"
|
||||
class="iconfont icon-bianzubeifen3"
|
||||
/>
|
||||
<span
|
||||
v-if="chooseId === item.deviceId"
|
||||
style="color: #c60135; font-size: 20px"
|
||||
class="iconfont icon-bianzubeifen3"
|
||||
/>
|
||||
<div>
|
||||
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.name}}</div>
|
||||
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.deviceId}}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul v-if="channelList.length > 0" style="list-style: none; margin: 0; padding: 10px; overflow: auto">
|
||||
<li v-for="item in channelList" :key="item.id" class="channel-list-li" @click="channelLstClickHandler(item)">
|
||||
<span
|
||||
v-if="item.gbStatus === 'ON'"
|
||||
style="color: #409EFF; font-size: 20px"
|
||||
class="iconfont icon-shexiangtou2"
|
||||
/>
|
||||
<span
|
||||
v-if="item.gbStatus !== 'ON'"
|
||||
style="color: #808181; font-size: 20px"
|
||||
class="iconfont icon-shexiangtou2"
|
||||
/>
|
||||
<div>
|
||||
<div style="margin-left: 4px; margin-bottom: 3px; font-size: 15px">{{item.gbName}}</div>
|
||||
<div style="margin-left: 4px; font-size: 13px; color: #808181">{{item.gbDeviceId}}</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="this.currentPage * this.count < this.total" style="text-align: center;">
|
||||
<el-button type="text" @click="loadListMore">加载更多</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<regionEdit ref="regionEdit" />
|
||||
<gbDeviceSelect ref="gbDeviceSelect" />
|
||||
<GbChannelSelect ref="gbChannelSelect" data-type="civilCode" />
|
||||
@ -86,6 +123,7 @@ import VueEasyTree from '@wchbrad/vue-easy-tree'
|
||||
import regionEdit from './../dialog/regionEdit'
|
||||
import gbDeviceSelect from './../dialog/GbDeviceSelect'
|
||||
import GbChannelSelect from '../dialog/GbChannelSelect.vue'
|
||||
import chooseCivilCode from '@/views/dialog/chooseCivilCode.vue'
|
||||
|
||||
export default {
|
||||
name: 'DeviceTree',
|
||||
@ -93,17 +131,24 @@ export default {
|
||||
GbChannelSelect,
|
||||
VueEasyTree, regionEdit, gbDeviceSelect
|
||||
},
|
||||
props: ['edit', 'enableAddChannel', 'clickEvent', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight'],
|
||||
props: ['edit', 'enableAddChannel', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight'],
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
label: 'name'
|
||||
label: 'name',
|
||||
children: 'children'
|
||||
},
|
||||
searchType: 0,
|
||||
showCode: false,
|
||||
showAlert: true,
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
chooseId: '',
|
||||
treeData: []
|
||||
treeData: [],
|
||||
currentPage: this.defaultPage | 1,
|
||||
count: this.defaultCount | 15,
|
||||
total: 0,
|
||||
regionList: [],
|
||||
channelList: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -117,8 +162,44 @@ export default {
|
||||
// this.performance = "";
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
|
||||
searchChange() {
|
||||
this.currentPage = 1
|
||||
this.total = 0
|
||||
if (this.edit) {
|
||||
this.regionList = []
|
||||
this.queryRegion()
|
||||
}else {
|
||||
this.channelList = []
|
||||
this.queryChannelList()
|
||||
}
|
||||
},
|
||||
loadListMore: function() {
|
||||
this.currentPage += 1
|
||||
if (this.edit) {
|
||||
this.queryRegion()
|
||||
}else {
|
||||
this.queryChannelList()
|
||||
}
|
||||
},
|
||||
queryRegion: function() {
|
||||
this.$store.dispatch('region/queryTree', {
|
||||
query: this.searchStr,
|
||||
page: this.currentPage,
|
||||
count: this.count
|
||||
}).then(data => {
|
||||
this.total = data.total
|
||||
this.regionList = this.regionList.concat(data.list)
|
||||
})
|
||||
},
|
||||
queryChannelList: function() {
|
||||
this.$store.dispatch('commonChanel/getList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchStr
|
||||
}).then(data => {
|
||||
this.total = data.total
|
||||
this.channelList = this.channelList.concat(data.list)
|
||||
})
|
||||
},
|
||||
loadNode: function(node, resolve) {
|
||||
if (node.level === 0) {
|
||||
@ -135,7 +216,7 @@ export default {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('region/getTreeList', {
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
parent: node.data.id,
|
||||
hasChannel: this.hasChannel
|
||||
})
|
||||
@ -158,7 +239,6 @@ export default {
|
||||
if (!this.edit) {
|
||||
return
|
||||
}
|
||||
console.log(node.level)
|
||||
if (node.data.type === 0) {
|
||||
const menuItem = [
|
||||
{
|
||||
@ -349,9 +429,17 @@ export default {
|
||||
},
|
||||
nodeClickHandler: function(data, node, tree) {
|
||||
this.chooseId = data.deviceId
|
||||
if (this.clickEvent) {
|
||||
this.clickEvent(data)
|
||||
}
|
||||
this.$emit('clickEvent', data)
|
||||
},
|
||||
listClickHandler: function(data) {
|
||||
this.chooseId = data.deviceId
|
||||
this.$emit('clickEvent', data)
|
||||
},
|
||||
channelLstClickHandler: function(data) {
|
||||
this.$emit('clickEvent', {
|
||||
leaf: true,
|
||||
id: data.gbId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -382,11 +470,18 @@ export default {
|
||||
|
||||
.flow-tree {
|
||||
overflow: auto;
|
||||
margin: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.flow-tree .vue-recycle-scroller__item-wrapper{
|
||||
height: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.channel-list-li {
|
||||
height: 24px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
grid-template-columns: 26px 1fr;
|
||||
margin-bottom: 18px
|
||||
}
|
||||
</style>
|
||||
|
||||
0
web_src/static/.gitkeep → web/src/views/common/channelPlayer/chooseChannelForJt.vue
Normal file → Executable file
@ -1,35 +1,106 @@
|
||||
<template>
|
||||
<div id="devicePlayer" v-loading="isLoging">
|
||||
|
||||
<el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" @close="close()" v-if="showVideoDialog">
|
||||
<el-dialog
|
||||
v-if="showVideoDialog"
|
||||
v-el-drag-dialog
|
||||
title="视频播放"
|
||||
top="0"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showVideoDialog"
|
||||
@close="close()"
|
||||
>
|
||||
<div style="width: 100%; height: 100%">
|
||||
<el-tabs type="card" :stretch="true" v-model="activePlayer" @tab-click="changePlayer"
|
||||
v-if="Object.keys(this.player).length > 1">
|
||||
<el-tabs
|
||||
v-if="Object.keys(this.player).length > 1"
|
||||
v-model="activePlayer"
|
||||
type="card"
|
||||
:stretch="true"
|
||||
@tab-click="changePlayer"
|
||||
>
|
||||
<el-tab-pane label="Jessibuca" name="jessibuca">
|
||||
<jessibucaPlayer v-if="activePlayer === 'jessibuca'" ref="jessibuca" :visible.sync="showVideoDialog"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
|
||||
<jessibucaPlayer
|
||||
v-if="activePlayer === 'jessibuca'"
|
||||
ref="jessibuca"
|
||||
:visible.sync="showVideoDialog"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="WebRTC" name="webRTC">
|
||||
<rtc-player v-if="activePlayer === 'webRTC'" ref="webRTC" :visible.sync="showVideoDialog"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px"
|
||||
:hasAudio="hasAudio" fluent autoplay live></rtc-player>
|
||||
<rtc-player
|
||||
v-if="activePlayer === 'webRTC'"
|
||||
ref="webRTC"
|
||||
:visible.sync="showVideoDialog"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
height="100px"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="h265web" name="h265web">
|
||||
<h265web v-if="activePlayer === 'h265web'" ref="h265web"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px"
|
||||
:hasAudio="hasAudio" fluent autoplay live></h265web>
|
||||
<h265web
|
||||
v-if="activePlayer === 'h265web'"
|
||||
ref="h265web"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
:show-button="true"
|
||||
/>
|
||||
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
|
||||
<rtc-player v-if="Object.keys(this.player).length == 1 && this.player.webRTC" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
height="100px" :hasAudio="hasAudio" fluent autoplay live></rtc-player>
|
||||
<h265web v-if="Object.keys(this.player).length == 1 && this.player.h265web" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
height="100px" :hasAudio="hasAudio" fluent autoplay live></h265web>
|
||||
<jessibucaPlayer
|
||||
v-if="Object.keys(this.player).length == 1 && this.player.jessibuca"
|
||||
ref="jessibuca"
|
||||
:visible.sync="showVideoDialog"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
<rtc-player
|
||||
v-if="Object.keys(this.player).length == 1 && this.player.webRTC"
|
||||
ref="jessibuca"
|
||||
:visible.sync="showVideoDialog"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
height="100px"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
<h265web
|
||||
v-if="Object.keys(this.player).length == 1 && this.player.h265web"
|
||||
ref="jessibuca"
|
||||
:visible.sync="showVideoDialog"
|
||||
:video-url="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
height="100px"
|
||||
:has-audio="hasAudio"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
</div>
|
||||
<div id="shared" style="text-align: right; margin-top: 1rem;">
|
||||
|
||||
@ -39,8 +110,12 @@
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">播放地址:</span>
|
||||
<el-input v-model="getPlayerShared.sharedUrl" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="getPlayerShared.sharedUrl"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
<i
|
||||
class="cpoy-btn el-icon-document-copy"
|
||||
title="点击拷贝"
|
||||
style="cursor: pointer"
|
||||
@click="copyUrl(getPlayerShared.sharedUrl)"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
@ -48,20 +123,28 @@
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">iframe:</span>
|
||||
<el-input v-model="getPlayerShared.sharedIframe" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="getPlayerShared.sharedIframe"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
<i
|
||||
class="cpoy-btn el-icon-document-copy"
|
||||
title="点击拷贝"
|
||||
style="cursor: pointer"
|
||||
@click="copyUrl(getPlayerShared.sharedIframe)"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;">
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">资源地址:</span>
|
||||
<el-input v-model="getPlayerShared.sharedRtmp" :disabled="true">
|
||||
<el-button slot="append" icon="el-icon-document-copy" title="点击拷贝"
|
||||
v-clipboard="getPlayerShared.sharedRtmp"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
|
||||
<el-dropdown slot="prepend" v-if="streamInfo" trigger="click" @command="copyUrl">
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-document-copy"
|
||||
title="点击拷贝"
|
||||
style="cursor: pointer"
|
||||
@click="copyUrl(getPlayerShared.sharedIframe)"
|
||||
/>
|
||||
<el-dropdown v-if="streamInfo" slot="prepend" trigger="click" @command="copyUrl">
|
||||
<el-button>
|
||||
更多地址<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
更多地址<i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-button>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv">
|
||||
@ -160,100 +243,106 @@
|
||||
</el-tab-pane>
|
||||
<!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}-->
|
||||
<!--遥控界面-->
|
||||
<el-tab-pane label="云台控制" name="control" v-if="showPtz">
|
||||
<el-tab-pane v-if="showPtz" label="云台控制" name="control">
|
||||
<div style="display: grid; grid-template-columns: 240px auto; height: 180px; overflow: auto">
|
||||
<div style="display: grid; grid-template-columns: 6.25rem auto;">
|
||||
|
||||
<div class="control-wrapper">
|
||||
<div class="control-btn control-top" @mousedown="ptzCamera('up')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-top"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
<i class="el-icon-caret-top" />
|
||||
<div class="control-inner-btn control-inner" />
|
||||
</div>
|
||||
<div class="control-btn control-left" @mousedown="ptzCamera('left')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-left"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
<i class="el-icon-caret-left" />
|
||||
<div class="control-inner-btn control-inner" />
|
||||
</div>
|
||||
<div class="control-btn control-bottom" @mousedown="ptzCamera('down')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-bottom"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
<i class="el-icon-caret-bottom" />
|
||||
<div class="control-inner-btn control-inner" />
|
||||
</div>
|
||||
<div class="control-btn control-right" @mousedown="ptzCamera('right')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-right"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
<i class="el-icon-caret-right" />
|
||||
<div class="control-inner-btn control-inner" />
|
||||
</div>
|
||||
<div class="control-round">
|
||||
<div class="control-round-inner"><i class="fa fa-pause-circle"></i></div>
|
||||
<div class="control-round-inner"><i class="fa fa-pause-circle" /></div>
|
||||
</div>
|
||||
<div class="contro-speed" style="position: absolute; left: 4px; top: 7rem; width: 6.25rem;">
|
||||
<el-slider v-model="controSpeed" :max="100"></el-slider>
|
||||
<el-slider v-model="controSpeed" :max="100" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="ptz-btn-box">
|
||||
<div style="" @mousedown="ptzCamera('zoomin')" @mouseup="ptzCamera('stop')" title="变倍+">
|
||||
<i class="el-icon-zoom-in control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div style="" title="变倍+" @mousedown="ptzCamera('zoomin')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-zoom-in control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
<div style="" @mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')" title="变倍-">
|
||||
<i class="el-icon-zoom-out control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div style="" title="变倍-" @mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-zoom-out control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ptz-btn-box">
|
||||
<div @mousedown="focusCamera('near')" @mouseup="focusCamera('stop')" title="聚焦+">
|
||||
<i class="iconfont icon-bianjiao-fangda control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div title="聚焦+" @mousedown="focusCamera('near')" @mouseup="focusCamera('stop')">
|
||||
<i class="iconfont icon-bianjiao-fangda control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
<div @mousedown="focusCamera('far')" @mouseup="focusCamera('stop')" title="聚焦-">
|
||||
<i class="iconfont icon-bianjiao-suoxiao control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div title="聚焦-" @mousedown="focusCamera('far')" @mouseup="focusCamera('stop')">
|
||||
<i class="iconfont icon-bianjiao-suoxiao control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ptz-btn-box">
|
||||
<div @mousedown="irisCamera('in')" @mouseup="irisCamera('stop')" title="光圈+">
|
||||
<i class="iconfont icon-guangquan control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div title="光圈+" @mousedown="irisCamera('in')" @mouseup="irisCamera('stop')">
|
||||
<i class="iconfont icon-guangquan control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
<div @mousedown="pirisCamera('out')" @mouseup="irisCamera('stop')" title="光圈-">
|
||||
<i class="iconfont icon-guangquan- control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
<div title="光圈-" @mousedown="irisCamera('out')" @mouseup="irisCamera('stop')">
|
||||
<i class="iconfont icon-guangquan- control-zoom-btn" style="font-size: 1.5rem;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left" >
|
||||
<div style="text-align: left" v-if="tabActiveName === 'control'">
|
||||
<el-select
|
||||
v-model="ptzMethod"
|
||||
style="width: 100%"
|
||||
size="mini"
|
||||
placeholder="请选择云台功能"
|
||||
>
|
||||
<el-option label="预置点" value="preset"></el-option>
|
||||
<el-option label="巡航组" value="cruise"></el-option>
|
||||
<el-option label="自动扫描" value="scan"></el-option>
|
||||
<el-option label="雨刷" value="wiper"></el-option>
|
||||
<el-option label="辅助开关" value="switch"></el-option>
|
||||
<el-option label="预置点" value="preset" />
|
||||
<el-option label="巡航组" value="cruise" />
|
||||
<el-option label="自动扫描" value="scan" />
|
||||
<el-option label="雨刷" value="wiper" />
|
||||
<el-option label="辅助开关" value="switch" />
|
||||
</el-select>
|
||||
|
||||
<ptzPreset :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'preset'" style="margin-top: 1rem"></ptzPreset>
|
||||
<ptzCruising :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'cruise'" style="margin-top: 1rem"></ptzCruising>
|
||||
<ptzScan :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'scan'" style="margin-top: 1rem"></ptzScan>
|
||||
<ptzWiper :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'wiper'" style="margin-top: 1rem"></ptzWiper>
|
||||
<ptzSwitch :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'switch'" style="margin-top: 1rem"></ptzSwitch>
|
||||
<ptzPreset v-if="ptzMethod === 'preset'" :channel-id="channelId" style="margin-top: 1rem" />
|
||||
<ptzCruising v-if="ptzMethod === 'cruise'" :channel-id="channelId" style="margin-top: 1rem" />
|
||||
<ptzScan v-if="ptzMethod === 'scan'" :channel-id="channelId" style="margin-top: 1rem" />
|
||||
<ptzWiper v-if="ptzMethod === 'wiper'" :channel-id="channelId" style="margin-top: 1rem" />
|
||||
<ptzSwitch v-if="ptzMethod === 'switch'" :channel-id="channelId" style="margin-top: 1rem" />
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="编码信息" name="codec" >
|
||||
<mediaInfo ref="mediaInfo" :app="app" :stream="streamId" :mediaServerId="mediaServerId"></mediaInfo>
|
||||
<el-tab-pane label="编码信息" name="codec">
|
||||
<mediaInfo ref="mediaInfo" :app="app" :stream="streamId" :media-server-id="mediaServerId" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="语音对讲" name="broadcast">
|
||||
<el-tab-pane v-if="showBroadcast" label="语音对讲" name="broadcast">
|
||||
<div style="padding: 0 10px">
|
||||
<!-- <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF"-->
|
||||
<!-- active-text="喊话(Broadcast)"-->
|
||||
<!-- inactive-text="对讲(Talk)"></el-switch>-->
|
||||
<!-- <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF"-->
|
||||
<!-- active-text="喊话(Broadcast)"-->
|
||||
<!-- inactive-text="对讲(Talk)"></el-switch>-->
|
||||
|
||||
<el-radio-group v-model="broadcastMode" :disabled="broadcastStatus !== -1">
|
||||
<el-radio :label="true" >喊话(Broadcast)</el-radio>
|
||||
<el-radio :label="false" >对讲(Talk)</el-radio>
|
||||
<el-radio :label="true">喊话(Broadcast)</el-radio>
|
||||
<el-radio :label="false">对讲(Talk)</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="trank" style="text-align: center;">
|
||||
<el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2"
|
||||
circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/>
|
||||
<el-button
|
||||
:type="getBroadcastStatus()"
|
||||
:disabled="broadcastStatus === -2"
|
||||
circle
|
||||
icon="el-icon-microphone"
|
||||
style="font-size: 32px; padding: 24px;margin-top: 24px;"
|
||||
@click="broadcastStatusClick()"
|
||||
/>
|
||||
<p>
|
||||
<span v-if="broadcastStatus === -2">正在释放资源</span>
|
||||
<span v-if="broadcastStatus === -1">点击开始对讲</span>
|
||||
@ -271,62 +360,45 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rtcPlayer from '../dialog/rtcPlayer.vue'
|
||||
import LivePlayer from '@liveqing/liveplayer'
|
||||
import elDragDialog from '@/directive/el-drag-dialog'
|
||||
import crypto from 'crypto'
|
||||
import jessibucaPlayer from '../common/jessibuca.vue'
|
||||
import PtzPreset from "../common/ptzPreset.vue";
|
||||
import PtzCruising from "../common/ptzCruising.vue";
|
||||
import ptzScan from "../common/ptzScan.vue";
|
||||
import ptzWiper from "../common/ptzWiper.vue";
|
||||
import ptzSwitch from "../common/ptzSwitch.vue";
|
||||
import mediaInfo from "../common/mediaInfo.vue";
|
||||
import H265web from "../common/h265web.vue";
|
||||
import rtcPlayer from '../rtcPlayer.vue'
|
||||
import jessibucaPlayer from '../jessibuca.vue'
|
||||
import PtzPreset from './ptzPreset.vue'
|
||||
import PtzCruising from './ptzCruising.vue'
|
||||
import ptzScan from './ptzScan.vue'
|
||||
import ptzWiper from './ptzWiper.vue'
|
||||
import ptzSwitch from './ptzSwitch.vue'
|
||||
import mediaInfo from '../mediaInfo.vue'
|
||||
import H265web from '../h265web.vue'
|
||||
|
||||
export default {
|
||||
name: 'devicePlayer',
|
||||
props: {},
|
||||
name: 'DevicePlayer',
|
||||
directives: { elDragDialog },
|
||||
components: {
|
||||
H265web,
|
||||
PtzPreset,PtzCruising,ptzScan,ptzWiper,ptzSwitch,mediaInfo,
|
||||
LivePlayer, jessibucaPlayer, rtcPlayer,
|
||||
},
|
||||
computed: {
|
||||
getPlayerShared: function () {
|
||||
return {
|
||||
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
|
||||
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
|
||||
sharedRtmp: this.videoUrl
|
||||
};
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log("created")
|
||||
console.log(this.player)
|
||||
this.broadcastStatus = -1;
|
||||
if (Object.keys(this.player).length === 1) {
|
||||
this.activePlayer = Object.keys(this.player)[0]
|
||||
}
|
||||
PtzPreset, PtzCruising, ptzScan, ptzWiper, ptzSwitch, mediaInfo,
|
||||
jessibucaPlayer, rtcPlayer
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
video: 'http://lndxyj.iqilu.com/public/upload/2019/10/14/8c001ea0c09cdc59a57829dabc8010fa.mp4',
|
||||
videoUrl: '',
|
||||
activePlayer: "jessibuca",
|
||||
activePlayer: 'jessibuca',
|
||||
// 如何你只是用一种播放器,直接注释掉不用的部分即可
|
||||
player: {
|
||||
jessibuca: ["ws_flv", "wss_flv"],
|
||||
webRTC: ["rtc", "rtcs"],
|
||||
h265web: ["ws_flv", "wss_flv"],
|
||||
jessibuca: ['ws_flv', 'wss_flv'],
|
||||
webRTC: ['rtc', 'rtcs'],
|
||||
h265web: ['ws_flv', 'wss_flv']
|
||||
},
|
||||
showVideoDialog: false,
|
||||
channelId: null,
|
||||
streamId: '',
|
||||
ptzMethod: 'preset',
|
||||
ptzPresetId: '',
|
||||
app: '',
|
||||
mediaServerId: '',
|
||||
deviceId: '',
|
||||
channelId: '',
|
||||
tabActiveName: 'media',
|
||||
hasAudio: false,
|
||||
loadingRecords: false,
|
||||
@ -344,164 +416,159 @@ export default {
|
||||
scanGroup: 0,
|
||||
tracks: [],
|
||||
showPtz: true,
|
||||
showBroadcast: true,
|
||||
showRrecord: true,
|
||||
sliderTime: 0,
|
||||
seekTime: 0,
|
||||
recordStartTime: 0,
|
||||
showTimeText: "00:00:00",
|
||||
showTimeText: '00:00:00',
|
||||
streamInfo: null,
|
||||
broadcastMode: true,
|
||||
broadcastRtc: null,
|
||||
broadcastStatus: -1, // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功
|
||||
};
|
||||
broadcastStatus: -1 // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getPlayerShared: function() {
|
||||
return {
|
||||
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
|
||||
sharedIframe: '' + window.location.origin + '<iframe src="/public#/play/wasm/"></iframe>' + encodeURIComponent(this.videoUrl) + '',
|
||||
sharedRtmp: this.videoUrl
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.broadcastStatus = -1
|
||||
if (Object.keys(this.player).length === 1) {
|
||||
this.activePlayer = Object.keys(this.player)[0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
tabHandleClick: function (tab, event) {
|
||||
tabHandleClick: function(tab, event) {
|
||||
console.log(tab)
|
||||
this.tracks = [];
|
||||
if (tab.name === "codec") {
|
||||
this.tracks = []
|
||||
if (tab.name === 'codec') {
|
||||
this.$refs.mediaInfo.startTask()
|
||||
}else {
|
||||
} else {
|
||||
this.$refs.mediaInfo.stopTask()
|
||||
}
|
||||
},
|
||||
changePlayer: function (tab) {
|
||||
changePlayer: function(tab) {
|
||||
console.log(this.player[tab.name][0])
|
||||
this.activePlayer = tab.name;
|
||||
this.activePlayer = tab.name
|
||||
this.videoUrl = this.getUrlByStreamInfo()
|
||||
console.log(this.videoUrl)
|
||||
},
|
||||
openDialog: function (tab, deviceId, channelId, param) {
|
||||
openDialog: function(tab, channelId, param) {
|
||||
if (this.showVideoDialog) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
this.tabActiveName = tab;
|
||||
this.channelId = channelId;
|
||||
this.deviceId = deviceId;
|
||||
this.streamId = "";
|
||||
this.mediaServerId = "";
|
||||
this.app = "";
|
||||
this.videoUrl = ""
|
||||
if (!!this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].pause();
|
||||
this.tabActiveName = tab
|
||||
this.channelId = channelId
|
||||
this.streamId = ''
|
||||
this.mediaServerId = ''
|
||||
this.app = ''
|
||||
this.videoUrl = ''
|
||||
if (this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].pause()
|
||||
}
|
||||
switch (tab) {
|
||||
case "media":
|
||||
case 'media':
|
||||
this.play(param.streamInfo, param.hasAudio)
|
||||
break;
|
||||
case "streamPlay":
|
||||
this.tabActiveName = "media";
|
||||
this.showRrecord = false;
|
||||
this.showPtz = false;
|
||||
break
|
||||
case 'streamPlay':
|
||||
this.tabActiveName = 'media'
|
||||
this.showRrecord = false
|
||||
this.showPtz = false
|
||||
this.showBroadcast = false
|
||||
this.play(param.streamInfo, param.hasAudio)
|
||||
break;
|
||||
case "control":
|
||||
break;
|
||||
break
|
||||
case 'control':
|
||||
break
|
||||
}
|
||||
},
|
||||
play: function (streamInfo, hasAudio) {
|
||||
this.streamInfo = streamInfo;
|
||||
this.hasAudio = hasAudio;
|
||||
this.isLoging = false;
|
||||
play: function(streamInfo, hasAudio) {
|
||||
this.streamInfo = streamInfo
|
||||
this.hasAudio = hasAudio
|
||||
this.isLoging = false
|
||||
// this.videoUrl = streamInfo.rtc;
|
||||
this.videoUrl = this.getUrlByStreamInfo();
|
||||
this.streamId = streamInfo.stream;
|
||||
this.app = streamInfo.app;
|
||||
this.mediaServerId = streamInfo.mediaServerId;
|
||||
this.videoUrl = this.getUrlByStreamInfo()
|
||||
this.streamId = streamInfo.stream
|
||||
this.app = streamInfo.app
|
||||
this.mediaServerId = streamInfo.mediaServerId
|
||||
this.playFromStreamInfo(false, streamInfo)
|
||||
},
|
||||
getUrlByStreamInfo() {
|
||||
console.log(this.streamInfo)
|
||||
let streamInfo = this.streamInfo
|
||||
if (this.streamInfo.transcodeStream) {
|
||||
streamInfo = this.streamInfo.transcodeStream;
|
||||
streamInfo = this.streamInfo.transcodeStream
|
||||
}
|
||||
if (location.protocol === "https:") {
|
||||
if (location.protocol === 'https:') {
|
||||
this.videoUrl = streamInfo[this.player[this.activePlayer][1]]
|
||||
} else {
|
||||
this.videoUrl = streamInfo[this.player[this.activePlayer][0]]
|
||||
}
|
||||
return this.videoUrl;
|
||||
|
||||
return this.videoUrl
|
||||
},
|
||||
|
||||
playFromStreamInfo: function (realHasAudio, streamInfo) {
|
||||
this.showVideoDialog = true;
|
||||
this.hasaudio = realHasAudio && this.hasaudio;
|
||||
playFromStreamInfo: function(realHasAudio, streamInfo) {
|
||||
this.showVideoDialog = true
|
||||
this.hasaudio = realHasAudio && this.hasaudio
|
||||
if (this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
|
||||
}else {
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
|
||||
});
|
||||
})
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
console.log('关闭视频');
|
||||
if (!!this.$refs[this.activePlayer]){
|
||||
this.$refs[this.activePlayer].pause();
|
||||
}
|
||||
this.videoUrl = '';
|
||||
this.coverPlaying = false;
|
||||
this.showVideoDialog = false;
|
||||
this.stopBroadcast()
|
||||
close: function() {
|
||||
console.log('关闭视频')
|
||||
if (this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].pause()
|
||||
}
|
||||
this.videoUrl = ''
|
||||
this.showVideoDialog = false
|
||||
this.stopBroadcast()
|
||||
},
|
||||
|
||||
copySharedInfo: function (data) {
|
||||
console.log('复制内容:' + data);
|
||||
this.coverPlaying = false;
|
||||
this.tracks = []
|
||||
let _this = this;
|
||||
this.$copyText(data).then(
|
||||
function (e) {
|
||||
_this.$message({
|
||||
showClose: true,
|
||||
message: '复制成功',
|
||||
type: 'success'
|
||||
});
|
||||
},
|
||||
function (e) {
|
||||
_this.$message({
|
||||
showClose: true,
|
||||
message: '复制失败,请手动复制',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
);
|
||||
ptzCamera: function(command) {
|
||||
console.log('云台控制:' + command)
|
||||
this.$store.dispatch('commonChanel/ptz',
|
||||
[
|
||||
this.channelId,
|
||||
command,
|
||||
parseInt(this.controSpeed * 255 / 100),
|
||||
parseInt(this.controSpeed * 255 / 100),
|
||||
parseInt(this.controSpeed * 16 / 100)
|
||||
])
|
||||
},
|
||||
ptzCamera: function (command) {
|
||||
console.log('云台控制:' + command);
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/ptz/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&horizonSpeed=' + parseInt(this.controSpeed * 255/100) + '&verticalSpeed=' + parseInt(this.controSpeed * 255/100) + '&zoomSpeed=' + parseInt(this.controSpeed * 16/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
irisCamera: function(command) {
|
||||
this.$store.dispatch('commonChanel/iris',
|
||||
[
|
||||
this.channelId,
|
||||
command,
|
||||
parseInt(this.controSpeed * 255 / 100)
|
||||
])
|
||||
},
|
||||
irisCamera: function (command) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/fi/iris/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&speed=' + parseInt(this.controSpeed * 255/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
focusCamera: function(command) {
|
||||
this.$store.dispatch('commonChanel/focus',
|
||||
[
|
||||
this.channelId,
|
||||
command,
|
||||
parseInt(this.controSpeed * 255 / 100)
|
||||
])
|
||||
},
|
||||
focusCamera: function (command) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/fi/focus/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&speed=' + parseInt(this.controSpeed * 255/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
// ////////////////////播放器事件处理//////////////////////////
|
||||
videoError: function(e) {
|
||||
console.log('播放器错误:' + JSON.stringify(e))
|
||||
},
|
||||
//////////////////////播放器事件处理//////////////////////////
|
||||
videoError: function (e) {
|
||||
console.log("播放器错误:" + JSON.stringify(e));
|
||||
},
|
||||
copyUrl: function (dropdownItem) {
|
||||
copyUrl: function(dropdownItem) {
|
||||
console.log(dropdownItem)
|
||||
this.$copyText(dropdownItem).then((e) => {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "成功拷贝到粘贴板"
|
||||
message: '成功拷贝到粘贴板'
|
||||
})
|
||||
}, (e) => {
|
||||
|
||||
@ -509,157 +576,123 @@ export default {
|
||||
},
|
||||
getBroadcastStatus() {
|
||||
if (this.broadcastStatus == -2) {
|
||||
return "primary"
|
||||
return 'primary'
|
||||
}
|
||||
if (this.broadcastStatus == -1) {
|
||||
return "primary"
|
||||
return 'primary'
|
||||
}
|
||||
if (this.broadcastStatus == 0) {
|
||||
return "warning"
|
||||
return 'warning'
|
||||
}
|
||||
if (this.broadcastStatus == 1) {
|
||||
return "danger"
|
||||
if (this.broadcastStatus === 1) {
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
},
|
||||
broadcastStatusClick() {
|
||||
if (this.broadcastStatus == -1) {
|
||||
if (this.broadcastStatus === -1) {
|
||||
// 默认状态, 开始
|
||||
this.broadcastStatus = 0
|
||||
// 发起语音对讲
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30&broadcastMode=" + this.broadcastMode
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
let streamInfo = res.data.data.streamInfo;
|
||||
if (document.location.protocol.includes("https")) {
|
||||
this.$store.dispatch('play/broadcastStart', [ this.channelId, this.broadcastMode])
|
||||
.then(data => {
|
||||
const streamInfo = data.streamInfo
|
||||
if (document.location.protocol.includes('https')) {
|
||||
this.startBroadcast(streamInfo.rtcs)
|
||||
} else {
|
||||
this.startBroadcast(streamInfo.rtc)
|
||||
}
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
} else if (this.broadcastStatus === 1) {
|
||||
this.broadcastStatus = -1;
|
||||
this.broadcastStatus = -1
|
||||
this.broadcastRtc.close()
|
||||
}
|
||||
},
|
||||
startBroadcast(url) {
|
||||
// 获取推流鉴权Key
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: '/api/user/userInfo',
|
||||
}).then((res) => {
|
||||
if (res.data.code !== 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "获取推流鉴权Key失败",
|
||||
type: "error",
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
} else {
|
||||
let pushKey = res.data.data.pushKey;
|
||||
this.$store.dispatch('user/getUserInfo')
|
||||
.then((data) => {
|
||||
if (data == null) {
|
||||
this.broadcastStatus = -1
|
||||
return
|
||||
}
|
||||
const pushKey = data.pushKey
|
||||
// 获取推流鉴权KEY
|
||||
url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
|
||||
console.log("开始语音喊话: " + url)
|
||||
url += '&sign=' + crypto.createHash('md5').update(pushKey, 'utf8').digest('hex')
|
||||
console.log('开始语音喊话: ' + url)
|
||||
this.broadcastRtc = new ZLMRTCClient.Endpoint({
|
||||
debug: true, // 是否打印日志
|
||||
zlmsdpUrl: url, //流地址
|
||||
zlmsdpUrl: url, // 流地址
|
||||
simulecast: false,
|
||||
useCamera: false,
|
||||
audioEnable: true,
|
||||
videoEnable: false,
|
||||
recvOnly: false,
|
||||
recvOnly: false
|
||||
})
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT, (e) => {// 获取到了本地流
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT, (e) => { // 获取到了本地流
|
||||
console.error('不支持webrtc', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '不支持webrtc, 无法进行语音喊话',
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
})
|
||||
this.broadcastStatus = -1
|
||||
})
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => { // ICE 协商出错
|
||||
console.error('ICE 协商出错')
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'ICE 协商出错',
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
})
|
||||
this.broadcastStatus = -1
|
||||
})
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {// offer anwser 交换失败
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => { // offer anwser 交换失败
|
||||
console.error('offer anwser 交换失败', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'offer anwser 交换失败' + e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (e) => {// offer anwser 交换失败
|
||||
})
|
||||
this.broadcastStatus = -1
|
||||
})
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (e) => { // offer anwser 交换失败
|
||||
console.log('状态改变', e)
|
||||
if (e === "connecting") {
|
||||
this.broadcastStatus = 0;
|
||||
} else if (e === "connected") {
|
||||
this.broadcastStatus = 1;
|
||||
} else if (e === "disconnected") {
|
||||
this.broadcastStatus = -1;
|
||||
if (e === 'connecting') {
|
||||
this.broadcastStatus = 0
|
||||
} else if (e === 'connected') {
|
||||
this.broadcastStatus = 1
|
||||
} else if (e === 'disconnected') {
|
||||
this.broadcastStatus = -1
|
||||
}
|
||||
});
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, (e) => {// offer anwser 交换失败
|
||||
})
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, (e) => { // offer anwser 交换失败
|
||||
console.log('捕获流失败', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '捕获流失败' + e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
}
|
||||
}).catch((e) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
stopBroadcast() {
|
||||
this.broadcastRtc.close();
|
||||
this.broadcastStatus = -1;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/stop/' + this.deviceId + '/' + this.channelId
|
||||
}).then((res) => {
|
||||
if (res.data.code == 0) {
|
||||
// this.broadcastStatus = -1;
|
||||
// this.broadcastRtc.close()
|
||||
} else {
|
||||
})
|
||||
this.broadcastStatus = -1
|
||||
})
|
||||
}).catch(e => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
message: e,
|
||||
type: 'error'
|
||||
})
|
||||
this.broadcastStatus = -1
|
||||
})
|
||||
},
|
||||
stopBroadcast() {
|
||||
this.broadcastRtc.close()
|
||||
this.broadcastStatus = -1
|
||||
this.$store.dispatch('play/broadcastStop', [this.channelId])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
328
web/src/views/common/channelPlayer/ptzCruising.vue
Normal file
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<div id="ptzCruising">
|
||||
<div style="display: grid; grid-template-columns: 80px auto; line-height: 28px">
|
||||
<span>巡航组号: </span>
|
||||
<el-input
|
||||
v-model="cruiseId"
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="巡航组号"
|
||||
addon-before="巡航组号"
|
||||
addon-after="(1-255)"
|
||||
size="mini"
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
<el-tag
|
||||
v-for="(item, index) in presetList"
|
||||
:key="item.presetId"
|
||||
closable
|
||||
style="margin-right: 1rem; cursor: pointer"
|
||||
@close="delPreset(item, index)"
|
||||
>
|
||||
{{ item.presetName ? item.presetName : item.presetId }}
|
||||
</el-tag>
|
||||
</p>
|
||||
|
||||
<el-form v-if="selectPresetVisible" size="mini" :inline="true">
|
||||
<el-form-item>
|
||||
<el-select v-model="selectPreset" placeholder="请选择预置点">
|
||||
<el-option
|
||||
v-for="item in allPresetList"
|
||||
:key="item.presetId"
|
||||
:label="item.presetName"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="addCruisePoint">保存</el-button>
|
||||
<el-button type="primary" @click="cancelAddCruisePoint">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="selectPresetVisible=true">添加巡航点</el-button>
|
||||
|
||||
<el-form v-if="setSpeedVisible" size="mini" :inline="true">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-if="setSpeedVisible"
|
||||
v-model="cruiseSpeed"
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航速度"
|
||||
addon-before="巡航速度"
|
||||
addon-after="(1-4095)"
|
||||
size="mini"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setCruiseSpeed">保存</el-button>
|
||||
<el-button @click="cancelSetCruiseSpeed">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setSpeedVisible = true">设置巡航速度</el-button>
|
||||
<el-form v-if="setTimeVisible" size="mini" :inline="true">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="cruiseTime"
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航停留时间(秒)"
|
||||
addon-before="巡航停留时间(秒)"
|
||||
addon-after="(1-4095)"
|
||||
style="width: 100%;"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setCruiseTime">保存</el-button>
|
||||
<el-button @click="cancelSetCruiseTime">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setTimeVisible = true">设置巡航时间</el-button>
|
||||
<el-button size="mini" @click="startCruise">开始巡航</el-button>
|
||||
<el-button size="mini" @click="stopCruise">停止巡航</el-button>
|
||||
<el-button size="mini" type="danger" @click="deleteCruise">删除巡航</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'PtzCruising',
|
||||
components: {},
|
||||
props: ['channelId'],
|
||||
data() {
|
||||
return {
|
||||
cruiseId: 1,
|
||||
presetList: [],
|
||||
allPresetList: [],
|
||||
selectPreset: '',
|
||||
inputVisible: false,
|
||||
selectPresetVisible: false,
|
||||
setSpeedVisible: false,
|
||||
setTimeVisible: false,
|
||||
cruiseSpeed: '',
|
||||
cruiseTime: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPresetList()
|
||||
},
|
||||
methods: {
|
||||
getPresetList: function() {
|
||||
this.$store.dispatch('commonChanel/queryPreset', [this.channelId])
|
||||
.then((data) => {
|
||||
this.allPresetList = data
|
||||
})
|
||||
},
|
||||
addCruisePoint: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/addPointForCruise',
|
||||
[this.channelId, this.cruiseId, this.selectPreset.presetId])
|
||||
.then((data) => {
|
||||
this.presetList.push(this.selectPreset)
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.selectPreset = ''
|
||||
this.selectPresetVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelAddCruisePoint: function() {
|
||||
this.selectPreset = ''
|
||||
this.selectPresetVisible = false
|
||||
},
|
||||
delPreset: function(preset, index) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/deletePointForCruise',
|
||||
[this.channelId, this.cruiseId, preset.presetId])
|
||||
.then((data) => {
|
||||
this.presetList.splice(index, 1)
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
deleteCruise: function(preset, index) {
|
||||
this.$confirm('确定删除此巡航组', '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/deletePointForCruise',
|
||||
[this.channelId, this.cruiseId, 0])
|
||||
.then((data) => {
|
||||
this.presetList = []
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
})
|
||||
},
|
||||
setCruiseSpeed: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/setCruiseSpeed',
|
||||
[this.channelId, this.cruiseId, this.cruiseSpeed])
|
||||
.then((data) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.cruiseSpeed = ''
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetCruiseSpeed: function() {
|
||||
this.cruiseSpeed = ''
|
||||
this.setSpeedVisible = false
|
||||
},
|
||||
setCruiseTime: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/setCruiseTime',
|
||||
[this.channelId, this.cruiseId, this.cruiseTime])
|
||||
.then((data) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.setTimeVisible = false
|
||||
this.cruiseTime = ''
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetCruiseTime: function() {
|
||||
this.setTimeVisible = false
|
||||
this.cruiseTime = ''
|
||||
},
|
||||
startCruise: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/startCruise',
|
||||
[this.channelId, this.cruiseId])
|
||||
.then((data) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '发送成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.setTimeVisible = false
|
||||
this.cruiseTime = ''
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
stopCruise: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/stopCruise',
|
||||
[this.channelId, this.cruiseId])
|
||||
.then((data) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '发送成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.setTimeVisible = false
|
||||
this.cruiseTime = ''
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
152
web/src/views/common/channelPlayer/ptzPreset.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div id="ptzPreset" style="width: 100%">
|
||||
<el-tag
|
||||
v-for="item in presetList"
|
||||
:key="item.presetId"
|
||||
closable
|
||||
size="mini"
|
||||
style="margin-right: 1rem; cursor: pointer; margin-bottom: 0.6rem"
|
||||
@close="delPreset(item)"
|
||||
@click="gotoPreset(item)"
|
||||
>
|
||||
{{ item.presetName?item.presetName:item.presetId }}
|
||||
</el-tag>
|
||||
<el-input
|
||||
v-if="inputVisible"
|
||||
ref="saveTagInput"
|
||||
v-model="ptzPresetId"
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="预置位编号"
|
||||
addon-before="预置位编号"
|
||||
addon-after="(1-255)"
|
||||
style="width: 300px; vertical-align: bottom;"
|
||||
size="small"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<el-button @click="addPreset()">保存</el-button>
|
||||
<el-button @click="cancel()">取消</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button v-else size="small" @click="showInput">+ 添加</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'PtzPreset',
|
||||
components: {},
|
||||
props: ['channelId'],
|
||||
data() {
|
||||
return {
|
||||
presetList: [],
|
||||
inputVisible: false,
|
||||
ptzPresetId: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPresetList()
|
||||
},
|
||||
methods: {
|
||||
getPresetList: function() {
|
||||
this.$store.dispatch('commonChanel/queryPreset', [this.channelId])
|
||||
.then(data => {
|
||||
this.presetList = data
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout()
|
||||
})
|
||||
})
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus()
|
||||
})
|
||||
},
|
||||
addPreset: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/addPreset', [this.channelId, this.ptzPresetId])
|
||||
.then(data => {
|
||||
setTimeout(() => {
|
||||
this.inputVisible = false
|
||||
this.ptzPresetId = ''
|
||||
this.getPresetList()
|
||||
}, 1000)
|
||||
}).catch((error) => {
|
||||
loading.close()
|
||||
this.inputVisible = false
|
||||
this.ptzPresetId = ''
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancel: function() {
|
||||
this.inputVisible = false
|
||||
this.ptzPresetId = ''
|
||||
},
|
||||
gotoPreset: function(preset) {
|
||||
console.log(preset)
|
||||
this.$store.dispatch('commonChanel/callPreset', [this.channelId, preset.presetId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '调用成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
delPreset: function(preset) {
|
||||
this.$confirm('确定删除此预置位', '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/deletePreset', [this.channelId, preset.presetId])
|
||||
.then(data => {
|
||||
setTimeout(() => {
|
||||
this.getPresetList()
|
||||
}, 1000)
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
212
web/src/views/common/channelPlayer/ptzScan.vue
Normal file
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div id="ptzScan">
|
||||
<div style="display: grid; grid-template-columns: 80px auto; line-height: 28px">
|
||||
<span>扫描组号: </span>
|
||||
<el-input
|
||||
v-model="scanId"
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="扫描组号"
|
||||
addon-before="扫描组号"
|
||||
addon-after="(1-255)"
|
||||
size="mini"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-button size="mini" @click="setScanLeft">设置左边界</el-button>
|
||||
<el-button size="mini" @click="setScanRight">设置右边界</el-button>
|
||||
|
||||
<el-form v-if="setSpeedVisible" size="mini" :inline="true">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-if="setSpeedVisible"
|
||||
v-model="speed"
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航速度"
|
||||
addon-before="巡航速度"
|
||||
addon-after="(1-4095)"
|
||||
size="mini"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setSpeed">保存</el-button>
|
||||
<el-button @click="cancelSetSpeed">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setSpeedVisible = true">设置扫描速度</el-button>
|
||||
|
||||
<el-button size="mini" @click="startScan">开始自动扫描</el-button>
|
||||
<el-button size="mini" @click="stopScan">停止自动扫描</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'PtzScan',
|
||||
components: {},
|
||||
props: ['channelId'],
|
||||
data() {
|
||||
return {
|
||||
scanId: 1,
|
||||
setSpeedVisible: false,
|
||||
speed: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
setSpeed: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/setSpeedForScan', [this.channelId, this.scanId, this.speed])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.speed = ''
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetSpeed: function() {
|
||||
this.speed = ''
|
||||
this.setSpeedVisible = false
|
||||
},
|
||||
setScanLeft: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/setLeftForScan', [this.channelId, this.scanId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.speed = ''
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
setScanRight: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/setRightForScan', [this.channelId, this.scanId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
this.speed = ''
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
startScan: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/startScan', [this.channelId, this.scanId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '发送成功',
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
stopScan: function() {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$store.dispatch('commonChanel/stopScan', [this.channelId, this.scanId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '发送成功',
|
||||
type: 'success'
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,17 +1,16 @@
|
||||
<template>
|
||||
<div id="ptzScan">
|
||||
<el-form size="mini" :inline="true" >
|
||||
<el-form-item >
|
||||
<el-form size="mini" :inline="true">
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="switchId"
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="开关编号"
|
||||
addonBefore="开关编号"
|
||||
addonAfter="(2-255)"
|
||||
v-model="switchId"
|
||||
addon-before="开关编号"
|
||||
addon-after="(2-255)"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button size="mini" @click="open('on')">开启</el-button>
|
||||
@ -25,18 +24,18 @@
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzScan",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
name: 'PtzScan',
|
||||
components: {},
|
||||
created() {
|
||||
},
|
||||
props: ['channelId'],
|
||||
data() {
|
||||
return {
|
||||
switchId: 1,
|
||||
};
|
||||
switchId: 1
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
open: function (command){
|
||||
open: function(command) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
@ -44,39 +43,26 @@ export default {
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/auxiliary/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
switchId: this.switchId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$store.dispatch('commonChanel/auxiliary', [this.channelId, command, this.switchId])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
@ -8,16 +8,16 @@
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzWiper",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
name: 'PtzWiper',
|
||||
components: {},
|
||||
props: ['channelId'],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
open: function (command){
|
||||
open: function(command) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
@ -25,38 +25,26 @@ export default {
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/wiper/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$store.dispatch('commonChanel/wiper', [this.channelId, command])
|
||||
.then(data => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
message: '保存成功',
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
})
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
@ -1,17 +1,21 @@
|
||||
<template>
|
||||
<div id="ConsoleNodeLoad" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" :legend-visible="true" />
|
||||
<ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend" :events="events" :settings="chartSettings"
|
||||
width="100%" height="100%" :legend-visible="true"/>
|
||||
|
||||
<HasStreamChannel ref="hasStreamChannel"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import veHistogram from 'v-charts/lib/histogram'
|
||||
import HasStreamChannel from "@/views/dialog/hasStreamChannel";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleNodeLoad',
|
||||
components: {
|
||||
veHistogram
|
||||
veHistogram,
|
||||
HasStreamChannel
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -43,6 +47,9 @@ export default {
|
||||
show: true,
|
||||
position: 'top'
|
||||
}
|
||||
},
|
||||
events: {
|
||||
click: this.onClick
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -56,10 +63,14 @@ export default {
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
setData: function (data) {
|
||||
this.chartData.rows = data
|
||||
},
|
||||
onClick(v) {
|
||||
if (v.seriesName === "国标收流") {
|
||||
this.$refs.hasStreamChannel.openDialog();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -248,7 +248,7 @@ export default {
|
||||
videoComponentList: [],
|
||||
currentPlayerInfo: {}, // 当前播放对象
|
||||
updateLooper: 0, // 数据刷新轮训标志
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
channelType: '',
|
||||
online: '',
|
||||
subStream: '',
|
||||
@ -322,7 +322,7 @@ export default {
|
||||
this.$store.dispatch('device/queryChannels', [this.deviceId, {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType
|
||||
}]).then(data => {
|
||||
@ -465,7 +465,7 @@ export default {
|
||||
|
||||
var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.deviceId}`
|
||||
this.$router.push(url).then(() => {
|
||||
this.searchSrt = ''
|
||||
this.searchStr = ''
|
||||
this.channelType = ''
|
||||
this.online = ''
|
||||
this.initParam()
|
||||
@ -477,7 +477,7 @@ export default {
|
||||
{
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType
|
||||
},
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -185,7 +185,7 @@ export default {
|
||||
return {
|
||||
deviceList: [], // 设备列表
|
||||
currentDevice: {}, // 当前操作设备对象
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
online: null,
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, // 数据刷新轮训标志
|
||||
@ -231,7 +231,7 @@ export default {
|
||||
this.$store.dispatch('device/queryDevices', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
status: this.online
|
||||
}).then((data) => {
|
||||
this.total = data.total
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -117,7 +117,7 @@ export default {
|
||||
showDialog: false,
|
||||
channelList: [], // 设备列表
|
||||
currentDevice: {}, // 当前操作设备对象
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
online: null,
|
||||
channelType: '',
|
||||
videoComponentList: [],
|
||||
@ -154,7 +154,7 @@ export default {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online
|
||||
})
|
||||
.then(data => {
|
||||
@ -167,7 +167,7 @@ export default {
|
||||
this.$store.dispatch('commonChanel/getParentList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
channelType: this.channelType,
|
||||
online: this.online
|
||||
})
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
><el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
size="mini"
|
||||
placeholder="关键字"
|
||||
@ -92,7 +92,7 @@ export default {
|
||||
showDialog: false,
|
||||
deviceList: [], // 设备列表
|
||||
currentDevice: {}, // 当前操作设备对象
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
online: null,
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, // 数据刷新轮训标志
|
||||
@ -129,7 +129,7 @@ export default {
|
||||
this.$store.dispatch('device/queryDevices', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
status: this.online
|
||||
})
|
||||
.then(data => {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
size="mini"
|
||||
placeholder="关键字"
|
||||
@ -132,7 +132,7 @@ export default {
|
||||
return {
|
||||
showDialog: false,
|
||||
channelList: [], // 设备列表
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
online: null,
|
||||
channelType: '',
|
||||
winHeight: 580,
|
||||
@ -165,7 +165,7 @@ export default {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online
|
||||
})
|
||||
.then(data => {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
size="mini"
|
||||
placeholder="关键字"
|
||||
@ -144,7 +144,7 @@ export default {
|
||||
return {
|
||||
showDialog: false,
|
||||
channelList: [], // 设备列表
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
online: null,
|
||||
channelType: '',
|
||||
winHeight: 580,
|
||||
@ -177,7 +177,7 @@ export default {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online
|
||||
})
|
||||
.then((data) => {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
v-el-drag-dialog
|
||||
title="视频播放"
|
||||
top="0"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showVideoDialog"
|
||||
@close="close()"
|
||||
|
||||
147
web/src/views/dialog/hasStreamChannel.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-if="showDialog"
|
||||
v-el-drag-dialog
|
||||
:visible.sync="showDialog"
|
||||
title="国标收流列表"
|
||||
width="70%"
|
||||
top="5rem"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form :inline="true" size="mini" @submit.native.prevent>
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="query"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@input="getChannelList"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" :data="channelList" :height="500" stripe>
|
||||
<el-table-column prop="parentDeviceId" label="设备编号" min-width="180"/>
|
||||
<el-table-column prop="parentName" label="设备名称" min-width="180"/>
|
||||
<el-table-column prop="deviceId" label="通道编号" min-width="180"/>
|
||||
<el-table-column prop="name" label="通道名称" min-width="180"/>
|
||||
<el-table-column prop="ptzType" label="云台类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div>{{ scope.row.ptzTypeText }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="120" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button
|
||||
size="medium"
|
||||
icon="el-icon-video-play"
|
||||
type="text"
|
||||
:loading="scope.row.playing"
|
||||
@click="sendDevicePush(scope.row)"
|
||||
>播放
|
||||
</el-button>
|
||||
<el-button
|
||||
size="medium"
|
||||
icon="el-icon-switch-button"
|
||||
type="text"
|
||||
style="color: #f56c6c"
|
||||
@click="stopDevicePush(scope.row)"
|
||||
>停止
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
style="margin-top: 10px; text-align: right"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<devicePlayer ref="devicePlayer"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import devicePlayer from "@/views/dialog/devicePlayer";
|
||||
import elDragDialog from "@/directive/el-drag-dialog";
|
||||
|
||||
export default {
|
||||
name: "HasStreamChannel",
|
||||
directives: {elDragDialog},
|
||||
components: {devicePlayer},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
loading: false,
|
||||
playing: false,
|
||||
channelList: [],
|
||||
query: null,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDialog: function () {
|
||||
this.showDialog = true;
|
||||
this.getChannelList();
|
||||
},
|
||||
getChannelList: function () {
|
||||
this.loading = true;
|
||||
this.$store.dispatch("device/queryHasStreamChannels", {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.query
|
||||
}).then((data) => {
|
||||
this.total = data.total
|
||||
this.channelList = data.list
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val
|
||||
this.getChannelList()
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val
|
||||
this.getChannelList()
|
||||
},
|
||||
sendDevicePush: function (row) {
|
||||
const deviceId = row.parentDeviceId
|
||||
const channelId = row.deviceId
|
||||
this.$set(row, "playing", true)
|
||||
this.$store.dispatch("play/play", [deviceId, channelId])
|
||||
.then((data) => {
|
||||
this.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
|
||||
streamInfo: data,
|
||||
hasAudio: row.hasAudio
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.$set(row, "playing", false)
|
||||
})
|
||||
},
|
||||
stopDevicePush: function (row) {
|
||||
this.$store.dispatch("play/stop", [row.parentDeviceId, row.deviceId]).then(_ => {
|
||||
this.getChannelList();
|
||||
}).catch((error) => {
|
||||
if (error.response.status === 402) {
|
||||
this.getChannelList();
|
||||
} else {
|
||||
this.$message.error({showClose: true, message: error})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="linkChannelRecord" style="width: 100%; background-color: #FFFFFF; display: grid; grid-template-columns: 200px auto;">
|
||||
<div id="linkChannelRecord" style="width: 100%; background-color: #FFFFFF;">
|
||||
<el-dialog v-el-drag-dialog v-if="showDialog" v-loading="dialogLoading" title="通道关联" top="2rem" width="80%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()">
|
||||
<div style="display: grid; grid-template-columns: 100px auto;">
|
||||
<div style="display: grid; grid-template-columns: 100px minmax(0, 1fr);">
|
||||
<el-tabs v-model="hasLink" tab-position="left" style="" @tab-click="search">
|
||||
<el-tab-pane label="未关联" name="false" />
|
||||
<el-tab-pane label="已关联" name="true" />
|
||||
@ -10,7 +10,7 @@
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item label="搜索">
|
||||
<el-input
|
||||
v-model="searchSrt"
|
||||
v-model="searchStr"
|
||||
style="margin-right: 1rem; width: auto;"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search"
|
||||
@ -120,7 +120,7 @@ export default {
|
||||
showDialog: false,
|
||||
chooseData: {},
|
||||
channelList: [],
|
||||
searchSrt: '',
|
||||
searchStr: '',
|
||||
channelType: '',
|
||||
online: '',
|
||||
hasLink: 'false',
|
||||
@ -161,7 +161,7 @@ export default {
|
||||
this.$store.dispatch('recordPlan/queryChannelList', {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
query: this.searchStr,
|
||||
online: this.online,
|
||||
channelType: this.channelType,
|
||||
planId: this.planId,
|
||||
|
||||