57 lines
2.1 KiB
JavaScript
57 lines
2.1 KiB
JavaScript
import { useEffect, useState } from 'react'
|
||
import { useParams, useNavigate } from 'react-router-dom'
|
||
import { NavBar } from 'antd-mobile'
|
||
import { api } from '../../api/client.js'
|
||
|
||
// 新闻详情: /news/:id
|
||
// 正文来自 News.content (MCP 返回的完整正文), 旧数据可能无 content, 兜底显示摘要
|
||
function fmtDate(s) {
|
||
if (!s) return ''
|
||
const d = new Date(s)
|
||
if (isNaN(d.getTime())) return s
|
||
const pad = (n) => String(n).padStart(2, '0')
|
||
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
|
||
}
|
||
|
||
export default function NewsDetail() {
|
||
const { id } = useParams()
|
||
const navigate = useNavigate()
|
||
const [item, setItem] = useState(null)
|
||
const [err, setErr] = useState('')
|
||
const [loading, setLoading] = useState(true)
|
||
|
||
useEffect(() => {
|
||
let cancelled = false
|
||
setLoading(true)
|
||
api('/news/' + encodeURIComponent(id))
|
||
.then((data) => { if (!cancelled) setItem(data.item) })
|
||
.catch((e) => !cancelled && setErr(e.message))
|
||
.finally(() => !cancelled && setLoading(false))
|
||
return () => { cancelled = true }
|
||
}, [id])
|
||
|
||
return (
|
||
<div className="article-page">
|
||
<NavBar onBack={() => navigate(-1)}>新闻详情</NavBar>
|
||
{loading && <div className="loading">加载中...</div>}
|
||
{err && <div className="error-banner">{err}</div>}
|
||
{!loading && !err && !item && <div className="empty">新闻不存在</div>}
|
||
{!loading && !err && item && (
|
||
<div className="news-detail">
|
||
<h1>{item.title}</h1>
|
||
<div className="meta">
|
||
{item.source || '未知来源'} · {fmtDate(item.publishedAt)} · #{item.impactRank}
|
||
{/^https?:\/\//i.test(item.url || '') && (
|
||
<a className="news-origin" href={item.url} target="_blank" rel="noreferrer">原文链接</a>
|
||
)}
|
||
</div>
|
||
<div className="news-content">
|
||
{item.content ? item.content : item.summary}
|
||
{!item.content && <div className="news-content-empty">(本条暂无全文,仅摘要)</div>}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|