Files
evus.acvisa.com/app/home/controller/News.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;
}
}