0228.4
Some checks failed
部署 Next.js 站点到 Gitea / deploy (push) Failing after 10m5s

This commit is contained in:
298977887 2025-02-28 22:04:13 +08:00
parent 3d83a2ac75
commit f5dc9a4843
7 changed files with 138 additions and 31 deletions

5
.env Normal file
View File

@ -0,0 +1,5 @@
# 聚合数据API
JUHE_NEWS_KEY=edbc3b96f022b59141961e2137f69b4a
# 彩云天气API
CAIYUN_API_KEY=TAkhjf8d1nlSlspN

3
.gitignore vendored
View File

@ -31,7 +31,8 @@ yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
#.env*
.env.local
# vercel
.vercel

View File

@ -13,7 +13,7 @@ COPY package.json ./
# 使用国内镜像源(如果网络连接较慢)
#RUN pnpm config set registry https://registry.npm.taobao.org
# 安装所有依赖(包括开发依赖)
RUN pnpm install --production=false
# RUN pnpm install --production=false
# 安装项目依赖
#RUN pnpm install

View File

@ -0,0 +1,67 @@
import { NextResponse } from 'next/server';
export async function GET() {
const apiKey = process.env.CAIYUN_API_KEY;
// 请替换为你的实际坐标(示例使用北京坐标)
const apiUrl = `https://api.caiyunapp.com/v2.6/${apiKey}/116.3974,39.9093/weather?alert=true&dailysteps=5`;
try {
const response = await fetch(apiUrl, { next: { revalidate: 600 } });
const data = await response.json();
// 数据格式转换
const formattedData = {
temp: Math.round(data.result.realtime.temperature),
feelsLike: Math.round(data.result.realtime.apparent_temperature),
condition: translateSkycon(data.result.realtime.skycon),
sunrise: data.result.daily.astro[0].sunrise.time,
sunset: data.result.daily.astro[0].sunset.time,
windSpeed: (data.result.realtime.wind.speed * 3.6).toFixed(1), // 转换为km/h
windDirection: getWindDirection(data.result.realtime.wind.direction),
uvIndex: data.result.realtime.life_index.ultraviolet.desc,
forecast: data.result.daily.temperature.map((item: any, index: number) => ({
day: formatDailyDate(item.date),
low: Math.round(item.min),
high: Math.round(item.max),
condition: translateSkycon(data.result.daily.skycon[index].value)
}))
};
return NextResponse.json(formattedData);
} catch (error) {
return NextResponse.json(
{ error: "天气数据获取失败" },
{ status: 500 }
);
}
}
// 天气状况翻译
function translateSkycon(skycon: string) {
const skyconMap: Record<string, string> = {
"CLEAR_DAY": "晴",
"CLEAR_NIGHT": "晴",
"PARTLY_CLOUDY_DAY": "多云",
"PARTLY_CLOUDY_NIGHT": "多云",
"CLOUDY": "阴",
"LIGHT_RAIN": "小雨",
"MODERATE_RAIN": "中雨",
"HEAVY_RAIN": "大雨",
"STORM_RAIN": "暴雨",
// 其他天气代码可继续补充...
};
return skyconMap[skycon] || skycon;
}
// 风向转换
function getWindDirection(degree: number) {
const directions = ["北风", "东北风", "东风", "东南风", "南风", "西南风", "西风", "西北风"];
return directions[Math.round(degree % 360 / 45) % 8];
}
// 日期格式化
function formatDailyDate(dateStr: string) {
const date = new Date(dateStr);
const weekdays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
return weekdays[date.getDay()];
}

View File

