529 lines
14 KiB
Vue
529 lines
14 KiB
Vue
<template>
|
|
<div class="box-2">
|
|
<ul class="nav">
|
|
<li
|
|
class="nav-item"
|
|
:class="{ active: current === index }"
|
|
v-for="(item, index) in routerList"
|
|
:key="index"
|
|
@click="handleNav(item, index)"
|
|
>
|
|
{{ item.name }}
|
|
</li>
|
|
</ul>
|
|
<div class="flex-1">
|
|
<div class="title-1">
|
|
<div class="title">
|
|
<span> 核心路段 </span>
|
|
</div>
|
|
</div>
|
|
<div id="traffic-map" class="traffic-map-big" :class="{ 'traffic-map': routers.length > 0 }" />
|
|
</div>
|
|
|
|
<div v-if="routers.length > 0" class="list">
|
|
<div class="item" v-for="(item, index) in routers" :key="index" @click="handleRouter(item)">
|
|
<div class="header">
|
|
<div class="header-left">
|
|
<img src="@/assets/images/work-icon-xl-1.png" />
|
|
<div class="header-left__title">{{ item.name }}</div>
|
|
<!-- <div class="header-left__camera" @click="videoShow = true">道路监控</div> -->
|
|
<!-- <div class="header-left__point" @click="videoShow = true">3号点位</div> -->
|
|
</div>
|
|
<div class="header-status">{{ item.congestLevelText }} </div>
|
|
</div>
|
|
<div class="statistics">
|
|
<div class="statistics-item">
|
|
<div class="statistics-item__label">
|
|
<img src="@/assets/images/t-icon-1.png" alt="" />平均车速
|
|
</div>
|
|
<div class="statistics-item__value flex">
|
|
<countup :end-val="item.speed" />
|
|
<span>km/h</span>
|
|
</div>
|
|
</div>
|
|
<div class="statistics-item">
|
|
<div class="statistics-item__label">
|
|
<img src="@/assets/images/t-icon-1.png" alt="" />拥堵距离
|
|
</div>
|
|
<div class="statistics-item__value flex">
|
|
{{ item.congestLength }}
|
|
<span>km</span>
|
|
</div>
|
|
</div>
|
|
<div class="statistics-item">
|
|
<div class="statistics-item__label">
|
|
<img src="@/assets/images/t-icon-1.png" alt="" />拥堵次数
|
|
</div>
|
|
<div class="statistics-item__value">
|
|
<countup :end-val="item.congestCount" />
|
|
</div>
|
|
</div>
|
|
<div class="statistics-item">
|
|
<div class="statistics-item__label">
|
|
<img src="@/assets/images/t-icon-1.png" alt="" />拥堵开始时间
|
|
</div>
|
|
<div class="statistics-item__value">
|
|
{{ item.startTime }}
|
|
</div>
|
|
</div>
|
|
<div class="statistics-item">
|
|
<div class="statistics-item__label">
|
|
<img src="@/assets/images/t-icon-1.png" alt="" />拥堵持续时长
|
|
</div>
|
|
<div class="statistics-item__value">
|
|
{{ item.congestDuration }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="chart-item">
|
|
<Title3 title="拥堵类型分析" />
|
|
<div class="chart-box">
|
|
<traffic-jam :series="item.series" :data="item.xdata" :key="index" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- <video-dialog v-model="videoShow" src="" /> -->
|
|
<video-dialog v-model="videoShow" :src="src" :isCollect="isCollect" :cameraIndexCode="cameraIndexCode" />
|
|
</template>
|
|
|
|
<script setup>
|
|
import countup from 'vue-countup-v3'
|
|
import trafficJam from './traffic-jam'
|
|
import { getPreviewUrlApi } from '@/api/home'
|
|
import { useMap } from '@/hooks/map'
|
|
import pubSub from 'pubsub-js'
|
|
import { getRouterListApi, getRoutersApi,getRoutersMapApi } from '@/api/traffic'
|
|
import mapIcon from '@/assets/images/map-video.png'
|
|
const { map, initMap,addMarker,marker } = useMap()
|
|
|
|
let props = defineProps({
|
|
list: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
})
|
|
let src = ref('')
|
|
let cameraIndexCode = ref('')
|
|
let current = ref(0)
|
|
let routerList = ref([])
|
|
let routers = ref([])
|
|
let videoShow = ref(false)
|
|
let markerList = ref([])
|
|
let isCollect = ref(0)
|
|
watch(
|
|
() => [routerList.value, routers.value],
|
|
(val) => {
|
|
if (val[0].length > 0) {
|
|
nextTick(() => {
|
|
let { longitude, latitude, level } = val[0][0]
|
|
// console.log(longitude, latitude, level,'longitude, latitude, level')
|
|
initMap('traffic-map', longitude, latitude, level)
|
|
map.value.setTrafficOn()
|
|
})
|
|
}
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
)
|
|
watch(
|
|
() => [markerList.value,map.value],
|
|
(val) => {
|
|
|
|
if(val[0].length&&val[1]){
|
|
nextTick(()=>{
|
|
val[0].forEach((item,index)=>{
|
|
addMarker(mapIcon,[item.longitude,item.latitude],[40, 60])
|
|
|
|
marker.value.addEventListener('click', (e) => {
|
|
console.log(item,'111111111111')
|
|
cameraIndexCode.value = item.cameraIndexCode
|
|
isCollect.value = item.isCollect
|
|
getPreviewUrl(item.cameraIndexCode)
|
|
})
|
|
var opts = {
|
|
position: new BMapGL.Point(item.longitude, item.latitude), // 指定文本标注所在的地理位置
|
|
offset: new BMapGL.Size(-50, 30) // 设置文本偏移量
|
|
};
|
|
// 创建文本标注对象
|
|
var label = new BMapGL.Label(item.cameraName, opts);
|
|
// 自定义文本标注样式
|
|
label.setStyle({
|
|
display:'block',
|
|
color: '#0b61b4',
|
|
borderRadius: '0',
|
|
borderColor: 'none',
|
|
padding: '10px',
|
|
border:0,
|
|
fontWeight:'bold',
|
|
fontFamily: '微软雅黑'
|
|
});
|
|
marker.value.addEventListener('mouseover', (e) => {
|
|
label.setStyle({
|
|
display:'block'
|
|
});
|
|
map.value.addOverlay(label);
|
|
})
|
|
marker.value.addEventListener('mouseout', (e) => {
|
|
console.log('11111')
|
|
label.setStyle({
|
|
display:'none'
|
|
});
|
|
|
|
})
|
|
})
|
|
|
|
})
|
|
}
|
|
},
|
|
{
|
|
immediate: true
|
|
}
|
|
)
|
|
const onVideoCollect = () => {
|
|
pubSub.subscribe('videoCollect', () => {
|
|
// clearHlsRefs()
|
|
getRoutersMap()
|
|
})
|
|
}
|
|
const getPreviewUrl = async (code) => {
|
|
let res = await getPreviewUrlApi({
|
|
cameraIndexCode: code,
|
|
type: 'hls',
|
|
subStream:0
|
|
})
|
|
src.value = res.data.url
|
|
videoShow.value = true
|
|
}
|
|
const getRoutersMap = async()=>{
|
|
let res = await getRoutersMapApi();
|
|
markerList.value = res.data
|
|
}
|
|
const handleNav = (e, index) => {
|
|
current.value = index
|
|
map.value.centerAndZoom(new BMapGL.Point(e.longitude, e.latitude), e.level)
|
|
}
|
|
|
|
const handleRouter = (e) => {
|
|
let location = e.location.split(',')
|
|
console.log(location, 'location')
|
|
current.value = ''
|
|
map.value.centerAndZoom(new BMapGL.Point(location[0], location[1]), 18)
|
|
}
|
|
|
|
const getRouterList = async () => {
|
|
let res = await getRouterListApi()
|
|
routerList.value = res.data
|
|
}
|
|
|
|
const getRouters = async () => {
|
|
let res = await getRoutersApi()
|
|
routers.value = res.data
|
|
}
|
|
|
|
onMounted(() => {
|
|
getRouterList()
|
|
getRouters()
|
|
getRoutersMap()
|
|
onVideoCollect()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.flex-1{
|
|
flex:1;
|
|
overflow:hidden;
|
|
height: 100%;
|
|
}
|
|
.title-1 {
|
|
position: relative;
|
|
margin-bottom:vh(20);
|
|
.title {
|
|
margin: vh(10) auto;
|
|
margin-top:0;
|
|
width: vw(1100);
|
|
height: vh(62);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-image: url('@/assets/images/title-4.png');
|
|
background-size: 100% 100%;
|
|
& > span {
|
|
font-weight: 800;
|
|
font-size: font-vw(24);
|
|
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent; /* 兼容WebKit内核浏览器 */
|
|
color: transparent; /* 兼容其他浏览器 */
|
|
}
|
|
}
|
|
}
|
|
.box-2 {
|
|
margin-top: vh(120);
|
|
display: flex;
|
|
flex:1;
|
|
}
|
|
.nav {
|
|
width: vw(330);
|
|
// height: vh(950);
|
|
height:100%;
|
|
margin-left: vw(8);
|
|
padding-left: vw(5);
|
|
overflow: auto;
|
|
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
|
|
|
|
&::-webkit-scrollbar {
|
|
width: vw(0); /* 滚动条的宽度 */
|
|
}
|
|
|
|
&-item {
|
|
cursor: pointer;
|
|
margin-bottom: vw(15);
|
|
width: 100%;
|
|
height: vh(100);
|
|
font-weight: bold;
|
|
font-size: font-vw(20);
|
|
color: #ffffff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: url('/src/assets/images/m-nav-bg-1.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
.active {
|
|
background: url('/src/assets/images/m-nav-bg-2.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
}
|
|
|
|
.traffic-map-big {
|
|
position: relative;
|
|
z-index: 9;
|
|
// width: vw(2116);
|
|
width:100%;
|
|
height: vh(890);
|
|
height: 100%;
|
|
margin-left: vw(8);
|
|
box-sizing: border-box;
|
|
background-image: url('/src/assets/images/map-bg-2.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
.traffic-map {
|
|
// width: vw(1500) !important;
|
|
}
|
|
.video-list {
|
|
width: vw(320);
|
|
height: vh(120);
|
|
background: #0a254b;
|
|
border-radius: 0px 0px 0px 0px;
|
|
position: absolute;
|
|
bottom: vw(40);
|
|
right: vw(40);
|
|
z-index: 99;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
.li {
|
|
width: vw(140);
|
|
height: vh(105);
|
|
background-image: url('/src/assets/images/small-v-bg.png');
|
|
background-size: 100% 100%;
|
|
margin-right: vw(6);
|
|
}
|
|
.menu {
|
|
width: vw(12);
|
|
height: vh(60);
|
|
font-family: Inter, Inter;
|
|
font-weight: 400;
|
|
font-size: font-vw(12);
|
|
color: #ffffff;
|
|
line-height: vh(14);
|
|
text-align: left;
|
|
font-style: normal;
|
|
text-transform: none;
|
|
}
|
|
}
|
|
.list {
|
|
width: vw(1000);
|
|
height: 100%;
|
|
margin-left: vw(8);
|
|
overflow: auto;
|
|
&::-webkit-scrollbar {
|
|
width: vw(0); /* 滚动条的宽度 */
|
|
}
|
|
}
|
|
.item {
|
|
margin-bottom: vh(10);
|
|
background-image: url('@/assets/images/bg-2.png');
|
|
background-size: 100% 100%;
|
|
.header {
|
|
height: vh(72);
|
|
display: flex;
|
|
align-items: center;
|
|
&-left {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
> img {
|
|
width: vw(30);
|
|
height: auto;
|
|
margin-right: vw(15);
|
|
}
|
|
}
|
|
&-left__title {
|
|
margin-right: vw(20);
|
|
font-size: font-vw(28);
|
|
font-weight: bold;
|
|
color: transparent;
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-image: linear-gradient(to bottom, #ffffff 0%, #87c9ff 100%);
|
|
}
|
|
&-left__camera {
|
|
cursor: pointer;
|
|
width: vw(120);
|
|
height: vw(72);
|
|
font-weight: 600;
|
|
font-size: font-vw(15);
|
|
color: #ffffff;
|
|
padding-left: vw(42);
|
|
display: flex;
|
|
align-items: center;
|
|
margin: 0 vw(20);
|
|
background-image: url('/src/assets/images/t-a-1.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
&-left__point {
|
|
cursor: pointer;
|
|
margin: 0 vw(20);
|
|
width: vw(120);
|
|
height: vw(72);
|
|
font-weight: 600;
|
|
font-size: font-vw(15);
|
|
color: #ffffff;
|
|
padding-left: vw(42);
|
|
display: flex;
|
|
align-items: center;
|
|
background-image: url('/src/assets/images/t-a-2.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
&-status {
|
|
min-width: vw(150);
|
|
height: vw(64);
|
|
font-weight: 600;
|
|
font-size: font-vw(22);
|
|
color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
padding-left: vw(50);
|
|
padding-right: vw(20);
|
|
background-image: url('/src/assets/images/t-b-1.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
}
|
|
|
|
.chart-item {
|
|
padding: vw(1);
|
|
margin-top: vh(10);
|
|
height: vh(500);
|
|
background-image: url('@/assets/images/bg-3.png');
|
|
background-size: 100% 100%;
|
|
|
|
.chart-box {
|
|
width: 100%;
|
|
height: vh(250);
|
|
}
|
|
|
|
.title-3 {
|
|
margin-left: vw(10);
|
|
position: relative;
|
|
width: vw(344);
|
|
height: vh(12);
|
|
margin-top: vh(20);
|
|
background-image: url('@/assets/images/title-6.png');
|
|
background-size: 100% 100%;
|
|
|
|
& > span {
|
|
position: absolute;
|
|
bottom: vh(4);
|
|
left: vw(20);
|
|
font-size: font-vw(15);
|
|
font-weight: bold;
|
|
background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
/* 兼容WebKit内核浏览器 */
|
|
color: transparent;
|
|
/* 兼容其他浏览器 */
|
|
}
|
|
}
|
|
}
|
|
|
|
.statistics {
|
|
height: vh(190);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-evenly;
|
|
background-image: url('@/assets/images/bg-3.png');
|
|
background-size: 100% 100%;
|
|
|
|
&-item__label {
|
|
font-weight: 400;
|
|
font-size: font-vw(22);
|
|
color: #fff;
|
|
margin-bottom: vh(30);
|
|
}
|
|
&-item__value {
|
|
padding-left: vw(15);
|
|
height: vh(90);
|
|
font-weight: bold;
|
|
font-size: font-vw(28);
|
|
color: #02f9fa;
|
|
background-image: url('@/assets/images/t-box-title-bg-1.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
.item-box {
|
|
.item-t {
|
|
display: flex;
|
|
font-weight: 400;
|
|
font-size: font-vw(14);
|
|
color: rgba(255, 255, 255, 0.8);
|
|
margin-bottom: vh(20);
|
|
img {
|
|
margin-right: vw(5);
|
|
width: vw(8);
|
|
height: vh(8);
|
|
}
|
|
}
|
|
|
|
.item-num {
|
|
width: vw(134);
|
|
height: vh(30);
|
|
background-image: url('@/assets/images/t-box-title-bg-1.png');
|
|
background-size: 100% 100%;
|
|
font-weight: bold;
|
|
font-size: font-vw(24);
|
|
color: #02f9fa;
|
|
text-align: left;
|
|
font-style: normal;
|
|
text-transform: none;
|
|
padding-left: vw(15);
|
|
position: relative;
|
|
left: vw(-8);
|
|
|
|
span {
|
|
position: absolute;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|