Compare commits

...

5 Commits

Author SHA1 Message Date
阿斌
c0bf55adfd
Pre Merge pull request !36 from 阿斌/N/A 2026-05-19 15:36:00 +00:00
lin
ce81a0724f 国标录像回放支持切换播放器 2026-05-19 10:59:40 +08:00
lin
459a8cd77a 部标-修复0003注销消息处理 2026-05-18 10:39:41 +08:00
lin
75575f939c 部标-完善位置日志打印 2026-05-18 09:28:55 +08:00
阿斌
da98101aac
update src/main/resources/civilCode.csv.
行政规划错误。江苏南通海门市,修改为海门区,浙江杭州删除下城区、江干区,新增钱塘区,临平区

Signed-off-by: 阿斌 <38912748@qq.com>
2024-12-15 08:58:42 +00:00
10 changed files with 119 additions and 43 deletions

View File

@ -12,17 +12,12 @@ import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger; import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* @author QingtaiJiang * @author QingtaiJiang
@ -93,6 +88,8 @@ public class Jt808Decoder extends ByteToMessageDecoder {
} }
/** /**
* 转义与验证校验码 * 转义与验证校验码
* *

View File

@ -1,13 +1,13 @@
package com.genersoft.iot.vmp.jt1078.proc.request; package com.genersoft.iot.vmp.jt1078.proc.request;
import com.genersoft.iot.vmp.jt1078.annotation.MsgId; import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
import com.genersoft.iot.vmp.jt1078.bean.JTDevice;
import com.genersoft.iot.vmp.jt1078.event.DeviceUpdateEvent;
import com.genersoft.iot.vmp.jt1078.proc.Header; import com.genersoft.iot.vmp.jt1078.proc.Header;
import com.genersoft.iot.vmp.jt1078.proc.response.Rs; import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service; import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service;
import com.genersoft.iot.vmp.jt1078.session.Session; import com.genersoft.iot.vmp.jt1078.session.Session;
import com.genersoft.iot.vmp.jt1078.session.SessionManager;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
@ -20,27 +20,30 @@ import org.springframework.context.ApplicationEvent;
@MsgId(id = "0003") @MsgId(id = "0003")
public class J0003 extends Re { public class J0003 extends Re {
int respNo; private JTDevice deviceForUpdate;
String respId;
int result;
@Override @Override
protected Rs decode0(ByteBuf buf, Header header, Session session) { protected Rs decode0(ByteBuf buf, Header header, Session session) {
respNo = buf.readUnsignedShort();
respId = ByteBufUtil.hexDump(buf.readSlice(2));
result = buf.readUnsignedByte();
log.info("[JT-注销] 设备: {}", header.getPhoneNumber()); log.info("[JT-注销] 设备: {}", header.getPhoneNumber());
return null; return null;
} }
@Override @Override
protected Rs handler(Header header, Session session, Ijt1078Service service) { protected Rs handler(Header header, Session session, Ijt1078Service service) {
SessionManager.INSTANCE.response(header.getPhoneNumber(), "0001", (long) respNo, result); // SessionManager.INSTANCE.response(header.getPhoneNumber(), "0001", (long) respNo, result);
JTDevice device = service.getDevice(header.getPhoneNumber());
if (device != null && device.isStatus()) {
deviceForUpdate = device;
deviceForUpdate.setStatus(false);
service.updateDevice(device);
}
return null; return null;
} }
@Override @Override
public ApplicationEvent getEvent() { public ApplicationEvent getEvent() {
return null; DeviceUpdateEvent registerEvent = new DeviceUpdateEvent(this);
registerEvent.setDevice(deviceForUpdate);
return registerEvent;
} }
} }

View File

@ -25,7 +25,9 @@ public class J0200 extends Re {
@Override @Override
protected Rs decode0(ByteBuf buf, Header header, Session session) { protected Rs decode0(ByteBuf buf, Header header, Session session) {
positionInfo = JTPositionBaseInfo.decode(buf); positionInfo = JTPositionBaseInfo.decode(buf);
log.debug("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString()); if (log.isDebugEnabled()) {
log.debug("[JT-位置汇报]: phoneNumber={} {}", header.getPhoneNumber(), positionInfo.toSimpleString());
}
// 读取附加信息 // 读取附加信息
// JTPositionAdditionalInfo positionAdditionalInfo = new JTPositionAdditionalInfo(); // JTPositionAdditionalInfo positionAdditionalInfo = new JTPositionAdditionalInfo();
// Map<Integer, byte[]> additionalMsg = new HashMap<>(); // Map<Integer, byte[]> additionalMsg = new HashMap<>();

View File

@ -861,7 +861,7 @@
320623,如东县,3206 320623,如东县,3206
320681,启东市,3206 320681,启东市,3206
320682,如皋市,3206 320682,如皋市,3206
320684,海门,3206 320684,海门,3206
320685,海安市,3206 320685,海安市,3206
3207,连云港市,32 3207,连云港市,32
320703,连云区,3207 320703,连云区,3207
@ -918,8 +918,6 @@
33,浙江省, 33,浙江省,
3301,杭州市,33 3301,杭州市,33
330102,上城区,3301 330102,上城区,3301
330103,下城区,3301
330104,江干区,3301
330105,拱墅区,3301 330105,拱墅区,3301
330106,西湖区,3301 330106,西湖区,3301
330108,滨江区,3301 330108,滨江区,3301
@ -927,6 +925,8 @@
330110,余杭区,3301 330110,余杭区,3301
330111,富阳区,3301 330111,富阳区,3301
330112,临安区,3301 330112,临安区,3301
330113,临平区,3301
330114,钱塘区,3301
330122,桐庐县,3301 330122,桐庐县,3301
330127,淳安县,3301 330127,淳安县,3301
330182,建德市,3301 330182,建德市,3301

1 编号 名称 上级
861 320623 如东县 3206
862 320681 启东市 3206
863 320682 如皋市 3206
864 320684 海门市 海门区 3206
865 320685 海安市 3206
866 3207 连云港市 32
867 320703 连云区 3207
918 33 浙江省
919 3301 杭州市 33
920 330102 上城区 3301
330103 下城区 3301
330104 江干区 3301
921 330105 拱墅区 3301
922 330106 西湖区 3301
923 330108 滨江区 3301
925 330110 余杭区 3301
926 330111 富阳区 3301
927 330112 临安区 3301
928 330113 临平区 3301
929 330114 钱塘区 3301
930 330122 桐庐县 3301
931 330127 淳安县 3301
932 330182 建德市 3301

View File

@ -5,10 +5,14 @@
spring: spring:
spring:
threads:
virtual:
enabled: true
cache: cache:
type: redis type: redis
thymeleaf: thymeleaf:
cache: false cache: false
# 设置接口超时时间 # 设置接口超时时间
mvc: mvc:
async: async:
@ -181,9 +185,6 @@ media:
# 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载 0 表示不使用 # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载 0 表示不使用
record-assist-port: 0 record-assist-port: 0
# [可选] 日志配置, 如果不需要在jar外修改日志内容那么可以不配置此项
logging:
config: classpath:logback-spring.xml
# [根据业务需求配置] # [根据业务需求配置]
user-settings: user-settings:
@ -281,3 +282,12 @@ springdoc:
enabled: false enabled: false
swagger-ui: swagger-ui:
enabled: false enabled: false
logging:
level:
# 日志级别 debug/info/warn/error
root: info
logback:
rollingpolicy:
# 日志文件最大历史保留天数默认30天
max-history: 30

View File

@ -5,7 +5,7 @@
@dblclick="fullscreenSwich" @dblclick="fullscreenSwich"
> >
<div style="width:100%; padding-top: 56.25%; position: relative;" /> <div style="width:100%; padding-top: 56.25%; position: relative;" />
<div id="buttonsBox" class="buttons-box" > <div id="buttonsBox" class="buttons-box" v-if="showButton">
<div class="buttons-box-left"> <div class="buttons-box-left">
<i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick" /> <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick" />
<i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause" /> <i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause" />

View File

@ -1,6 +1,6 @@
<template> <template>
<div id="rtcPlayer"> <div id="rtcPlayer">
<video id="webRtcPlayerBox" controls autoplay style="text-align:left;"> <video id="webRtcPlayerBox" :controls="showControls" autoplay style="text-align:left;">
Your browser is too old which doesn't support HTML5 video. Your browser is too old which doesn't support HTML5 video.
</video> </video>
</div> </div>
@ -10,7 +10,12 @@
let webrtcPlayer = null let webrtcPlayer = null
export default { export default {
name: 'RtcPlayer', name: 'RtcPlayer',
props: ['videoUrl', 'error', 'hasaudio'], props: {
videoUrl: { type: String, default: '' },
error: { type: String, default: '' },
hasaudio: { type: Boolean, default: false },
showControls: { type: Boolean, default: true }
},
data() { data() {
return { return {
timer: null timer: null
@ -97,10 +102,12 @@ export default {
} }
#rtcPlayer{ #rtcPlayer{
width: 100%; width: 100%;
height: 100%;
} }
#webRtcPlayerBox{ #webRtcPlayerBox{
width: 100%; width: 100%;
max-height: 56vh; height: 100%;
max-height: 100%;
background-color: #000; background-color: #000;
} }
/* 隐藏logo */ /* 隐藏logo */

