229 lines
6.7 KiB
PHP
229 lines
6.7 KiB
PHP
<?php
|
|
|
|
namespace app\home\controller;
|
|
|
|
use api\Httpcurl;
|
|
use app\service\SeoMetaService;
|
|
use think\facade\Log;
|
|
use think\facade\Request;
|
|
use think\facade\View;
|
|
|
|
class News extends Base
|
|
{
|
|
public function index()
|
|
{
|
|
$page = intval(input('page') ? input('page') : 1);
|
|
$size = intval(input('size') ? input('size') : 10);
|
|
$page = max(1, $page);
|
|
$size = max(1, $size);
|
|
|
|
$news_list = $this->requestNewsList($page, $size);
|
|
if (!empty($news_list) && isset($news_list['code']) && $news_list['code'] == 1) {
|
|
$data = $this->normalizeNewsList(isset($news_list['data']) ? $news_list['data'] : []);
|
|
$count = isset($news_list['count']) ? intval($news_list['count']) : count($data);
|
|
} else {
|
|
$data = [];
|
|
$count = 0;
|
|
}
|
|
|
|
View::assign('data', $data);
|
|
View::assign('count', $count);
|
|
View::assign('page', $page);
|
|
View::assign('size', $size);
|
|
$this->assignSeo([
|
|
'title' => $page > 1
|
|
? 'EVUS与美国签证新闻资讯 - 第' . $page . '页'
|
|
: 'EVUS与美国签证新闻资讯',
|
|
'canonical_path' => '/home/news/index',
|
|
'canonical_query_keys' => ['page'],
|
|
]);
|
|
return View::fetch();
|
|
}
|
|
|
|
public function detail()
|
|
{
|
|
$id = Request::instance()->param('id');
|
|
if (
|
|
!is_scalar($id)
|
|
|| filter_var((string) $id, FILTER_VALIDATE_INT, [
|
|
'options' => ['min_range' => 1],
|
|
]) === false
|
|
) {
|
|
abort(404, '新闻不存在');
|
|
}
|
|
$id = (int) $id;
|
|
|
|
$info = $this->requestNewsDetail($id);
|
|
if ($info === null) {
|
|
abort(503, '新闻服务暂时不可用');
|
|
}
|
|
if (empty($info) || !isset($info['code']) || $info['code'] != 1 || empty($info['data'])) {
|
|
abort(404, '新闻不存在');
|
|
}
|
|
|
|
$info_detail = $this->normalizeNewsItem($info['data']);
|
|
$latest = $this->requestNewsList(1, 50);
|
|
$latest_data = [];
|
|
if (!empty($latest) && isset($latest['code']) && $latest['code'] == 1) {
|
|
$latest_data = $this->normalizeNewsList(isset($latest['data']) ? $latest['data'] : [], true);
|
|
}
|
|
|
|
$nav = $this->resolveArticleNav($id, $latest_data);
|
|
$article = $this->filterRelatedArticles($id, $latest_data, 8);
|
|
|
|
View::assign('data', $info_detail);
|
|
View::assign('last', $nav['last']);
|
|
View::assign('next', $nav['next']);
|
|
View::assign('article', $article);
|
|
|
|
$seoService = new SeoMetaService();
|
|
$title = $seoService->descriptionFromHtml((string) $info_detail['title'], 60);
|
|
$description = $seoService->descriptionFromHtml(
|
|
(string) $info_detail['contents']
|
|
);
|
|
$seo = [
|
|
'canonical_path' => '/home/news/detail',
|
|
'canonical_query_keys' => ['id'],
|
|
];
|
|
if ($title !== '') {
|
|
$seo['title'] = $title;
|
|
}
|
|
if ($description !== '') {
|
|
$seo['description'] = $description;
|
|
}
|
|
$this->assignSeo($seo);
|
|
|
|
return View::fetch();
|
|
}
|
|
|
|
private function requestNewsList($page, $size)
|
|
{
|
|
$response = Httpcurl::request(NEWS_LIST, 'post', [
|
|
'model' => 'article',
|
|
'source_code' => DOMAIN,
|
|
'page' => $page,
|
|
'size' => $size,
|
|
]);
|
|
|
|
return $this->decodeApiResponse($response, 'news list');
|
|
}
|
|
|
|
private function requestNewsDetail($id)
|
|
{
|
|
$response = Httpcurl::request(NEWS_DETAIL, 'post', [
|
|
'model' => 'article',
|
|
'id' => $id,
|
|
]);
|
|
|
|
return $this->decodeApiResponse($response, 'news detail');
|
|
}
|
|
|
|
private function decodeApiResponse($response, $scene)
|
|
{
|
|
if (!is_array($response) || !isset($response[0]) || !empty($response[3])) {
|
|
Log::error($scene . ' api request failed: ' . json_encode($response));
|
|
return null;
|
|
}
|
|
|
|
$status_code = intval(isset($response[2]['http_code']) ? $response[2]['http_code'] : 0);
|
|
if ($status_code < 200 || $status_code >= 300) {
|
|
Log::error($scene . ' api returned HTTP status: ' . $status_code);
|
|
return null;
|
|
}
|
|
|
|
$result = json_decode($response[0], true);
|
|
Log::info(json_encode($result));
|
|
return is_array($result) ? $result : null;
|
|
}
|
|
|
|
private function normalizeNewsList($list, $short_date = false)
|
|
{
|
|
if (!is_array($list)) {
|
|
return [];
|
|
}
|
|
|
|
$data = [];
|
|
foreach ($list as $item) {
|
|
$item = $this->normalizeNewsItem($item);
|
|
if ($short_date) {
|
|
$item['create_time'] = $this->formatDate($item['create_time']);
|
|
}
|
|
$data[] = $item;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function normalizeNewsItem($item)
|
|
{
|
|
if (!is_array($item)) {
|
|
return [];
|
|
}
|
|
|
|
$item['id'] = isset($item['id']) ? $item['id'] : 0;
|
|
$item['title'] = isset($item['title']) ? $item['title'] : '';
|
|
$contents = isset($item['contents'])
|
|
? $item['contents']
|
|
: (isset($item['content']) ? $item['content'] : '');
|
|
$item['contents'] = is_scalar($contents)
|
|
? str_replace('https://www.evus.gov/', '', (string) $contents)
|
|
: '';
|
|
$item['create_time'] = isset($item['create_time']) ? $item['create_time'] : '';
|
|
|
|
return $item;
|
|
}
|
|
|
|
private function resolveArticleNav($id, $list)
|
|
{
|
|
$id = intval($id);
|
|
$last = [];
|
|
$next = [];
|
|
|
|
foreach ($list as $item) {
|
|
$item_id = intval(isset($item['id']) ? $item['id'] : 0);
|
|
if ($item_id <= 0 || $item_id == $id) {
|
|
continue;
|
|
}
|
|
|
|
if ($item_id < $id && (empty($last) || $item_id > intval($last['id']))) {
|
|
$last = $item;
|
|
}
|
|
|
|
if ($item_id > $id && (empty($next) || $item_id < intval($next['id']))) {
|
|
$next = $item;
|
|
}
|
|
}
|
|
|
|
return ['last' => $last, 'next' => $next];
|
|
}
|
|
|
|
private function filterRelatedArticles($id, $list, $limit)
|
|
{
|
|
$data = [];
|
|
$id = intval($id);
|
|
|
|
foreach ($list as $item) {
|
|
if (intval($item['id']) == $id) {
|
|
continue;
|
|
}
|
|
|
|
$data[] = $item;
|
|
if (count($data) >= $limit) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function formatDate($date)
|
|
{
|
|
if (empty($date)) {
|
|
return '';
|
|
}
|
|
|
|
$timestamp = strtotime($date);
|
|
return $timestamp ? date('Y-m-d', $timestamp) : $date;
|
|
}
|
|
}
|