优化设备订阅的操作方式

pull/1742/head
648540858 2024-12-30 15:59:15 +08:00
parent 058909197e
commit 0dd2826b9e
10 changed files with 225 additions and 103 deletions

View File

@ -489,4 +489,21 @@ public class DeviceQuery {
public DeviceChannel getRawChannel(int id) {
return deviceChannelService.getRawChannel(id);
}
@GetMapping("/subscribe/catalog")
@Operation(summary = "开启/关闭目录订阅")
@Parameter(name = "id", description = "通道的Id", required = true)
@Parameter(name = "cycle", description = "订阅周期", required = true)
public void subscribeCatalog(int id, int cycle) {
deviceService.subscribeCatalog(id, cycle);
}
@GetMapping("/subscribe/mobile-position")
@Operation(summary = "开启/关闭移动位置订阅")
@Parameter(name = "id", description = "通道的Id", required = true)
@Parameter(name = "cycle", description = "订阅周期", required = true)
@Parameter(name = "interval", description = "报送间隔", required = true)
public void subscribeMobilePosition(int id, int cycle, int interval) {
deviceService.subscribeMobilePosition(id, cycle, interval);
}
}

View File

@ -247,9 +247,8 @@ public interface DeviceMapper {
@Update(value = {" <script>" +
"UPDATE wvp_device " +
"SET update_time=#{updateTime}, custom_name=#{name} , password=#{password}, stream_mode=#{streamMode}" +
", ip=#{ip}, sdp_ip=#{sdpIp}, port=#{port}, charset=#{charset}, subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}" +
", subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}" +
", subscribe_cycle_for_alarm=#{subscribeCycleForAlarm}, ssrc_check=#{ssrcCheck}, as_message_channel=#{asMessageChannel}" +
", ip=#{ip}, sdp_ip=#{sdpIp}, port=#{port}, charset=#{charset}" +
", ssrc_check=#{ssrcCheck}, as_message_channel=#{asMessageChannel}" +
", broadcast_push_after_ack=#{broadcastPushAfterAck}, geo_coord_sys=#{geoCoordSys}, media_server_id=#{mediaServerId}" +
" WHERE id=#{id}"+
" </script>"})
@ -351,4 +350,17 @@ public interface DeviceMapper {
@Select("select wd.* from wvp_device wd left join wvp_device_channel wdc on wdc.data_type = #{dataType} and wd.id = wdc.data_device_id where wdc.device_id = #{channelDeviceId}")
Device getDeviceBySourceChannelDeviceId(@Param("dataType") Integer dataType, @Param("channelDeviceId") String channelDeviceId);
@Update(value = {" <script>" +
" UPDATE wvp_device " +
" SET subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}" +
" WHERE id=#{id}"+
" </script>"})
void updateSubscribeCatalog(Device device);
@Update(value = {" <script>" +
"UPDATE wvp_device " +
"SET subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}" +
" WHERE id=#{id}"+
" </script>"})
void updateSubscribeMobilePosition(Device device);
}

View File

@ -125,4 +125,5 @@ public interface IDeviceChannelService {
List<DeviceChannel> queryChaneListByDeviceDbId(Integer deviceDbId);
List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> deviceDbId);
}

View File

@ -161,4 +161,9 @@ public interface IDeviceService {
Device getDeviceByChannelId(Integer channelId);
Device getDeviceBySourceChannelDeviceId(String requesterId);
void subscribeCatalog(int id, int cycle);
void subscribeMobilePosition(int id, int cycle, int interval);
}

View File

