Files
td_official/src/views/largeScreen/components/header.vue
2025-09-09 09:42:28 +08:00

347 lines
8.5 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="header">
<div class="header_left">
<div class="header_left_img">
<img src="@/assets/large/secure.png" style="width: 100%; height: 100%" />
</div>
<div style="font-size: 12px; padding-left: 10px">安全生产天数</div>
<div class="header_left_text">
{{ safetyDay }}
<span style="font-size: 12px"></span>
</div>
</div>
<div class="title">
<div class="title_text">资金管理看板</div>
<div>Fund Management Dashboard</div>
</div>
<div class="right">
<div class="top-bar">
<!-- 左侧天气轮播区域 -->
<div class="left-section">
<div class="weather-list" @mouseenter="requestPause" @mouseleave="resumeScroll">
<div
v-for="(item, i) in weatherList"
:key="i"
class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
>
<img :src="`../../../src/assets/images/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
<div>{{ item.week }}({{ item.date }})</div>
</div>
</div>
</div>
<!-- 分割线 -->
<div class="divider">
<div class="top-block"></div>
<div class="bottom-block"></div>
</div>
<!-- 右侧管理系统图标 + 文字 -->
<div class="right-section">
<img src="@/assets/large/setting.png" alt="设置图标" />
<span>管理系统</span>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { useUserStoreHook } from '@/store/modules/user';
import { getSafetyDay, getWeather } from '@/api/largeScreen/index';
interface WeatherData {
date: string;
week: string;
tempMax: string;
tempMin: string;
sunRise: string;
sunSet: string;
dayStatus: string;
dayIcon: string;
nightStatus: string;
nightIcon: string;
}
// 星期映射
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
// 日期数据
const date = ref({
ymd: '',
hms: '',
week: 0
});
// 安全生产天数
const safetyDay = ref('');
// 用户存储
const userStore = useUserStoreHook();
const currentProject = computed(() => userStore.selectedProject);
// 天气轮播相关变量
const weatherList = ref<WeatherData[]>([]);
const offsetY = ref<number>(0);
const curIndex = ref(0);
const transition = ref('transform 0.5s ease');
const timer = ref<number | null>(0);
const pendingPause = ref(false);
// 判断当前时间是白天/夜晚
function judgeDayOrNight(sunRise: string, sunSet: string) {
const timeToMinutes = (timeStr: string) => {
const [hours, minutes] = timeStr.split(':').map(Number);
return isNaN(hours) || isNaN(minutes) ? 0 : hours * 60 + minutes;
};
const sunRiseMinutes = timeToMinutes(sunRise);
const sunSetMinutes = timeToMinutes(sunSet);
const now = new Date();
const currentMinutes = now.getHours() * 60 + now.getMinutes();
return currentMinutes >= sunRiseMinutes && currentMinutes <= sunSetMinutes;
}
// 天气轮播逻辑每5秒切换一次
const setWeatherScroll = () => {
curIndex.value += 1;
transition.value = 'transform 0.3s ease';
offsetY.value = curIndex.value * 60; // 每个天气项高度60px需和样式一致
// 轮播到最后一项时,无缝衔接回第一项
if (curIndex.value === weatherList.value.length - 1) {
setTimeout(() => {
transition.value = 'none';
curIndex.value = 0;
offsetY.value = 0;
}, 350);
}
};
// 启动轮播定时器
function startScroll() {
if (timer.value) clearInterval(timer.value);
timer.value = window.setInterval(setWeatherScroll, 5000) as unknown as number;
}
// 鼠标悬浮暂停轮播
function requestPause() {
if (timer.value) {
clearInterval(timer.value);
timer.value = null;
}
pendingPause.value = true;
}
// 鼠标离开恢复轮播
function resumeScroll() {
pendingPause.value = false;
startScroll();
}
// 设置实时时间
const setTime = () => {
const date1 = new Date();
const year = date1.getFullYear();
const month = date1.getMonth() + 1;
const day = date1.getDate();
const hours = date1.getHours().toString().padStart(2, '0');
const minutes = date1.getMinutes().toString().padStart(2, '0');
const seconds = date1.getSeconds().toString().padStart(2, '0');
date.value.ymd = `${year}-${month}-${day}`;
date.value.hms = `${hours}:${minutes}:${seconds}`;
date.value.week = date1.getDay();
};
// 获取天气数据
const getWeatherData = async () => {
try {
if (currentProject.value?.id) {
const res = await getWeather(currentProject.value.id);
if (res.code === 200 && res.data && res.data.length > 0) {
weatherList.value = res.data;
// 处理每一天的天气(白天/夜晚切换图标和状态)
weatherList.value.forEach((item) => {
const isDay = judgeDayOrNight(item.sunRise, item.sunSet);
item.status = isDay ? item.dayStatus : item.nightStatus;
item.icon = isDay ? item.dayIcon : item.nightIcon;
item.tempRange = `${item.tempMin}°/${item.tempMax}°`;
});
// 复制第一项实现无缝轮播
weatherList.value = [...weatherList.value, weatherList.value[0]];
startScroll(); // 数据加载后启动轮播
}
}
} catch (error) {
console.error('获取天气数据失败:', error);
}
};
// 获取安全生产天数
const getSafetyDays = async () => {
try {
if (currentProject.value?.id) {
const res = await getSafetyDay(currentProject.value.id);
if (res.code === 200 && res.data) {
safetyDay.value = res.data.safetyDay.toString();
}
}
} catch (error) {
console.error('获取安全生产天数失败:', error);
}
};
// 组件挂载时初始化
onMounted(() => {
setTime(); // 初始化时间
getSafetyDays();
getWeatherData();
// 时间定时器(每秒更新)
window.setInterval(setTime, 1000);
});
// 组件卸载时清除定时器
onUnmounted(() => {
if (timer.value) {
clearInterval(timer.value);
}
});
</script>
<style scoped lang="scss">
.header {
width: 100%;
height: 80px;
box-sizing: border-box;
padding: 10px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
color: #fff;
}
.header_left {
display: flex;
align-items: center;
.header_left_img {
width: 48px;
height: 48px;
box-sizing: border-box;
// padding-right: 10px;
}
.header_left_text {
font-weight: 500;
text-shadow: 0px 1.24px 6.21px rgba(25, 179, 250, 1);
}
}
.header_right {
width: 100%;
height: 100%;
display: flex;
}
.title {
color: #fff;
font-family: 'AlimamaShuHeiTi', sans-serif;
text-align: center;
}
.title > div:first-child {
/* 第一个子元素的样式 */
font-size: 38px;
letter-spacing: 0.1em;
}
.title > div:last-child {
/* 最后一个子元素的样式 */
font-size: 14px;
}
/* 顶部栏容器Flex 水平布局 + 垂直居中 */
.top-bar {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
color: #fff;
padding: 8px 16px;
font-size: 14px;
}
/* 左侧区域(天气 + 日期):自身也用 Flex 水平排列,确保元素在一行 */
.left-section {
height: 100%;
display: flex;
align-items: center;
.weather-list {
height: 60px;
overflow: hidden;
.weather-item {
height: 60px;
line-height: 60px;
display: flex;
align-items: center;
& > div:last-child {
margin-left: 10px;
}
img {
width: 50px;
height: 50px;
}
}
}
}
/* 分割线(视觉分隔,可根据需求调整样式) */
.divider {
display: grid;
grid-template-rows: 1fr 1fr;
gap: 2px;
padding: 14px 10px;
}
.divider .top-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: start;
}
.divider .bottom-block {
width: 2px;
height: 7px;
background: #19b5fb;
align-self: end;
}
/* 右侧区域(管理系统):图标 + 文字水平排列 */
.right-section {
display: flex;
align-items: center;
font-family: 'AlimamaShuHeiTi', sans-serif;
font-size: 20px;
cursor: pointer;
}
.right-section img {
width: 20px;
height: 20px;
margin-right: 6px;
/* 图标与文字间距 */
}
.change {
display: grid;
place-items: center;
margin-right: 10px;
cursor: pointer;
}
</style>