修复
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
this.endpoints = endpoints.map(endpoint => `${endpoint}/v2/epic`);
|
||||
} catch (e) {
|
||||
// 如果无法加载接口集合,使用默认接口
|
||||
this.endpoints = ['https://60s-api.viki.moe/v2/epic'];
|
||||
this.endpoints = ['https://60s.api.shumengya.top/v2/epic'];
|
||||
}
|
||||
},
|
||||
// 获取当前接口URL
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 公网IP地址查询应用
|
||||
class IPQueryApp {
|
||||
constructor() {
|
||||
this.apiEndpoint = 'https://60s.viki.moe/v2/ip';
|
||||
this.apiEndpoint = 'https://60s.api.shumengya.top/v2/ip';
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[
|
||||
"https://60s.viki.moe/v2/ip"
|
||||
"https://60s.api.shumengya.top/v2/ip"
|
||||
]
|
||||
@@ -1,10 +1,6 @@
|
||||
// API接口列表
|
||||
const API_ENDPOINTS = [
|
||||
"https://60s-cf.viki.moe",
|
||||
"https://60s.viki.moe",
|
||||
"https://60s.b23.run",
|
||||
"https://60s.114128.xyz",
|
||||
"https://60s-cf.114128.xyz"
|
||||
"https://60s.api.shumengya.top",
|
||||
];
|
||||
|
||||
// 当前使用的API索引
|
||||
@@ -118,7 +114,7 @@ function displayLunarInfo(lunarData) {
|
||||
<div class="item-value">${lunarData.solar.week_desc}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon"><EFBFBD></div>
|
||||
<div class="item-icon">🍂</div>
|
||||
<div class="item-label">季节</div>
|
||||
<div class="item-value">${lunarData.solar.season_name_desc}</div>
|
||||
</div>
|
||||
@@ -147,7 +143,7 @@ function displayLunarInfo(lunarData) {
|
||||
<div class="item-value">${lunarData.zodiac.year}年</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">⚡</div>
|
||||
<div class="item-icon">☯️</div>
|
||||
<div class="item-label">天干地支</div>
|
||||
<div class="item-value">${lunarData.sixty_cycle.year.name}</div>
|
||||
</div>
|
||||
@@ -161,27 +157,27 @@ function displayLunarInfo(lunarData) {
|
||||
|
||||
<div class="info-card">
|
||||
<div class="card-header">
|
||||
<div class="card-icon">🌸</div>
|
||||
<div class="card-icon">🌾</div>
|
||||
<div class="card-title">节气节日</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="info-item">
|
||||
<div class="item-icon">🍃</div>
|
||||
<div class="item-icon">🌱</div>
|
||||
<div class="item-label">当前节气</div>
|
||||
<div class="item-value">${lunarData.term.stage ? lunarData.term.stage.name : '无节气'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">🎊</div>
|
||||
<div class="item-icon">🎉</div>
|
||||
<div class="item-label">法定假日</div>
|
||||
<div class="item-value">${lunarData.legal_holiday ? lunarData.legal_holiday.name : '无假日'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon"><EFBFBD></div>
|
||||
<div class="item-icon">🎊</div>
|
||||
<div class="item-label">传统节日</div>
|
||||
<div class="item-value">${lunarData.festival.both_desc || '无特殊节日'}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">🔢</div>
|
||||
<div class="item-icon">📊</div>
|
||||
<div class="item-label">一年第几天</div>
|
||||
<div class="item-value">第${lunarData.stats.day_of_year}天</div>
|
||||
</div>
|
||||
@@ -200,12 +196,12 @@ function displayLunarInfo(lunarData) {
|
||||
<div class="item-value">${lunarData.lunar.hour_desc}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">⚡</div>
|
||||
<div class="item-icon">☯️</div>
|
||||
<div class="item-label">时辰干支</div>
|
||||
<div class="item-value">${lunarData.sixty_cycle.hour.name}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">🐓</div>
|
||||
<div class="item-icon">🐾</div>
|
||||
<div class="item-label">时辰生肖</div>
|
||||
<div class="item-value">${lunarData.zodiac.hour}</div>
|
||||
</div>
|
||||
@@ -219,7 +215,7 @@ function displayLunarInfo(lunarData) {
|
||||
|
||||
<div class="info-card">
|
||||
<div class="card-header">
|
||||
<div class="card-icon">🔮</div>
|
||||
<div class="card-icon">📖</div>
|
||||
<div class="card-title">黄历宜忌</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
@@ -253,7 +249,7 @@ function displayLunarInfo(lunarData) {
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="info-item">
|
||||
<div class="item-icon">🎯</div>
|
||||
<div class="item-icon">🍀</div>
|
||||
<div class="item-label">今日运势</div>
|
||||
<div class="item-value">${lunarData.fortune.today_luck}</div>
|
||||
</div>
|
||||
@@ -268,7 +264,7 @@ function displayLunarInfo(lunarData) {
|
||||
<div class="item-value">${lunarData.fortune.money}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="item-icon">💕</div>
|
||||
<div class="item-icon">💖</div>
|
||||
<div class="item-label">感情运</div>
|
||||
<div class="item-value">${lunarData.fortune.love}</div>
|
||||
</div>
|
||||
@@ -277,12 +273,12 @@ function displayLunarInfo(lunarData) {
|
||||
|
||||
<div class="info-card">
|
||||
<div class="card-header">
|
||||
<div class="card-icon">📊</div>
|
||||
<div class="card-icon">📈</div>
|
||||
<div class="card-title">年度统计</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="info-item">
|
||||
<div class="item-icon">📈</div>
|
||||
<div class="item-icon">📊</div>
|
||||
<div class="item-label">年度进度</div>
|
||||
<div class="item-value">${lunarData.stats.percents_formatted.year}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// API配置
|
||||
const API_BASE_URL = 'https://60s.viki.moe/v2/hash';
|
||||
const API_BASE_URL = 'https://60s.api.shumengya.top/v2/hash';
|
||||
|
||||
// DOM元素
|
||||
const elements = {
|
||||
|
||||
@@ -162,95 +162,6 @@ body {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 天气详情 */
|
||||
.weather-details {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
background: rgba(168, 213, 186, 0.1);
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(168, 213, 186, 0.2);
|
||||
}
|
||||
|
||||
.detail-item .label {
|
||||
display: block;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
margin-bottom: 5px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.detail-item span:last-child {
|
||||
color: #2d5a3d;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 生活指数 */
|
||||
.life-index {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.life-index h3 {
|
||||
color: #2d5a3d;
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.index-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.index-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(168, 213, 186, 0.05);
|
||||
padding: 20px;
|
||||
border-radius: 15px;
|
||||
border: 1px solid rgba(168, 213, 186, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.index-item:hover {
|
||||
background: rgba(168, 213, 186, 0.1);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(168, 213, 186, 0.2);
|
||||
}
|
||||
|
||||
.index-icon {
|
||||
font-size: 2rem;
|
||||
margin-right: 15px;
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.index-content h4 {
|
||||
color: #2d5a3d;
|
||||
font-size: 16px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.index-content p {
|
||||
color: #6bb77b;
|
||||
font-weight: 600;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.index-content span {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 更新时间 */
|
||||
.update-time {
|
||||
text-align: center;
|
||||
@@ -285,10 +196,6 @@ body {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
|
||||
.weather-details {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.index-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
@@ -308,10 +215,6 @@ body {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.weather-details {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
.index-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
@@ -355,15 +258,6 @@ body {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.weather-details {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.index-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 15px;
|
||||
@@ -398,12 +292,121 @@ body {
|
||||
.temperature {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.weather-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* 预报区域样式 */
|
||||
.forecast-section {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.forecast-section h3 {
|
||||
color: #2d5a3d;
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.forecast-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.forecast-item {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 15px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(168, 213, 186, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.forecast-item:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.forecast-date {
|
||||
font-weight: bold;
|
||||
color: #2d5a3d;
|
||||
margin-bottom: 10px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.forecast-weather {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.weather-day {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.weather-night {
|
||||
color: #888;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.forecast-temp {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.temp-high {
|
||||
color: #ff6b6b;
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.temp-low {
|
||||
color: #4ecdc4;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.forecast-wind {
|
||||
color: #666;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.forecast-humidity {
|
||||
color: #888;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* 预报区域响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.forecast-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
padding: 10px;
|
||||
.forecast-item {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.forecast-date {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.temp-high {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.forecast-section {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.forecast-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
66
frontend/60sapi/实用功能/天气预报/index.html
Normal file
66
frontend/60sapi/实用功能/天气预报/index.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>天气预报</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1>天气预报</h1>
|
||||
</header>
|
||||
|
||||
<div class="search-section">
|
||||
<div class="search-box">
|
||||
<input type="text" id="cityInput" placeholder="请输入城市名称(如:北京)" value="北京">
|
||||
<button id="searchBtn">查询天气</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading" id="loading" style="display: none;">
|
||||
<div class="spinner"></div>
|
||||
<p>正在获取天气信息...</p>
|
||||
</div>
|
||||
|
||||
<div class="weather-container" id="weatherContainer" style="display: none;">
|
||||
<div class="location-info">
|
||||
<h2 id="locationName"></h2>
|
||||
<p id="locationDetail"></p>
|
||||
</div>
|
||||
|
||||
<div class="current-weather">
|
||||
<div class="weather-main">
|
||||
<div class="temperature">
|
||||
<span id="temperature"></span>
|
||||
<span class="unit">°C</span>
|
||||
</div>
|
||||
<div class="weather-desc">
|
||||
<p id="weatherCondition"></p>
|
||||
<p id="feelsLike"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="forecast-section">
|
||||
<h3>未来天气预报</h3>
|
||||
<div class="forecast-grid" id="forecastGrid">
|
||||
<!-- 预报数据将通过JavaScript动态生成 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="update-time">
|
||||
<p>更新时间:<span id="updateTime"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-message" id="errorMessage" style="display: none;">
|
||||
<p>获取天气信息失败,请稍后重试</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,11 +2,7 @@
|
||||
class WeatherApp {
|
||||
constructor() {
|
||||
this.apiEndpoints = [
|
||||
'https://60s-cf.viki.moe',
|
||||
'https://60s.viki.moe',
|
||||
'https://60s.b23.run',
|
||||
'https://60s.114128.xyz',
|
||||
'https://60s-cf.114128.xyz'
|
||||
"https://60s.api.shumengya.top/v2/weather/forecast"
|
||||
];
|
||||
this.currentEndpointIndex = 0;
|
||||
this.init();
|
||||
@@ -74,7 +70,7 @@ class WeatherApp {
|
||||
}
|
||||
|
||||
async fetchWeatherData(endpoint, city) {
|
||||
const url = `${endpoint}/v2/weather?query=${encodeURIComponent(city)}`;
|
||||
const url = `${endpoint}?query=${encodeURIComponent(city)}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
@@ -93,90 +89,61 @@ class WeatherApp {
|
||||
}
|
||||
|
||||
displayWeatherData(data) {
|
||||
const { location, realtime } = data;
|
||||
const { location, forecast } = data;
|
||||
|
||||
// 显示位置信息
|
||||
document.getElementById('locationName').textContent = location.formatted;
|
||||
document.getElementById('locationDetail').textContent =
|
||||
`${location.province} ${location.city} | 邮编: ${location.zip_code}`;
|
||||
|
||||
// 显示当前天气
|
||||
document.getElementById('temperature').textContent = realtime.temperature;
|
||||
document.getElementById('weatherCondition').textContent = realtime.weather;
|
||||
// 使用第一天的预报数据作为当前天气(今天的天气)
|
||||
const todayWeather = forecast[0];
|
||||
|
||||
// 体感温度转换(API返回的是华氏度,需要转换为摄氏度)
|
||||
const feelsLikeCelsius = this.fahrenheitToCelsius(realtime.temperature_feels_like);
|
||||
// 显示当前天气(使用今天的最高温度)
|
||||
document.getElementById('temperature').textContent = todayWeather.temperature_high;
|
||||
document.getElementById('weatherCondition').textContent =
|
||||
`${todayWeather.weather_day} 转 ${todayWeather.weather_night}`;
|
||||
|
||||
// 体感温度(使用温度范围)
|
||||
document.getElementById('feelsLike').textContent =
|
||||
`体感温度 ${feelsLikeCelsius}°C`;
|
||||
`温度范围 ${todayWeather.temperature_low}°C - ${todayWeather.temperature_high}°C`;
|
||||
|
||||
// 显示天气详情
|
||||
document.getElementById('humidity').textContent = `${realtime.humidity}%`;
|
||||
document.getElementById('windDirection').textContent = realtime.wind_direction;
|
||||
document.getElementById('windStrength').textContent = realtime.wind_strength;
|
||||
document.getElementById('pressure').textContent = `${realtime.pressure} hPa`;
|
||||
document.getElementById('visibility').textContent = realtime.visibility;
|
||||
|
||||
// 空气质量显示
|
||||
const aqiElement = document.getElementById('aqi');
|
||||
aqiElement.textContent = `${realtime.aqi} (PM2.5: ${realtime.pm25})`;
|
||||
aqiElement.className = this.getAQIClass(realtime.aqi);
|
||||
|
||||
// 显示生活指数
|
||||
const lifeIndex = realtime.life_index;
|
||||
this.displayLifeIndex('comfort', lifeIndex.comfort);
|
||||
this.displayLifeIndex('clothing', lifeIndex.clothing);
|
||||
this.displayLifeIndex('umbrella', lifeIndex.umbrella);
|
||||
this.displayLifeIndex('uv', lifeIndex.uv);
|
||||
this.displayLifeIndex('travel', lifeIndex.travel);
|
||||
this.displayLifeIndex('sport', lifeIndex.sport);
|
||||
|
||||
// 显示更新时间
|
||||
// 显示更新时间(使用当前时间)
|
||||
document.getElementById('updateTime').textContent =
|
||||
`${realtime.updated} (${realtime.updated_at})`;
|
||||
`${this.formatDate(new Date())} (基于预报数据)`;
|
||||
|
||||
// 显示天气预报
|
||||
this.displayForecast(forecast);
|
||||
|
||||
this.showWeatherContainer();
|
||||
}
|
||||
|
||||
displayLifeIndex(type, indexData) {
|
||||
const levelElement = document.getElementById(`${type}Level`);
|
||||
const descElement = document.getElementById(`${type}Desc`);
|
||||
displayForecast(forecast) {
|
||||
const forecastGrid = document.getElementById('forecastGrid');
|
||||
forecastGrid.innerHTML = '';
|
||||
|
||||
if (levelElement && descElement && indexData) {
|
||||
levelElement.textContent = indexData.level;
|
||||
descElement.textContent = indexData.desc;
|
||||
forecast.forEach((day, index) => {
|
||||
const forecastItem = document.createElement('div');
|
||||
forecastItem.className = 'forecast-item';
|
||||
|
||||
// 根据指数级别设置颜色
|
||||
levelElement.className = this.getIndexLevelClass(indexData.level);
|
||||
}
|
||||
}
|
||||
|
||||
getAQIClass(aqi) {
|
||||
if (aqi <= 50) return 'aqi-good';
|
||||
if (aqi <= 100) return 'aqi-moderate';
|
||||
if (aqi <= 150) return 'aqi-unhealthy-sensitive';
|
||||
if (aqi <= 200) return 'aqi-unhealthy';
|
||||
if (aqi <= 300) return 'aqi-very-unhealthy';
|
||||
return 'aqi-hazardous';
|
||||
}
|
||||
|
||||
getIndexLevelClass(level) {
|
||||
const levelMap = {
|
||||
'优': 'level-excellent',
|
||||
'良': 'level-good',
|
||||
'适宜': 'level-suitable',
|
||||
'舒适': 'level-comfortable',
|
||||
'较适宜': 'level-fairly-suitable',
|
||||
'不宜': 'level-unsuitable',
|
||||
'较不宜': 'level-fairly-unsuitable',
|
||||
'带伞': 'level-bring-umbrella',
|
||||
'最弱': 'level-weakest',
|
||||
'弱': 'level-weak',
|
||||
'中等': 'level-moderate',
|
||||
'强': 'level-strong',
|
||||
'很强': 'level-very-strong'
|
||||
};
|
||||
|
||||
return levelMap[level] || 'level-default';
|
||||
forecastItem.innerHTML = `
|
||||
<div class="forecast-date">${day.date_desc}</div>
|
||||
<div class="forecast-weather">
|
||||
<div class="weather-day">${day.weather_day}</div>
|
||||
<div class="weather-night">${day.weather_night}</div>
|
||||
</div>
|
||||
<div class="forecast-temp">
|
||||
<span class="temp-high">${day.temperature_high}°</span>
|
||||
<span class="temp-low">${day.temperature_low}°</span>
|
||||
</div>
|
||||
<div class="forecast-wind">
|
||||
<div>${day.wind_direction_day} ${day.wind_strength_day}</div>
|
||||
</div>
|
||||
<div class="forecast-humidity">湿度: ${day.humidity}%</div>
|
||||
`;
|
||||
|
||||
forecastGrid.appendChild(forecastItem);
|
||||
});
|
||||
}
|
||||
|
||||
// 华氏度转摄氏度
|
||||
@@ -185,6 +152,18 @@ class WeatherApp {
|
||||
return Math.round(celsius * 10) / 10; // 保留一位小数
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
formatDate(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
showLoading() {
|
||||
document.getElementById('loading').style.display = 'block';
|
||||
document.getElementById('weatherContainer').style.display = 'none';
|
||||
@@ -206,26 +185,6 @@ class WeatherApp {
|
||||
}
|
||||
}
|
||||
|
||||
// 添加生活指数级别样式
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.aqi-good { color: #52c41a; }
|
||||
.aqi-moderate { color: #faad14; }
|
||||
.aqi-unhealthy-sensitive { color: #fa8c16; }
|
||||
.aqi-unhealthy { color: #f5222d; }
|
||||
.aqi-very-unhealthy { color: #a0206e; }
|
||||
.aqi-hazardous { color: #722ed1; }
|
||||
|
||||
.level-excellent, .level-suitable, .level-comfortable { color: #52c41a; }
|
||||
.level-good, .level-fairly-suitable { color: #1890ff; }
|
||||
.level-bring-umbrella, .level-moderate { color: #faad14; }
|
||||
.level-unsuitable, .level-fairly-unsuitable { color: #f5222d; }
|
||||
.level-weakest, .level-weak { color: #52c41a; }
|
||||
.level-strong, .level-very-strong { color: #fa8c16; }
|
||||
.level-default { color: #666; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// 页面加载完成后初始化应用
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new WeatherApp();
|
||||
3
frontend/60sapi/实用功能/天气预报/接口集合.json
Normal file
3
frontend/60sapi/实用功能/天气预报/接口集合.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top/v2/weather/forecast"
|
||||
]
|
||||
101
frontend/60sapi/实用功能/天气预报/返回接口.json
Normal file
101
frontend/60sapi/实用功能/天气预报/返回接口.json
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"location": {
|
||||
"province": "北京",
|
||||
"city": "北京",
|
||||
"town": "北京",
|
||||
"formatted": "北京",
|
||||
"location_id": "101010100",
|
||||
"detail_url": "http://www.weather.com.cn/weather/101010100.shtml",
|
||||
"is_province": true,
|
||||
"is_city": false,
|
||||
"is_town": false,
|
||||
"area_code": "10",
|
||||
"zip_code": "100000"
|
||||
},
|
||||
"forecast": [
|
||||
{
|
||||
"date": "9/4",
|
||||
"date_desc": "今天",
|
||||
"weather_day": "多云",
|
||||
"weather_night": "阴",
|
||||
"weather_code_day": "01",
|
||||
"weather_code_night": "02",
|
||||
"temperature_high": 31,
|
||||
"temperature_low": 21,
|
||||
"wind_direction_day": "南风",
|
||||
"wind_direction_night": "南风",
|
||||
"wind_strength_day": "\u003C3级",
|
||||
"wind_strength_night": "\u003C3级",
|
||||
"rainfall": 96.1,
|
||||
"humidity": 83
|
||||
},
|
||||
{
|
||||
"date": "9/5",
|
||||
"date_desc": "星期五",
|
||||
"weather_day": "中雨",
|
||||
"weather_night": "多云",
|
||||
"weather_code_day": "08",
|
||||
"weather_code_night": "01",
|
||||
"temperature_high": 23,
|
||||
"temperature_low": 19,
|
||||
"wind_direction_day": "西南风",
|
||||
"wind_direction_night": "北风",
|
||||
"wind_strength_day": "\u003C3级",
|
||||
"wind_strength_night": "\u003C3级",
|
||||
"rainfall": 100,
|
||||
"humidity": 68
|
||||
},
|
||||
{
|
||||
"date": "9/6",
|
||||
"date_desc": "星期六",
|
||||
"weather_day": "多云",
|
||||
"weather_night": "晴",
|
||||
"weather_code_day": "01",
|
||||
"weather_code_night": "00",
|
||||
"temperature_high": 30,
|
||||
"temperature_low": 19,
|
||||
"wind_direction_day": "南风",
|
||||
"wind_direction_night": "西南风",
|
||||
"wind_strength_day": "\u003C3级",
|
||||
"wind_strength_night": "\u003C3级",
|
||||
"rainfall": 85.2,
|
||||
"humidity": 36
|
||||
},
|
||||
{
|
||||
"date": "9/7",
|
||||
"date_desc": "星期日",
|
||||
"weather_day": "多云",
|
||||
"weather_night": "晴",
|
||||
"weather_code_day": "01",
|
||||
"weather_code_night": "00",
|
||||
"temperature_high": 29,
|
||||
"temperature_low": 20,
|
||||
"wind_direction_day": "北风",
|
||||
"wind_direction_night": "北风",
|
||||
"wind_strength_day": "\u003C3级",
|
||||
"wind_strength_night": "\u003C3级",
|
||||
"rainfall": 87.3,
|
||||
"humidity": 27
|
||||
},
|
||||
{
|
||||
"date": "9/8",
|
||||
"date_desc": "星期一",
|
||||
"weather_day": "多云",
|
||||
"weather_night": "多云",
|
||||
"weather_code_day": "01",
|
||||
"weather_code_night": "01",
|
||||
"temperature_high": 28,
|
||||
"temperature_low": 20,
|
||||
"wind_direction_day": "南风",
|
||||
"wind_direction_night": "南风",
|
||||
"wind_strength_day": "\u003C3级",
|
||||
"wind_strength_night": "\u003C3级",
|
||||
"rainfall": 84.8,
|
||||
"humidity": 41
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>实时天气查询</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/background.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<h1>实时天气查询</h1>
|
||||
</header>
|
||||
|
||||
<div class="search-section">
|
||||
<div class="search-box">
|
||||
<input type="text" id="cityInput" placeholder="请输入城市名称(如:北京)" value="北京">
|
||||
<button id="searchBtn">查询天气</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loading" id="loading" style="display: none;">
|
||||
<div class="spinner"></div>
|
||||
<p>正在获取天气信息...</p>
|
||||
</div>
|
||||
|
||||
<div class="weather-container" id="weatherContainer" style="display: none;">
|
||||
<div class="location-info">
|
||||
<h2 id="locationName"></h2>
|
||||
<p id="locationDetail"></p>
|
||||
</div>
|
||||
|
||||
<div class="current-weather">
|
||||
<div class="weather-main">
|
||||
<div class="temperature">
|
||||
<span id="temperature"></span>
|
||||
<span class="unit">°C</span>
|
||||
</div>
|
||||
<div class="weather-desc">
|
||||
<p id="weatherCondition"></p>
|
||||
<p id="feelsLike"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="weather-details">
|
||||
<div class="detail-item">
|
||||
<span class="label">湿度</span>
|
||||
<span id="humidity"></span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">风向</span>
|
||||
<span id="windDirection"></span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">风力</span>
|
||||
<span id="windStrength"></span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">气压</span>
|
||||
<span id="pressure"></span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">能见度</span>
|
||||
<span id="visibility"></span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">空气质量</span>
|
||||
<span id="aqi"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="life-index">
|
||||
<h3>生活指数</h3>
|
||||
<div class="index-grid">
|
||||
<div class="index-item">
|
||||
<div class="index-icon comfort">🌡️</div>
|
||||
<div class="index-content">
|
||||
<h4>舒适度</h4>
|
||||
<p id="comfortLevel"></p>
|
||||
<span id="comfortDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-item">
|
||||
<div class="index-icon clothing">👕</div>
|
||||
<div class="index-content">
|
||||
<h4>穿衣指数</h4>
|
||||
<p id="clothingLevel"></p>
|
||||
<span id="clothingDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-item">
|
||||
<div class="index-icon umbrella">☂️</div>
|
||||
<div class="index-content">
|
||||
<h4>雨伞指数</h4>
|
||||
<p id="umbrellaLevel"></p>
|
||||
<span id="umbrellaDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-item">
|
||||
<div class="index-icon uv">☀️</div>
|
||||
<div class="index-content">
|
||||
<h4>紫外线</h4>
|
||||
<p id="uvLevel"></p>
|
||||
<span id="uvDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-item">
|
||||
<div class="index-icon travel">🚗</div>
|
||||
<div class="index-content">
|
||||
<h4>出行指数</h4>
|
||||
<p id="travelLevel"></p>
|
||||
<span id="travelDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="index-item">
|
||||
<div class="index-icon sport">🏃</div>
|
||||
<div class="index-content">
|
||||
<h4>运动指数</h4>
|
||||
<p id="sportLevel"></p>
|
||||
<span id="sportDesc"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="update-time">
|
||||
<p>更新时间:<span id="updateTime"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-message" id="errorMessage" style="display: none;">
|
||||
<p>获取天气信息失败,请稍后重试</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"location": {
|
||||
"province": "北京",
|
||||
"city": "北京",
|
||||
"town": "北京",
|
||||
"formatted": "北京",
|
||||
"location_id": "101010100",
|
||||
"detail_url": "http://www.weather.com.cn/weather/101010100.shtml",
|
||||
"is_province": true,
|
||||
"is_city": false,
|
||||
"is_town": false,
|
||||
"area_code": "10",
|
||||
"zip_code": "100000"
|
||||
},
|
||||
"realtime": {
|
||||
"weather": "小雨转多云",
|
||||
"weather_desc": "未知",
|
||||
"weather_code": "d7",
|
||||
"temperature": 26,
|
||||
"temperature_feels_like": 81.1,
|
||||
"humidity": 78,
|
||||
"wind_direction": "南风转北风",
|
||||
"wind_strength": "\u003C3级",
|
||||
"wind_speed": "5km/h",
|
||||
"pressure": 1008,
|
||||
"visibility": "8km",
|
||||
"aqi": 37,
|
||||
"pm25": 37,
|
||||
"rainfall": 0,
|
||||
"rainfall_24h": 0,
|
||||
"updated": "2025-08-29 08:00:00",
|
||||
"updated_at": "15:10",
|
||||
"life_index": {
|
||||
"comfort": {
|
||||
"level": "舒适",
|
||||
"desc": "白天温度宜人,风力不大。"
|
||||
},
|
||||
"clothing": {
|
||||
"level": "舒适",
|
||||
"desc": "建议穿长袖衬衫单裤等服装。"
|
||||
},
|
||||
"umbrella": {
|
||||
"level": "带伞",
|
||||
"desc": "有降水,带雨伞,短期外出可收起雨伞。"
|
||||
},
|
||||
"uv": {
|
||||
"level": "最弱",
|
||||
"desc": "辐射弱,涂擦SPF8-12防晒护肤品。"
|
||||
},
|
||||
"car_wash": {
|
||||
"level": "不宜",
|
||||
"desc": "有雨,雨水和泥水会弄脏爱车。"
|
||||
},
|
||||
"travel": {
|
||||
"level": "适宜",
|
||||
"desc": "较弱降水和微风将伴您共赴旅程。"
|
||||
},
|
||||
"sport": {
|
||||
"level": "较不宜",
|
||||
"desc": "有降水,推荐您在室内进行休闲运动。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,10 @@ class QRCodeGenerator {
|
||||
// 加载API接口列表
|
||||
async loadApiEndpoints() {
|
||||
try {
|
||||
const response = await fetch('./接口集合.json');
|
||||
this.apiEndpoints = await response.json();
|
||||
// 直接在代码中配置API接口,避免CORS问题
|
||||
this.apiEndpoints = [
|
||||
"https://60s.api.shumengya.top"
|
||||
];
|
||||
console.log('已加载API接口:', this.apiEndpoints);
|
||||
} catch (error) {
|
||||
console.error('加载API接口失败:', error);
|
||||
@@ -32,16 +34,26 @@ class QRCodeGenerator {
|
||||
const downloadBtn = document.querySelector('.download-btn');
|
||||
const copyBtn = document.querySelector('.copy-btn');
|
||||
const newBtn = document.querySelector('.new-btn');
|
||||
|
||||
form.addEventListener('submit', (e) => this.handleSubmit(e));
|
||||
retryBtn.addEventListener('click', () => this.retryGeneration());
|
||||
downloadBtn.addEventListener('click', () => this.downloadQRCode());
|
||||
copyBtn.addEventListener('click', () => this.copyImageLink());
|
||||
newBtn.addEventListener('click', () => this.resetForm());
|
||||
|
||||
// 实时字符计数
|
||||
const textArea = document.getElementById('text');
|
||||
textArea.addEventListener('input', () => this.updateCharCount());
|
||||
|
||||
if (form) {
|
||||
form.addEventListener('submit', (e) => this.handleSubmit(e));
|
||||
}
|
||||
if (retryBtn) {
|
||||
retryBtn.addEventListener('click', () => this.retryGeneration());
|
||||
}
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', () => this.downloadQRCode());
|
||||
}
|
||||
if (copyBtn) {
|
||||
copyBtn.addEventListener('click', () => this.copyImageLink());
|
||||
}
|
||||
if (newBtn) {
|
||||
newBtn.addEventListener('click', () => this.resetForm());
|
||||
}
|
||||
if (textArea) {
|
||||
textArea.addEventListener('input', () => this.updateCharCount());
|
||||
}
|
||||
}
|
||||
|
||||
// 设置表单验证
|
||||
@@ -162,7 +174,7 @@ class QRCodeGenerator {
|
||||
|
||||
// 添加查询参数
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value) {
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
url.searchParams.append(key, value);
|
||||
}
|
||||
});
|
||||
@@ -188,20 +200,44 @@ class QRCodeGenerator {
|
||||
}
|
||||
|
||||
// 根据返回格式处理
|
||||
if (params.encoding === 'image') {
|
||||
const blob = await response.blob();
|
||||
const imageUrl = URL.createObjectURL(blob);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
imageUrl: imageUrl,
|
||||
text: params.text,
|
||||
size: params.size,
|
||||
level: params.level,
|
||||
format: 'image'
|
||||
if (params.encoding === 'image' || !params.encoding) {
|
||||
// 默认返回图片格式
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.startsWith('image/')) {
|
||||
const blob = await response.blob();
|
||||
const imageUrl = URL.createObjectURL(blob);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
imageUrl: imageUrl,
|
||||
text: params.text,
|
||||
size: params.size,
|
||||
level: params.level,
|
||||
format: 'image'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// 如果返回的不是图片,尝试解析JSON
|
||||
const jsonData = await response.json();
|
||||
if (jsonData.code === 0 && jsonData.data && jsonData.data.data_uri) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
imageUrl: jsonData.data.data_uri,
|
||||
text: params.text,
|
||||
size: params.size,
|
||||
level: params.level,
|
||||
format: 'json',
|
||||
base64: jsonData.data.base64,
|
||||
mimeType: jsonData.data.mime_type
|
||||
}
|
||||
};
|
||||
} else {
|
||||
throw new Error(jsonData.message || '生成失败');
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// JSON或text格式
|
||||
const jsonData = await response.json();
|
||||
if (jsonData.code === 0 && jsonData.data) {
|
||||
return {
|
||||
@@ -211,7 +247,7 @@ class QRCodeGenerator {
|
||||
text: params.text,
|
||||
size: params.size,
|
||||
level: params.level,
|
||||
format: 'json',
|
||||
format: params.encoding,
|
||||
base64: jsonData.data.base64,
|
||||
mimeType: jsonData.data.mime_type
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"base64": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7Z15fBTV...",
|
||||
"data_uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7Z15fBTV...",
|
||||
"mime_type": "image/png",
|
||||
"text": "https://example.com"
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,7 @@ class BaikeApp {
|
||||
constructor() {
|
||||
// API接口列表
|
||||
this.apiEndpoints = [
|
||||
'https://60s-cf.viki.moe',
|
||||
'https://60s.viki.moe',
|
||||
'https://60s.b23.run',
|
||||
'https://60s.114128.xyz',
|
||||
'https://60s-cf.114128.xyz'
|
||||
'https://60s.api.shumengya.top',
|
||||
];
|
||||
|
||||
this.currentApiIndex = 0;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
class OGAnalyzer {
|
||||
constructor() {
|
||||
this.apiUrl = 'https://60s.viki.moe/v2/og';
|
||||
this.apiUrl = 'https://60s.api.shumengya.top/v2/og';
|
||||
this.isAnalyzing = false;
|
||||
this.currentUrl = '';
|
||||
this.animationFrameId = null;
|
||||
|
||||
Reference in New Issue
Block a user