chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace addon\haonav\controller;
|
||||
use ywxapp\controller\FrontendBase;
|
||||
|
||||
use think\facade\Cache;
|
||||
use addon\haonav\model\Configure as ConfigureModel;
|
||||
|
||||
/**
|
||||
* 首页小组件:实时热搜榜 + 天气(服务端代理 + 缓存,规避跨域并保护第三方接口)
|
||||
*
|
||||
* @author ywxapp <admin@ywxapp.cn>
|
||||
*/
|
||||
class Widget extends FrontendBase
|
||||
{
|
||||
protected $noNeedLogin = ['*'];
|
||||
protected $noNeedVerify = ['*'];
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时热搜榜(缓存 10 分钟)
|
||||
* GET /haonav/widget/hot?source=baidu|weibo|zhihu
|
||||
*/
|
||||
public function hot()
|
||||
{
|
||||
if ((int)ConfigureModel::getVal('enable_hot_api', '0') !== 1) {
|
||||
return $this->result->success([], '未开启');
|
||||
}
|
||||
$source = $this->request->param('source', ConfigureModel::getVal('hot_api_source', 'baidu'));
|
||||
$source = in_array($source, ['baidu', 'weibo', 'zhihu'], true) ? $source : 'baidu';
|
||||
|
||||
$cacheKey = 'haonav_hot_' . $source;
|
||||
$data = Cache::get($cacheKey);
|
||||
if (is_array($data)) {
|
||||
return $this->result->success($data, '缓存');
|
||||
}
|
||||
|
||||
$map = [
|
||||
'baidu' => 'https://api.vvhan.com/api/hotlist/baiduRD',
|
||||
'weibo' => 'https://api.vvhan.com/api/hotlist/wbHot',
|
||||
'zhihu' => 'https://api.vvhan.com/api/hotlist/zhihuHot',
|
||||
];
|
||||
$list = $this->fetchHot($map[$source]);
|
||||
// 即便为空也短缓存,避免频繁打第三方
|
||||
Cache::set($cacheKey, $list, $list ? 600 : 120);
|
||||
return $this->result->success($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 天气(缓存 30 分钟)
|
||||
* GET /haonav/widget/weather?city=北京
|
||||
*/
|
||||
public function weather()
|
||||
{
|
||||
if ((int)ConfigureModel::getVal('enable_weather', '0') !== 1) {
|
||||
return $this->result->success([], '未开启');
|
||||
}
|
||||
$city = trim((string)$this->request->param('city', ConfigureModel::getVal('weather_city', '')));
|
||||
|
||||
$cacheKey = 'haonav_weather_' . ($city !== '' ? md5($city) : 'auto');
|
||||
$data = Cache::get($cacheKey);
|
||||
if (is_array($data) && $data) {
|
||||
return $this->result->success($data, '缓存');
|
||||
}
|
||||
|
||||
$info = $this->fetchWeather($city);
|
||||
if ($info) {
|
||||
Cache::set($cacheKey, $info, 1800);
|
||||
return $this->result->success($info);
|
||||
}
|
||||
return $this->result->success([], '暂无数据');
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取并归一化热搜列表 -> [ {title,url,hot}, ... ]
|
||||
*/
|
||||
protected function fetchHot(string $api): array
|
||||
{
|
||||
$json = $this->httpGet($api);
|
||||
if (!$json) {
|
||||
return [];
|
||||
}
|
||||
$arr = json_decode($json, true);
|
||||
if (!is_array($arr)) {
|
||||
return [];
|
||||
}
|
||||
$rows = $arr['data'] ?? ($arr['result'] ?? []);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($rows as $r) {
|
||||
if (!is_array($r)) {
|
||||
continue;
|
||||
}
|
||||
$title = $r['title'] ?? ($r['name'] ?? '');
|
||||
if ($title === '') {
|
||||
continue;
|
||||
}
|
||||
$out[] = [
|
||||
'title' => (string)$title,
|
||||
'url' => (string)($r['url'] ?? ($r['mobil_url'] ?? '')),
|
||||
'hot' => (string)($r['hot'] ?? ($r['num'] ?? '')),
|
||||
];
|
||||
if (count($out) >= 20) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取并归一化天气 -> {city,type,low,high,tips,...}
|
||||
*/
|
||||
protected function fetchWeather(string $city)
|
||||
{
|
||||
$api = 'https://api.vvhan.com/api/weather';
|
||||
if ($city !== '') {
|
||||
$api .= '?city=' . urlencode($city);
|
||||
}
|
||||
$json = $this->httpGet($api);
|
||||
if (!$json) {
|
||||
return false;
|
||||
}
|
||||
$arr = json_decode($json, true);
|
||||
if (!is_array($arr) || empty($arr['success'])) {
|
||||
return false;
|
||||
}
|
||||
$today = $arr['data'][0] ?? [];
|
||||
return [
|
||||
'city' => (string)($arr['city'] ?? $city),
|
||||
'date' => (string)($today['date'] ?? ''),
|
||||
'type' => (string)($today['type'] ?? ''),
|
||||
'low' => (string)($today['low'] ?? ''),
|
||||
'high' => (string)($today['high'] ?? ''),
|
||||
'fx' => (string)($today['fengxiang'] ?? ''),
|
||||
'tips' => (string)($arr['tip'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 轻量 GET(优先 Guzzle,失败回退 file_get_contents),失败返回 ''
|
||||
*/
|
||||
protected function httpGet(string $url): string
|
||||
{
|
||||
try {
|
||||
if (class_exists(\GuzzleHttp\Client::class)) {
|
||||
$client = new \GuzzleHttp\Client(['timeout' => 5, 'verify' => false]);
|
||||
$resp = $client->get($url, ['headers' => ['Member-Agent' => 'Mozilla/5.0']]);
|
||||
return (string)$resp->getBody();
|
||||
}
|
||||
$ctx = stream_context_create(['http' => ['timeout' => 5, 'header' => "Member-Agent: Mozilla/5.0\r\n"]]);
|
||||
$body = @file_get_contents($url, false, $ctx);
|
||||
return $body === false ? '' : (string)$body;
|
||||
} catch (\Throwable $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user