feat: 实时消息与管理端运营能力

新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-15 22:58:16 +08:00
parent 29db9ae9b5
commit 42c395a864
55 changed files with 7607 additions and 346 deletions

View File

@@ -4,9 +4,11 @@ import { cookies } from "next/headers";
import { PenSquare, MessagesSquare, ChevronRight } from "lucide-react";
import { fetchPosts, fetchBoards } from "@/lib/api";
import { authCookieHeader } from "@/lib/cookies";
import { getMeCached } from "@/lib/serverData";
import Pagination from "@/components/Pagination";
import PostRow from "@/components/PostRow";
import PinnedPosts from "@/components/PinnedPosts";
import FeedNewTip from "@/components/home/FeedNewTip";
interface PageProps {
params: Promise<{ id: string }>;
@@ -28,12 +30,14 @@ export default async function BoardPage({ params, searchParams }: PageProps) {
const { page: pageStr } = await searchParams;
const page = Math.max(1, parseInt(pageStr || "1", 10) || 1);
const cookie = authCookieHeader(await cookies());
const [postsData, boardsData] = await Promise.all([
const [postsData, boardsData, me] = await Promise.all([
fetchPosts(page, 20, Number(id), "latest", "", false, cookie),
fetchBoards(),
getMeCached(cookie || undefined),
]);
const boardIndex = boardsData.boards.findIndex((b) => b.id === Number(id));
const board = boardIndex >= 0 ? boardsData.boards[boardIndex] : null;
const user = me.user;
// 第一页:置顶帖独立成区,列表只保留非置顶
const pinned = page === 1 ? postsData.posts.filter((p) => p.pinned > 0) : [];
@@ -88,6 +92,16 @@ export default async function BoardPage({ params, searchParams }: PageProps) {
<span className="font-bold text-[15px]" style={{ color: "var(--ink)" }}>全部讨论</span>
<span className="meta text-xs">第 {page} 页</span>
</div>
{user && (
<div className="pt-2.5">
<FeedNewTip
sort="latest"
boardId={Number(id)}
page={page}
userId={user.id}
/>
</div>
)}
{rows.map((post, i) => (
<PostRow key={post.id} post={post} index={i} />
))}