Commit 2dc3308f authored by ninglx's avatar ninglx

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

parent 2a75496c
syntax = "proto3"; syntax = "proto3";
package com.wanji.holo.proto; package com.wanji.holo.proto;
option optimize_for = SPEED; option optimize_for = SPEED;
option java_package = "com.wanji.holo.proto"; option java_package = "com.wanji.holo.proto";
option java_multiple_files = true; option java_multiple_files = true;
...@@ -23,7 +21,9 @@ message RealtimeCarInfo { ...@@ -23,7 +21,9 @@ message RealtimeCarInfo {
bool isAggregate = 13; //是否聚合 bool isAggregate = 13; //是否聚合
string aggregatePointNum = 14; //聚合点数量 string aggregatePointNum = 14; //聚合点数量
string dateTime = 15; //车辆时间 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 { ...@@ -34,20 +34,44 @@ message DataType {
double level= 4;//缩放级别 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 { message RealtimeCarTrack {
//轨迹 //轨迹
repeated RealtimeCarInfo carInfo = 1; repeated RealtimeCarInfo carInfo = 1;
//数据帧时间 //数据帧时间
string frameTime = 2; string frameTime = 2;
map<string, int32> detectorState = 3; //检测器状态 map<string, int32> detectorState = 3; //检测器状态
} }
//分页信息 //分页信息
message Page { message Page {
int32 pageNum = 1;//页号 int32 pageNum = 1;//页号
int32 pageSize = 2;//每页大小 int32 pageSize = 2;//每页大小
int32 totalPageNum = 3;//总页数 int32 totalPageNum = 3;//总页数
} }
message FrameList { message FrameList {
......
<template> <template>
<div <div class="loopVideo" v-loading="videoLoading" element-loading-text="加载中..."
class="loopVideo" element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)">
v-loading="videoLoading" <video :id="`historyVideoComponent${channel}`" style="object-fit: fill;" @canplay="videoCanPlay" :autoplay="autoplay" muted controls loop
element-loading-text="加载中..." class="videoControl" ref="loopVideoPlayer">
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"
>
<source :src="videoUrl" type="video/mp4" /> <source :src="videoUrl" type="video/mp4" />
您的浏览器不支持 video 属性。 您的浏览器不支持 video 属性。
</video> </video>
...@@ -65,7 +51,7 @@ export default { ...@@ -65,7 +51,7 @@ export default {
.replaceAll(" ", "_") .replaceAll(" ", "_")
.replaceAll(":", "_"); .replaceAll(":", "_");
}, },
destroy() {}, destroy() { },
async getVideoStreamUrl() { async getVideoStreamUrl() {
if (this.timeModel.startTime && this.timeModel.endTime) { if (this.timeModel.startTime && this.timeModel.endTime) {
try { try {
...@@ -75,11 +61,15 @@ export default { ...@@ -75,11 +61,15 @@ export default {
starttime: this.replaceTimeGap(this.timeModel.startTime), starttime: this.replaceTimeGap(this.timeModel.startTime),
endtime: this.replaceTimeGap(this.timeModel.endTime), endtime: this.replaceTimeGap(this.timeModel.endTime),
}); });
console.log("response", response); console.log("video response", response);
this.videoUrl = response.content; this.videoUrl = response.content;
setTimeout(() => { setTimeout(() => {
this.$refs.loopVideoPlayer.load(); this.$refs.loopVideoPlayer.load();
}, 200); }, 200);
// this.videoUrl = 'video/111.mp4';
// setTimeout(() => {
// this.$refs.loopVideoPlayer.load();
// }, 200);
} catch (error) { } catch (error) {
console.error(`Failed to get video stream url: ${error}`); console.error(`Failed to get video stream url: ${error}`);
} }
...@@ -124,5 +114,4 @@ export default { ...@@ -124,5 +114,4 @@ export default {
// left: 30%; // left: 30%;
// top: -14px; // top: -14px;
// transform: translateX(-50%); // transform: translateX(-50%);
// } // }</style>
</style>
...@@ -18,6 +18,7 @@ export default { ...@@ -18,6 +18,7 @@ export default {
}, },
carTypeGlbMap:{ carTypeGlbMap:{
1:'0', 1:'0',
2:'170',
9:'0', 9:'0',
13:'0', 13:'0',
15:'0', 15:'0',
......
...@@ -31,11 +31,11 @@ export function initWs(data) { ...@@ -31,11 +31,11 @@ export function initWs(data) {
// 接收消息 // 接收消息
currentSocket.onmessage = (res) => { currentSocket.onmessage = (res) => {
// protobuf 解压数据 // protobuf 解压数据
if (data.name === "callCar") { if (data.name.includes("callCar")) {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
let buf = new Uint8Array(e.target.result); let data1 = new Uint8Array(e.target.result);
let responseCarTrack = ResponseCarTrack.decode(buf); let responseCarTrack = ResponseCarTrack.decode(data1);
data.callback(responseCarTrack.carInfo); data.callback(responseCarTrack.carInfo);
}; };
reader.readAsArrayBuffer(res.data); reader.readAsArrayBuffer(res.data);
......
...@@ -20,7 +20,7 @@ import 'element-ui/lib/theme-chalk/index.css'; ...@@ -20,7 +20,7 @@ import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI, { Vue.use(ElementUI, {
size: 'small', 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.Message写法
window.ELEMENT = ElementUI window.ELEMENT = ElementUI
// 事件总线 // 事件总线
......
...@@ -30,27 +30,30 @@ export default { ...@@ -30,27 +30,30 @@ export default {
}); });
}, },
mxRefreshLightWs() { mxRefreshLightWs() {
let targetPoint = turf.point([window.map.getCenter().lng, window.map.getCenter().lat]); if (this.shouldShowLight) {
// 取最近点的crossId 判断哪个路口离当前视野中心点最近 请求对应的灯态websocket let targetPoint = turf.point([window.map.getCenter().lng, window.map.getCenter().lat]);
let nearest = turf.nearestPoint(targetPoint, this.crossGeo); // 取最近点的crossId 判断哪个路口离当前视野中心点最近 请求对应的灯态websocket
let nearestCrossId = nearest.properties.id; let nearest = turf.nearestPoint(targetPoint, this.crossGeo);
// 如果求得最近路口不是上次的最近路口,则关闭上个ws,请求最新路口ws let nearestCrossId = nearest.properties.id;
if (nearestCrossId !== this.currentNearestCrossId) { // 如果求得最近路口不是上次的最近路口,则关闭上个ws,请求最新路口ws
this.currentNearestCrossId = nearestCrossId; if (nearestCrossId !== this.currentNearestCrossId) {
this.closeWs("callLight").then(() => { this.currentNearestCrossId = nearestCrossId;
let socket = initWs({ this.closeWs("callLight").then(() => {
// url: `${ws_config.CROSS_CONTROL}${nearestCrossId},holo-web`, let socket = initWs({
url: `ws://${window.wsHost}/utc/signalStatus/${nearestCrossId},holo-web`, // url: `${ws_config.CROSS_CONTROL}${nearestCrossId},holo-web`,
callback: this.callLight, url: `ws://${window.wsHost}/utc/signalStatus/${nearestCrossId},holo-web`,
name: "callLight", 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) { callLight(msg) {
......
...@@ -174,11 +174,13 @@ export default { ...@@ -174,11 +174,13 @@ export default {
radarTimers.push(timer); radarTimers.push(timer);
}, },
loadUpdateRadars() { loadUpdateRadars() {
if (!this.radarShow) { if (this.shouldShowRadar) {
this.radarShow = true; if (!this.radarShow) {
this.loadRadars(); this.radarShow = true;
} else { this.loadRadars();
this.updateRadars() } else {
this.updateRadars()
}
} }
}, },
updateRadars() { updateRadars() {
......
...@@ -112,7 +112,7 @@ ...@@ -112,7 +112,7 @@
</template> </template>
<script> <script>
import { download, getBlob } from "../../../utils/request"; import { getBlob } from "../../../utils/request";
// import fetch from "@/utils/fetch"; // import fetch from "@/utils/fetch";
import { getReports, getReportsByPage } from "../../../dao/analysis"; import { getReports, getReportsByPage } from "../../../dao/analysis";
import JSZip from "jszip"; import JSZip from "jszip";
...@@ -292,7 +292,7 @@ export default { ...@@ -292,7 +292,7 @@ export default {
link.href = window.URL.createObjectURL(blob); link.href = window.URL.createObjectURL(blob);
link.download = report.name; link.download = report.name;
link.click(); link.click();
download(url, {}, report.name); // download(url, {}, report.name);
}, },
screenReports() { screenReports() {
let filter = this.reportSearchValue; let filter = this.reportSearchValue;
......
...@@ -107,7 +107,8 @@ ...@@ -107,7 +107,8 @@
<div class="traffics"> <div class="traffics">
<vue-seamless-scroll ref='22' class="warningMsg" :data="overData" :class-option="optionSetting1" <vue-seamless-scroll ref='22' class="warningMsg" :data="overData" :class-option="optionSetting1"
v-show="overData.length"> 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='topLicense'> <span>预警时间:</span>{{ item.timeStamp }}</div>
<div class='detailMsg'> <div class='detailMsg'>
<div><span>车牌:</span>{{ item.plateNo }}</div> <div><span>车牌:</span>{{ item.plateNo }}</div>
...@@ -157,7 +158,7 @@ export default { ...@@ -157,7 +158,7 @@ export default {
dict, dict,
activeName: '11', activeName: '11',
overData: [ 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" }, // { "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 { ...@@ -229,13 +230,46 @@ export default {
this.timers.push(timer4); this.timers.push(timer4);
}, },
methods: { 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() { getOverData() {
getAlarmOverDatas().then(res => { getAlarmOverDatas().then(res => {
this.overLoading = false this.overLoading = false
console.log("超限列表", res.content); console.log("超限列表", res.content);
// todo // todo
this.overData = res.content; if (res.content) {
this.overData = res.content.map(item => {
item.timeStamp = item.timeStamp.replace('T', ' ')
return item
}) || [];
}
}) })
}, },
tabClick(e) { tabClick(e) {
...@@ -642,15 +676,18 @@ export default { ...@@ -642,15 +676,18 @@ export default {
text-overflow: ellipsis; text-overflow: ellipsis;
margin-right: 5px; margin-right: 5px;
} }
div:nth-child(1) { div:nth-child(1) {
width: 25%; width: 25%;
} }
div:nth-child(2) { div:nth-child(2) {
width: calc(50% - 10px); width: calc(50% - 10px);
} }
div:nth-child(3) { div:nth-child(3) {
width: 25%; width: 25%;
margin-right:0 margin-right: 0
} }
} }
} }
......
This diff is collapsed.
...@@ -30,6 +30,12 @@ ...@@ -30,6 +30,12 @@
<div class="detailItem" v-show="!notExceed"> <div class="detailItem" v-show="!notExceed">
<span class="left">超限类型:</span>{{ overTypeStr }} <span class="left">超限类型:</span>{{ overTypeStr }}
</div> </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"> <div class="detailItem">
<span class="left">ID :</span>{{ model.id }} <span class="left">ID :</span>{{ model.id }}
</div> </div>
...@@ -78,12 +84,21 @@ export default { ...@@ -78,12 +84,21 @@ export default {
}, },
}, },
computed: { computed: {
overWidth() {
return this.model.overRun?.vehicleWidth || '--'
},
overHeight() {
return this.model.overRun?.vehicleHeight || '--'
},
notExceed() { notExceed() {
return !this.model.overType if (!this.model.overRun || !this.model.overRun.overType) {
return true
}
return false
}, },
overTypeStr() { overTypeStr() {
if (this.model.overType) { if (this.model.overRun?.overType) {
let overArr = this.model.overType.split(',') let overArr = this.model.overRun.overType.split(',')
let overStr = '' let overStr = ''
for (let t of overArr) { for (let t of overArr) {
overStr += dict.overCarType[t] overStr += dict.overCarType[t]
...@@ -92,7 +107,7 @@ export default { ...@@ -92,7 +107,7 @@ export default {
} }
}, },
overTime() { overTime() {
return this.model.timeStamp || '--' return this.model.overRun?.timeStamp || '--'
} }
}, },
beforeDestroy() { }, 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