View File

@ -49,8 +49,8 @@
</div> </div>
</div> </div>
</div> </div>
<div id="playerBox" style="width: 100%"> <div id="playerBox" style="width: 100%;">
<div class="playBox" style="height: calc(100% - 90px); width: 100%; background-color: #000000"> <div class="playBox" style="height: calc(100vh - 220px); width: 100%; background-color: #000000">
<div <div
v-if="playLoading" v-if="playLoading"
style="position: relative; left: calc(50% - 32px); top: 43%; z-index: 100;color: #fff;float: left; text-align: center;" style="position: relative; left: calc(50% - 32px); top: 43%; z-index: 100;color: #fff;float: left; text-align: center;"
@ -58,10 +58,32 @@
<div class="el-icon-loading" /> <div class="el-icon-loading" />
<div style="width: 100%; line-height: 2rem">正在加载</div> <div style="width: 100%; line-height: 2rem">正在加载</div>
</div> </div>
<h265web <jessibucaPlayer
v-if="activePlayer === 'jessibuca'"
ref="recordVideoPlayer"
:has-audio="true"
:height="'calc(100vh - 90px)'"
:show-button="false"
autoplay
@playStatusChange="playingChange"
@playTimeChange="showPlayTimeChange"
/>
<rtcPlayer
v-if="activePlayer === 'webRTC'"
ref="recordVideoPlayer" ref="recordVideoPlayer"
:video-url="videoUrl" :video-url="videoUrl"
:height="'calc(100vh - 250px)'" :has-audio="true"
:show-controls="false"
style="height: calc(100vh - 220px)"
autoplay
@playStatusChange="playingChange"
@playTimeChange="showPlayTimeChange"
/>
<h265web
v-if="activePlayer === 'h265web'"
ref="recordVideoPlayer"
:video-url="videoUrl"
:height="'calc(100vh - 220px)'"
:show-button="false" :show-button="false"
:has-audio="true" :has-audio="true"
@playStatusChange="playingChange" @playStatusChange="playingChange"
@ -181,6 +203,18 @@
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
<div class="record-play-control" style="background-color: transparent; box-shadow: 0 0 10px transparent"> <div class="record-play-control" style="background-color: transparent; box-shadow: 0 0 10px transparent">
<el-dropdown @command="changePlayer">
<a
target="_blank"
class="record-play-control-item record-play-control-speed"
title="切换播放器"
>{{ playerLabel }}</a>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="jessibuca">Jessibuca</el-dropdown-item>
<el-dropdown-item command="webRTC">WebRTC</el-dropdown-item>
<el-dropdown-item command="h265web">H265Web</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<a <a
v-if="!isFullScreen" v-if="!isFullScreen"
target="_blank" target="_blank"
@ -208,6 +242,8 @@
<script> <script>
import h265web from '../../common/h265web.vue' import h265web from '../../common/h265web.vue'
import jessibucaPlayer from '../../common/jessibuca.vue'
import rtcPlayer from '../../common/rtcPlayer.vue'
import VideoTimeline from '../../common/VideoTimeLine/index.vue' import VideoTimeline from '../../common/VideoTimeLine/index.vue'
import recordDownload from '../../dialog/recordDownload.vue' import recordDownload from '../../dialog/recordDownload.vue'
import ChooseTimeRange from '../../dialog/chooseTimeRange.vue' import ChooseTimeRange from '../../dialog/chooseTimeRange.vue'
@ -217,7 +253,7 @@ import screenfull from 'screenfull'
export default { export default {
name: 'DeviceRecord', name: 'DeviceRecord',
components: { components: {
h265web, VideoTimeline, recordDownload, ChooseTimeRange h265web, jessibucaPlayer, rtcPlayer, VideoTimeline, recordDownload, ChooseTimeRange
}, },
data() { data() {
return { return {
@ -251,6 +287,12 @@ export default {
timelineControl: false, timelineControl: false,
showOtherSpeed: true, showOtherSpeed: true,
timeSegments: [], timeSegments: [],
activePlayer: 'jessibuca',
playerUrls: {
jessibuca: ['ws_flv', 'wss_flv'],
webRTC: ['rtc', 'rtcs'],
h265web: ['ws_flv', 'wss_flv']
},
pickerOptions: { pickerOptions: {
cellClassName: (date) => { cellClassName: (date) => {
// //
@ -266,6 +308,10 @@ export default {
} }
}, },
computed: { computed: {
playerLabel() {
const labels = { jessibuca: 'Jessibuca', webRTC: 'WebRTC', h265web: 'H265Web' }
return labels[this.activePlayer] || 'Jessibuca'
},
boxStyle() { boxStyle() {
if (this.showSidebar) { if (this.showSidebar) {
return { return {
@ -300,6 +346,18 @@ export default {
window.removeEventListener('beforeunload', this.stopPlayRecord) window.removeEventListener('beforeunload', this.stopPlayRecord)
}, },
methods: { methods: {
changePlayer(player) {
if (this.activePlayer === player) return
this.activePlayer = player
if (this.streamInfo) {
this.videoUrl = this.getUrlByStreamInfo()
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
}
},
sidebarControl() { sidebarControl() {
this.showSidebar = !this.showSidebar this.showSidebar = !this.showSidebar
}, },
@ -468,14 +526,20 @@ export default {
this.streamInfo = data this.streamInfo = data
this.videoUrl = this.getUrlByStreamInfo() this.videoUrl = this.getUrlByStreamInfo()
this.hasAudio = this.streamInfo.tracks && this.streamInfo.tracks.length > 1 this.hasAudio = this.streamInfo.tracks && this.streamInfo.tracks.length > 1
this.$nextTick(() => {
if (this.$refs.recordVideoPlayer) {
this.$refs.recordVideoPlayer.play(this.videoUrl)
}
})
}) })
} }
}, },
getUrlByStreamInfo() { getUrlByStreamInfo() {
const keys = this.playerUrls[this.activePlayer]
if (location.protocol === 'https:') { if (location.protocol === 'https:') {
this.videoUrl = this.streamInfo['wss_flv'] this.videoUrl = this.streamInfo[keys[1]]
} else { } else {
this.videoUrl = this.streamInfo['ws_flv'] this.videoUrl = this.streamInfo[keys[0]]
} }
return this.videoUrl return this.videoUrl
}, },

View File

@ -1,4 +1,3 @@
drop table IF EXISTS wvp_jt_terminal;
create table IF NOT EXISTS wvp_jt_terminal ( create table IF NOT EXISTS wvp_jt_terminal (
id serial primary key, id serial primary key,
phone_number character varying(50), phone_number character varying(50),
@ -23,7 +22,6 @@ create table IF NOT EXISTS wvp_jt_terminal (
constraint uk_jt_device_id_device_id unique (id, phone_number) constraint uk_jt_device_id_device_id unique (id, phone_number)
); );
drop table IF EXISTS wvp_jt_channel;
create table IF NOT EXISTS wvp_jt_channel ( create table IF NOT EXISTS wvp_jt_channel (
id serial primary key, id serial primary key,
terminal_db_id integer, terminal_db_id integer,
@ -141,8 +139,6 @@ call wvp_202601025();
DROP PROCEDURE wvp_202601025; DROP PROCEDURE wvp_202601025;
DELIMITER ; DELIMITER ;
drop table IF EXISTS wvp_alarm;
create table IF NOT EXISTS wvp_alarm ( create table IF NOT EXISTS wvp_alarm (
id serial primary key COMMENT '主键ID', id serial primary key COMMENT '主键ID',
channel_id integer COMMENT '关联通道的数据库id', channel_id integer COMMENT '关联通道的数据库id',

View File

@ -1,4 +1,3 @@
drop table IF EXISTS wvp_jt_terminal;
create table IF NOT EXISTS wvp_jt_terminal ( create table IF NOT EXISTS wvp_jt_terminal (
id serial primary key, id serial primary key,
phone_number character varying(50), phone_number character varying(50),
@ -22,7 +21,6 @@ create table IF NOT EXISTS wvp_jt_terminal (
sdp_ip character varying(50), sdp_ip character varying(50),
constraint uk_jt_device_id_device_id unique (id, phone_number) constraint uk_jt_device_id_device_id unique (id, phone_number)
); );
drop table IF EXISTS wvp_jt_channel;
create table IF NOT EXISTS wvp_jt_channel ( create table IF NOT EXISTS wvp_jt_channel (
id serial primary key, id serial primary key,
terminal_db_id integer, terminal_db_id integer,
@ -48,7 +46,6 @@ drop index uk_media_server_unique_ip_http_port on wvp_media_server;
ALTER table wvp_device DROP COLUMN IF EXISTS register_time; ALTER table wvp_device DROP COLUMN IF EXISTS register_time;
ALTER table wvp_device DROP COLUMN IF EXISTS keepalive_time; ALTER table wvp_device DROP COLUMN IF EXISTS keepalive_time;
drop table IF EXISTS wvp_alarm;
create table IF NOT EXISTS wvp_alarm ( create table IF NOT EXISTS wvp_alarm (
id serial primary key, id serial primary key,
channel_id integer, channel_id integer,