diff --git a/app/(tabs)/ask.tsx b/app/(tabs)/ask.tsx index 1d8ed53..5644c98 100644 --- a/app/(tabs)/ask.tsx +++ b/app/(tabs)/ask.tsx @@ -4,10 +4,11 @@ import AskHello from "@/components/ask/hello"; import SendMessage from "@/components/ask/send"; import { ThemedText } from "@/components/ThemedText"; import { fetchApi } from "@/lib/server-api-util"; -import { webSocketManager, WsMessage } from "@/lib/websocket-util"; +import { getWebSocketErrorMessage, webSocketManager, WsMessage } from "@/lib/websocket-util"; import { Assistant, Message } from "@/types/ask"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { useCallback, useEffect, useRef, useState } from 'react'; +import { useTranslation } from "react-i18next"; import { Animated, FlatList, @@ -31,6 +32,7 @@ export default function AskScreen() { const [selectedImages, setSelectedImages] = useState([]); const fadeAnim = useRef(new Animated.Value(1)).current; const fadeAnimChat = useRef(new Animated.Value(0)).current; + const { t } = useTranslation(); const { sessionId, newSession } = useLocalSearchParams<{ sessionId: string; @@ -132,16 +134,23 @@ export default function AskScreen() { const handleError = (message: WsMessage) => { if (message.type === 'Error') { - console.error(`WebSocket Error: ${message.code} - ${message.message}`); + console.log(`WebSocket Error: ${message.code} - ${message.message}`); // 可以在这里添加错误提示,例如替换最后一条消息为错误信息 setUserMessages(prev => { - const newMessages = [...prev]; - const lastMessage = newMessages[newMessages.length - 1]; - if (lastMessage && typeof lastMessage.content === 'string' && lastMessage.content === 'keepSearchIng') { - lastMessage.content = `Error: ${message.message}`; - } - return newMessages; - }) + // 创建新的数组和新的消息对象 + return prev.map((msg, index) => { + if (index === prev.length - 1 && + typeof msg.content === 'string' && + msg.content === 'keepSearchIng') { + // 返回新的消息对象 + return { + ...msg, + content: getWebSocketErrorMessage(message.code, t) + }; + } + return msg; + }); + }); } }; diff --git a/app/(tabs)/owner.tsx b/app/(tabs)/owner.tsx index 5fbe53c..0e92e2f 100644 --- a/app/(tabs)/owner.tsx +++ b/app/(tabs)/owner.tsx @@ -1,7 +1,9 @@ import ConversationsSvg from '@/assets/icons/svg/conversations.svg'; import StoriesSvg from '@/assets/icons/svg/stories.svg'; +import CarouselComponent from '@/components/owner/carousel'; import CreateCountComponent from '@/components/owner/createCount'; +import Ranking from '@/components/owner/ranking'; import MemberCard from '@/components/owner/rights/memberCard'; import SettingModal from '@/components/owner/setting'; import SkeletonOwner from '@/components/owner/SkeletonOwner'; @@ -126,9 +128,9 @@ export default function OwnerPage() { {/* 分类 */} - {/* + - */} + {/* 作品数据 */} @@ -137,7 +139,7 @@ export default function OwnerPage() { {/* 排行榜 */} - {/* */} + } // 优化性能:添加 getItemLayout diff --git a/components/ask/chat.tsx b/components/ask/chat.tsx index 3a999cb..f5e4b80 100644 --- a/components/ask/chat.tsx +++ b/components/ask/chat.tsx @@ -1,5 +1,5 @@ import { ContentPart, Message } from '@/types/ask'; -import React, { Dispatch, ForwardedRef, forwardRef, SetStateAction, useCallback, useMemo, useState } from 'react'; +import React, { Dispatch, ForwardedRef, forwardRef, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FlatList, @@ -12,6 +12,8 @@ import MessageItem from '../chat/message-item/message-item'; import SelectModel from "./selectModel"; import SingleContentModel from "./singleContentModel"; + + // 继承 FlatListProps 来接收所有 FlatList 的属性 interface ChatProps extends Omit, 'data' | 'renderItem'> { userMessages: Message[]; @@ -37,6 +39,18 @@ function ChatComponent( }), []); const [modalDetailsVisible, setModalDetailsVisible] = useState<{ visible: boolean, content: any }>({ visible: false, content: [] }); + const flatListRef = useRef(null); + const prevMessagesLength = useRef(0); + + // 自动滚动到底部 + useEffect(() => { + if (userMessages.length > 0 && userMessages.length !== prevMessagesLength.current) { + setTimeout(() => { + flatListRef.current?.scrollToEnd({ animated: true }); + }, 100); + prevMessagesLength.current = userMessages.length; + } + }, [userMessages.length]); const renderMessageItem = useCallback(({ item, index }: { item: Message, index: number }) => { const itemStyle = index === 0 ? { marginTop: 16, marginHorizontal: 16 } : { marginHorizontal: 16 }; @@ -63,7 +77,17 @@ function ChatComponent( return ( { + // 处理转发 ref 和内部 ref + if (ref) { + if (typeof ref === 'function') { + ref(node); + } else { + ref.current = node; + } + } + flatListRef.current = node; + }} data={userMessages} keyExtractor={keyExtractor} renderItem={renderMessageItem} @@ -75,7 +99,17 @@ function ChatComponent( updateCellsBatchingPeriod={50} initialNumToRender={10} windowSize={11} - {...restProps} // 将所有其他属性传递给 FlatList + onContentSizeChange={() => { + if (userMessages.length > 0) { + flatListRef.current?.scrollToEnd({ animated: true }); + } + }} + onLayout={() => { + if (userMessages.length > 0) { + flatListRef.current?.scrollToEnd({ animated: false }); + } + }} + {...restProps} /> {/* 单个图片弹窗 */} diff --git a/components/ask/threeCircle.tsx b/components/ask/threeCircle.tsx index 767dd3b..6c9c348 100644 --- a/components/ask/threeCircle.tsx +++ b/components/ask/threeCircle.tsx @@ -100,7 +100,7 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', - padding: 8, + padding: 16, }, dot: { width: 8, diff --git a/components/chat/message-item/MessageRow.tsx b/components/chat/message-item/MessageRow.tsx index 4559d4b..c098760 100644 --- a/components/chat/message-item/MessageRow.tsx +++ b/components/chat/message-item/MessageRow.tsx @@ -1,7 +1,7 @@ -import React from 'react'; -import { View, Text } from 'react-native'; -import MessageBubble from './MessageBubble'; import { getMessageText } from "@/types/ask"; +import React from 'react'; +import { Text, View } from 'react-native'; +import MessageBubble from './MessageBubble'; interface MessageRowProps { item: any; @@ -14,19 +14,19 @@ interface MessageRowProps { setModalDetailsVisible: React.Dispatch>; } -const MessageRow = ({ - item, - isUser, - setModalVisible, - setCancel, - cancel, - t, - setSelectedImages, +const MessageRow = ({ + item, + isUser, + setModalVisible, + setCancel, + cancel, + t, + setSelectedImages, setModalDetailsVisible }: MessageRowProps) => { return ( - - + {!isUser && } - - + { // 获取.env文件中的变量 -export const API_ENDPOINT = Constants.expoConfig?.extra?.API_ENDPOINT || "https://api.memorywake.com/api"; +export const API_ENDPOINT = Constants.expoConfig?.extra?.API_ENDPOINT || "http://192.168.31.16:31646/api"; + // 更新 access_token 的逻辑 - 用于React组件中 export const useAuthToken = async(message: string | null) => { diff --git a/lib/websocket-util.ts b/lib/websocket-util.ts index 1b83926..70e8290 100644 --- a/lib/websocket-util.ts +++ b/lib/websocket-util.ts @@ -1,9 +1,10 @@ import Constants from 'expo-constants'; import * as SecureStore from 'expo-secure-store'; +import { TFunction } from 'i18next'; import { Platform } from 'react-native'; // 从环境变量或默认值中定义 WebSocket 端点 -export const WEBSOCKET_ENDPOINT = Constants.expoConfig?.extra?.WEBSOCKET_ENDPOINT || "wss://api.memorywake.com/ws"; +export const WEBSOCKET_ENDPOINT = Constants.expoConfig?.extra?.WEBSOCKET_ENDPOINT || "ws://192.168.31.16:31646/ws/chat"; export type WebSocketStatus = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'; @@ -225,3 +226,17 @@ class WebSocketManager { // 导出一个单例,确保整个应用共享同一个 WebSocket 连接 export const webSocketManager = new WebSocketManager(); + + +// webscoket 错误映射 +export const getWebSocketErrorMessage = (key: string, t: TFunction) => { + const messages = { + 'INSUFFICIENT_POINTS': t('ask:ask.insufficientPoints'), + 'INVALID_TOKEN': t('ask:ask.invalidToken'), + 'NOT_FOUND': t('ask:ask.notFound'), + 'PERMISSION_DENIED': t('ask:ask.permissionDenied'), + 'NOT_CONNECTED': t('ask:ask.notConnected'), + }; + + return messages[key as keyof typeof messages] || t('ask:ask.unknownError'); +}; \ No newline at end of file