@ -20,23 +20,11 @@ const MagicMirror = () => {
const calendarDays = useMemo(() => generateCalendarDays(), []);
// 天气示例数据
const weatherData: WeatherData = {
temp: 24,
feelsLike: 26,
condition: "晴",
sunrise: "06:12",
sunset: "18:34",
windSpeed: 5,
windDirection: "东南风",
uvIndex: "中等",
forecast: [
{ day: "周二", low: 18, high: 26, condition: "☀️" },
{ day: "周三", low: 20, high: 28, condition: "⛅" },
{ day: "周四", low: 19, high: 27, condition: "🌤️" },
{ day: "周五", low: 17, high: 25, condition: "☀️" },
{ day: "周六", low: 16, high: 24, condition: "🌧️" },
],
};
// 替换原有的weatherData定义部分
const { data: weatherData, error: weatherError } = useSWR<WeatherData>(
"/api/weather",
(url: string) => fetch(url).then((res) => res.json())
);
// 新闻数据
// 替换原有的newsItems定义部分

View File

@ -3,21 +3,62 @@
/**
*
*
* API数据格式转换
*/
import { FC } from "react";
import { WeatherData } from "../types/magic-mirror";
import WbSunnyIcon from "@mui/icons-material/WbSunny";
import CircularProgress from "@mui/material/CircularProgress";
interface WeatherSectionProps {
data: WeatherData;
data?: WeatherData; // 允许undefined状态加载中
}
const WeatherSection: FC<WeatherSectionProps> = ({ data }) => {
// 处理加载状态
if (!data) {
return (
<div className="absolute top-8 right-0 w-64 flex items-center justify-center h-32">
<CircularProgress size={24} color="inherit" />
<span className="ml-2 text-gray-400">...</span>
</div>
);
}
// 日出日落时间格式化(去除日期部分)
const formatTime = (isoTime: string) => {
try {
return new Date(isoTime).toLocaleTimeString("zh-CN", {
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
} catch {
return isoTime.split("T")[1]?.slice(0, 5) || isoTime; // 回退处理
}
};
// 获取天气图标
const getWeatherIcon = (condition: string) => {
const iconMap: Record<string, string> = {
: "☀️",
: "⛅",
: "☁️",
: "🌧️",
: "🌧️",
: "⛈️",
: "🌧️💦",
// 其他天气类型可继续扩展...
};
return iconMap[condition] || "🌤️";
};
return (
<>
{/* 当前天气模块 */}
<div className="absolute top-8 right-0 w-64 space-y-4">
{/* 风速和日出日落信息 */}
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="space-y-1">
<div className="text-gray-400"></div>
@ -28,19 +69,21 @@ const WeatherSection: FC<WeatherSectionProps> = ({ data }) => {
<div className="space-y-1">
<div className="text-gray-400">/</div>
<div className="text-gray-300">
{data.sunrise} / {data.sunset}
{formatTime(data.sunrise)} / {formatTime(data.sunset)}
</div>
</div>
</div>
{/* 温度显示区域 */}
<div className="flex items-center gap-4">
<div className="text-4xl"></div>
<div className="text-4xl">{getWeatherIcon(data.condition)}</div>
<div>
<div className="text-3xl">{data.temp}°C</div>
<div className="text-gray-400 text-sm"> {data.feelsLike}°C</div>
</div>
</div>
{/* 紫外线指数 */}
<div className="space-y-2">
<div className="text-gray-400 text-sm">线</div>
<div className="text-gray-300">{data.uvIndex}</div>
@ -49,16 +92,19 @@ const WeatherSection: FC<WeatherSectionProps> = ({ data }) => {
{/* 天气预报模块 */}
<div className="absolute top-64 right-8 w-64 space-y-2">
{data.forecast.map((day, index) => (
{data.forecast.slice(0, 5).map((day, index) => (
<div
key={day.day}
className="flex justify-between text-sm"
className="flex justify-between items-center text-sm group"
style={{ opacity: 1 - index * 0.15 }}
>
<div className="text-gray-300">{day.day}</div>
<div className="text-gray-400">{day.condition}</div>
<div className="text-gray-300">
{day.low}° {day.high}°
<div className="text-gray-300 w-12">{day.day}</div>
<div className="text-gray-400 transition-opacity opacity-70 group-hover:opacity-100">
{getWeatherIcon(day.condition)}
</div>
<div className="flex gap-2">
<span className="text-blue-300">{day.low}°</span>
<span className="text-red-300">{day.high}°</span>
</div>
</div>
))}

View File

@ -3,13 +3,13 @@
*
*/
export type WeatherData = {
export interface WeatherData {
temp: number;
feelsLike: number;
condition: string;
sunrise: string;
sunset: string;
windSpeed: number;
windSpeed: string;
windDirection: string;
uvIndex: string;
forecast: {
@ -18,7 +18,7 @@ export type WeatherData = {
high: number;
condition: string;
}[];
};
}
export interface NewsItem {
uniquekey: string;