import { useEffect, useState } from 'react'; import { useChat } from '../context/ChatProvider'; import { INSUFFICIENT_BALANCE_NOTICE } from '../hooks/useTKMindChat'; import type { CapabilityMap, PortalUser } from '../types'; import { useNetworkStatus } from '../hooks/useNetworkStatus'; import { getSessionDisplayName } from '../utils/sessions'; import { openAvatarPicker } from '../utils/userAvatar'; import { BalanceRing } from './BalanceRing'; import { HistorySidebar } from './HistorySidebar'; import { TKMindAvatar } from './TKMindAvatar'; import { ChatPanel } from './ChatPanel'; import { WechatBindPrompt } from './WechatBindPrompt'; import { WechatAccountButton } from './WechatAccountButton'; import { ChatHeaderMoreMenu } from './ChatHeaderMoreMenu'; import { NotificationCenter } from './NotificationCenter'; import type { MindSpaceSaveCategory } from '../types'; export function ChatView({ user, capabilities, grantedSkills, onLogout, onOpenSpace, onOpenPage, onOpenAdmin, }: { user?: PortalUser | null; capabilities?: CapabilityMap; grantedSkills?: string[]; onUserUpdate?: (user: PortalUser) => void; onLogout?: () => void; onOpenSpace?: (target?: { categoryCode?: MindSpaceSaveCategory; pageId?: string }) => void; onOpenPage?: (pageId: string) => void; onOpenAdmin?: () => void; }) { const { session, sessions, sessionsLoading, messages, chatState, error, notice, pendingTool, memoryLoading, submit, stop, approveTool, newSession, rememberCurrentContext, refreshProjectMemory, switchSession, deleteSession, retryConnect, dismissNotice, onSidebarOpen, balanceCents, totalCreditCents, tokensUsed, subscription, openRecharge, openSubscribe, uploadChatImage, } = useChat(); const online = useNetworkStatus(); const [sidebarOpen, setSidebarOpen] = useState(false); useEffect(() => { if (sidebarOpen) { onSidebarOpen(); } }, [sidebarOpen, onSidebarOpen]); const busy = chatState === 'streaming' || chatState === 'loading' || chatState === 'connecting'; const handleSelectSession = (sessionId: string) => { void switchSession(sessionId); setSidebarOpen(false); }; const handleNewSession = () => { void newSession(); setSidebarOpen(false); }; const sessionTitle = session ? getSessionDisplayName(session) : chatState === 'connecting' ? '新对话' : '连接中…'; const moreMenuItems = [ { id: 'new-session', label: '新会话', onClick: () => void handleNewSession(), }, { id: 'remember', label: '记住本轮', onClick: () => void rememberCurrentContext(), disabled: busy || memoryLoading || messages.length === 0, }, { id: 'refresh-memory', label: memoryLoading ? '同步中…' : '刷新记忆', onClick: () => void refreshProjectMemory(), disabled: busy || memoryLoading, }, ...(onOpenAdmin ? [{ id: 'admin', label: '管理', onClick: () => onOpenAdmin() }] : []), ...(onLogout ? [{ id: 'logout', label: '登出', onClick: () => onLogout(), danger: true }] : []), ]; return (
setSidebarOpen(false)} onSelect={handleSelectSession} onNew={handleNewSession} onDelete={(sessionId) => void deleteSession(sessionId)} />
{user?.displayName ?? 'TKMind'}
{sessionTitle}
{typeof balanceCents === 'number' && ( )} openRecharge(false)} /> {onOpenAdmin && ( )} {onOpenSpace && ( )} {user && } {onLogout && ( )}
{typeof balanceCents === 'number' && ( )} openRecharge(false)} /> {onOpenSpace && ( )}
{!online && (
网络已断开,请检查连接后重试
)} {user && } {typeof balanceCents === 'number' && balanceCents <= 0 && (
余额不足,请充值后继续使用
)} {typeof balanceCents === 'number' && balanceCents > 0 && balanceCents <= 100 && (
余额较低(¥{(balanceCents / 100).toFixed(2)}),建议提前充值
)} {notice && (
{notice} {notice === INSUFFICIENT_BALANCE_NOTICE ? ( <> ) : ( )}
)} {error && (
{error}
)} void submit(text, undefined, imageUrls)} onUploadImage={uploadChatImage} onStop={stop} onApproveTool={approveTool} onPageSaved={(result) => { if (result.kind === 'page' && result.pageId) { onOpenPage?.(result.pageId); return; } onOpenSpace?.({ categoryCode: result.categoryCode }); }} />
); }