Compare commits
33 Commits
main
...
fix/unexpe
| Author | SHA1 | Date | |
|---|---|---|---|
| c6be061130 | |||
| 60152a64f0 | |||
| 9de8c3b5c7 | |||
| 4c4360cefc | |||
| 76f2e6ed48 | |||
| 384e607fe1 | |||
| a7b6aeeb31 | |||
| 4e755b8f10 | |||
| 797414e78b | |||
| 2ff82495ac | |||
| 0482f23d97 | |||
| 85d9b823de | |||
| 027f7b1672 | |||
| 8f0cb0ada2 | |||
| 1891f5c359 | |||
| f8bd3b13be | |||
| 1a28d8becd | |||
| 3f2b849db2 | |||
| 995f5ad981 | |||
| 9341a1560f | |||
| f2b09cb013 | |||
| 827bf7b164 | |||
| fd5ea7f318 | |||
| 162f3b91e4 | |||
| b1031cf2b6 | |||
| 45a3660ab8 | |||
| ce50710818 | |||
| 448e8dfb53 | |||
| d59378c2da | |||
| 15fc8f3ad4 | |||
| da0b949ca4 | |||
| da00968586 | |||
| 193084fb62 |
@ -1,4 +1,3 @@
|
||||
import { HapticTab } from '@/components/HapticTab';
|
||||
import AskNavbar from '@/components/layout/ask';
|
||||
import { TabBarIcon } from '@/components/navigation/TabBarIcon';
|
||||
import { requestNotificationPermission } from '@/components/owner/utils';
|
||||
@ -188,28 +187,13 @@ export default function TabLayout() {
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
|
||||
headerShown: false,
|
||||
tabBarButton: HapticTab,
|
||||
tabBarBackground: TabBarBackground,
|
||||
tabBarStyle: Platform.select({
|
||||
ios: {
|
||||
// Use a transparent background on iOS to show the blur effect
|
||||
position: 'absolute',
|
||||
},
|
||||
default: {},
|
||||
}),
|
||||
}}
|
||||
tabBar={props => <AskNavbar {...props} wsStatus={wsStatus} />}
|
||||
>
|
||||
{/* 落地页 */}
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: 'Memo',
|
||||
tabBarButton: () => null, // 隐藏底部标签栏
|
||||
headerShown: false, // 隐藏导航栏
|
||||
tabBarStyle: { display: 'none' } // 确保在标签栏中不显示
|
||||
href: null,
|
||||
}}
|
||||
/>
|
||||
{/* 登录 */}
|
||||
@ -260,10 +244,7 @@ export default function TabLayout() {
|
||||
<Tabs.Screen
|
||||
name="ask"
|
||||
options={{
|
||||
title: 'ask',
|
||||
tabBarButton: () => null, // 隐藏底部标签栏
|
||||
headerShown: false, // 隐藏导航栏
|
||||
tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示
|
||||
href: null,
|
||||
...TransitionPresets.ShiftTransition,
|
||||
}}
|
||||
/>
|
||||
@ -271,10 +252,7 @@ export default function TabLayout() {
|
||||
<Tabs.Screen
|
||||
name="memo-list"
|
||||
options={{
|
||||
title: 'memo-list',
|
||||
tabBarButton: () => null, // 隐藏底部标签栏
|
||||
headerShown: false, // 隐藏导航栏
|
||||
tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示
|
||||
href: null,
|
||||
...TransitionPresets.ShiftTransition,
|
||||
}}
|
||||
/>
|
||||
@ -282,10 +260,7 @@ export default function TabLayout() {
|
||||
<Tabs.Screen
|
||||
name="owner"
|
||||
options={{
|
||||
title: 'owner',
|
||||
tabBarButton: () => null, // 隐藏底部标签栏
|
||||
headerShown: false, // 隐藏导航栏
|
||||
tabBarStyle: { display: 'none' }, // 确保在标签栏中不显示
|
||||
href: null,
|
||||
...TransitionPresets.ShiftTransition,
|
||||
}}
|
||||
/>
|
||||
@ -377,7 +352,6 @@ export default function TabLayout() {
|
||||
}}
|
||||
/>
|
||||
</Tabs >
|
||||
<AskNavbar wsStatus={wsStatus} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
import ReturnArrow from "@/assets/icons/svg/returnArrow.svg";
|
||||
import Chat from "@/components/ask/chat";
|
||||
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 { getWebSocketErrorMessage, webSocketManager, WsMessage } from "@/lib/websocket-util";
|
||||
import { Assistant, Message } from "@/types/ask";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { Message } from "@/types/ask";
|
||||
import { useFocusEffect, useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
@ -25,6 +22,7 @@ import { runOnJS } from 'react-native-reanimated';
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
||||
export default function AskScreen() {
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const chatListRef = useRef<FlatList>(null);
|
||||
@ -99,88 +97,88 @@ export default function AskScreen() {
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
webSocketManager.connect();
|
||||
// webSocketManager.connect();
|
||||
|
||||
const handleChatStream = (message: WsMessage) => {
|
||||
if (message.type === 'ChatStream') {
|
||||
setUserMessages(prevMessages => {
|
||||
const newMessages = [...prevMessages];
|
||||
const lastMessage = newMessages[newMessages.length - 1];
|
||||
// const handleChatStream = (message: WsMessage) => {
|
||||
// if (message.type === 'ChatStream') {
|
||||
// setUserMessages(prevMessages => {
|
||||
// const newMessages = [...prevMessages];
|
||||
// const lastMessage = newMessages[newMessages.length - 1];
|
||||
|
||||
if (lastMessage && lastMessage.role === Assistant) {
|
||||
if (typeof lastMessage.content === 'string') {
|
||||
if (lastMessage.content === 'keepSearchIng') {
|
||||
// 第一次收到流式消息,替换占位符
|
||||
lastMessage.content = message.chunk;
|
||||
} else {
|
||||
// 持续追加流式消息
|
||||
lastMessage.content += message.chunk;
|
||||
}
|
||||
} else {
|
||||
// 如果 content 是数组,则更新第一个 text 部分
|
||||
const textPart = lastMessage.content.find(p => p.type === 'text');
|
||||
if (textPart) {
|
||||
textPart.text = (textPart.text || '') + message.chunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newMessages;
|
||||
});
|
||||
}
|
||||
};
|
||||
// if (lastMessage && lastMessage.role === Assistant) {
|
||||
// if (typeof lastMessage.content === 'string') {
|
||||
// if (lastMessage.content === 'keepSearchIng') {
|
||||
// // 第一次收到流式消息,替换占位符
|
||||
// lastMessage.content = message.chunk;
|
||||
// } else {
|
||||
// // 持续追加流式消息
|
||||
// lastMessage.content += message.chunk;
|
||||
// }
|
||||
// } else {
|
||||
// // 如果 content 是数组,则更新第一个 text 部分
|
||||
// const textPart = lastMessage.content.find(p => p.type === 'text');
|
||||
// if (textPart) {
|
||||
// textPart.text = (textPart.text || '') + message.chunk;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return newMessages;
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleChatStreamEnd = (message: WsMessage) => {
|
||||
if (message.type === 'ChatStreamEnd') {
|
||||
setUserMessages(prevMessages => {
|
||||
const newMessages = [...prevMessages];
|
||||
const lastMessage = newMessages[newMessages.length - 1];
|
||||
if (lastMessage && lastMessage.role === Assistant) {
|
||||
// 使用最终消息替换流式消息,确保 message.message 存在
|
||||
if (message.message) {
|
||||
newMessages[newMessages.length - 1] = message.message as Message;
|
||||
} else {
|
||||
// 如果最终消息为空,则移除 'keepSearchIng' 占位符
|
||||
return prevMessages.filter(m => !(typeof m.content === 'string' && m.content === 'keepSearchIng'));
|
||||
}
|
||||
}
|
||||
return newMessages;
|
||||
});
|
||||
}
|
||||
};
|
||||
// const handleChatStreamEnd = (message: WsMessage) => {
|
||||
// if (message.type === 'ChatStreamEnd') {
|
||||
// setUserMessages(prevMessages => {
|
||||
// const newMessages = [...prevMessages];
|
||||
// const lastMessage = newMessages[newMessages.length - 1];
|
||||
// if (lastMessage && lastMessage.role === Assistant) {
|
||||
// // 使用最终消息替换流式消息,确保 message.message 存在
|
||||
// if (message.message) {
|
||||
// newMessages[newMessages.length - 1] = message.message as Message;
|
||||
// } else {
|
||||
// // 如果最终消息为空,则移除 'keepSearchIng' 占位符
|
||||
// return prevMessages.filter(m => !(typeof m.content === 'string' && m.content === 'keepSearchIng'));
|
||||
// }
|
||||
// }
|
||||
// return newMessages;
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleError = (message: WsMessage) => {
|
||||
if (message.type === 'Error') {
|
||||
console.log(`WebSocket Error: ${message.code} - ${message.message}`);
|
||||
// 可以在这里添加错误提示,例如替换最后一条消息为错误信息
|
||||
setUserMessages(prev => {
|
||||
// 创建新的数组和新的消息对象
|
||||
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;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
// const handleError = (message: WsMessage) => {
|
||||
// if (message.type === 'Error') {
|
||||
// console.log(`WebSocket Error: ${message.code} - ${message.message}`);
|
||||
// // 可以在这里添加错误提示,例如替换最后一条消息为错误信息
|
||||
// setUserMessages(prev => {
|
||||
// // 创建新的数组和新的消息对象
|
||||
// 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;
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
webSocketManager.subscribe('ChatStream', handleChatStream);
|
||||
webSocketManager.subscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
webSocketManager.subscribe('Error', handleError);
|
||||
// webSocketManager.subscribe('ChatStream', handleChatStream);
|
||||
// webSocketManager.subscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
// webSocketManager.subscribe('Error', handleError);
|
||||
|
||||
return () => {
|
||||
webSocketManager.unsubscribe('ChatStream', handleChatStream);
|
||||
webSocketManager.unsubscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
webSocketManager.unsubscribe('Error', handleError);
|
||||
// 可以在这里选择断开连接,或者保持连接以加快下次进入页面的速度
|
||||
// webSocketManager.disconnect();
|
||||
};
|
||||
// return () => {
|
||||
// webSocketManager.unsubscribe('ChatStream', handleChatStream);
|
||||
// webSocketManager.unsubscribe('ChatStreamEnd', handleChatStreamEnd);
|
||||
// webSocketManager.unsubscribe('Error', handleError);
|
||||
// // 可以在这里选择断开连接,或者保持连接以加快下次进入页面的速度
|
||||
// // webSocketManager.disconnect();
|
||||
// };
|
||||
}, [])
|
||||
);
|
||||
|
||||
@ -196,7 +194,7 @@ export default function AskScreen() {
|
||||
setIsHello(true);
|
||||
setConversationId(null);
|
||||
}
|
||||
}, [sessionId, newSession]);
|
||||
}, [sessionId, newSession])
|
||||
|
||||
useEffect(() => {
|
||||
if (isHello) {
|
||||
@ -234,23 +232,6 @@ export default function AskScreen() {
|
||||
}
|
||||
}, [isHello, fadeAnim, fadeAnimChat]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isHello) {
|
||||
// 不再自动关闭键盘,让用户手动控制
|
||||
// 这里可以添加其他需要在隐藏hello界面时执行的逻辑
|
||||
scrollToEnd(false);
|
||||
}
|
||||
}, [isHello]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!sessionId) {
|
||||
setIsHello(true);
|
||||
setUserMessages([])
|
||||
}
|
||||
}, [sessionId])
|
||||
);
|
||||
|
||||
return (
|
||||
<GestureDetector gesture={gesture}>
|
||||
<View style={[styles.container, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
|
||||
@ -268,7 +249,9 @@ export default function AskScreen() {
|
||||
console.log('失去焦点失败:', error);
|
||||
}
|
||||
Keyboard.dismiss();
|
||||
router.push('/memo-list');
|
||||
setTimeout(() => {
|
||||
router.replace('/memo-list');
|
||||
}, 100);
|
||||
}}
|
||||
>
|
||||
<ReturnArrow />
|
||||
@ -303,7 +286,7 @@ export default function AskScreen() {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Chat
|
||||
{/* <Chat
|
||||
ref={chatListRef}
|
||||
userMessages={userMessages}
|
||||
sessionId={sessionId}
|
||||
@ -313,7 +296,7 @@ export default function AskScreen() {
|
||||
contentContainerStyle={styles.chatContentContainer}
|
||||
showsVerticalScrollIndicator={false}
|
||||
onContentSizeChange={() => scrollToEnd()}
|
||||
/>
|
||||
/> */}
|
||||
</Animated.View>
|
||||
</View>
|
||||
|
||||
@ -322,14 +305,14 @@ export default function AskScreen() {
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
keyboardVerticalOffset={0} >
|
||||
<View style={styles.inputContainer} key={conversationId}>
|
||||
<SendMessage
|
||||
{/* <SendMessage
|
||||
setIsHello={setIsHello}
|
||||
conversationId={conversationId}
|
||||
setConversationId={setConversationId}
|
||||
setUserMessages={setUserMessages}
|
||||
selectedImages={selectedImages}
|
||||
setSelectedImages={setSelectedImages}
|
||||
/>
|
||||
/> */}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</View >
|
||||
|
||||
@ -225,7 +225,7 @@ export default function HomeScreen() {
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
checkAuthStatus(router, () => {
|
||||
router.replace('/ask')
|
||||
router.replace('/memo-list')
|
||||
}, false).then(() => {
|
||||
setIsLoading(false);
|
||||
}).catch(() => {
|
||||
|
||||
@ -14,7 +14,7 @@ import SkeletonItem from '@/components/memo/SkeletonItem';
|
||||
|
||||
// 类型定义
|
||||
import { useUploadManager } from '@/hooks/useUploadManager';
|
||||
import { getCachedData, prefetchChatDetail, prefetchChats } from '@/lib/prefetch';
|
||||
import { getCachedData, prefetchChatDetail } from '@/lib/prefetch';
|
||||
import { fetchApi } from '@/lib/server-api-util';
|
||||
import { Chat, getMessageText } from '@/types/ask';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -105,18 +105,11 @@ const MemoList = () => {
|
||||
|
||||
const initialize = async () => {
|
||||
try {
|
||||
// 并行预加载资源和数据
|
||||
// 并行预加载资源和主数据
|
||||
await Promise.all([
|
||||
preloadAssets(),
|
||||
prefetchChats().then((data) => {
|
||||
if (isActive && data) {
|
||||
setHistoryList(data as Chat[]);
|
||||
}
|
||||
}),
|
||||
fetchHistoryList()
|
||||
]);
|
||||
|
||||
// 主数据加载
|
||||
await fetchHistoryList();
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error);
|
||||
} finally {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { ThemedText } from "@/components/ThemedText";
|
||||
import { webSocketManager } from "@/lib/websocket-util";
|
||||
import { Message } from "@/types/ask";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { Dispatch, SetStateAction, useCallback, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Dimensions, Image, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import { Image, ScrollView, StyleSheet, TouchableOpacity, useWindowDimensions, View } from 'react-native';
|
||||
import { createNewConversation } from "./utils";
|
||||
|
||||
interface AskHelloProps {
|
||||
@ -13,10 +13,15 @@ interface AskHelloProps {
|
||||
}
|
||||
export default function AskHello({ setUserMessages, setConversationId, setIsHello }: AskHelloProps) {
|
||||
const { t } = useTranslation();
|
||||
const width = Dimensions.get('window').width;
|
||||
const height = Dimensions.get('window').height;
|
||||
const { width, height } = useWindowDimensions();
|
||||
|
||||
const handleCase = async (text: string) => {
|
||||
const inFlightRef = useRef(false);
|
||||
|
||||
const handleCase = useCallback(async (text: string) => {
|
||||
if (inFlightRef.current) return;
|
||||
inFlightRef.current = true;
|
||||
try {
|
||||
// UI
|
||||
setIsHello(false);
|
||||
setUserMessages([
|
||||
{
|
||||
@ -34,18 +39,37 @@ export default function AskHello({ setUserMessages, setConversationId, setIsHell
|
||||
]);
|
||||
|
||||
const sessionId = await createNewConversation(text);
|
||||
if (sessionId) {
|
||||
if (!sessionId) {
|
||||
console.error("Failed to create a new conversation.");
|
||||
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
return;
|
||||
}
|
||||
|
||||
setConversationId(sessionId);
|
||||
webSocketManager.send({
|
||||
try {
|
||||
if (webSocketManager && typeof (webSocketManager as any).send === 'function') {
|
||||
(webSocketManager as any).send({
|
||||
type: 'Chat',
|
||||
session_id: sessionId,
|
||||
message: text
|
||||
});
|
||||
} else {
|
||||
console.error("Failed to create a new conversation.");
|
||||
throw new Error('WebSocket manager is not ready');
|
||||
}
|
||||
} catch (wsErr) {
|
||||
console.error('WebSocket send failed:', wsErr);
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('handleCase failed:', err);
|
||||
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
} finally {
|
||||
inFlightRef.current = false;
|
||||
}
|
||||
}, [setConversationId, setIsHello, setUserMessages]);
|
||||
|
||||
return (
|
||||
<View className="flex-1 bg-white w-full">
|
||||
<ScrollView
|
||||
@ -106,7 +130,6 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
width: '100%',
|
||||
marginTop: 16
|
||||
},
|
||||
@ -115,6 +138,8 @@ const styles = StyleSheet.create({
|
||||
borderColor: "#AC7E35",
|
||||
borderRadius: 10,
|
||||
paddingHorizontal: 8,
|
||||
marginHorizontal: 4,
|
||||
marginVertical: 4,
|
||||
width: 'auto',
|
||||
fontSize: 14,
|
||||
color: "#4C320C"
|
||||
|
||||
@ -3,7 +3,6 @@ import { Message } from "@/types/ask";
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import * as MediaLibrary from 'expo-media-library';
|
||||
import { TFunction } from "i18next";
|
||||
import { useCallback } from "react";
|
||||
import { Alert } from 'react-native';
|
||||
|
||||
// 实现一个函数,从两个数组中轮流插入新数组
|
||||
@ -19,12 +18,12 @@ export const mergeArrays = (arr1: any[], arr2: any[]) => {
|
||||
|
||||
|
||||
// 创建新对话并获取消息
|
||||
export const createNewConversation = useCallback(async (user_text: string) => {
|
||||
export const createNewConversation = async (user_text: string) => {
|
||||
const data = await fetchApi<string>("/chat/new", {
|
||||
method: "POST",
|
||||
});
|
||||
return data
|
||||
}, []);
|
||||
};
|
||||
|
||||
// 获取对话信息
|
||||
export const getConversation = async ({
|
||||
|
||||
@ -3,8 +3,9 @@ import ChatNotInSvg from "@/assets/icons/svg/chatNotIn.svg";
|
||||
import PersonInSvg from "@/assets/icons/svg/personIn.svg";
|
||||
import PersonNotInSvg from "@/assets/icons/svg/personNotIn.svg";
|
||||
import { WebSocketStatus } from "@/lib/websocket-util";
|
||||
import { router, usePathname } from "expo-router";
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import { BottomTabBarProps } from "@react-navigation/bottom-tabs";
|
||||
import { router } from "expo-router";
|
||||
import React, { useMemo } from 'react';
|
||||
import { Dimensions, Image, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import Svg, { Circle, Ellipse, G, Mask, Path, Rect } from "react-native-svg";
|
||||
|
||||
@ -42,14 +43,15 @@ const CenterButtonSvg = React.memo(() => (
|
||||
</Svg>
|
||||
));
|
||||
|
||||
interface AskNavbarProps {
|
||||
type AskNavbarProps = BottomTabBarProps & {
|
||||
wsStatus: WebSocketStatus;
|
||||
}
|
||||
};
|
||||
|
||||
const AskNavbar = ({ wsStatus }: AskNavbarProps) => {
|
||||
const AskNavbar = ({ state, descriptors, navigation, wsStatus }: AskNavbarProps) => {
|
||||
// 获取设备尺寸
|
||||
const { width } = useMemo(() => Dimensions.get('window'), []);
|
||||
const pathname = usePathname();
|
||||
const { routes, index } = state;
|
||||
const currentRouteName = routes[index].name;
|
||||
|
||||
const statusColor = useMemo(() => {
|
||||
switch (wsStatus) {
|
||||
@ -64,34 +66,6 @@ const AskNavbar = ({ wsStatus }: AskNavbarProps) => {
|
||||
}
|
||||
}, [wsStatus]);
|
||||
|
||||
// 预加载目标页面
|
||||
useEffect(() => {
|
||||
const preloadPages = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
router.prefetch('/memo-list'),
|
||||
router.prefetch('/ask'),
|
||||
router.prefetch('/owner')
|
||||
]);
|
||||
} catch (error) {
|
||||
console.warn('预加载页面失败:', error);
|
||||
}
|
||||
};
|
||||
preloadPages();
|
||||
}, []);
|
||||
|
||||
// 使用 useCallback 缓存导航函数
|
||||
const navigateTo = useCallback((route: string) => {
|
||||
if (route === '/ask') {
|
||||
router.push({
|
||||
pathname: '/ask',
|
||||
params: { newSession: "true" }
|
||||
});
|
||||
} else {
|
||||
router.push(route as any);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 使用 useMemo 缓存样式对象
|
||||
const styles = useMemo(() => StyleSheet.create({
|
||||
container: {
|
||||
@ -156,7 +130,7 @@ const AskNavbar = ({ wsStatus }: AskNavbarProps) => {
|
||||
}), [width, statusColor]);
|
||||
|
||||
// 如果当前路径是ask页面,则不渲染导航栏
|
||||
if (pathname != '/memo-list' && pathname != '/owner') {
|
||||
if (currentRouteName !== 'memo-list' && currentRouteName !== 'owner') {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -165,18 +139,18 @@ const AskNavbar = ({ wsStatus }: AskNavbarProps) => {
|
||||
<Image source={require('@/assets/images/png/owner/ask.png')} style={{ width: width * 1.18, height: 100, resizeMode: 'cover', marginLeft: -width * 0.07 }} />
|
||||
<View style={styles.navContainer}>
|
||||
<TouchableOpacity
|
||||
onPress={() => navigateTo('/memo-list')}
|
||||
onPress={() => navigation.navigate('memo-list')}
|
||||
style={[styles.navButton, { alignItems: "flex-start", paddingLeft: 16 }]}
|
||||
>
|
||||
<TabIcon
|
||||
isActive={pathname === "/memo-list"}
|
||||
isActive={currentRouteName === "memo-list"}
|
||||
ActiveIcon={ChatInSvg}
|
||||
InactiveIcon={ChatNotInSvg}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => navigateTo('/ask')}
|
||||
onPress={() => router.push({ pathname: '/ask', params: { newSession: "true" } })}
|
||||
style={styles.centerButton}
|
||||
>
|
||||
<View style={styles.statusIndicator} />
|
||||
@ -184,11 +158,11 @@ const AskNavbar = ({ wsStatus }: AskNavbarProps) => {
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => navigateTo('/owner')}
|
||||
onPress={() => navigation.navigate('owner')}
|
||||
style={styles.navButton}
|
||||
>
|
||||
<TabIcon
|
||||
isActive={pathname === "/owner"}
|
||||
isActive={currentRouteName === "owner"}
|
||||
ActiveIcon={PersonInSvg}
|
||||
InactiveIcon={PersonNotInSvg}
|
||||
/>
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
|
||||
// This is a shim for web and Android where the tab bar is generally opaque.
|
||||
export default undefined;
|
||||
export default function TabBarBackground() {
|
||||
return <View style={{ flex: 1, backgroundColor: 'transparent' }} />;
|
||||
}
|
||||
|
||||
export function useBottomTabOverflow() {
|
||||
return 0;
|
||||
|
||||
@ -25,7 +25,7 @@ export interface PagedResult<T> {
|
||||
// 获取.env文件中的变量
|
||||
|
||||
|
||||
export const API_ENDPOINT = Constants.expoConfig?.extra?.API_ENDPOINT || "http://192.168.31.16:31646/api";
|
||||
export const API_ENDPOINT = process.env.EXPO_PUBLIC_API_ENDPOINT || Constants.expoConfig?.extra?.API_ENDPOINT;
|
||||
|
||||
|
||||
// 更新 access_token 的逻辑 - 用于React组件中
|
||||
|
||||
@ -4,7 +4,7 @@ import { TFunction } from 'i18next';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
// 从环境变量或默认值中定义 WebSocket 端点
|
||||
export const WEBSOCKET_ENDPOINT = Constants.expoConfig?.extra?.WEBSOCKET_ENDPOINT || "ws://192.168.31.16:31646/ws/chat";
|
||||
export const WEBSOCKET_ENDPOINT = process.env.EXPO_PUBLIC_WEBSOCKET_ENDPOINT || Constants.expoConfig?.extra?.WEBSOCKET_ENDPOINT;
|
||||
|
||||
export type WebSocketStatus = 'connecting' | 'connected' | 'disconnected' | 'reconnecting';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user