yunsan-pc/src/views/home/components/DashboardHeader.vue

294 lines
6.8 KiB
Vue

<template>
<div class="dashboard-header">
<nav class="layout-menu" aria-label="">
<RouterLink v-for="item in menuItems" :key="item.to" :to="item.to" class="layout-menu__item">
<span>{{ item.label }}</span>
</RouterLink>
<div class="weather-info">
<el-icon class="weather-icon"><Pouring /></el-icon>
<span class="weather-temperature">{{ temperatureRange }}</span>
<span class="weather-name">{{ weatherInfo.weather || '--' }}</span>
</div>
</nav>
<div class="header-title">
<img src="/imgs/title.png" alt="title" class="title-img" />
</div>
<div class="header-time">{{ currentTime }}</div>
<div class="notice-marquee" v-if="noticeList.length > 0">
<div class="marquee-content" :class="{ 'marquee-scroll': noticeList.length > 1 }">
<div class="notice-item" v-for="(item, index) in displayNoticeList" :key="index">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { Pouring } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
import server from '@/utils/service'
const router = useRouter()
const goHome = () => {
router.push('/home')
}
const goTraffic = () => {
router.push('/traffic')
}
const currentTime = ref('')
const weatherInfo = ref({})
const noticeList = ref([])
const currentNoticeIndex = ref(0)
let noticeTimer = null
let timeTimer = null
const menuItems = [
{ label: '常规', to: '/home' },
{ label: '客运', to: '/traffic' },
{ label: '行车', to: '/driving' },
{ label: '施工', to: '/construction' }
]
const displayNoticeList = computed(() => {
if (noticeList.value.length === 0) return []
return [noticeList.value[currentNoticeIndex.value]]
})
const temperatureRange = computed(() => {
const min = weatherInfo.value.tem_min ?? weatherInfo.value.min_tem ?? weatherInfo.value.temp_min ?? 21
const max = weatherInfo.value.tem_max ?? weatherInfo.value.max_tem ?? weatherInfo.value.temp_max
?? (weatherInfo.value.tem ? Math.round(Number(weatherInfo.value.tem)) : 27)
return `${min}°~${max}°`
})
const updateTime = () => {
const now = new Date()
currentTime.value = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
}).replace(/\//g, '-')
}
const fetchWeather = async () => {
try {
const response = await server.getQxjGdybHour()
if (response.data.success) {
weatherInfo.value = response.data.data.tq
}
} catch (error) {
console.error('获取天气信息失败:', error)
}
}
const fetchTaskNotice = async () => {
try {
const response = await server.getTaskNotice()
console.log('原始数据-走马灯:', response.data.data)
if (response.data.success) {
const data = response.data.data
if (data && data.content) {
const textContent = data.content.replace(/<[^>]+>/g, '')
noticeList.value = [textContent]
startNoticeScroll()
}
}
} catch (error) {
console.error('获取走马灯数据失败:', error)
}
}
const startNoticeScroll = () => {
if (noticeList.value.length <= 1) return
noticeTimer = setInterval(() => {
currentNoticeIndex.value = (currentNoticeIndex.value + 1) % noticeList.value.length
}, 3000)
}
onMounted(() => {
updateTime()
fetchWeather()
fetchTaskNotice()
timeTimer = setInterval(updateTime, 1000)
})
onUnmounted(() => {
clearInterval(timeTimer)
clearInterval(noticeTimer)
})
</script>
<style lang="scss" scoped>
.dashboard-header {
position: absolute;
left: -2px;
top: -36px;
width: 4802px;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
background: url('/imgs/top.png') no-repeat center center;
background-size: 100% 100%;
// border-bottom: 2px solid rgba(0, 212, 255, 0.5);
.layout-menu {
position: absolute;
top: 82px;
left: 42px;
z-index: 10;
display: flex;
align-items: center;
&__item {
display: flex;
align-items: center;
justify-content: center;
width: 214px;
height: 58px;
padding-bottom: 8px;
background: url('/imgs/layout/menu-bg.png') no-repeat center / 100% 100%;
text-decoration: none;
margin-left: -10px;
span {
color: #fff;
font-size: 36px;
font-weight: 500;
background: linear-gradient(180deg, #ffffff 53%, #8dc2ff 69%, #66b5ff 75%), #FFFFFF;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
&:hover {
filter: brightness(1.15);
}
&.router-link-active {
background-image: url('/imgs/layout/menu-bg-active.png');
color: #eafaff;
}
}
}
.header-title {
.title-img {
margin-top: 18px;
max-height: 100%;
max-width: 100%;
}
}
.header-time {
position: absolute;
// right: 40px;
top: 148px;
left: 50%;
font-family: BlackOpsOne, sans-serif;
font-size: 44px;
color: #19EBFF;
text-align: center;
// 居中显示
transform: translateX(-50%);
}
.notice-marquee {
position: absolute;
right: 40px;
top: 55px;
width: 1300px;
height: 45px;
overflow: hidden;
.marquee-content {
display: flex;
flex-direction: column;
.notice-item {
font-size: 40px;
color: rgba(255, 255, 255, 0.9);
white-space: nowrap;
animation: marquee 20s linear infinite;
}
}
}
@keyframes marquee {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
.function-switch {
position: absolute;
left: 100px;
top: 80px;
transform: translateY(-50%);
display: flex;
gap: 0px;
.switch-btn {
border: none;
background: transparent;
cursor: pointer;
padding: 0;
img {
display: block;
}
&:hover {
opacity: 0.8;
}
&:active {
transform: scale(0.95);
}
}
}
.weather-info {
display: flex;
align-items: center;
height: 58px;
margin-left: 46px;
gap: 14px;
white-space: nowrap;
color: #fff;
.weather-icon {
width: 40px;
height: 40px;
color: #82f6ff;
font-size: 40px;
filter: drop-shadow(0 0 6px rgba(70, 224, 255, 0.75));
}
.weather-temperature,
.weather-name {
font-size: 30px;
font-weight: 500;
line-height: 58px;
text-shadow: 0px 0px 10px rgba(30, 198, 255, 0.8);
}
}
}
</style>