- {it.summary &&
{it.summary}
}
-
- {Array.isArray(it.images) && it.images.length > 0 && (
-
- {it.images.map((u, i) =>

)}
-
- )}
- {it.link &&
原文链接 ↗}
+
+ {big && (
+
+ {img ?

: null}
+ {it.video ?
▶
: null}
)}
+
+
{it.title}
+
+
+ {it.publisher_avatar ?
: null}
+
+ {author}·{fmt(it.created_at)}
+
+
);
}
diff --git a/website/src/user/ContentDetail.jsx b/website/src/user/ContentDetail.jsx
new file mode 100644
index 0000000..6bf97cf
--- /dev/null
+++ b/website/src/user/ContentDetail.jsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import { ContentTemplate } from '@/components/templates';
+import { Button } from '@/components/atoms';
+import AuthGate from '@/components/AuthGate';
+import { isAuthed } from '@/services/auth';
+import { getOne, getComments, addComment } from '@/services/content';
+import '@/styles/booking.css';
+
+const rw = (s) => (s || '').replace('T', ' ').replace('Z', '').slice(0, 16);
+const getId = () => new URLSearchParams((window.location.hash.split('?')[1] || '')).get('id');
+
+/** 资讯独立详情页(微信文章式):标题/作者/阅读 + 正文 + 动作条 + 留言。 */
+export default function ContentDetail() {
+ const [item, setItem] = React.useState(null);
+ const [comments, setComments] = React.useState([]);
+ const [err, setErr] = React.useState('');
+ const [loaded, setLoaded] = React.useState(false);
+ const [like, setLike] = React.useState(false);
+ const [fav, setFav] = React.useState(false);
+ const [draft, setDraft] = React.useState('');
+ const [sending, setSending] = React.useState(false);
+
+ React.useEffect(() => {
+ const id = getId();
+ if (!id) { setErr('无效内容'); setLoaded(true); return; }
+ getOne(id).then((r) => { if (!r) setErr('内容不存在'); else setItem(r); }).catch(() => setErr('加载失败')).finally(() => setLoaded(true));
+ getComments(id).then(setComments).catch(() => {});
+ }, []);
+
+ const send = async () => {
+ if (!draft.trim()) return;
+ setSending(true);
+ try {
+ const c = await addComment(item.id, draft.trim());
+ if (c) { setComments((m) => [c, ...m]); setDraft(''); }
+ } catch (e) { setErr((e && e.message) || '留言失败,请先登录'); }
+ finally { setSending(false); }
+ };
+ const copyLink = () => navigator.clipboard?.writeText(`https://opc.pinesound.cn/#/content-detail?id=${item?.id}`).then(() => setErr(''));
+
+ if (!loaded) return
;
+ if (err || !item) return
;
+
+ const author = item.publisher_name || '云超服';
+ const views = item.read_count || 0;
+ return (
+
+
+ {item.cover &&
}
+
+ {item.publisher_avatar
+ ?

+ :
}
+
{author} ✓
+
· {rw(item.created_at)}
+
· 阅读 {views}
+
+
+ {Array.isArray(item.images) && item.images.length > 0 && (
+
+ {item.images.map((u, i) =>

)}
+
+ )}
+ {item.link && 原文链接 ↗}
+
+ {/* 动作条 */}
+
+ 👍 0{like ? ' · 已赞' : ''}
+
+
+
+
+
+
+ {/* 阅读 + 留言 */}
+ 阅读 {views}
+
+
留言
+ {isAuthed() ? (
+
+ setDraft(e.target.value)} />
+ 😊 🖼
+
+
+ ) : (
+
+ )}
+ {comments.length === 0
+ ?
还没有留言,来写首评
+ : comments.map((c) => (
+
+
+ {c.avatar ?

:
}
+
{c.nickname || c.username || '用户'}
+
{rw(c.created_at)}
+
+
{c.content}
+
+ ))}
+
+
+
+ );
+}