feat: 实时消息与管理端运营能力
新增群聊/私信与公共 WebSocket 总线,站长用户内容档案,并将通知与待审角标改为推送驱动;同步精简管理仪表盘并修复主题换肤 DOM 冲突。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
94
frontend/app/chat/[id]/page.tsx
Normal file
94
frontend/app/chat/[id]/page.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { Metadata } from "next";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { cookies } from "next/headers";
|
||||
import { authCookieHeader } from "@/lib/cookies";
|
||||
import { getMeCached } from "@/lib/serverData";
|
||||
import { fetchChatRoom, fetchChatMessages, fetchChatRooms } from "@/lib/api";
|
||||
import ChatShell from "../ChatShell";
|
||||
import ChatRoomClient from "./ChatRoomClient";
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
const { id } = await params;
|
||||
try {
|
||||
const { room } = await fetchChatRoom(id, authCookieHeader(await cookies()));
|
||||
const title =
|
||||
room.room_type === "direct"
|
||||
? room.peer?.nickname || room.peer?.username || room.name || "私聊"
|
||||
: room.name;
|
||||
return { title: `消息 · ${title}` };
|
||||
} catch {
|
||||
return { title: "会话不存在" };
|
||||
}
|
||||
}
|
||||
|
||||
export default async function ChatRoomPage({ params }: PageProps) {
|
||||
const { id } = await params;
|
||||
const cookie = authCookieHeader(await cookies());
|
||||
const me = await getMeCached(cookie || undefined);
|
||||
if (!me.user) {
|
||||
redirect(`/login?redirect=${encodeURIComponent(`/chat/${id}`)}`);
|
||||
}
|
||||
|
||||
let rooms: Awaited<ReturnType<typeof fetchChatRooms>>["rooms"] = [];
|
||||
try {
|
||||
const data = await fetchChatRooms(1, 50, "", cookie, "joined");
|
||||
rooms = data.rooms || [];
|
||||
} catch {
|
||||
rooms = [];
|
||||
}
|
||||
|
||||
let room: Awaited<ReturnType<typeof fetchChatRoom>>["room"];
|
||||
try {
|
||||
({ room } = await fetchChatRoom(id, cookie));
|
||||
} catch {
|
||||
notFound();
|
||||
}
|
||||
|
||||
let initialMessages: Awaited<ReturnType<typeof fetchChatMessages>> = {
|
||||
messages: [],
|
||||
has_more: false,
|
||||
};
|
||||
if (room.joined) {
|
||||
try {
|
||||
initialMessages = await fetchChatMessages(id, 0, 30, cookie);
|
||||
} catch {
|
||||
// 客户端兜底
|
||||
}
|
||||
}
|
||||
|
||||
const displayName =
|
||||
room.room_type === "direct"
|
||||
? room.peer?.nickname || room.peer?.username || room.name || "私聊"
|
||||
: room.name;
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<ChatShell meId={me.user.id} initialRooms={rooms} activeRoomId={room.id}>
|
||||
<ChatRoomClient
|
||||
roomId={room.id}
|
||||
roomName={displayName}
|
||||
roomDescription={room.description}
|
||||
ownerId={room.owner_id}
|
||||
memberCount={room.member_count}
|
||||
myRole={room.my_role}
|
||||
joined={room.joined}
|
||||
isPrivate={room.is_private}
|
||||
isDefault={room.is_default}
|
||||
roomType={room.room_type || "group"}
|
||||
peer={room.peer || null}
|
||||
meId={me.user.id}
|
||||
meRole={me.user.role}
|
||||
meName={me.user.nickname || me.user.username}
|
||||
meAvatar={me.user.avatar || ""}
|
||||
initialMessages={initialMessages.messages}
|
||||
initialHasMore={initialMessages.has_more}
|
||||
embedded
|
||||
/>
|
||||
</ChatShell>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user