Snavigation/src/components/WeatherTime.vue
imsyy 2edc0cfd62
🐞 fix: 天气 API 切换至高德 #32
- 修复捷径无法添加 ip 地址 #31
2024-01-17 10:54:53 +08:00

270 lines
6.7 KiB
Vue

<template>
<!-- 天气时钟 -->
<div
:class="[
'weather-time',
status.siteStatus,
status.mainBoxBig && status.siteStatus !== 'normal' && status.siteStatus !== 'focus'
? 'hidden'
: null,
set.showLunar ? 'lunar' : null,
set.timeStyle,
]"
@click.stop
>
<div
class="time"
@click.stop="
status.setSiteStatus(
status.siteStatus !== 'normal' && status.siteStatus !== 'focus' ? 'normal' : 'box',
)
"
>
<span class="hour">{{ timeData.hour ?? "00" }}</span>
<span class="separator" :key="set.showSeconds">:</span>
<span class="minute">{{ timeData.minute ?? "00" }}</span>
<Transition name="fade" mode="out-in">
<span v-if="set.showSeconds" class="second">
<span class="separator">:</span>
<span class="second-num">{{ timeData.second ?? "00" }}</span>
</span>
</Transition>
<template v-if="set.use12HourFormat">
<span class="amPm">{{ timeData.amPm ?? "am" }}</span>
</template>
</div>
<div v-if="set.showLunar" class="lunar">
<span class="year">{{ timeData.lunar?.GanZhiYear }}</span>
<span class="text">{{ timeData.lunar?.text }}</span>
</div>
<div class="date">
<span class="month">{{ timeData.month ?? "0" }}</span>
<span class="day">{{ timeData.day ?? "0" }}</span>
<span class="weekday">{{ timeData.weekday ?? "星期八" }}</span>
</div>
<div v-if="set.showWeather" class="weather">
<span class="status">{{ weatherData?.condition ?? "N/A" }}</span>
<span class="temperature">{{ weatherData?.temp ?? "N/A" }} ℃</span>
<span class="wind">{{ weatherData?.windDir ?? "N/A" }}</span>
<span v-if="weatherData?.windLevel" class="wind-level"> {{ weatherData.windLevel }} </span>
</div>
</div>
</template>
<script setup>
import { getCurrentTime } from "@/utils/timeTools";
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import { statusStore, setStore } from "@/stores";
import { getAdcode, getWeather } from "@/api";
const set = setStore();
const status = statusStore();
// 时间数据
const timeData = ref({});
const timeInterval = ref(null);
// 天气数据
const weatherData = ref(null);
const weatherKey = import.meta.env.VITE_WEATHER_KEY;
// 更新时间
const updateTimeData = () => {
timeData.value = getCurrentTime(set.showZeroTime, set.use12HourFormat);
};
// 获取天气数据
const getWeatherData = async () => {
if (!weatherKey) {
return $message.warning("请配置天气 Key");
}
// 当前时间戳
const currentTime = Date.now();
// 上次获取天气数据的数据
let lastWeatherData = JSON.parse(localStorage.getItem("lastWeatherData")) || {
data: {},
lastFetchTime: 0,
};
// 上次获取天气数据的时间戳与当前时间的时间差(毫秒)
const timeDifference = currentTime - lastWeatherData.lastFetchTime;
// 是否超出 5 分钟
if (timeDifference >= 5 * 60 * 1000) {
const adCodeResult = await getAdcode(weatherKey);
if (adCodeResult.infocode !== "10000") {
return $message.error("地区查询失败");
}
// 获取天气数据
const weatherResult = await getWeather(weatherKey, adCodeResult.adcode);
if (weatherResult.infocode !== "10000") {
return $message.error("地区查询失败");
}
const data = weatherResult.lives[0];
weatherData.value = {
condition: data.weather,
temp: data.temperature,
windDir: data.winddirection + "风",
windLevel: data.windpower,
};
lastWeatherData = { data: weatherData.value, lastFetchTime: currentTime };
// 储存新天气数据
localStorage.setItem("lastWeatherData", JSON.stringify(lastWeatherData));
} else {
console.log("从缓存中读取天气数据:", lastWeatherData);
weatherData.value = lastWeatherData.data;
}
};
// 监听配置发生改变
watch(
() => [set.showZeroTime, set.use12HourFormat],
() => {
updateTimeData();
},
);
onMounted(() => {
// 时间
updateTimeData();
timeInterval.value = setInterval(updateTimeData, 1000);
// 天气
getWeatherData();
});
onBeforeUnmount(() => {
clearInterval(timeInterval.value);
});
</script>
<style lang="scss" scoped>
.weather-time {
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
transform: translateY(-140px);
color: var(--main-text-color);
animation: fade-time-in 0.6s cubic-bezier(0.21, 0.78, 0.36, 1);
transition:
transform 0.3s,
opacity 0.5s,
margin-bottom 0.3s;
z-index: 1;
.time {
cursor: pointer;
font-size: 3rem;
margin: 6px 0px;
text-shadow: var(--main-text-shadow);
transition: transform 0.3s;
.separator {
opacity: 0.8;
font-size: 2.8rem;
display: inline-block;
margin: 0 5px;
transform: translateY(-4px);
animation: separator-breathe 0.7s infinite alternate;
}
.amPm {
font-size: 1rem;
opacity: 0.6;
margin-left: 6px;
}
&:hover {
transform: scale(1.08);
}
&:active {
transform: scale(1);
}
}
.date {
font-size: 1.15rem;
opacity: 0.8;
margin: 4px 0px;
text-shadow: var(--main-text-shadow);
.month {
&::after {
margin: 0 4px;
content: "月";
}
}
.day {
&::after {
margin: 0 8px 0 4px;
content: "日";
}
}
}
.lunar {
font-size: 0.9rem;
opacity: 0.6;
text-shadow: var(--main-text-shadow);
.year {
&::after {
margin-right: 4px;
content: "年";
}
}
}
.weather {
opacity: 0.7;
font-size: 1rem;
text-shadow: var(--main-text-shadow);
.temperature {
margin: 0 6px;
}
.wind-level {
margin-left: 6px;
}
}
&.focus {
transform: translateY(-180px);
// transform: translateY(-24vh);
}
&.box,
&.set {
// transform: translateY(-220px);
transform: translateY(-34vh);
@media (max-width: 478px) {
transform: translateY(-32vh);
}
}
&.hidden {
transform: translateY(-180px);
// transform: translateY(-24vh);
opacity: 0;
}
&.lunar {
margin-bottom: 50px;
}
&.two {
padding-bottom: 60px;
.time {
display: flex;
flex-direction: column;
align-items: center;
span {
line-height: normal;
}
.separator,
.second {
display: none;
}
.hour {
&::after {
content: "/";
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
line-height: 0;
opacity: 0.4;
transform: rotate(50deg);
margin: 12px 0;
}
}
}
}
}
</style>