更新天气接口为和风天气,移除天气城市与 API Key 配置,简化主题部署
This commit is contained in:
13
README.md
13
README.md
@@ -63,8 +63,15 @@ Typecho 系统运行时代码库:
|
|||||||
* 加入 OpenWeatherMap 图标,优化字体、行高、布局与对齐,使输出居中且更协调。
|
* 加入 OpenWeatherMap 图标,优化字体、行高、布局与对齐,使输出居中且更协调。
|
||||||
* 注释和调试输出更详细,方便开发者阅读与排查。
|
* 注释和调试输出更详细,方便开发者阅读与排查。
|
||||||
|
|
||||||
|
- 2026-03-21:切换默认天气接口为和风天气(QWeather)。
|
||||||
|
* 为提高国内访问稳定性,主题已将默认天气请求改为使用和风天气(QWeather)API(v7 now)。
|
||||||
|
* 请到 https://dev.qweather.com/ 注册并获取 API Key,然后在后台主题设置的“天气 API Key”项中填写。
|
||||||
|
* 如果暂时不希望调用网络天气接口,可在后台关闭侧边栏“天气”模块以加速页面加载。
|
||||||
|
|
||||||
|
注意:和风天气已启用 API Host 功能,公共域名(如 devapi.qweather.com)将逐步停止服务。如果你在控制台配置了 API Host,请在主题设置的“天气 API Host”中填写你的 Host(例如:p66mtfux4j.re.qweatherapi.com)。
|
||||||
|
|
||||||
### 注意事项
|
### 注意事项
|
||||||
|
|
||||||
- 请使用 **有效的天气 API Key**。上述 key `464032d12749b7c0df937df0215af884` 返回错误“Invalid API key”,说明并非 OpenWeatherMap 认可的密钥。访问 https://openweathermap.org/ 获取或检查你的帐号密钥。
|
- 请使用 **有效的天气 API Key**。推荐使用和风天气(QWeather);获取与使用请参考:https://dev.qweather.com/ 。
|
||||||
- 也可以替换为其他天气服务(和风、心知等),只需改写 `widget-weather.php` 中的请求 URL 和参数。
|
- 如果你更倾向于无需注册的快速方案,可使用 `tianqiapi.com` 作为备用接口,但稳定性与功能可能有限。
|
||||||
- 错误信息会在侧边栏显示便于调试。
|
- 错误信息会在侧边栏以注释或文本形式显示,便于调试。
|
||||||
@@ -1 +1 @@
|
|||||||
{"city":"Guangzhou","timestamp":1774074655,"data":{"coord":{"lon":113.25,"lat":23.1167},"weather":[{"id":803,"main":"Clouds","description":"\u591a\u4e91","icon":"04d"}],"base":"stations","main":{"temp":25.38,"feels_like":25.46,"temp_min":25.38,"temp_max":25.38,"pressure":1015,"humidity":57,"sea_level":1015,"grnd_level":1015},"visibility":10000,"wind":{"speed":3.89,"deg":182,"gust":3.83},"clouds":{"all":84},"dt":1774074242,"sys":{"country":"CN","sunrise":1774045833,"sunset":1774089483},"timezone":28800,"id":1809858,"name":"Guangzhou","cod":200}}
|
{"city":"Guangzhou","timestamp":1774087093,"data":{"code":"200","updateTime":"2026-03-21T17:53+08:00","fxLink":"https:\/\/www.qweather.com\/weather\/guangzhou-101280101.html","now":{"obsTime":"2026-03-21T17:50+08:00","temp":"21","feelsLike":"23","icon":"501","text":"\u96fe","wind360":"9","windDir":"\u5317\u98ce","windScale":"0","windSpeed":"1","humidity":"92","precip":"0.0","pressure":"1007","vis":"2","cloud":"100","dew":"19"},"refer":{"sources":["QWeather"],"license":["QWeather Developers License"]}}}
|
||||||
@@ -13,98 +13,244 @@ if ( ! defined('__TYPECHO_ROOT_DIR__')) {
|
|||||||
// 只有在侧边栏开启且不是文章页面时显示
|
// 只有在侧边栏开启且不是文章页面时显示
|
||||||
if ( ! empty($this->options->sidebarBlock) && in_array('ShowSidebarWeather', $this->options->sidebarBlock) && ! $this->is('post')): ?>
|
if ( ! empty($this->options->sidebarBlock) && in_array('ShowSidebarWeather', $this->options->sidebarBlock) && ! $this->is('post')): ?>
|
||||||
<?php
|
<?php
|
||||||
// 获取配置信息
|
$city = 'Guangzhou';
|
||||||
$city = trim($this->options->weatherCity ?: 'Beijing');
|
$apiKey = '71215dad0abc4250897761e3fa8ca796';
|
||||||
$apiKey = trim($this->options->weatherApiKey ?: '');
|
$apiHost = 'p66mtfux4j.re.qweatherapi.com';
|
||||||
|
$cacheNote = '注意:API Key/Host 已硬编码在主题文件中,如需更换请编辑 components/widgets/widget-weather.php';
|
||||||
$cacheFile = dirname(__DIR__, 2) . '/assets/weather_cache.json';
|
$cacheFile = dirname(__DIR__, 2) . '/assets/weather_cache.json';
|
||||||
|
|
||||||
// 缓存机制:记录城市和时间,过期 1 小时,城市变更时自动失效
|
// 缓存机制:记录城市和时间,过期 1 小时,城市变更时自动失效
|
||||||
function hh_fetch_weather($city, $apiKey, $cacheFile) {
|
function hh_fetch_weather($city, $apiKey, $cacheFile, $apiHost = '') {
|
||||||
if (file_exists($cacheFile)) {
|
if (file_exists($cacheFile)) {
|
||||||
$raw = @file_get_contents($cacheFile);
|
$raw = @file_get_contents($cacheFile);
|
||||||
$cached = $raw ? json_decode($raw, true) : null;
|
$cached = $raw ? json_decode($raw, true) : null;
|
||||||
// 缓存结构:{"city":"xxx","timestamp":12345678,"data":{…}}
|
// 缓存结构:{"city":"xxx","timestamp":12345678,"data":{…}}
|
||||||
if ($cached && isset($cached['city'], $cached['timestamp'], $cached['data'])) {
|
if ($cached && isset($cached['city'], $cached['timestamp'], $cached['data'])) {
|
||||||
if ($cached['city'] === $city && time() - $cached['timestamp'] < 3600) {
|
if ($cached['city'] === $city && time() - $cached['timestamp'] < 3600) {
|
||||||
return $cached['data'];
|
return $cached['data'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($apiKey) || empty($city)) {
|
if (empty($apiKey) || empty($city)) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = 'https://api.openweathermap.org/data/2.5/weather?q=' . urlencode($city)
|
|
||||||
. '&appid=' . $apiKey . '&units=metric&lang=zh_cn';
|
|
||||||
$json = @file_get_contents($url);
|
|
||||||
if ($json) {
|
|
||||||
$payload = json_encode([
|
|
||||||
'city' => $city,
|
|
||||||
'timestamp' => time(),
|
|
||||||
'data' => json_decode($json, true),
|
|
||||||
]);
|
|
||||||
@file_put_contents($cacheFile, $payload);
|
|
||||||
return json_decode($json, true);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用和风天气(QWeather)API:v7 now,使用自定义 API Host 替换公共域名
|
||||||
|
$host = !empty($apiHost) ? $apiHost : 'devapi.qweather.com';
|
||||||
|
|
||||||
|
// 如果 city 不是纯数字(city id),先使用 Geo API 查找城市 ID(geo/v2/city/lookup)
|
||||||
|
$location = $city;
|
||||||
|
if (!preg_match('/^\d+$/', $city)) {
|
||||||
|
$geoUrl = 'https://' . $host . '/geo/v2/city/lookup?location=' . urlencode($city) . '&key=' . $apiKey;
|
||||||
|
$geoJson = false;
|
||||||
|
if (function_exists('curl_init')) {
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $geoUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_ENCODING, '');
|
||||||
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'HarmonyHues-Weather/1.0');
|
||||||
|
$geoJson = curl_exec($ch);
|
||||||
|
$geo_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
if ($geoJson === false || intval($geo_code) !== 200) {
|
||||||
|
$geoJson = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ctx = stream_context_create(['http' => ['timeout' => 6, 'method' => 'GET']]);
|
||||||
|
$geoJson = @file_get_contents($geoUrl, false, $ctx);
|
||||||
|
}
|
||||||
|
if ($geoJson) {
|
||||||
|
$geoData = json_decode($geoJson, true);
|
||||||
|
if (isset($geoData['location'][0]['id'])) {
|
||||||
|
$location = $geoData['location'][0]['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = 'https://' . $host . '/v7/weather/now?location=' . urlencode($location) . '&key=' . $apiKey . '&lang=zh';
|
||||||
|
|
||||||
|
// 优先使用 cURL,以支持连接/读取超时
|
||||||
|
$json = false;
|
||||||
|
if (function_exists('curl_init')) {
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_ENCODING, '');
|
||||||
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); // 连接超时 3s
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 6); // 总超时 6s
|
||||||
|
curl_setopt($ch, CURLOPT_USERAGENT, 'HarmonyHues-Weather/1.0');
|
||||||
|
$json = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
if ($json === false || intval($http_code) !== 200) {
|
||||||
|
$json = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 回退到 file_get_contents,但设置默认的 socket 超时
|
||||||
|
$ctx = stream_context_create([
|
||||||
|
'http' => [
|
||||||
|
'timeout' => 6,
|
||||||
|
'method' => 'GET',
|
||||||
|
'header' => "User-Agent: HarmonyHues-Weather/1.0\r\n"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$json = @file_get_contents($url, false, $ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($json) {
|
||||||
|
$data = json_decode($json, true);
|
||||||
|
// 和风返回示例:{"code":"200","updateTime":"...","now":{...}}
|
||||||
|
if (isset($data['code']) && ($data['code'] === '200' || $data['code'] === 200)) {
|
||||||
|
$payload = json_encode([
|
||||||
|
'city' => $city,
|
||||||
|
'timestamp' => time(),
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
|
@file_put_contents($cacheFile, $payload);
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$weather = hh_fetch_weather($city, $apiKey, $cacheFile);
|
$weather = hh_fetch_weather($city, $apiKey, $cacheFile, $apiHost);
|
||||||
// 用于调试:在 HTML 注释中输出参数和值,方便查看
|
// 用于调试:记录请求 URL(和风天气)
|
||||||
$reqUrl = 'https://api.openweathermap.org/data/2.5/weather?q=' . urlencode($city)
|
$reqUrl = 'https://' . $apiHost . '/v7/weather/now?location=' . urlencode($city)
|
||||||
. '&appid=' . $apiKey . '&units=metric&lang=zh_cn';
|
. '&key=' . $apiKey . '&lang=zh';
|
||||||
?>
|
?>
|
||||||
|
<?php
|
||||||
|
// 统一解析不同天气接口的返回为标准字段
|
||||||
|
function hh_normalize_weather($raw) {
|
||||||
|
$out = [
|
||||||
|
'ok' => false,
|
||||||
|
'city' => null,
|
||||||
|
'description' => null,
|
||||||
|
'temp' => null,
|
||||||
|
'feels_like' => null,
|
||||||
|
'humidity' => null,
|
||||||
|
'pressure' => null,
|
||||||
|
'wind_speed' => null,
|
||||||
|
'wind_deg' => null,
|
||||||
|
'wind_dir' => null,
|
||||||
|
'wind_scale' => null,
|
||||||
|
'icon_code' => null,
|
||||||
|
'precip' => null,
|
||||||
|
'vis' => null,
|
||||||
|
'cloud' => null,
|
||||||
|
'dew' => null,
|
||||||
|
'obsTime' => null,
|
||||||
|
'refer' => null,
|
||||||
|
'raw' => $raw,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!is_array($raw)) return $out;
|
||||||
|
|
||||||
|
// QWeather 格式
|
||||||
|
if (isset($raw['now'])) {
|
||||||
|
$now = $raw['now'];
|
||||||
|
$out['ok'] = (isset($raw['code']) && ($raw['code'] === '200' || $raw['code'] === 200));
|
||||||
|
// 某些 Host 返回 location 字段,某些返回 location 数组
|
||||||
|
if (isset($raw['location']) && is_array($raw['location'])) {
|
||||||
|
$out['city'] = $raw['location'][0]['name'] ?? $raw['location'][0]['adm2'] ?? null;
|
||||||
|
} else {
|
||||||
|
$out['city'] = $raw['location'] ?? null;
|
||||||
|
}
|
||||||
|
$out['description'] = $now['text'] ?? null;
|
||||||
|
$out['temp'] = $now['temp'] ?? null;
|
||||||
|
$out['feels_like'] = $now['feelsLike'] ?? null;
|
||||||
|
$out['humidity'] = $now['humidity'] ?? null;
|
||||||
|
$out['pressure'] = $now['pressure'] ?? null;
|
||||||
|
$out['wind_speed'] = $now['windSpeed'] ?? null;
|
||||||
|
$out['wind_dir'] = $now['windDir'] ?? ($now['wind360'] ?? null);
|
||||||
|
$out['wind_scale'] = $now['windScale'] ?? null;
|
||||||
|
$out['wind_deg'] = $now['wind360'] ?? null;
|
||||||
|
$out['icon_code'] = $now['icon'] ?? null;
|
||||||
|
$out['precip'] = $now['precip'] ?? null;
|
||||||
|
$out['vis'] = $now['vis'] ?? null;
|
||||||
|
$out['cloud'] = $now['cloud'] ?? null;
|
||||||
|
$out['dew'] = $now['dew'] ?? null;
|
||||||
|
$out['obsTime'] = $now['obsTime'] ?? null;
|
||||||
|
$out['refer'] = $raw['refer'] ?? null;
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenWeatherMap 格式
|
||||||
|
if (isset($raw['weather'][0]) && isset($raw['main'])) {
|
||||||
|
$w = $raw['weather'][0];
|
||||||
|
$m = $raw['main'];
|
||||||
|
$out['ok'] = true;
|
||||||
|
$out['city'] = $raw['name'] ?? null;
|
||||||
|
$out['description'] = $w['description'] ?? null;
|
||||||
|
$out['temp'] = $m['temp'] ?? null;
|
||||||
|
$out['feels_like'] = $m['feels_like'] ?? ($m['feels_like'] ?? null);
|
||||||
|
$out['humidity'] = $m['humidity'] ?? null;
|
||||||
|
$out['pressure'] = $m['pressure'] ?? null;
|
||||||
|
$out['wind_speed'] = $raw['wind']['speed'] ?? null;
|
||||||
|
$out['wind_deg'] = $raw['wind']['deg'] ?? null;
|
||||||
|
$out['icon'] = $w['icon'] ?? null;
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
$norm = hh_normalize_weather($weather);
|
||||||
|
// 格式化更新时间为“YYYY-MM-DD HH:MM”便于阅读
|
||||||
|
$displayObsTime = '-';
|
||||||
|
if (!empty($norm['obsTime'])) {
|
||||||
|
try {
|
||||||
|
$dt = new DateTime($norm['obsTime']);
|
||||||
|
$displayObsTime = $dt->format('Y-m-d H:i');
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$displayObsTime = $norm['obsTime'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
<!-- weather widget debug: city=<?php echo htmlspecialchars($city, ENT_QUOTES); ?>, key_len=<?php echo strlen($apiKey); ?>, url=<?php echo htmlspecialchars($reqUrl, ENT_QUOTES); ?>, allow_url_fopen=<?php echo ini_get('allow_url_fopen') ? 'on' : 'off'; ?>, last_err=<?php $e = error_get_last(); echo $e ? htmlspecialchars($e['message'], ENT_QUOTES) : 'none'; ?> -->
|
<!-- weather widget debug: city=<?php echo htmlspecialchars($city, ENT_QUOTES); ?>, key_len=<?php echo strlen($apiKey); ?>, url=<?php echo htmlspecialchars($reqUrl, ENT_QUOTES); ?>, allow_url_fopen=<?php echo ini_get('allow_url_fopen') ? 'on' : 'off'; ?>, last_err=<?php $e = error_get_last(); echo $e ? htmlspecialchars($e['message'], ENT_QUOTES) : 'none'; ?> -->
|
||||||
|
|
||||||
<div class="hh-widget mt-3 weather-widget" style="font-size:0.9rem;line-height:1.4;">
|
<div class="hh-widget mt-3 weather-widget" style="font-size:0.9rem;line-height:1.4;">
|
||||||
<?php if ($weather && isset($weather['weather'][0])): ?>
|
<?php if ($norm['ok']): ?>
|
||||||
<?php
|
<div style="font-size:0.95rem;font-weight:600;margin-bottom:6px;">作者的城市天气</div>
|
||||||
// 语言友好的城市显示(中英文互译)
|
<div class="weather-header" style="display:flex;align-items:center;justify-content:space-between;">
|
||||||
function hh_display_city($inputCity, $weather) {
|
<div style="display:flex;align-items:center;">
|
||||||
static $map = [
|
<div style="width:64px;height:64px;display:flex;align-items:center;justify-content:center;margin-right:10px;">
|
||||||
'Beijing' => '北京',
|
<!-- 简易条件 SVG(根据描述选择,保持通用) -->
|
||||||
'Guangzhou' => '广州',
|
<?php if (stripos($norm['description'] ?? '', '雨') !== false): ?>
|
||||||
'Shenzhen' => '深圳',
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 13a4 4 0 014-4h1" stroke="#2b7cff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 9a5 5 0 0110 0" stroke="#2b7cff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 19l1.5-2M12 19l1.5-2M16 19l1.5-2" stroke="#2b7cff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
'Shanghai' => '上海',
|
<?php elseif (stripos($norm['description'] ?? '', '云') !== false || stripos($norm['description'] ?? '', '阴') !== false): ?>
|
||||||
'Chengdu' => '成都',
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20 17.5A4.5 4.5 0 0015.5 13H7a4 4 0 010-8 5 5 0 015 5h.5" stroke="#999" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
// 可根据需要继续添加
|
<?php elseif (stripos($norm['description'] ?? '', '雾') !== false || stripos($norm['description'] ?? '', '霾') !== false): ?>
|
||||||
];
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 12h20" stroke="#999" stroke-width="1.5" stroke-linecap="round"/><path d="M2 16h20" stroke="#999" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||||
if (isset($map[$inputCity])) {
|
<?php else: ?>
|
||||||
return $map[$inputCity];
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="4" stroke="#ffb400" stroke-width="1.5"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" stroke="#ffb400" stroke-width="1.2" stroke-linecap="round"/></svg>
|
||||||
}
|
<?php endif; ?>
|
||||||
if (isset($map[$weather['name']])) {
|
</div>
|
||||||
return $map[$weather['name']];
|
<div>
|
||||||
}
|
<p style="margin:0;font-weight:bold;line-height:1;font-size:1rem;"><?php echo htmlspecialchars($norm['city'] ?: $city, ENT_QUOTES); ?></p>
|
||||||
return $weather['name'];
|
<p style="margin:0;line-height:1;color:#333;"><?php echo htmlspecialchars($norm['description'] ?? '-', ENT_QUOTES); ?> • <strong><?php echo htmlspecialchars($norm['temp'] ?? '-', ENT_QUOTES); ?>°C</strong></p>
|
||||||
}
|
</div>
|
||||||
$displayCity = hh_display_city($city, $weather);
|
|
||||||
$w = $weather['weather'][0];
|
|
||||||
$m = $weather['main'];
|
|
||||||
$wind = $weather['wind'] ?? [];
|
|
||||||
$iconUrl = 'https://openweathermap.org/img/wn/' . $w['icon'] . '@2x.png';
|
|
||||||
?>
|
|
||||||
<div class="weather-header" style="display:flex;align-items:center;justify-content:center;">
|
|
||||||
<img src="<?php echo $iconUrl; ?>"
|
|
||||||
alt="<?php echo htmlspecialchars($w['description'], ENT_QUOTES); ?>"
|
|
||||||
style="width:48px;height:48px;margin-right:8px;">
|
|
||||||
<div style="text-align:left;">
|
|
||||||
<p style="margin:0;font-weight:bold;line-height:1;"><?php echo $displayCity; ?></p>
|
|
||||||
<p style="margin:0;line-height:1;"><?php echo $w['description']; ?> <?php echo $m['temp']; ?>°C</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div style="width:1px"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="weather-details" style="font-size:0.85rem;color:#555;text-align:center;margin-top:4px;">
|
|
||||||
<p style="margin:0;">体感:<?php echo $m['feels_like']; ?>°C;湿度:<?php echo $m['humidity']; ?>%;气压:<?php echo $m['pressure']; ?> hPa</p>
|
<div class="weather-grid" style="display:grid;grid-template-columns:repeat(2,1fr);gap:6px;margin-top:8px;font-size:0.9rem;color:#444;">
|
||||||
<?php if (!empty($wind)): ?>
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M12 2v20" stroke="#ff6b6b" stroke-width="1.5" stroke-linecap="round"/></svg> 体感:<?php echo htmlspecialchars($norm['feels_like'] ?? '-', ENT_QUOTES); ?>°C</div>
|
||||||
<p style="margin:0;">风速:<?php echo $wind['speed']; ?> m/s<?php
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M3 12h18" stroke="#5aa9ff" stroke-width="1.5" stroke-linecap="round"/></svg> 湿度:<?php echo htmlspecialchars($norm['humidity'] ?? '-', ENT_QUOTES); ?>%</div>
|
||||||
if (isset($wind['deg'])) echo ',方向:' . $wind['deg'] . '°'; ?></p>
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M3 6h18" stroke="#888" stroke-width="1.5" stroke-linecap="round"/></svg> 气压:<?php echo htmlspecialchars($norm['pressure'] ?? '-', ENT_QUOTES); ?> hPa</div>
|
||||||
<?php endif; ?>
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M3 6l3 6h12l3-6" stroke="#6c6cff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> 风:<?php echo htmlspecialchars($norm['wind_speed'] ?? '-', ENT_QUOTES); ?> m/s <?php echo htmlspecialchars($norm['wind_dir'] ?? '', ENT_QUOTES); ?><?php if (!empty($norm['wind_scale'])) echo ' | 级别 ' . htmlspecialchars($norm['wind_scale'], ENT_QUOTES); ?></div>
|
||||||
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M12 2v4" stroke="#2b7cff" stroke-width="1.5" stroke-linecap="round"/></svg> 降水:<?php echo htmlspecialchars($norm['precip'] ?? '-', ENT_QUOTES); ?> mm</div>
|
||||||
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M3 12h18" stroke="#999" stroke-width="1.5" stroke-linecap="round"/></svg> 能见度:<?php echo htmlspecialchars($norm['vis'] ?? '-', ENT_QUOTES); ?> km</div>
|
||||||
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M12 2c4 0 7 3 7 7s-3 7-7 7-7-3-7-7 3-7 7-7z" stroke="#999" stroke-width="1.2"/></svg> 云量:<?php echo htmlspecialchars($norm['cloud'] ?? '-', ENT_QUOTES); ?>%</div>
|
||||||
|
<div style="display:flex;align-items:center;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" style="margin-right:6px"><path d="M3 12h18" stroke="#666" stroke-width="1.2"/></svg> 露点:<?php echo htmlspecialchars($norm['dew'] ?? '-', ENT_QUOTES); ?>°C</div>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif ($weather && isset($weather['cod']) && $weather['cod'] != 200): ?>
|
<?php if (!empty($norm['refer'])): ?>
|
||||||
<p>天气接口错误:<?php echo htmlspecialchars($weather['message'] ?? '未知', ENT_QUOTES); ?></p>
|
<div style="font-size:0.65rem;color:#888;margin-top:6px;">来源:<?php echo htmlspecialchars(implode(', ', $norm['refer']['sources'] ?? $norm['refer'] ?? []), ENT_QUOTES); ?> • 更新时间:<?php echo htmlspecialchars($displayObsTime, ENT_QUOTES); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p>天气获取失败</p>
|
<p>天气获取失败(请检查 API Key 与网络)</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -239,27 +239,7 @@ function themeConfig($form) {
|
|||||||
$form->addInput($blogSignageText);
|
$form->addInput($blogSignageText);
|
||||||
$blogSignageText->setAttribute('class', 'setting-content my-3');
|
$blogSignageText->setAttribute('class', 'setting-content my-3');
|
||||||
|
|
||||||
// 天气城市设置
|
// (已移除天气配置)天气城市与 API Key/Host 已改为直接写入主题代码以便简化部署
|
||||||
$weatherCity = new Typecho_Widget_Helper_Form_Element_Text(
|
|
||||||
'weatherCity',
|
|
||||||
NULL,
|
|
||||||
'Beijing',
|
|
||||||
'天气城市(非必填)',
|
|
||||||
'介绍:填写用于查询天气的城市名称,例如北京或Beijing'
|
|
||||||
);
|
|
||||||
$form->addInput($weatherCity);
|
|
||||||
$weatherCity->setAttribute('class', 'setting-content my-3');
|
|
||||||
|
|
||||||
// 天气 API Key
|
|
||||||
$weatherApiKey = new Typecho_Widget_Helper_Form_Element_Text(
|
|
||||||
'weatherApiKey',
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
'天气 API Key(非必填)',
|
|
||||||
'介绍:在此填写 OpenWeatherMap 或其他天气接口的 API Key'
|
|
||||||
);
|
|
||||||
$form->addInput($weatherApiKey);
|
|
||||||
$weatherApiKey->setAttribute('class', 'setting-content my-3');
|
|
||||||
|
|
||||||
// 首页内容显示
|
// 首页内容显示
|
||||||
$indexBlock = new Typecho_Widget_Helper_Form_Element_Checkbox(
|
$indexBlock = new Typecho_Widget_Helper_Form_Element_Checkbox(
|
||||||
|
|||||||
Reference in New Issue
Block a user