294 lines
6.8 KiB
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>
|