服务区弹框

This commit is contained in:
fengshiwang 2025-06-06 16:53:45 +08:00
parent 9ec6f41e6f
commit 01d8de7f11
6 changed files with 238 additions and 124 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -17,7 +17,7 @@
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">设备编号</span> <span class="info-label">设备编号</span>
<span class="info-value blue-value">{{ props.deviceInfo.deviceCode }}</span> <span class="info-value blue-value">{{ props.deviceInfo.deviceId }}</span>
</div> </div>
</div> </div>
<div class="info-row"> <div class="info-row">
@ -31,21 +31,21 @@
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">桩号</span> <span class="info-label">桩号</span>
<span class="info-value blue-value">{{ props.deviceInfo.stakeNumber }}</span> <span class="info-value blue-value">{{ props.deviceInfo.pilEnum }}</span>
</div> </div>
</div> </div>
<div class="info-row"> <div class="info-row">
<div class="info-item"> <div class="info-item">
<span class="info-label">经度</span> <span class="info-label">经度</span>
<span class="info-value blue-value">{{ props.deviceInfo.longitude }}</span> <span class="info-value blue-value">{{ props.deviceInfo.lon }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">维度</span> <span class="info-label">维度</span>
<span class="info-value blue-value">{{ props.deviceInfo.latitude }}</span> <span class="info-value blue-value">{{ props.deviceInfo.lat }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">IP</span> <span class="info-label">IP</span>
<span class="info-value blue-value">{{ props.deviceInfo.ipAddress }}</span> <span class="info-value blue-value">{{ props.deviceInfo.ip }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -67,7 +67,7 @@
</template> </template>
<script setup> <script setup>
import { ref, nextTick, onMounted } from "vue";
// props // props
const props = defineProps({ const props = defineProps({
deviceInfo: { deviceInfo: {
@ -76,6 +76,9 @@ const props = defineProps({
}) })
} }
}); });
onMounted(()=>{
console.log(props.deviceInfo, 'ddddddddddddd')
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -12,12 +12,12 @@
<span class="info-value blue-value">{{ props.deviceInfo.deviceType }}</span> <span class="info-value blue-value">{{ props.deviceInfo.deviceType }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">可变信息标志</span> <span class="info-label">摄像机类型</span>
<span class="info-value blue-value">{{ props.deviceInfo.cameraType }}</span> <span class="info-value blue-value">{{ props.deviceInfo.cameraType }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">设备编号</span> <span class="info-label">设备编号</span>
<span class="info-value blue-value">{{ props.deviceInfo.deviceCode }}</span> <span class="info-value blue-value">{{ props.deviceInfo.deviceId }}</span>
</div> </div>
</div> </div>
<div class="info-row"> <div class="info-row">
@ -31,21 +31,21 @@
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">桩号</span> <span class="info-label">桩号</span>
<span class="info-value blue-value">{{ props.deviceInfo.stakeNumber }}</span> <span class="info-value blue-value">{{ props.deviceInfo.pilEnum }}</span>
</div> </div>
</div> </div>
<div class="info-row"> <div class="info-row">
<div class="info-item"> <div class="info-item">
<span class="info-label">经度</span> <span class="info-label">经度</span>
<span class="info-value blue-value">{{ props.deviceInfo.longitude }}</span> <span class="info-value blue-value">{{ props.deviceInfo.lon }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">维度</span> <span class="info-label">维度</span>
<span class="info-value blue-value">{{ props.deviceInfo.latitude }}</span> <span class="info-value blue-value">{{ props.deviceInfo.lat }}</span>
</div> </div>
<div class="info-item"> <div class="info-item">
<span class="info-label">IP</span> <span class="info-label">IP</span>
<span class="info-value blue-value">{{ props.deviceInfo.ipAddress }}</span> <span class="info-value blue-value">{{ props.deviceInfo.ip }}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,8 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, onMounted } from "vue";
import demoImage from "@/assets/img/demo.png"; import demoImage from "@/assets/img/demo.png";
import fwqImage from "@/assets/img/fwq.png"; import fwqImage from "@/assets/img/fwq.png";
import { getVideoDeviceList, videoStream } from "@/api/modules/index";
import dayjs from "dayjs";
// //
const deviceStatus = ref({ const deviceStatus = ref({
normal: 248, normal: 248,
@ -25,50 +26,42 @@ const parkingData = ref([
// //
const monitoringGroups = ref([ const monitoringGroups = ref([
{ // {
id: 1, // id: 1,
name: "邯港方向", // name: "",
count: 5, // count: 5,
expanded: true, // expanded: true,
points: [ // points: [
{ id: 1, name: "邯港方向监控001", status: "正常" }, // { id: 1, name: "001", status: "" },
{ id: 2, name: "邯港方向监控002", status: "正常" }, // { id: 2, name: "002", status: "" },
{ id: 3, name: "邯港方向监控003", status: "正常" }, // { id: 3, name: "003", status: "" },
{ id: 4, name: "邯港方向监控004", status: "正常" }, // { id: 4, name: "004", status: "" },
{ id: 5, name: "邯港方向监控005", status: "正常" }, // { id: 5, name: "005", status: "" },
], // ],
}, // },
{ // {
id: 2, // id: 2,
name: "黄驿港方向", // name: "驿",
count: 12, // count: 12,
expanded: false, // expanded: false,
points: [], // points: [],
}, // },
{ // {
id: 3, // id: 3,
name: "收费站", // name: "",
count: 5, // count: 5,
expanded: true, // expanded: true,
points: [ // points: [
{ id: 6, name: "收费站监控001", status: "正常" }, // { id: 6, name: "001", status: "" },
{ id: 7, name: "收费站监控002", status: "正常" }, // { id: 7, name: "002", status: "" },
{ id: 8, name: "收费站监控003", status: "正常" }, // { id: 8, name: "003", status: "" },
{ id: 9, name: "收费站监控004", status: "正常" }, // { id: 9, name: "004", status: "" },
], // ],
}, // },
]); ]);
// //
const fixedRoadMonitors = ref([ const fixedRoadMonitors = ref([
{ id: 101, name: "高速公路监控001", image: demoImage },
{ id: 102, name: "高速公路监控002", image: demoImage },
{ id: 103, name: "高速公路监控003", image: demoImage },
{ id: 104, name: "高速公路监控004", image: demoImage },
{ id: 105, name: "高速公路监控005", image: demoImage },
{ id: 106, name: "高速公路监控006", image: demoImage },
{ id: 107, name: "高速公路监控007", image: demoImage },
{ id: 108, name: "高速公路监控008", image: demoImage },
]); ]);
// //
@ -80,14 +73,58 @@ const toggleGroup = (group: any) => {
const selectedPoints = ref<any[]>([]); const selectedPoints = ref<any[]>([]);
// //
const togglePoint = (point: any) => { // const togglePoint = (point: any) => {
const index = selectedPoints.value.findIndex((p) => p.id === point.id); // const index = selectedPoints.value.findIndex((p) => p.id === point.id);
// if (index > -1) {
// selectedPoints.value.splice(index, 1);
// } else {
// selectedPoints.value.push(point);
// }
// };
const togglePoint = async (point: any) => {
const index = selectedPoints.value.findIndex((p) => p.channelCode === point.channelCode);
if (index > -1) { if (index > -1) {
//
selectedPoints.value.splice(index, 1); selectedPoints.value.splice(index, 1);
const monitorIdx = fixedRoadMonitors.value.findIndex(m => m.channelCode === point.channelCode);
if (monitorIdx > -1) {
fixedRoadMonitors.value.splice(monitorIdx, 1);
}
} else { } else {
// 8
if (selectedPoints.value.length >= 8) {
const removed = selectedPoints.value.shift();
// fixedRoadMonitors
const rmIdx = fixedRoadMonitors.value.findIndex(m => m.channelCode === removed.channelCode);
if (rmIdx > -1) fixedRoadMonitors.value.splice(rmIdx, 1);
}
selectedPoints.value.push(point); selectedPoints.value.push(point);
// fixedRoadMonitors
const res = await videoStream({ deviceCode: point.deviceCode, channelCode: point.channelCode });
// fixedRoadMonitors6
if (fixedRoadMonitors.value.length >= 8) {
fixedRoadMonitors.value.shift();
}
fixedRoadMonitors.value.push({
...point,
src: res
});
} }
}; };
onMounted(() => {
const endTime = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss');
getVideoDeviceList({ endTime: endTime, currentPage: 1, pageSize: 2 }).then((res) => { //
console.log(res, 'rrrrrrrrrrrrrrrrrrrrrrrrrsssssssssssss')
if (res.code == 200) {
res.data.data.forEach((item) => {
item.expanded = true
})
monitoringGroups.value = res.data.data
}
console.log(monitoringGroups.value, 'monitoringGroups.value')
})
})
</script> </script>
<template> <template>
@ -123,11 +160,7 @@ const togglePoint = (point: any) => {
<!-- 添加车位信息展示 --> <!-- 添加车位信息展示 -->
<div class="parking-info"> <div class="parking-info">
<div <div v-for="(item, index) in parkingData" :key="index" class="parking-item">
v-for="(item, index) in parkingData"
:key="index"
class="parking-item"
>
<div class="parking-label">{{ item.label }}</div> <div class="parking-label">{{ item.label }}</div>
<div class="parking-value">{{ item.value }}</div> <div class="parking-value">{{ item.value }}</div>
</div> </div>
@ -142,38 +175,22 @@ const togglePoint = (point: any) => {
<span>视频监控列表</span> <span>视频监控列表</span>
</div> </div>
<div class="list-content"> <div class="list-content">
<div <div v-for="(group, index) in monitoringGroups" :key="index" class="group-item">
v-for="group in monitoringGroups"
:key="group.id"
class="group-item"
>
<div class="group-header" @click="toggleGroup(group)"> <div class="group-header" @click="toggleGroup(group)">
<div class="group-name"> <div class="group-name">
<i class="arrow" :class="{ expanded: group.expanded }"></i> <!-- <i class="arrow" :class="{ expanded: group.expanded }"></i> -->
<span style="font-size: 22.5px" <span style="font-size: 22.5px">{{ group.deviceName }}{{ group.channels.length }}</span>
>{{ group.name }}{{ group.count }}</span
>
</div> </div>
</div> </div>
<div class="group-content" v-show="group.expanded"> <div class="group-content" v-show="group.channels">
<div <div v-for="(point, vic) in group.channels" :key="point.channelCode" class="point-item"
v-for="point in group.points" :class="{ active: selectedPoints.some((p) => p.channelCode === point.channelCode) }"
:key="point.id" @click="togglePoint(point)">
class="point-item"
:class="{ active: selectedPoints.some((p) => p.id === point.id) }"
@click="togglePoint(point)"
>
<div class="point-info"> <div class="point-info">
<span class="point-name">{{ point.name }}</span> <span class="point-name">{{ point.channelName }}</span>
<div class="status-wrapper"> <div class="status-wrapper">
<span <span class="status-indicator" :class="point.status === 1 ? 'normal' : 'warning'"></span>
class="status-indicator" <span class="point-status" :class="point.status === 1 ? 'normal' : 'warning'">
:class="point.status === '正常' ? 'normal' : 'warning'"
></span>
<span
class="point-status"
:class="point.status === '正常' ? 'normal' : 'warning'"
>
{{ point.status }} {{ point.status }}
</span> </span>
</div> </div>
@ -186,12 +203,8 @@ const togglePoint = (point: any) => {
<!-- 右侧图像网格 - 改为固定显示六张图片 --> <!-- 右侧图像网格 - 改为固定显示六张图片 -->
<div class="monitor-grid"> <div class="monitor-grid">
<div class="fixed-grid-container"> <!-- <div class="fixed-grid-container">
<div <div v-for="monitor in fixedRoadMonitors" :key="monitor.id" class="grid-item">
v-for="monitor in fixedRoadMonitors"
:key="monitor.id"
class="grid-item"
>
<div class="corner-decoration top-left"></div> <div class="corner-decoration top-left"></div>
<div class="corner-decoration top-right"></div> <div class="corner-decoration top-right"></div>
<div class="corner-decoration bottom-left"></div> <div class="corner-decoration bottom-left"></div>
@ -200,6 +213,19 @@ const togglePoint = (point: any) => {
<img :src="monitor.image" :alt="monitor.name" /> <img :src="monitor.image" :alt="monitor.name" />
</div> </div>
</div> </div>
</div> -->
<div class="fixed-grid-container">
<div v-for="(monitor, idx) in fixedRoadMonitors" :key="monitor.channelCode || monitor.id || idx"
class="grid-item">
<div class="corner-decoration top-left"></div>
<div class="corner-decoration top-right"></div>
<div class="corner-decoration bottom-left"></div>
<div class="corner-decoration bottom-right"></div>
<div class="image-container">
<video v-if="monitor.src" :src="monitor.src" controls autoplay
style="width:100%;height:300px;background:#000" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -210,11 +236,11 @@ const togglePoint = (point: any) => {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
background: rgba(0, 24, 65, 0.7); // background: rgba(0, 24, 65, 0.7);
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
border: 1px solid rgba(0, 198, 255, 0.3); // border: 1px solid rgba(0, 198, 255, 0.3);
box-shadow: 0 0 15px rgba(0, 198, 255, 0.1); // box-shadow: 0 0 15px rgba(0, 198, 255, 0.1);
padding: 2px; padding: 2px;
padding: 30px; padding: 30px;
} }
@ -249,12 +275,10 @@ const togglePoint = (point: any) => {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: linear-gradient( background: linear-gradient(45deg,
45deg,
rgba(0, 198, 255, 0.05), rgba(0, 198, 255, 0.05),
transparent, transparent,
rgba(0, 198, 255, 0.05) rgba(0, 198, 255, 0.05));
);
animation: gradientPulse 3s ease-in-out infinite; animation: gradientPulse 3s ease-in-out infinite;
z-index: 0; z-index: 0;
} }
@ -785,6 +809,7 @@ const togglePoint = (point: any) => {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
} }
100% { 100% {
transform: rotate(360deg); transform: rotate(360deg);
} }
@ -794,9 +819,11 @@ const togglePoint = (point: any) => {
0% { 0% {
background-position: 0% 50%; background-position: 0% 50%;
} }
50% { 50% {
background-position: 100% 50%; background-position: 100% 50%;
} }
100% { 100% {
background-position: 0% 50%; background-position: 0% 50%;
} }

View File

@ -1,23 +1,61 @@
<template> <template>
<div class="center-container"> <div class="center-container">
<div class="statistics-panel"> <div class="statistics-panel">
<div v-for="(stat, index) in statistics" :key="index" class="stat-card"> <div v-for="(stat, index) in statistics" :key="index" class="stat-card" style="position: relative;">
<div class="card-background"></div> <div
class="box"
@mouseenter="stat.label === '服务区' && (showDropdown = true)"
@mouseleave="stat.label === '服务区' && (showDropdown = false)"
style="position: relative;"
>
<div class="icon-wrapper"> <div class="icon-wrapper">
<img :src="stat.image" :alt="stat.label" /> <img :src="stat.image" :alt="stat.label" />
</div> </div>
<div class="stat-content"> <div class="stat-content">
<div class="stat-label">{{ stat.label }}</div> <div class="stat-label">
{{ stat.label }}
</div>
<div class="stat-value"> <div class="stat-value">
<span class="number">{{ stat.value }}</span> <span class="number">{{ stat.value }}</span>
</div> </div>
</div> </div>
<!-- 只在服务区显示下拉选择 -->
<template v-if="stat.label === '服务区'">
<div
v-show="showDropdown"
class="dropdown large-dropdown"
@mouseenter="showDropdown = true"
@mouseleave="showDropdown = false"
>
<div
class="dropdown-item"
v-for="area in serviceAreas"
:key="area"
@click="selectServiceArea(area)"
>
{{ area }}
</div> </div>
</div> </div>
<div v-if="showServiceArea" class="map-container"> </template>
</div>
</div>
</div>
<!-- 下面弹框标题用当前选中的服务区 -->
<!-- <div v-if="showServiceArea" class="map-container">
<div class="map-title"> <div class="map-title">
<div class="title-content"> <div class="title-content">
<span class="title-text">南皮服务区</span> <span class="title-text">{{ selectedServiceArea }}</span>
</div>
<div class="close-btn" @click="closeDialog">×</div>
</div>
<div class="map-con">
<RealTimeImageCenter />
</div>
</div> -->
<div v-if="showServiceArea" style="width: 5664px;" class="map-container RealTimeImage">
<div class="map-title">
<div class="title-content">
<span class="title-text">{{selectedServiceArea}}</span>
</div> </div>
<div class="close-btn" @click="closeDialog">×</div> <div class="close-btn" @click="closeDialog">×</div>
</div> </div>
@ -28,7 +66,7 @@
<div class="map-container bg-header bg-header-one" style="width: 1800px;" v-if="showDeviceInfo"> <div class="map-container bg-header bg-header-one" style="width: 1800px;" v-if="showDeviceInfo">
<div class="map-title"> <div class="map-title">
<div class="title-content"> <div class="title-content">
<span class="title-text">设备信息NO3_ZFJ12_3</span> <span class="title-text">设备信息NO{{ deviceInfo.deviceId }}</span>
</div> </div>
<div class="close-btn" @click="closeDeviceInfo">×</div> <div class="close-btn" @click="closeDeviceInfo">×</div>
</div> </div>
@ -39,7 +77,7 @@
<div class="map-container bg-header bg-header-two" style="width: 1800px;height: 1000px;" v-if="showDeviceInfoTwo"> <div class="map-container bg-header bg-header-two" style="width: 1800px;height: 1000px;" v-if="showDeviceInfoTwo">
<div class="map-title"> <div class="map-title">
<div class="title-content"> <div class="title-content">
<span class="title-text">设备信息NO3_TCMS1</span> <span class="title-text">设备信息NO{{ deviceInfo.deviceId }}</span>
</div> </div>
<div class="close-btn" @click="closeDeviceInfo">×</div> <div class="close-btn" @click="closeDeviceInfo">×</div>
</div> </div>
@ -71,6 +109,15 @@ const showDeviceInfoTwo = ref(false);
const closeDialog = () => { const closeDialog = () => {
showServiceArea.value = false; showServiceArea.value = false;
}; };
const showDropdown = ref(false);
const serviceAreas = ["南皮服务区", "东光服务区"];
const selectedServiceArea = ref("南皮服务区");
function selectServiceArea(area) {
selectedServiceArea.value = area;
showServiceArea.value = true;
showDropdown.value = false;
}
// //
const statistics = ref([ const statistics = ref([
{ {
@ -138,7 +185,7 @@ function handleShowDeviceInfo(data) {
} else if (data.deviceTypeId === "15" || data.deviceTypeId === "53") { } else if (data.deviceTypeId === "15" || data.deviceTypeId === "53") {
showDeviceInfoTwo.value = true; showDeviceInfoTwo.value = true;
} }
deviceInfoTwo.value = data;
deviceInfo.value = data; deviceInfo.value = data;
} }
const closeDeviceInfo = () => { const closeDeviceInfo = () => {
@ -160,6 +207,10 @@ onMounted(() => {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
position: relative; position: relative;
.RealTimeImage{
background-image: url("@/assets/img/eqm/fuwuqu.png");
background-size: 100% 100%;
}
.map-container.bg-header { .map-container.bg-header {
position: absolute; position: absolute;
top: 500px; top: 500px;
@ -168,11 +219,13 @@ onMounted(() => {
z-index: 2000; z-index: 2000;
// box-shadow: 0 8px 40px rgba(0,0,0,0.3); // box-shadow: 0 8px 40px rgba(0,0,0,0.3);
} }
.bg-header-one{
.bg-header-one {
background-image: url("@/assets/img/eqm/eqminfo.png"); background-image: url("@/assets/img/eqm/eqminfo.png");
background-size: 100% 100%; background-size: 100% 100%;
} }
.bg-header-two{
.bg-header-two {
background-image: url("@/assets/img/eqm/eqminfo2.png"); background-image: url("@/assets/img/eqm/eqminfo2.png");
background-size: 100% 100%; background-size: 100% 100%;
} }
@ -187,6 +240,11 @@ onMounted(() => {
gap: 30px; gap: 30px;
padding-top: 200px; padding-top: 200px;
padding-bottom: 50px; padding-bottom: 50px;
.box{
display: flex;
justify-content: space-around;
align-items: center;
}
} }
.stat-card { .stat-card {
@ -268,7 +326,7 @@ onMounted(() => {
margin-bottom: 15px; margin-bottom: 15px;
padding: 15px 40px; padding: 15px 40px;
position: relative; position: relative;
border-bottom: 1px solid rgba(26, 233, 238, 0.2); // border-bottom: 1px solid rgba(26, 233, 238, 0.2);
height: 150px; height: 150px;
background: repeating-linear-gradient(-65deg, background: repeating-linear-gradient(-65deg,
rgba(15, 43, 89, 0.3) 0px, rgba(15, 43, 89, 0.3) 0px,
@ -362,4 +420,30 @@ onMounted(() => {
} }
} }
.dropdown {
position: absolute;
right: 0;
bottom: -190px;
background: #112a44;
border: 1px solid #1ae9ee;
border-radius: 6px;
z-index: 100;
min-width: 220px;
min-height: 120px;
box-shadow: 0 4px 16px rgba(0,0,0,0.25);
padding: 16px 0;
.dropdown-item {
padding: 20px 32px;
font-size: 28px;
color: #fff;
cursor: pointer;
text-align: left;
&:hover {
background: #1ae9ee;
color: #112a44;
}
}
}
</style> </style>

View File

@ -42,9 +42,9 @@ const weather = [
<!--<div class="youjuxing"></div> --> <!--<div class="youjuxing"></div> -->
<!-- <div class="guang"></div> --> <!-- <div class="guang"></div> -->
<div class="d-flex jc-center"> <div class="d-flex jc-center">
<div class="title"> <!-- <div class="title">
<span class="title-text"></span> <span class="title-text"></span>
</div> </div> -->
</div> </div>
<div class="timers"> <div class="timers">
<span>admin</span> <span>admin</span>