@ -12,7 +12,6 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper;
import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper;
import com.genersoft.iot.vmp.gb28181.dao.PlatformChannelMapper;
import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
import com.genersoft.iot.vmp.gb28181.service.IDeviceService;
import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
@ -35,6 +34,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
@ -263,6 +263,9 @@ public class DeviceServiceImpl implements IDeviceService {
@Override
public boolean removeCatalogSubscribe(Device device, CommonCallback<Boolean> callback) {
if (device == null || device.getSubscribeCycleForCatalog() < 0) {
if (callback != null) {
callback.run(false);
}
return false;
}
log.info("[移除目录订阅]: {}", device.getDeviceId());
@ -272,6 +275,16 @@ public class DeviceServiceImpl implements IDeviceService {
if (runnable instanceof ISubscribeTask) {
ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
subscribeTask.stop(callback);
}else {
log.info("[移除目录订阅]失败,未找到订阅任务 : {}", device.getDeviceId());
if (callback != null) {
callback.run(false);
}
}
}else {
log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId());
if (callback != null) {
callback.run(false);
}
}
dynamicTask.stop(taskKey);
@ -297,6 +310,9 @@ public class DeviceServiceImpl implements IDeviceService {
@Override
public boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback) {
if (device == null || device.getSubscribeCycleForCatalog() < 0) {
if (callback != null) {
callback.run(false);
}
return false;
}
log.info("[移除移动位置订阅]: {}", device.getDeviceId());
@ -306,6 +322,16 @@ public class DeviceServiceImpl implements IDeviceService {
if (runnable instanceof ISubscribeTask) {
ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
subscribeTask.stop(callback);
}else {
log.info("[移除移动位置订阅]失败,未找到订阅任务 : {}", device.getDeviceId());
if (callback != null) {
callback.run(false);
}
}
}else {
log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId());
if (callback != null) {
callback.run(false);
}
}
dynamicTask.stop(taskKey);
@ -421,64 +447,12 @@ public class DeviceServiceImpl implements IDeviceService {
@Override
public void updateCustomDevice(Device device) {
// 订阅状态的修改使用一个单独方法控制,此处不再进行状态修改
Device deviceInStore = deviceMapper.query(device.getId());
if (deviceInStore == null) {
log.warn("更新设备时未找到设备信息");
return;
}
// 目录订阅相关的信息
if (deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) {
if (device.getSubscribeCycleForCatalog() > 0) {
// 若已开启订阅,但订阅周期不同,则先取消
if (deviceInStore.getSubscribeCycleForCatalog() != 0) {
removeCatalogSubscribe(deviceInStore, result->{
// 开启订阅
deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
addCatalogSubscribe(deviceInStore);
// 因为是异步执行,需要在这里更新下数据
deviceMapper.updateCustom(deviceInStore);
redisCatchStorage.updateDevice(deviceInStore);
});
}else {
// 开启订阅
deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
addCatalogSubscribe(deviceInStore);
}
}else if (device.getSubscribeCycleForCatalog() == 0) {
// 取消订阅
deviceInStore.setSubscribeCycleForCatalog(0);
removeCatalogSubscribe(deviceInStore, null);
}
}
// 移动位置订阅相关的信息
if (deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) {
if (device.getSubscribeCycleForMobilePosition() > 0) {
// 若已开启订阅,但订阅周期不同,则先取消
if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) {
removeMobilePositionSubscribe(deviceInStore, result->{
// 开启订阅
deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval());
addMobilePositionSubscribe(deviceInStore);
// 因为是异步执行,需要在这里更新下数据
deviceMapper.updateCustom(deviceInStore);
redisCatchStorage.updateDevice(deviceInStore);
});
}else {
// 开启订阅
deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval());
addMobilePositionSubscribe(deviceInStore);
}
}else if (device.getSubscribeCycleForMobilePosition() == 0) {
// 取消订阅
deviceInStore.setSubscribeCycleForMobilePosition(0);
deviceInStore.setMobilePositionSubmissionInterval(0);
removeMobilePositionSubscribe(deviceInStore, null);
}
}
if (deviceInStore.getGeoCoordSys() != null) {
// 坐标系变化需要重新计算GCJ02坐标和WGS84坐标
if (!deviceInStore.getGeoCoordSys().equals(device.getGeoCoordSys())) {
@ -547,4 +521,68 @@ public class DeviceServiceImpl implements IDeviceService {
public Device getDeviceBySourceChannelDeviceId(String channelId) {
return deviceMapper.getDeviceBySourceChannelDeviceId(ChannelDataType.GB28181.value,channelId);
}
@Override
public void subscribeCatalog(int id, int cycle) {
Device device = deviceMapper.query(id);
Assert.notNull(device, "未找到设备");
if (device.getSubscribeCycleForCatalog() == cycle) {
return;
}
// 目录订阅相关的信息
if (device.getSubscribeCycleForCatalog() > 0) {
// 订阅周期不同,则先取消
removeCatalogSubscribe(device, result->{
device.setSubscribeCycleForCatalog(cycle);
if (cycle > 0) {
// 开启订阅
addCatalogSubscribe(device);
}
// 因为是异步执行,需要在这里更新下数据
deviceMapper.updateSubscribeCatalog(device);
redisCatchStorage.updateDevice(device);
});
}else {
// 开启订阅
device.setSubscribeCycleForCatalog(cycle);
addCatalogSubscribe(device);
deviceMapper.updateSubscribeCatalog(device);
redisCatchStorage.updateDevice(device);
}
}
@Override
public void subscribeMobilePosition(int id, int cycle, int interval) {
Device device = deviceMapper.query(id);
Assert.notNull(device, "未找到设备");
if (device.getSubscribeCycleForMobilePosition() == cycle) {
return;
}
// 目录订阅相关的信息
if (device.getSubscribeCycleForMobilePosition() > 0) {
// 订阅周期已经开启,则先取消
removeMobilePositionSubscribe(device, result->{
// 开启订阅
device.setSubscribeCycleForMobilePosition(cycle);
device.setMobilePositionSubmissionInterval(interval);
if (cycle > 0) {
addMobilePositionSubscribe(device);
}
// 因为是异步执行,需要在这里更新下数据
deviceMapper.updateSubscribeMobilePosition(device);
redisCatchStorage.updateDevice(device);
});
}else {
// 订阅未开启
device.setSubscribeCycleForMobilePosition(cycle);
device.setMobilePositionSubmissionInterval(interval);
// 开启订阅
addMobilePositionSubscribe(device);
// 因为是异步执行,需要在这里更新下数据
deviceMapper.updateSubscribeMobilePosition(device);
redisCatchStorage.updateDevice(device);
}
}
}

View File

@ -4,10 +4,10 @@
<div class="page-title">设备列表</div>
<div class="page-header-btn">
搜索:
<el-input @input="getDeviceList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
<el-input @input="initData" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
在线状态:
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getDeviceList" v-model="online" placeholder="请选择"
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="initData" v-model="online" placeholder="请选择"
default-first-option>
<el-option label="全部" value=""></el-option>
<el-option label="在线" value="true"></el-option>
@ -22,10 +22,10 @@
</div>
</div>
<!--设备列表-->
<el-table size="medium" :data="deviceList" style="width: 100%;font-size: 12px;" :height="winHeight" header-row-class-name="table-header">
<el-table size="medium" :data="deviceList" style="width: 100%;font-size: 12px;" :height="winHeight" header-row-class-name="table-header">
<el-table-column prop="name" label="名称" min-width="160">
</el-table-column>
<el-table-column prop="deviceId" label="设备编号" min-width="200" >
<el-table-column prop="deviceId" label="设备编号" min-width="160" >
</el-table-column>
<el-table-column label="地址" min-width="160" >
<template v-slot:default="scope">
@ -35,9 +35,9 @@
</div>
</template>
</el-table-column>
<el-table-column prop="manufacturer" label="厂家" min-width="120" >
<el-table-column prop="manufacturer" label="厂家" min-width="100" >
</el-table-column>
<el-table-column prop="transport" label="信令传输模式" min-width="120" >
<el-table-column prop="transport" label="信令传输模式" min-width="100" >
</el-table-column>
<el-table-column label="流传输模式" min-width="160" >
<template v-slot:default="scope">
@ -48,9 +48,12 @@
</el-select>
</template>
</el-table-column>
<el-table-column prop="channelCount" label="通道数" min-width="120" >
<el-table-column label="通道数" min-width="100" >
<template v-slot:default="scope">
<span style="font-size: 1rem">{{scope.row.channelCount}}</span>
</template>
</el-table-column>
<el-table-column label="状态" min-width="120">
<el-table-column label="状态" min-width="100">
<template v-slot:default="scope">
<div slot="reference" class="name-wrapper">
<el-tag size="medium" v-if="scope.row.onLine">线</el-tag>
@ -58,18 +61,20 @@
</div>
</template>
</el-table-column>
<el-table-column prop="keepaliveTime" label="最近心跳" min-width="160" >
</el-table-column>
<el-table-column prop="registerTime" label="最近注册" min-width="160">
</el-table-column>
<!-- <el-table-column prop="updateTime" label="更新时间" width="140">-->
<!-- </el-table-column>-->
<!-- <el-table-column prop="createTime" label="创建时间" width="140">-->
<!-- </el-table-column>-->
<el-table-column label="操作" min-width="380" fixed="right">
<el-table-column label="订阅" min-width="260" >
<template v-slot:default="scope">
<el-button type="text" size="medium" v-bind:disabled="scope.row.online==0" icon="el-icon-refresh" @click="refDevice(scope.row)"
<el-checkbox label="目录" :checked="scope.row.subscribeCycleForCatalog > 0" @change="(e)=>subscribeForCatalog(scope.row.id, e)"></el-checkbox>
<el-checkbox label="位置" :checked="scope.row.subscribeCycleForMobilePosition > 0" @change="(e)=>subscribeForMobilePosition(scope.row.id, e)"></el-checkbox>
<el-checkbox label="报警" disabled :checked="scope.row.subscribeCycleForAlarm > 0"></el-checkbox>
</template>
</el-table-column>
<el-table-column prop="keepaliveTime" label="最近心跳" min-width="140" >
</el-table-column>
<el-table-column prop="registerTime" label="最近注册" min-width="140">
</el-table-column>
<el-table-column label="操作" min-width="300" fixed="right">
<template v-slot:default="scope">
<el-button type="text" size="medium" v-bind:disabled="scope.row.online===0" icon="el-icon-refresh" @click="refDevice(scope.row)"
@mouseover="getTooltipContent(scope.row.deviceId)">刷新
</el-button>
<el-divider direction="vertical"></el-divider>
@ -79,13 +84,13 @@
<el-divider direction="vertical"></el-divider>
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)"></el-button>
<el-divider direction="vertical"></el-divider>
<el-button size="medium" icon="el-icon-delete" type="text" @click="deleteDevice(scope.row)" style="color: #f56c6c">删除</el-button>
<el-divider direction="vertical"></el-divider>
<el-dropdown @command="(command)=>{moreClick(command, scope.row)}">
<el-button size="medium" type="text" >
操作<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-menu>
<el-dropdown-item command="delete" style="color: #f56c6c">
删除</el-dropdown-item>
<el-dropdown-item command="setGuard" v-bind:disabled="!scope.row.onLine">
布防</el-dropdown-item>
<el-dropdown-item command="resetGuard" v-bind:disabled="!scope.row.onLine">
@ -164,6 +169,8 @@ export default {
},
methods: {
initData: function () {
this.currentPage = 1;
this.total= 0;
this.getDeviceList();
},
currentChange: function (val) {
@ -346,6 +353,8 @@ export default {
this.setGuard(itemData)
}else if (command === "resetGuard") {
this.resetGuard(itemData)
}else if (command === "delete") {
this.deleteDevice(itemData)
}
},
setGuard: function (itemData) {
@ -394,6 +403,67 @@ export default {
})
});
},
subscribeForCatalog: function (data, value) {
console.log(data)
console.log(value)
this.$axios({
method: 'get',
url: `/api/device/query/subscribe/catalog`,
params: {
id: data,
cycle: value?60:0
}
}).then( (res)=> {
if (res.data.code === 0) {
this.$message.success({
showClose: true,
message: value?"订阅成功":"取消订阅成功"
})
}else {
this.$message.error({
showClose: true,
message: res.data.msg
})
}
}).catch( (error)=> {
this.$message.error({
showClose: true,
message: error.message
})
});
},
subscribeForMobilePosition: function (data, value) {
console.log(data)
console.log(value)
this.$axios({
method: 'get',
url: `/api/device/query/subscribe/mobile-position`,
params: {
id: data,
cycle: value?60:0,
interval: value?5:0
}
}).then( (res)=> {
if (res.data.code === 0) {
this.$message.success({
showClose: true,
message: value?"订阅成功":"取消订阅成功"
})
}else {
this.$message.error({
showClose: true,
message: res.data.msg
})
}
}).catch( (error)=> {
this.$message.error({
showClose: true,
message: error.message
})
});
},
}
};

