Commit 2dc3308f authored by ninglx's avatar ninglx

首页 超限车辆检测 历史播放

parent 2a75496c
syntax = "proto3";
package com.wanji.holo.proto;
option optimize_for = SPEED;
option java_package = "com.wanji.holo.proto";
option java_multiple_files = true;
......@@ -23,7 +21,9 @@ message RealtimeCarInfo {
bool isAggregate = 13; //是否聚合
string aggregatePointNum = 14; //聚合点数量
string dateTime = 15; //车辆时间
map<string, string> extendAttribute = 17;
RoadNet roadNet = 16; //路网数据
map<string, string> extendAttribute = 17; //扩展属性
OverRun overRun = 18;//超限数据
}
//数据类型对象
......@@ -34,20 +34,44 @@ message DataType {
double level= 4;//缩放级别
}
//数据类型对象
message OverRun {
string overType = 1;//超限类型 1超高 2超宽
string timeStamp = 2;//超限预警时间
double vehicleHeight = 3;//车高
double vehicleWidth= 4;//车宽
}
//数据类型对象
message RoadNet {
string crossId = 1;//路口ID
string rid = 2;//路段ID
string laneId = 3;//车道ID
string segmentId= 4;//渠化段ID
}
//数据类型对象
message DetectorState {
string laneId = 1;//车道ID
int32 state = 2;//状态
}
//轨迹信息
message RealtimeCarTrack {
//轨迹
repeated RealtimeCarInfo carInfo = 1;
//数据帧时间
string frameTime = 2;
map<string, int32> detectorState = 3; //检测器状态
}
//分页信息
message Page {
int32 pageNum = 1;//页号
int32 pageSize = 2;//每页大小
int32 totalPageNum = 3;//总页数
int32 pageNum = 1;//页号
int32 pageSize = 2;//每页大小
int32 totalPageNum = 3;//总页数
}
message FrameList {
......
<template>
<div
class="loopVideo"
v-loading="videoLoading"
element-loading-text="加载中..."
v-show="videoUrl"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
<video
:id="`historyVideoComponent${channel}`"
@canplay="videoCanPlay"
:autoplay="autoplay"
muted
controls
loop
class="videoControl"
ref="loopVideoPlayer"
>
<div class="loopVideo" v-loading="videoLoading" element-loading-text="加载中..."
element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)">
<video :id="`historyVideoComponent${channel}`" style="object-fit: fill;" @canplay="videoCanPlay" :autoplay="autoplay" muted controls loop
class="videoControl" ref="loopVideoPlayer">
<source :src="videoUrl" type="video/mp4" />
您的浏览器不支持 video 属性。
</video>
......@@ -65,7 +51,7 @@ export default {
.replaceAll(" ", "_")
.replaceAll(":", "_");
},
destroy() {},
destroy() { },
async getVideoStreamUrl() {
if (this.timeModel.startTime && this.timeModel.endTime) {
try {
......@@ -75,11 +61,15 @@ export default {
starttime: this.replaceTimeGap(this.timeModel.startTime),
endtime: this.replaceTimeGap(this.timeModel.endTime),
});
console.log("response", response);
console.log("video response", response);
this.videoUrl = response.content;
setTimeout(() => {
this.$refs.loopVideoPlayer.load();
}, 200);
// this.videoUrl = 'video/111.mp4';
// setTimeout(() => {
// this.$refs.loopVideoPlayer.load();
// }, 200);
} catch (error) {
console.error(`Failed to get video stream url: ${error}`);
}
......@@ -124,5 +114,4 @@ export default {
// left: 30%;
// top: -14px;
// transform: translateX(-50%);
// }
</style>
// }</style>
......@@ -18,6 +18,7 @@ export default {
},
carTypeGlbMap:{
1:'0',
2:'170',
9:'0',
13:'0',
15:'0',
......
......@@ -31,11 +31,11 @@ export function initWs(data) {
// 接收消息
currentSocket.onmessage = (res) => {
// protobuf 解压数据
if (data.name === "callCar") {
if (data.name.includes("callCar")) {
let reader = new FileReader();
reader.onload = (e) => {
let buf = new Uint8Array(e.target.result);
let responseCarTrack = ResponseCarTrack.decode(buf);
let data1 = new Uint8Array(e.target.result);
let responseCarTrack = ResponseCarTrack.decode(data1);
data.callback(responseCarTrack.carInfo);
};
reader.readAsArrayBuffer(res.data);
......
......@@ -20,7 +20,7 @@ import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI, {
size: 'small',
})
window.wsHost = (process.env.NODE_ENV==='development'?'10.102.1.181:9000':location.host)
window.wsHost = (process.env.NODE_ENV==='development'?'10.102.1.182:9000':location.host)
// 暂时挂载到window 以支持项目之前的ELEMENT.Message写法
window.ELEMENT = ElementUI
// 事件总线
......
......@@ -30,27 +30,30 @@ export default {
});
},
mxRefreshLightWs() {
let targetPoint = turf.point([window.map.getCenter().lng, window.map.getCenter().lat]);
// 取最近点的crossId 判断哪个路口离当前视野中心点最近 请求对应的灯态websocket
let nearest = turf.nearestPoint(targetPoint, this.crossGeo);
let nearestCrossId = nearest.properties.id;
// 如果求得最近路口不是上次的最近路口,则关闭上个ws,请求最新路口ws
if (nearestCrossId !== this.currentNearestCrossId) {
this.currentNearestCrossId = nearestCrossId;
this.closeWs("callLight").then(() => {
let socket = initWs({
// url: `${ws_config.CROSS_CONTROL}${nearestCrossId},holo-web`,
url: `ws://${window.wsHost}/utc/signalStatus/${nearestCrossId},holo-web`,
callback: this.callLight,
name: "callLight",
if (this.shouldShowLight) {
let targetPoint = turf.point([window.map.getCenter().lng, window.map.getCenter().lat]);
// 取最近点的crossId 判断哪个路口离当前视野中心点最近 请求对应的灯态websocket
let nearest = turf.nearestPoint(targetPoint, this.crossGeo);
let nearestCrossId = nearest.properties.id;
// 如果求得最近路口不是上次的最近路口,则关闭上个ws,请求最新路口ws
if (nearestCrossId !== this.currentNearestCrossId) {
this.currentNearestCrossId = nearestCrossId;
this.closeWs("callLight").then(() => {
let socket = initWs({
// url: `${ws_config.CROSS_CONTROL}${nearestCrossId},holo-web`,
url: `ws://${window.wsHost}/utc/signalStatus/${nearestCrossId},holo-web`,
callback: this.callLight,
name: "callLight",
});
socket.ws.onopen = () => {
if (socket.ws.readyState === 1) {
this.sockets.push(socket);
}
};
});
socket.ws.onopen = () => {
if (socket.ws.readyState === 1) {
this.sockets.push(socket);
}
};
});
}
}
},
// 处理灯态
callLight(msg) {
......
......@@ -174,11 +174,13 @@ export default {
radarTimers.push(timer);
},
loadUpdateRadars() {
if (!this.radarShow) {
this.radarShow = true;
this.loadRadars();
} else {
this.updateRadars()
if (this.shouldShowRadar) {
if (!this.radarShow) {
this.radarShow = true;
this.loadRadars();
} else {
this.updateRadars()
}
}
},
updateRadars() {
......
......@@ -112,7 +112,7 @@
</template>
<script>
import { download, getBlob } from "../../../utils/request";
import { getBlob } from "../../../utils/request";
// import fetch from "@/utils/fetch";
import { getReports, getReportsByPage } from "../../../dao/analysis";
import JSZip from "jszip";
......@@ -292,7 +292,7 @@ export default {
link.href = window.URL.createObjectURL(blob);
link.download = report.name;
link.click();
download(url, {}, report.name);
// download(url, {}, report.name);
},
screenReports() {
let filter = this.reportSearchValue;
......
......@@ -107,7 +107,8 @@
<div class="traffics">
<vue-seamless-scroll ref='22' class="warningMsg" :data="overData" :class-option="optionSetting1"
v-show="overData.length">
<li v-for="(item, index) of overData" class="overItem" :key="index">
<li @click="playOverHistoryTrace(item)" v-for="(item, index) of overData" class="overItem"
:key="index">
<div class='topLicense'> <span>预警时间:</span>{{ item.timeStamp }}</div>
<div class='detailMsg'>
<div><span>车牌:</span>{{ item.plateNo }}</div>
......@@ -157,7 +158,7 @@ export default {
dict,
activeName: '11',
overData: [
// { "plateNo": "京A895413", "inDirName": "东向西", "type": "201", "timeStamp": "2024-08-27 15:39:18" },
{ "plateNo": "京A895413", "inDirName": "东向西", "type": "201", "timeStamp": "2024-08-27 15:39:18" },
// { "plateNo": "京A895413", "inDirName": "东向西", "type": "504", "timeStamp": "2024-08-27 15:39:18" },
// { "plateNo": "京A895413", "inDirName": "东向西", "type": "504", "timeStamp": "2024-08-27 15:39:18" },
// { "plateNo": "京A895413", "inDirName": "东向西", "type": "504", "timeStamp": "2024-08-27 15:39:18" },
......@@ -229,13 +230,46 @@ export default {
this.timers.push(timer4);
},
methods: {
timeFormat(date) {
let time = new Date(date);
let year, month, day, hour, min, sec;
year = time.getFullYear();
month =
time.getMonth() + 1 < 10
? "0" + (time.getMonth() + 1)
: time.getMonth() + 1;
day = time.getDate() < 10 ? "0" + time.getDate() : time.getDate();
hour = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();
min =
time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
sec =
time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
let dateTime = `${year}-${month}-${day} ${hour}:${min}:${sec}`; //+year + month + day + hour + min + sec;
return dateTime;
},
playOverHistoryTrace(row) {
let wsSend = {
"dataType": "OVER_RUN", //数据类型【固定值】
"timeStamp": row.timeStamp, //时间
'endTime': this.timeFormat(new Date(new Date(row.timeStamp).getTime() + 1000 * 10)),
"globalId": row.globalId, //车辆ID
"overType": row.type //超限类型
}
console.log('close real time', row, wsSend);
this.$emit("playOverHistoryTrace", wsSend)
},
// 获取超限列表
getOverData() {
getAlarmOverDatas().then(res => {
this.overLoading = false
console.log("超限列表", res.content);
// todo
this.overData = res.content;
if (res.content) {
this.overData = res.content.map(item => {
item.timeStamp = item.timeStamp.replace('T', ' ')
return item
}) || [];
}
})
},
tabClick(e) {
......@@ -642,15 +676,18 @@ export default {
text-overflow: ellipsis;
margin-right: 5px;
}
div:nth-child(1) {
width: 25%;
}
div:nth-child(2) {
width: calc(50% - 10px);
}
div:nth-child(3) {
width: 25%;
margin-right:0
margin-right: 0
}
}
}
......
This diff is collapsed.
......@@ -30,6 +30,12 @@
<div class="detailItem" v-show="!notExceed">
<span class="left">超限类型:</span>{{ overTypeStr }}
</div>
<div class="detailItem" v-show="!notExceed">
<span class="left">宽度:</span>{{ overWidth }}
</div>
<div class="detailItem" v-show="!notExceed">
<span class="left">高度:</span>{{ overHeight }}
</div>
<div class="detailItem">
<span class="left">ID :</span>{{ model.id }}
</div>
......@@ -78,12 +84,21 @@ export default {
},
},
computed: {
overWidth() {
return this.model.overRun?.vehicleWidth || '--'
},
overHeight() {
return this.model.overRun?.vehicleHeight || '--'
},
notExceed() {
return !this.model.overType
if (!this.model.overRun || !this.model.overRun.overType) {
return true
}
return false
},
overTypeStr() {
if (this.model.overType) {
let overArr = this.model.overType.split(',')
if (this.model.overRun?.overType) {
let overArr = this.model.overRun.overType.split(',')
let overStr = ''
for (let t of overArr) {
overStr += dict.overCarType[t]
......@@ -92,7 +107,7 @@ export default {
}
},
overTime() {
return this.model.timeStamp || '--'
return this.model.overRun?.timeStamp || '--'
}
},
beforeDestroy() { },
......
<template>
<div id="holo_historyCameraContainer" class="eventCameraContainer" v-show="true">
<div id="historyCameraContainer" class="historyCameraContainer">
<div class="cameraVideoShow" :key="index" v-for="(item, index) of channels" v-show="true"
:id="`videoVisibles${item}`">
<loop-video class="holo_his" ref="hisVideo" :autoplay="true" :timeModel="timeDuration" :channel="item"></loop-video>
</div>
</div>
</div>
</template>
<script>
import LoopVideo from "../../../components/Standard/loopVideo.vue";
export default {
name: "historyVideos",
components: {
LoopVideo,
},
props: {
channels: {
type: Array,
default() {
return ['2', '9']
}
},
timeDuration: {
type: Object,
default() {
return {
startTime: '',
endTime: ''
}
}
},
},
data() {
return {
}
},
computed: {},
methods: {
// playHisVideos() {
// if (this.$refs.hisVideo) {
// for (let container of this.$refs.hisVideo) {
// container?.startPlay();
// }
// }
// }
},
};
</script>
<style lang="less" scoped>
.eventCameraContainer {
position: absolute;
width: 600px;
height: 200px;
max-width: 600px;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
display: flex;
margin: 0 auto;
border: 1px solid rgba(83, 146, 189, 1);
background: rgba(10, 26, 41, 0.9);
border-radius: 6px;
.holo_his{
border: 1px solid rgba(255,255,255,0.3);
}
.historyCameraContainer {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
height: 100%;
.cameraVideoShow {
width: 50%;
height: 100%;
padding: 4px;
}
.lessWidthVideo {
width: calc(100% - 6px);
}
.normalWidthVideo {
width: 100%;
}
}
.noVideo {
pointer-events: none;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
color: #04396f;
}
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment