右侧实时图像 接口联调 视频流解析

地图图标 控制显示隐藏
This commit is contained in:
fengshiwang 2025-06-04 16:46:08 +08:00
parent f70b2905dd
commit 9ec6f41e6f
8 changed files with 375 additions and 169 deletions

6
package-lock.json generated
View File

@ -13,6 +13,7 @@
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"element-plus": "^2.6.2", "element-plus": "^2.6.2",
"hls.js": "^1.6.5",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
@ -2892,6 +2893,11 @@
"he": "bin/he" "he": "bin/he"
} }
}, },
"node_modules/hls.js": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.5.tgz",
"integrity": "sha512-KMn5n7JBK+olC342740hDPHnGWfE8FiHtGMOdJPfUjRdARTWj9OB+8c13fnsf9sk1VtpuU2fKSgUjHvg4rNbzQ=="
},
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
"version": "2.8.9", "version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",

View File

@ -16,6 +16,7 @@
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"element-plus": "^2.6.2", "element-plus": "^2.6.2",
"hls.js": "^1.6.5",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",

View File

@ -86,3 +86,23 @@ export const todayHourly=(param:any={})=>{
export const trafficTrend=(param:any={})=>{ export const trafficTrend=(param:any={})=>{
return GET('/device/trafficFlow/trafficTrend',param) return GET('/device/trafficFlow/trafficTrend',param)
} }
/**事件历史记录管理 历史数据 */
export const meventListHistory=(param:any={})=>{
return GET('/device/mevent/listHistory',param)
}
/**数据字典-根据类型获取字典数据 */
export const getDictData = (dictType: string) => {
return GET(`/system/dict/data/type/${dictType}`);
}
/**视频监控设备列表*/
export const getVideoDeviceList = (param: any = {}) => {
return POST('/video/device/list', param);
}
/**视频流 */
export const videoStream=(param:any={})=>{
return GET('/video/stream',param)
}

View File

@ -1,52 +1,79 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from "vue"; import { ref, computed, onMounted } from "vue";
import { meventListHistory } from "@/api/modules/index";
import dayjs from "dayjs"; import dayjs from "dayjs";
interface EventItem { interface EventItem {
type: string;
location: string; location: string;
time: string; time: string;
status: "处置中" | "待处置"; status: "处置中" | "待处置";
} }
// const allEvents = ref<EventItem[]>([
const wrongWayEvents = ref<EventItem[]>([ // {
{ // type: "",
location: "邯郸方向 K34+230", // location: " K34+230",
time: "2025-4-15 12:34:56", // time: "2025-4-15 12:34:56",
status: "处置中", // status: "",
}, // },
// {
// type: "",
// location: " K34+230",
// time: "2025-4-15 12:34:56",
// status: "",
// },
// {
// type: "",
// location: " K34+230",
// time: "2025-4-15 12:34:56",
// status: "",
// },
]); ]);
const roadWorkEvents = ref<EventItem[]>([ // const wrongWayEvents = computed(() =>
{ // allEvents.value.filter((e) => e.type === "")
location: "邯郸方向 K34+230", // );
time: "2025-4-15 12:34:56", // const roadWorkEvents = computed(() =>
status: "待处置", // allEvents.value.filter((e) => e.type === "")
}, // );
]);
const formatTime = (time: string) => { const formatTime = (time: string) => {
return dayjs(time).format("YYYY-MM-DD HH:mm:ss"); return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
}; };
onMounted(()=>{
const endTime = dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss');
const startTime = dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss');
meventListHistory({startTime, endTime}).then((res)=>{
console.log(res, 'rrreeesss')
allEvents.value = res.rows.map((item: any) => ({
type: item.eventType,
location: (item.direction === '1' ? '黄骅港方向 ' : item.direction === '2' ? '邯郸方向 ' : '') + item.pilenum,
time: item.time,
status: item.status == '0' ? '待处置' : '处置中',
}));
})
})
</script> </script>
<template> <template>
<div class="event-task"> <div class="event-task">
<div class="event-section"> <div v-for="(event, index) in allEvents"
:key="index" class="event-section">
<div class="section-header"> <div class="section-header">
<div style="color: #fbfbfc">车辆逆行</div> <div style="color: #fbfbfc">{{event.type}}</div>
<div <div
v-if="wrongWayEvents.length"
class="event-status" class="event-status"
:class="{ processing: wrongWayEvents[0].status === '处置中' }" :class="{
processing: event.status === '处置中',
pending: event.status === '待处置'
}"
> >
{{ wrongWayEvents[0].status }} {{ event.status }}
</div> </div>
</div> </div>
<div class="event-list" v-if="wrongWayEvents.length"> <div class="event-list">
<div <div
v-for="(event, index) in wrongWayEvents"
:key="index"
class="event-item" class="event-item"
> >
<div class="event-info"> <div class="event-info">
@ -55,10 +82,10 @@ const formatTime = (time: string) => {
</div> </div>
</div> </div>
</div> </div>
<div v-else class="empty-state">暂无逆行事件</div> <!-- <div v-else class="empty-state">暂无逆行事件</div> -->
</div> </div>
<div class="event-section"> <!-- <div class="event-section">
<div class="section-header"> <div class="section-header">
<div style="color: #fbfbfc">道路施工</div> <div style="color: #fbfbfc">道路施工</div>
<div <div
@ -82,7 +109,7 @@ const formatTime = (time: string) => {
</div> </div>
</div> </div>
<div v-else class="empty-state">暂无施工事件</div> <div v-else class="empty-state">暂无施工事件</div>
</div> </div> -->
</div> </div>
</template> </template>
@ -96,7 +123,22 @@ const formatTime = (time: string) => {
background: transparent; background: transparent;
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
overflow-y: scroll;
z-index: 9999;
&::-webkit-scrollbar {
width: 8px;
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: linear-gradient(180deg, #00c6ff 0%, #085b9f 100%);
border-radius: 4px;
}
&::-webkit-scrollbar-track {
background: rgba(0, 198, 255, 0.08);
border-radius: 4px;
}
.event-section { .event-section {
height: calc(50% - 10px); height: calc(50% - 10px);
background: linear-gradient( background: linear-gradient(
@ -112,7 +154,7 @@ const formatTime = (time: string) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;
overflow: hidden; // overflow: hidden;
&::before { &::before {
content: ""; content: "";
@ -129,20 +171,20 @@ const formatTime = (time: string) => {
); );
} }
&::after { // &::after {
content: ""; // content: "";
position: absolute; // position: absolute;
bottom: 0; // bottom: 0;
left: 0; // left: 0;
right: 0; // right: 0;
height: 1px; // height: 1px;
background: linear-gradient( // background: linear-gradient(
90deg, // 90deg,
transparent, // transparent,
rgba(0, 198, 255, 0.3), // rgba(0, 198, 255, 0.3),
transparent // transparent
); // );
} // }
.section-header { .section-header {
display: flex; display: flex;
@ -151,22 +193,22 @@ const formatTime = (time: string) => {
gap: 12px; gap: 12px;
margin-bottom: 20px; margin-bottom: 20px;
padding-bottom: 12px; padding-bottom: 12px;
border-bottom: 1px solid rgba(0, 198, 255, 0.1); border: 1px solid rgba(0, 198, 255, 0.1);
position: relative; // position: relative;
background-color: #0e2d51; background-color: #0e2d51;
border-radius: 15px; border-radius: 15px;
padding: 14px; padding: 14px;
font-size: 22px; font-size: 22px;
&::after { // &::after {
content: ""; // content: "";
position: absolute; // position: absolute;
bottom: -1px; // bottom: -1px;
left: 0; // left: 0;
width: 100px; // width: 100px;
height: 1px; // height: 1px;
background: linear-gradient(90deg, #00c6ff, transparent); // background: linear-gradient(90deg, #00c6ff, transparent);
} // }
i { i {
width: 32px; width: 32px;
@ -229,7 +271,7 @@ const formatTime = (time: string) => {
.event-list { .event-list {
flex: 1; flex: 1;
overflow-y: auto; //overflow-y: auto;
padding-right: 4px; padding-right: 4px;
&::-webkit-scrollbar { &::-webkit-scrollbar {
@ -258,36 +300,36 @@ const formatTime = (time: string) => {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
&::before { // &::before {
content: ""; // content: "";
position: absolute; // position: absolute;
top: 0; // top: 0;
left: 0; // left: 0;
right: 0; // right: 0;
height: 1px; // height: 1px;
background: linear-gradient( // background: linear-gradient(
90deg, // 90deg,
transparent, // transparent,
rgba(0, 198, 255, 0.2), // rgba(0, 198, 255, 0.2),
transparent // transparent
); // );
} // }
&:hover { // &:hover {
background: rgba(4, 49, 128, 0.3); // background: rgba(4, 49, 128, 0.3);
border-color: rgba(0, 198, 255, 0.3); // border-color: rgba(0, 198, 255, 0.3);
transform: translateY(-2px); // transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(0, 198, 255, 0.15); // box-shadow: 0 4px 20px rgba(0, 198, 255, 0.15);
&::before { // &::before {
background: linear-gradient( // background: linear-gradient(
90deg, // 90deg,
transparent, // transparent,
rgba(0, 198, 255, 0.4), // rgba(0, 198, 255, 0.4),
transparent // transparent
); // );
} // }
} // }
.event-info { .event-info {
display: flex; display: flex;

View File

@ -1,7 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref, onMounted, nextTick } from "vue";
import demoImage from "@/assets/img/demo.png"; import demoImage from "@/assets/img/demo.png";
import { getVideoDeviceList, videoStream } from "@/api/modules/index";
import Hls from "hls.js";
import dayjs from "dayjs";
const videoUrl = ref(""); // m3u8
const videoRef = ref<HTMLVideoElement | null>(null);
// //
const deviceStatus = ref({ const deviceStatus = ref({
normal: 248, normal: 248,
@ -10,49 +15,50 @@ const deviceStatus = 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: 101, name: "001", src:'' },
{ id: 102, name: "高速公路监控002", image: demoImage }, // { id: 102, name: "002", src:'' },
{ id: 103, name: "高速公路监控003", image: demoImage }, // { id: 103, name: "003", src:'' },
{ id: 104, name: "高速公路监控004", image: demoImage }, // { id: 104, name: "004", src:'' },
{ id: 105, name: "高速公路监控005", image: demoImage }, // { id: 105, name: "005", src:'' },
{ id: 106, name: "高速公路监控006", image: demoImage }, // { id: 106, name: "006", src:'' },
]); // ]);
const fixedRoadMonitors = ref<any[]>([]);
// //
const toggleGroup = (group: any) => { const toggleGroup = (group: any) => {
@ -62,15 +68,72 @@ 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.channelCode === point.channelCode);
// if (index > -1) {
// selectedPoints.value.splice(index, 1);
// } else {
// selectedPoints.value.push(point);
// }
// videoStream({deviceCode:'00000000001311027500',channelCode:'00000000001311028602',}).then((res)=>{
// videoUrl.value = res;
// nextTick();
// if (videoRef.value) {
// if (Hls.isSupported()) {
// const hls = new Hls();
// hls.loadSource(videoUrl.value);
// hls.attachMedia(videoRef.value);
// } else if (videoRef.value.canPlayType('application/vnd.apple.mpegurl')) {
// videoRef.value.src = videoUrl.value;
// }
// }
// })
// };
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 {
// 6
if (selectedPoints.value.length >= 6) {
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 >= 6) {
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>
@ -107,36 +170,36 @@ const togglePoint = (point: any) => {
</div> </div>
<div class="list-content"> <div class="list-content">
<div <div
v-for="group in monitoringGroups" v-for="(group, index) in monitoringGroups"
:key="group.id" :key="index"
class="group-item" 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.name }}{{ group.count }}</span >{{ group.deviceName }}{{ group.channels.length }}</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 in group.points" v-for="(point, vic) in group.channels"
:key="point.id" :key="point.channelCode"
class="point-item" class="point-item"
:class="{ active: selectedPoints.some((p) => p.id === point.id) }" :class="{ active: selectedPoints.some((p) => p.channelCode === point.channelCode) }"
@click="togglePoint(point)" @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="status-indicator"
:class="point.status === '正常' ? 'normal' : 'warning'" :class="point.status === 1 ? 'normal' : 'warning'"
></span> ></span>
<span <span
class="point-status" class="point-status"
:class="point.status === '正常' ? 'normal' : 'warning'" :class="point.status === 1 ? 'normal' : 'warning'"
> >
{{ point.status }} {{ point.status }}
</span> </span>
@ -150,7 +213,7 @@ 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" v-for="monitor in fixedRoadMonitors"
:key="monitor.id" :key="monitor.id"
@ -161,7 +224,34 @@ const togglePoint = (point: any) => {
<div class="corner-decoration bottom-left"></div> <div class="corner-decoration bottom-left"></div>
<div class="corner-decoration bottom-right"></div> <div class="corner-decoration bottom-right"></div>
<div class="image-container"> <div class="image-container">
<img :src="monitor.image" :alt="monitor.name" /> <video
ref="videoRef"
v-if="videoUrl"
controls
autoplay
style="width:100%;height:300px;background:#000"
></video>
</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>

View File

@ -324,27 +324,35 @@ const items = ref([
{ {
defaultImg: eqm1Default, defaultImg: eqm1Default,
activeImg: eqm1Active, activeImg: eqm1Active,
isActive: false, isActive: true, //
type: '44', //
}, },
{ {
defaultImg: eqm2Default, defaultImg: eqm2Default,
activeImg: eqm2Active, activeImg: eqm2Active,
isActive: false, isActive: true,
type: '22', //
}, },
{ {
defaultImg: eqm3Default, defaultImg: eqm3Default,
activeImg: eqm3Active, activeImg: eqm3Active,
isActive: false, isActive: true,
type: '53', // 广
}, },
{ {
defaultImg: eqm4Default, defaultImg: eqm4Default,
activeImg: eqm4Active, activeImg: eqm4Active,
isActive: false, isActive: true,
type: '15', //
}, },
]); ]);
const toggleSelection = (index: number) => { const toggleSelection = (index: number) => {
items.value[index].isActive = !items.value[index].isActive; items.value[index].isActive = !items.value[index].isActive;
// /
window.dispatchEvent(new CustomEvent('toggle-map-device', {
detail: { type: items.value[index].type, show: items.value[index].isActive }
}));
}; };
</script> </script>

View File

@ -50,14 +50,14 @@ const iconModules = import.meta.glob("@/assets/img/map/*.png", {
function getIcon(type, active = false) { function getIcon(type, active = false) {
const iconName = const iconName =
{ {
1: active ? "lianzhen.png" : "lianzhen.png", // 1: active ? "lianzhen.png" : "lianzhen.png",
2: active ? "datun.png" : "datun.png", // 2: active ? "datun.png" : "datun.png",
3: active ? "zhaowang.png" : "zhaowang.png", // 3: active ? "zhaowang.png" : "zhaowang.png",
4: active ? "dongguang.png" : "dongguang.png", // 4: active ? "dongguang.png" : "dongguang.png",
5: active ? "nanpi.png" : "nanpi.png", // 5: active ? "nanpi.png" : "nanpi.png",
6: active ? "zhaizi.png" : "zhaizi.png", // 6: active ? "zhaizi.png" : "zhaizi.png",
7: active ? "xiaozhuang.png" : "xiaozhuang.png", // 7: active ? "xiaozhuang.png" : "xiaozhuang.png",
8: active ? "warning.png" : "warning.png", // 8: active ? "warning.png" : "warning.png",
22: active ? "video-active.png" : "video.png", 22: active ? "video-active.png" : "video.png",
44: active ? "weather-active.png" : "weather.png", 44: active ? "weather-active.png" : "weather.png",
53: active ? "broadcast-active.png" : "broadcast.png", 53: active ? "broadcast-active.png" : "broadcast.png",
@ -101,6 +101,18 @@ const customDevices = [
]; ];
onMounted(async () => { onMounted(async () => {
//
window.addEventListener('toggle-map-device', (e) => {
const { type, show } = e.detail;
showType.value[type] = show;
markerMap.value[type]?.forEach((marker) => {
if (show) {
map.addOverlay(marker);
} else {
map.removeOverlay(marker);
}
});
});
await nextTick(); await nextTick();
map = new BMap.Map("baiduMap"); map = new BMap.Map("baiduMap");
const point = new BMap.Point(116.827009, 37.890385); const point = new BMap.Point(116.827009, 37.890385);

View File

@ -1,19 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from "vue"; import { ref, onMounted, computed } from "vue";
import EventStatus from "./EventStatus.vue"; import EventStatus from "./EventStatus.vue";
import EventTask from "./EventTask.vue"; import EventTask from "./EventTask.vue";
import RealTimeImage from "./RealTimeImage.vue"; import RealTimeImage from "./RealTimeImage.vue";
import { weatherForecast, weatherHourly, todayStatusCount, todayHourly } from "@/api/modules/index"; import { weatherForecast, weatherHourly, todayStatusCount, todayHourly, getDictData } from "@/api/modules/index";
import { useTodayTime, } from "@/utils/packge"; import { useTodayTime, } from "@/utils/packge";
const { todayTime, getTodayTime } = useTodayTime(); const { todayTime, getTodayTime } = useTodayTime();
// API // API
const pendingCount = ref<string>(''); const pendingCount = ref<string>('');
const processingCount = ref<string>(''); const processingCount = ref<string>('');
const serviceArea = ref<any[]>([]);
const Hub = ref<any[]>([]);
const Intercommunication = ref<any[]>([]);
// //
const selectedServiceArea = ref("全部"); const selectedServiceArea = ref("全部");
const serviceAreas = ref(["全部", "南皮服务区", "东光服务区"]); const serviceAreas = ref([]);
// //
const handleServiceAreaChange = (area: string) => { const handleServiceAreaChange = (area: string) => {
selectedServiceArea.value = area; selectedServiceArea.value = area;
@ -28,25 +30,49 @@ const areaTypes = ref([
// //
const toggleAreaType = (id: string) => { const toggleAreaType = (id: string) => {
const areaType = areaTypes.value.find((type) => type.id === id); areaTypes.value.forEach((type) => {
if (areaType) { type.selected = type.id === id;
areaType.selected = !areaType.selected; });
}
}; };
onMounted(()=>{ onMounted(()=>{
todayStatusCount({todayTime: todayTime.value}).then((res: any) => { todayStatusCount({todayTime: todayTime.value}).then((res: any) => {
if(res.code === 200){ if(res.code === 200){
res.data.forEach((item: any) => { res.data.forEach((item: any) => {
if(item.status == '0'){ // if(item.status == '0'){ //
pendingCount.value = item.count pendingCount.value = item.count || 0
} else if(item.status == '2'){ // } else if(item.status == '2'){ //
processingCount.value = item.count processingCount.value = item.count || 0
} }
}); });
} }
}) })
getDictData("hb_service_area").then((res: any) => { //
if (res.code === 200) {
serviceArea.value = res.data || [];
}
});
getDictData("hb_hub").then((res: any) => { //
if (res.code === 200) {
Hub.value = res.data || [];
}
});
getDictData("hb_interchange").then((res: any) => { //
if (res.code === 200) {
Intercommunication.value = res.data || [];
}
});
}) })
const currentAreaList = computed(() => {
const selectedType = areaTypes.value.find((type) => type.selected);
if (selectedType?.id === "service") {
return serviceArea.value;
} else if (selectedType?.id === "interchange") {
return Intercommunication.value;
} else if (selectedType?.id === "hub") {
return Hub.value;
}
return [];
});
const isDropdownOpen = ref(false); const isDropdownOpen = ref(false);
</script> </script>
@ -91,16 +117,16 @@ const isDropdownOpen = ref(false);
</div> </div>
<div class="dropdown-menu" v-show="isDropdownOpen"> <div class="dropdown-menu" v-show="isDropdownOpen">
<div <div
v-for="area in serviceAreas" v-for="(item, index) in currentAreaList"
:key="area" :key="index"
class="dropdown-item" class="dropdown-item"
:class="{ active: selectedServiceArea === area }" :class="{ active: selectedServiceArea === item.dictLabel }"
@click=" @click="
handleServiceAreaChange(area); handleServiceAreaChange(item.dictLabel);
isDropdownOpen = false; isDropdownOpen = false;
" "
> >
{{ area }} {{ item.dictLabel }}
</div> </div>
</div> </div>
</div> </div>
@ -118,6 +144,7 @@ const isDropdownOpen = ref(false);
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-right: 20px;
// justify-content: space-between; // justify-content: space-between;
// align-items: flex-start; // align-items: flex-start;
.top { .top {