View File

@ -64,7 +64,7 @@
<el-button size="mini">
倍速 <i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-menu>
<el-dropdown-item command="0.25">0.25倍速</el-dropdown-item>
<el-dropdown-item command="0.5">0.5倍速</el-dropdown-item>
<el-dropdown-item command="1.0">1倍速</el-dropdown-item>

View File

@ -141,7 +141,7 @@
<el-button size="medium" type="text" >
更多<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-menu>
<el-dropdown-item command="records" v-bind:disabled="device == null || device.online === 0">
设备录像</el-dropdown-item>
<el-dropdown-item command="cloudRecords" v-bind:disabled="device == null || device.online === 0" >

View File

@ -43,21 +43,6 @@
<el-option key="UTF-8" label="UTF-8" value="utf-8"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="地理坐标系" prop="geoCoordSys" >-->
<!-- <el-select v-model="form.geoCoordSys" style="float: left; width: 100%" >-->
<!-- <el-option key="WGS84" label="WGS84" value="WGS84"></el-option>-->
<!-- <el-option key="GCJ02" label="GCJ02" value="GCJ02"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item v-if="this.isEdit" label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" >
<el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input>
</el-form-item>
<el-form-item v-if="this.isEdit" label="移动位置订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" >
<el-input v-model="form.subscribeCycleForMobilePosition" clearable ></el-input>
</el-form-item>
<el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" >
<el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input>
</el-form-item>
<el-form-item label="其他选项">
<el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox>
<el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox>
@ -122,12 +107,6 @@ export default {
onSubmit: function () {
console.log("onSubmit");
console.log(this.form);
this.form.subscribeCycleForCatalog = this.form.subscribeCycleForCatalog||0
this.form.subscribeCycleForMobilePosition = this.form.subscribeCycleForMobilePosition||0
this.form.mobilePositionSubmissionInterval = this.form.mobilePositionSubmissionInterval||0
if (this.form.mobilePositionSubmissionInterval === 0) {
this.form.mobilePositionSubmissionInterval = 5
}
this.$axios({
method: 'post',
url:`/api/device/query/device/${this.isEdit?'update':'add'}/`,

View File

@ -57,7 +57,7 @@
<el-button>
更多地址<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-menu>
<el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv">
<el-tag>FLV:</el-tag>
<span>{{ streamInfo.flv }}</span>