424 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="bottom-panel">
<div class="nav-menu">
<div
v-for="(item, index) in menuItems"
:key="index"
class="nav-item"
:class="{ active: activeIndex === index }"
@click="handleClick(item, index)"
>
<div class="nav-icon-box" :ref="(el) => setNavIconRef(el, index)">
<!-- <i :class="item.icon"></i> -->
<img :src="activeIndex === index ? item.icon1 : item.icon" alt="" />
</div>
<div class="nav-label">{{ item.label }}</div>
</div>
</div>
<!-- 气象预警监测表格组件 -->
<WeatherWarningTable ref="weatherWarningTableRef" :getdateRange="getdateRange" @clearFilters="handleClearFilters" />
<!-- 涉灾隐患点图片弹窗 -->
<div v-if="showHazardPopup" class="hazard-popup" :style="popupStyle">
<div class="hazard-popup-content">
<div v-for="(item, index) in hazardItems" :key="index" class="hazard-item" @click="handleHazardItemClick(item)">
<img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span>
</div>
</div>
</div>
<!-- 路段图片弹窗 -->
<div v-if="showRoadPopup" class="hazard-popup road-popup" :style="roadPopupStyle">
<div class="hazard-popup-content">
<div v-for="(item, index) in roadItems" :key="index" class="hazard-item" @click="handleRoadItemClick(item)">
<img :src="item.icon" :alt="item.label" />
<span>{{ item.label }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, nextTick, inject } from 'vue'
import WeatherWarningTable from './component/WeatherWarningTable.vue'
import warningIconIcon from '../../assets/RiskWarning_img/风险预警icon@2x.png'
import tunnelIconIcon from '../../assets/RiskWarning_img/隧道icon@2x.png'
import slopeIconIcon from '../../assets/RiskWarning_img/边坡icon@2x.png'
import bridgeIconIcon from '../../assets/RiskWarning_img/桥梁icon@2x.png'
import roadIconIcon from '../../assets/RiskWarning_img/线路路段icon@2x.png'
import teamIconIcon from '../../assets/RiskWarning_img/队伍icon@2x.png'
import hazardIconIconIcon from '../../assets/RiskWarning_img/隐患点icon@2x.png'
import engineeringIconIconIcon from '../../assets/RiskWarning_img/危大工程icon@2x.png'
import warningIconIcon1 from '../../assets/RiskWarning_img/风险预警icon1@2x.png'
import tunnelIconIcon1 from '../../assets/RiskWarning_img/隧道icon1@2x.png'
import slopeIconIcon1 from '../../assets/RiskWarning_img/边坡icon1@2x.png'
import bridgeIconIcon1 from '../../assets/RiskWarning_img/桥梁icon1@2x.png'
import roadIconIcon1 from '../../assets/RiskWarning_img/线路路段icon1@2x.png'
import teamIconIcon1 from '../../assets/RiskWarning_img/队伍icon1@2x.png'
import hazardIconIcon from '../../assets/RiskWarning_img/隐患点icon1@2x.png'
import engineeringIconIcon from '../../assets/RiskWarning_img/危大工程icon1@2x.png'
import hazardIconIcon1 from '../../assets/MaMap_img/一般路内隐患点@2x.png'
import hazardIconIcon2 from '../../assets/MaMap_img/一般路外隐患点@2x.png'
import hazardIconIcon3 from '../../assets/MaMap_img/较大路内隐患点@2x.png'
import hazardIconIcon4 from '../../assets/MaMap_img/较大路外隐患点@2x.png'
import hazardIconIcon5 from '../../assets/MaMap_img/重大路内隐患点@2x.png'
import hazardIconIcon6 from '../../assets/MaMap_img/重大路外隐患点@2x.png'
import tunnelLineIcon3 from '../../assets/MaMap_img/高风险路段@2x.png'
import tunnelLineIcon2 from '../../assets/MaMap_img/较高风险路段@2x.png'
import tunnelLineIcon1 from '../../assets/MaMap_img/中风险路段@2x.png'
import tunnelLineIcon from '../../assets/MaMap_img/线路icon定位@2x.png'
const getdateRange = inject('getdateRange', ref([]))
const emit = defineEmits(['changeActiveIndex', 'clearMapMarkers', 'hazardItemClick', 'roadItemClick', 'showHazardPopupfn'])
const activeIndex = ref(-1)
const menuItems = [
{
label: '涉灾隐患点',
icon: 'icon-hazard',
iconClass: 'hazard',
icon: hazardIconIconIcon,
icon1: hazardIconIcon,
},
{
label: '路段',
icon: 'icon-road',
iconClass: 'road',
icon: roadIconIcon,
icon1: roadIconIcon1,
},
{
label: '驻地',
icon: 'icon-warning',
iconClass: 'warning',
icon: warningIconIcon,
icon1: warningIconIcon1,
},
{
label: '隧道',
icon: 'icon-tunnel',
iconClass: 'tunnel',
icon: tunnelIconIcon,
icon1: tunnelIconIcon1,
},
{
label: '边坡',
icon: 'icon-slope',
iconClass: 'slope',
icon: slopeIconIcon,
icon1: slopeIconIcon1,
},
{
label: '桥梁',
icon: 'icon-bridge',
iconClass: 'bridge',
icon: bridgeIconIcon,
icon1: bridgeIconIcon1,
},
{
label: '队伍',
icon: 'icon-team',
iconClass: 'team',
icon: teamIconIcon,
icon1: teamIconIcon1,
},
{
label: '危大工程',
icon: 'icon-hazard',
iconClass: 'hazard',
icon: engineeringIconIconIcon,
icon1: engineeringIconIcon,
},
]
// 涉灾隐患点弹窗相关
const showHazardPopup = ref(false)
const popupStyle = ref({})
const navIconRefs = ref([])
// 隐患点数据
const hazardItems = ref([
{ icon: hazardIconIcon5, label: '重大路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon6, label: '重大路外隐患点', isWithinRedLine: '否' },
{ icon: hazardIconIcon3, label: '较大路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon4, label: '较大路外隐患点', isWithinRedLine: '否' },
{ icon: hazardIconIcon1, label: '一般路内隐患点', isWithinRedLine: '是' },
{ icon: hazardIconIcon2, label: '一般路外隐患点', isWithinRedLine: '否' },
])
// 路段弹窗相关
const showRoadPopup = ref(false)
const roadPopupStyle = ref({})
// 路段数据
const roadItems = ref([
{ icon: tunnelLineIcon3, label: '高风险路段' },
{ icon: tunnelLineIcon2, label: '较高风险路段' },
{ icon: tunnelLineIcon1, label: '中风险路段' },
{ icon: tunnelLineIcon, label: '低风险路段' },
])
// 设置nav-icon-box的ref
const setNavIconRef = (el, index) => {
if (el) {
navIconRefs.value[index] = el
}
}
const weatherWarningTableRef = ref(null)
// 点击切换导航项
const handleClick = (item, index) => {
// 如果点击的是涉灾隐患点
if (item.label === '涉灾隐患点') {
// 切换弹窗显示状态
showHazardPopup.value = !showHazardPopup.value
if (showHazardPopup.value) {
showRoadPopup.value = false
}
if (showHazardPopup.value) {
// 计算弹窗位置
const navIconBox = navIconRefs.value[index]
if (navIconBox) {
const rect = navIconBox.getBoundingClientRect()
popupStyle.value = {
position: 'fixed',
left: rect.right + 10 + 'px',
top: rect.top + 'px',
zIndex: 2,
}
}
}
} else if (item.label === '路段') {
// 如果点击的是路段
// 切换弹窗显示状态
showRoadPopup.value = !showRoadPopup.value
if (showRoadPopup.value) {
showHazardPopup.value = false
}
if (showRoadPopup.value) {
// 计算弹窗位置
const navIconBox = navIconRefs.value[index]
if (navIconBox) {
const rect = navIconBox.getBoundingClientRect()
roadPopupStyle.value = {
position: 'fixed',
left: rect.right + 10 + 'px',
top: rect.top + 'px',
zIndex: 2,
}
}
}
emit('showHazardPopupfn', false)
} else {
showHazardPopup.value = false
showRoadPopup.value = false
emit('showHazardPopupfn', false)
// 点击非路段,隐藏路段统计
emit('hideRoadStats')
}
activeIndex.value = index
if (item.label !== '路段') {
emit('changeActiveIndex', {
...item,
})
}
}
// 点击隐患点项
const handleHazardItemClick = (item) => {
console.log('点击隐患点:', item)
emit('hazardItemClick', item)
// 可以在这里添加其他逻辑,比如关闭弹窗
// showHazardPopup.value = false;
emit('showHazardPopupfn', true)
}
const roadItem = ref({})
// 点击路段项
const handleRoadItemClick = (item) => {
console.log('点击路段:', item)
roadItem.value = item
emit('roadItemClick', item)
// 可以在这里添加其他逻辑,比如关闭弹窗
// showRoadPopup.value = false;
}
// 处理清除筛选事件
const handleClearFilters = () => {
console.log('清除筛选条件')
// 重置活动索引
activeIndex.value = -1
// 关闭弹窗
showHazardPopup.value = false
showRoadPopup.value = false
// 触发清除地图标记事件
emit('clearMapMarkers')
emit('showHazardPopupfn', false)
}
</script>
<style lang="scss" scoped>
// 视频屏幕自适应 - 基于视口宽度动态调整
// 基准宽度 1920px使用 vw 单位实现自适应
@function vw($px) {
@return calc($px / 1920 * 100vw);
}
.bottom-panel {
position: relative;
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
@media (max-width: 1366px) {
padding: vw(8);
}
@media (max-width: 1024px) {
padding: vw(6);
}
}
// 涉灾隐患点弹窗样式
.hazard-popup {
background: rgba(20, 46, 73, 0.95);
border: 1px solid rgba(64, 169, 255, 0.4);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
.hazard-popup-content {
display: flex;
flex-direction: column;
gap: vw(8);
.hazard-item {
display: flex;
align-items: center;
gap: vw(8);
padding: vw(5) vw(10);
// border-radius: 4px;
transition: background 0.3s;
cursor: pointer;
&:hover {
background: rgba(64, 169, 255, 0.2);
}
img {
width: vw(40);
height: vw(40);
object-fit: contain;
}
span {
color: rgba(255, 255, 255, 0.9);
font-size: vw(16);
white-space: nowrap;
}
}
}
}
.nav-menu {
width: vw(80);
min-width: vw(80);
height: 100%;
display: flex;
flex-direction: column;
justify-content: end;
align-items: center;
gap: vw(5);
z-index: 2;
position: absolute;
bottom: 0;
left: 0;
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover,
&.active {
.nav-icon-box {
background: rgba(64, 169, 255, 0.3);
border-color: rgba(64, 169, 255, 0.6);
}
.nav-label {
color: #40a9ff;
}
}
.nav-icon-box {
width: vw(50);
height: vw(50);
min-width: vw(36);
min-height: vw(36);
margin-bottom: vw(5);
background: rgba(64, 169, 255, 0.1);
// border: 1px solid rgba(64, 169, 255, 0.3);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
img {
width: vw(50);
height: vw(50);
min-width: vw(32);
min-height: vw(32);
}
i {
font-size: vw(24);
color: #40a9ff;
}
// 使用 emoji 作为图标占位
&.warning::before {
content: '📍';
font-size: vw(24);
}
&.tunnel::before {
content: '🚇';
font-size: vw(24);
}
&.slope::before {
content: '⛰️';
font-size: vw(24);
}
&.bridge::before {
content: '🌉';
font-size: vw(24);
}
&.road::before {
content: '🛣️';
font-size: vw(24);
}
}
.nav-label {
display: flex;
align-items: center;
justify-content: center;
font-size: vw(14);
color: #fff;
transition: all 0.3s ease;
}
}
}
</style>