feat: 新增站点公告系统与多项体验优化
此提交完成了以下核心功能与优化: 1. 新增站点公告全流程支持:包含公告模型、CRUD接口、管理后台页面、公告详情页与首页展示 2. 实现评论楼层化与回复嵌套:重构评论系统为树状结构,支持回复评论与层级限制 3. 添加用户在线状态追踪:异步更新用户最后活跃时间并做SQL限频 4. 优化用户体验:移动端浮动操作条、统一板块标签样式、用户页签到积分展示、注册即登录优化 5. 其他细节优化:SEO站点地图新增公告页、评论分页与统计、登录/注册表单增强等
This commit is contained in:
@@ -23,16 +23,20 @@ import {
|
||||
type Board,
|
||||
} from "@/lib/api";
|
||||
import { authCookieHeader } from "@/lib/cookies";
|
||||
import { getMeCached } from "@/lib/serverData";
|
||||
import CommentSection from "@/components/CommentSection";
|
||||
import PostActions from "@/components/PostActions";
|
||||
import LikeButton from "@/components/LikeButton";
|
||||
import ReadingProgress from "@/components/ReadingProgress";
|
||||
import PostToc, { type TocItem } from "@/components/PostToc";
|
||||
import MobilePostBar from "@/components/MobilePostBar";
|
||||
import Avatar from "@/components/Avatar";
|
||||
import { IconComment, IconEye } from "@/components/Icons";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
// page 同时用于评论分页(?page=N),帖子正文本身不分页
|
||||
searchParams: Promise<{ page?: string }>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
@@ -313,14 +317,17 @@ function AuthorCardStacked({ profile }: { profile: UserProfile }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default async function PostDetailPage({ params }: PageProps) {
|
||||
export default async function PostDetailPage({ params, searchParams }: PageProps) {
|
||||
const { id } = await params;
|
||||
const sp = await searchParams;
|
||||
const commentPage = Math.max(1, parseInt(sp.page || "1", 10) || 1);
|
||||
const cookie = authCookieHeader(await cookies());
|
||||
const { post } = await fetchPostDetail(id, cookie);
|
||||
|
||||
// 评论 / 作者资料 / 同板块热议并行拉取;侧栏数据失败一律静默降级,不阻塞正文
|
||||
const [commentsData, profile, relatedData] = await Promise.all([
|
||||
fetchComments(id),
|
||||
// 评论 / 当前用户 / 作者资料 / 同板块热议并行拉取;侧栏数据失败一律静默降级,不阻塞正文
|
||||
const [commentsData, me, profile, relatedData] = await Promise.all([
|
||||
fetchComments(id, commentPage),
|
||||
getMeCached(cookie || undefined),
|
||||
fetchUserProfile(String(post.user.id), 1, cookie).catch(() => null),
|
||||
fetchPosts(1, 8, post.board_id, "hot", "", false, cookie).catch(() => null),
|
||||
]);
|
||||
@@ -369,6 +376,8 @@ export default async function PostDetailPage({ params }: PageProps) {
|
||||
<>
|
||||
<ReadingProgress />
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
|
||||
{/* 移动端浮动操作条:长文阅读中途可点赞 / 跳评论 / 回顶部 */}
|
||||
<MobilePostBar postId={id} liked={post.liked} likeCount={post.like_count} />
|
||||
|
||||
{/* 三栏阅读布局:xl = 左导航240 + 正文 + 右辅助280;lg = 正文 + 右辅助260;以下单栏 */}
|
||||
<div className="grid grid-cols-1 items-start lg:grid-cols-[minmax(0,1fr)_260px] xl:grid-cols-[240px_minmax(0,1fr)_280px] gap-x-6 xl:gap-x-7">
|
||||
@@ -487,7 +496,15 @@ export default async function PostDetailPage({ params }: PageProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CommentSection postId={id} comments={comments} />
|
||||
<CommentSection
|
||||
postId={id}
|
||||
comments={comments}
|
||||
total={commentsData.total}
|
||||
totalComments={commentsData.total_comments}
|
||||
page={commentsData.page}
|
||||
size={commentsData.size}
|
||||
user={me.user}
|
||||
/>
|
||||
|
||||
{/* 窄屏相关讨论(lg 起由右栏承载) */}
|
||||
<div className="lg:hidden mt-6">
|
||||
@@ -505,6 +522,9 @@ export default async function PostDetailPage({ params }: PageProps) {
|
||||
<RelatedPosts posts={related} boardId={post.board_id} />
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{/* 给移动端浮动操作条让位,避免遮住页尾内容 */}
|
||||
<div className="lg:hidden h-16" aria-hidden />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user