"use client"; /** * ChatScreen 编排层 * * 原始 Dart: lib/ui/chat/chat_screen.dart(172 行) * * 职责(本文件): * - 屏幕生命周期事件(init / visible / invisible) * - 配额告警监听(quotaExceededTrigger + warningThreshold) * - 渲染骨架(背景 + 顶部栏 + 消息区 + 输入栏) * * 子组件职责: * - ChatHeader:顶部栏(游客 banner / 菜单按钮) * - ChatArea:消息列表 * - ChatInputBar:输入栏(文字 + 发送 + More) * - QuotaDialog:配额告警弹窗 * - PwaInstallOverlay:PWA 安装提示触发器 * - BrowserHintOverlay:浏览器提示 * - CharacterIntro:角色介绍卡片(首屏) */ import { useEffect, useRef, useState } from "react"; import Image from "next/image"; import { useChatDispatch, useChatState } from "@/stores/chat/chat-context"; import { GuestChatQuota } from "@/stores/chat"; import { MobileShell } from "@/app/_components/core/mobile-shell"; import { BrowserHintOverlay } from "./browser-hint-overlay"; import { ChatArea } from "./chat-area"; import { ChatHeader } from "./chat-header"; import { ChatInputBar } from "./chat-input-bar"; import { PwaInstallOverlay } from "./pwa-install-overlay"; import { QuotaDialog } from "./quota-dialog"; import styles from "./chat-screen.module.css"; export function ChatScreen() { const state = useChatState(); const dispatch = useChatDispatch(); const [quotaDialogOpen, setQuotaDialogOpen] = useState(false); const [quotaExhausted, setQuotaExhausted] = useState(false); // 屏幕生命周期 useEffect(() => { dispatch({ type: "ChatInit" }); dispatch({ type: "ChatScreenVisible" }); return () => { dispatch({ type: "ChatScreenInvisible" }); }; }, [dispatch]); // 配额耗尽触发器 const prevTriggerRef = useRef(state.quotaExceededTrigger); useEffect(() => { if ( state.quotaExceededTrigger !== prevTriggerRef.current && state.quotaExceededTrigger > 0 ) { setQuotaExhausted(true); setQuotaDialogOpen(true); } prevTriggerRef.current = state.quotaExceededTrigger; }, [state.quotaExceededTrigger]); // 配额警告(剩余 = 5) const prevRemainingRef = useRef(state.guestRemainingQuota); useEffect(() => { if ( state.isGuest && state.guestRemainingQuota === GuestChatQuota.warningThreshold && prevRemainingRef.current !== state.guestRemainingQuota ) { setQuotaExhausted(false); setQuotaDialogOpen(true); } prevRemainingRef.current = state.guestRemainingQuota; }, [state.guestRemainingQuota, state.isGuest]); return (
{/* 背景图(与原 Dart MobileLayout 一致) */}
{/* 浏览器提示(应用内浏览器检测) */} {/* PWA 安装提示触发器(无可见 UI,3.5s 后弹 dialog) */} {/* 配额告警弹窗 */} setQuotaDialogOpen(false)} isExhausted={quotaExhausted} />
); }