|
|
@ -31,7 +31,6 @@ import widthUtils from "../utils/widthUtils"; |
|
|
|
import fontSize from "../utils/fontsizeUtils"; |
|
|
|
import fontSize from "../utils/fontsizeUtils"; |
|
|
|
import useUserStore from "../store/user"; |
|
|
|
import useUserStore from "../store/user"; |
|
|
|
import { getSubjectTransLanguage } from "../utils/languageUtils"; |
|
|
|
import { getSubjectTransLanguage } from "../utils/languageUtils"; |
|
|
|
|
|
|
|
|
|
|
|
// 图标组件 - 使用React.memo优化渲染
|
|
|
|
// 图标组件 - 使用React.memo优化渲染
|
|
|
|
const IconComponent = React.memo( |
|
|
|
const IconComponent = React.memo( |
|
|
|
({ name, size, color }: { name: string; size: number; color: string }) => { |
|
|
|
({ name, size, color }: { name: string; size: number; color: string }) => { |
|
|
@ -39,18 +38,15 @@ const IconComponent = React.memo( |
|
|
|
return <Icon name={name} size={size} color={color} />; |
|
|
|
return <Icon name={name} size={size} color={color} />; |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 路由参数类型
|
|
|
|
// 路由参数类型
|
|
|
|
type SearchResultRouteParams = { |
|
|
|
type SearchResultRouteParams = { |
|
|
|
keyword: string; |
|
|
|
keyword: string; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 组件Props类型
|
|
|
|
// 组件Props类型
|
|
|
|
type SearchResultScreenProps = { |
|
|
|
type SearchResultScreenProps = { |
|
|
|
route: RouteProp<Record<string, SearchResultRouteParams>, string>; |
|
|
|
route: RouteProp<Record<string, SearchResultRouteParams>, string>; |
|
|
|
navigation: NativeStackNavigationProp<any>; |
|
|
|
navigation: NativeStackNavigationProp<any>; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 懒加载图片组件 - 改进版本
|
|
|
|
// 懒加载图片组件 - 改进版本
|
|
|
|
const LazyImage = React.memo( |
|
|
|
const LazyImage = React.memo( |
|
|
|
({ |
|
|
|
({ |
|
|
@ -64,16 +60,13 @@ const LazyImage = React.memo( |
|
|
|
}) => { |
|
|
|
}) => { |
|
|
|
const [isLoaded, setIsLoaded] = useState(false); |
|
|
|
const [isLoaded, setIsLoaded] = useState(false); |
|
|
|
const [hasError, setHasError] = useState(false); |
|
|
|
const [hasError, setHasError] = useState(false); |
|
|
|
|
|
|
|
|
|
|
|
const onLoad = useCallback(() => { |
|
|
|
const onLoad = useCallback(() => { |
|
|
|
setIsLoaded(true); |
|
|
|
setIsLoaded(true); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
const onError = useCallback(() => { |
|
|
|
const onError = useCallback(() => { |
|
|
|
setHasError(true); |
|
|
|
setHasError(true); |
|
|
|
setIsLoaded(true); // Also mark as loaded on error to remove placeholder
|
|
|
|
setIsLoaded(true); // Also mark as loaded on error to remove placeholder
|
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<View style={[style, { overflow: "hidden" }]}> |
|
|
|
<View style={[style, { overflow: "hidden" }]}> |
|
|
|
{/* Show placeholder while image is loading */} |
|
|
|
{/* Show placeholder while image is loading */} |
|
|
@ -92,7 +85,6 @@ const LazyImage = React.memo( |
|
|
|
</Text> |
|
|
|
</Text> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{/* Actual image */} |
|
|
|
{/* Actual image */} |
|
|
|
<Image |
|
|
|
<Image |
|
|
|
source={{ uri }} |
|
|
|
source={{ uri }} |
|
|
@ -105,7 +97,6 @@ const LazyImage = React.memo( |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 产品骨架屏组件 - 用于加载状态
|
|
|
|
// 产品骨架屏组件 - 用于加载状态
|
|
|
|
const ProductSkeleton = React.memo(() => ( |
|
|
|
const ProductSkeleton = React.memo(() => ( |
|
|
|
<View style={styles.productCard}> |
|
|
|
<View style={styles.productCard}> |
|
|
@ -118,7 +109,6 @@ const ProductSkeleton = React.memo(() => ( |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
)); |
|
|
|
)); |
|
|
|
|
|
|
|
|
|
|
|
// 产品项组件 - 使用React.memo优化渲染
|
|
|
|
// 产品项组件 - 使用React.memo优化渲染
|
|
|
|
const ProductItem = React.memo( |
|
|
|
const ProductItem = React.memo( |
|
|
|
({ |
|
|
|
({ |
|
|
@ -148,7 +138,6 @@ const ProductItem = React.memo( |
|
|
|
) : ( |
|
|
|
) : ( |
|
|
|
<Text style={styles.placeholderText}>{t('productPicture')}</Text> |
|
|
|
<Text style={styles.placeholderText}>{t('productPicture')}</Text> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{userStore.user?.user_id && ( |
|
|
|
{userStore.user?.user_id && ( |
|
|
|
<TouchableOpacity style={styles.vipIcon}> |
|
|
|
<TouchableOpacity style={styles.vipIcon}> |
|
|
|
<Text style={styles.vipButtonText}>VIP</Text> |
|
|
|
<Text style={styles.vipButtonText}>VIP</Text> |
|
|
@ -189,7 +178,6 @@ const ProductItem = React.memo( |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
) |
|
|
|
) |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProps) => { |
|
|
|
export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProps) => { |
|
|
|
const { t } = useTranslation(); |
|
|
|
const { t } = useTranslation(); |
|
|
|
const [searchText, setSearchText] = useState(""); |
|
|
|
const [searchText, setSearchText] = useState(""); |
|
|
@ -208,7 +196,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
); |
|
|
|
); |
|
|
|
const userStore = useUserStore(); |
|
|
|
const userStore = useUserStore(); |
|
|
|
const [showSkeleton, setShowSkeleton] = useState(true); |
|
|
|
const [showSkeleton, setShowSkeleton] = useState(true); |
|
|
|
|
|
|
|
|
|
|
|
const [searchParams, setSearchParams] = useState<ProductParams>({ |
|
|
|
const [searchParams, setSearchParams] = useState<ProductParams>({ |
|
|
|
keyword: route.params?.keyword || "", |
|
|
|
keyword: route.params?.keyword || "", |
|
|
|
page: 1, |
|
|
|
page: 1, |
|
|
@ -219,7 +206,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
language: "en", |
|
|
|
language: "en", |
|
|
|
user_id: userStore.user.user_id, |
|
|
|
user_id: userStore.user.user_id, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 初始化搜索关键字
|
|
|
|
// 初始化搜索关键字
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
if (route.params?.keyword) { |
|
|
|
if (route.params?.keyword) { |
|
|
@ -233,7 +219,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
searchProducts(newParams); |
|
|
|
searchProducts(newParams); |
|
|
|
} |
|
|
|
} |
|
|
|
}, [route.params?.keyword]); |
|
|
|
}, [route.params?.keyword]); |
|
|
|
|
|
|
|
|
|
|
|
// 搜索产品的API调用
|
|
|
|
// 搜索产品的API调用
|
|
|
|
const searchProducts = useCallback( |
|
|
|
const searchProducts = useCallback( |
|
|
|
async (params: ProductParams, isLoadMore = false) => { |
|
|
|
async (params: ProductParams, isLoadMore = false) => { |
|
|
@ -277,7 +262,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
}, |
|
|
|
}, |
|
|
|
[] |
|
|
|
[] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 处理搜索提交
|
|
|
|
// 处理搜索提交
|
|
|
|
const handleSearch = useCallback(() => { |
|
|
|
const handleSearch = useCallback(() => { |
|
|
|
if (searchText.trim()) { |
|
|
|
if (searchText.trim()) { |
|
|
@ -288,7 +272,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
setActiveTab("default"); |
|
|
|
setActiveTab("default"); |
|
|
|
// Show skeleton for new search
|
|
|
|
// Show skeleton for new search
|
|
|
|
setShowSkeleton(true); |
|
|
|
setShowSkeleton(true); |
|
|
|
|
|
|
|
|
|
|
|
const newParams = { |
|
|
|
const newParams = { |
|
|
|
...searchParams, |
|
|
|
...searchParams, |
|
|
|
keyword: searchText.trim(), |
|
|
|
keyword: searchText.trim(), |
|
|
@ -298,12 +281,10 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
searchProducts(newParams); |
|
|
|
searchProducts(newParams); |
|
|
|
} |
|
|
|
} |
|
|
|
}, [searchText, searchParams, searchProducts]); |
|
|
|
}, [searchText, searchParams, searchProducts]); |
|
|
|
|
|
|
|
|
|
|
|
// 切换筛选器显示状态
|
|
|
|
// 切换筛选器显示状态
|
|
|
|
const toggleFilter = useCallback(() => { |
|
|
|
const toggleFilter = useCallback(() => { |
|
|
|
setIsFilterVisible(!isFilterVisible); |
|
|
|
setIsFilterVisible(!isFilterVisible); |
|
|
|
}, [isFilterVisible]); |
|
|
|
}, [isFilterVisible]); |
|
|
|
|
|
|
|
|
|
|
|
// 处理点击产品
|
|
|
|
// 处理点击产品
|
|
|
|
const handleProductPress = useCallback( |
|
|
|
const handleProductPress = useCallback( |
|
|
|
(product: Product) => { |
|
|
|
(product: Product) => { |
|
|
@ -316,12 +297,10 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
}, |
|
|
|
}, |
|
|
|
[navigation, searchText] |
|
|
|
[navigation, searchText] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
|
|
// 返回上一页
|
|
|
|
const goBack = useCallback(() => { |
|
|
|
const goBack = useCallback(() => { |
|
|
|
navigation.goBack(); |
|
|
|
navigation.goBack(); |
|
|
|
}, [navigation]); |
|
|
|
}, [navigation]); |
|
|
|
|
|
|
|
|
|
|
|
// 渲染列表为空时的组件
|
|
|
|
// 渲染列表为空时的组件
|
|
|
|
const renderEmptyList = useCallback( |
|
|
|
const renderEmptyList = useCallback( |
|
|
|
() => ( |
|
|
|
() => ( |
|
|
@ -335,7 +314,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
), |
|
|
|
), |
|
|
|
[searchText, t] |
|
|
|
[searchText, t] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 渲染产品项
|
|
|
|
// 渲染产品项
|
|
|
|
const renderProductItem = useCallback( |
|
|
|
const renderProductItem = useCallback( |
|
|
|
({ item }: { item: Product }) => ( |
|
|
|
({ item }: { item: Product }) => ( |
|
|
@ -348,23 +326,19 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
), |
|
|
|
), |
|
|
|
[handleProductPress, t, userStore] |
|
|
|
[handleProductPress, t, userStore] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 创建产品列表项的key提取器
|
|
|
|
// 创建产品列表项的key提取器
|
|
|
|
const keyExtractor = useCallback( |
|
|
|
const keyExtractor = useCallback( |
|
|
|
(item: Product, index: number) => `${item.offer_id}-${index}`, |
|
|
|
(item: Product, index: number) => `${item.offer_id}-${index}`, |
|
|
|
[] |
|
|
|
[] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 处理排序
|
|
|
|
// 处理排序
|
|
|
|
const handleSort = useCallback( |
|
|
|
const handleSort = useCallback( |
|
|
|
(field: "price" | "time", order: "asc" | "desc") => { |
|
|
|
(field: "price" | "time", order: "asc" | "desc") => { |
|
|
|
setSortField(field); |
|
|
|
setSortField(field); |
|
|
|
setSortOrder(order); |
|
|
|
setSortOrder(order); |
|
|
|
|
|
|
|
|
|
|
|
// 本地排序,不发送API请求
|
|
|
|
// 本地排序,不发送API请求
|
|
|
|
setProducts((prevProducts) => { |
|
|
|
setProducts((prevProducts) => { |
|
|
|
const sortedProducts = [...prevProducts]; |
|
|
|
const sortedProducts = [...prevProducts]; |
|
|
|
|
|
|
|
|
|
|
|
if (field === "price") { |
|
|
|
if (field === "price") { |
|
|
|
sortedProducts.sort((a, b) => { |
|
|
|
sortedProducts.sort((a, b) => { |
|
|
|
const priceA = a.min_price || 0; |
|
|
|
const priceA = a.min_price || 0; |
|
|
@ -379,19 +353,15 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
return order === "asc" ? timeA - timeB : timeB - timeA; |
|
|
|
return order === "asc" ? timeA - timeB : timeB - timeA; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return sortedProducts; |
|
|
|
return sortedProducts; |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
[] |
|
|
|
[] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 处理加载更多
|
|
|
|
// 处理加载更多
|
|
|
|
const handleLoadMore = useCallback(() => { |
|
|
|
const handleLoadMore = useCallback(() => { |
|
|
|
if (loading || !hasMore || loadingMore) return; |
|
|
|
if (loading || !hasMore || loadingMore) return; |
|
|
|
|
|
|
|
|
|
|
|
setLoadingMore(true); |
|
|
|
setLoadingMore(true); |
|
|
|
|
|
|
|
|
|
|
|
const newParams = { |
|
|
|
const newParams = { |
|
|
|
...searchParams, |
|
|
|
...searchParams, |
|
|
|
page: searchParams.page + 1, |
|
|
|
page: searchParams.page + 1, |
|
|
@ -399,7 +369,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
setSearchParams(newParams); |
|
|
|
setSearchParams(newParams); |
|
|
|
searchProducts(newParams, true); |
|
|
|
searchProducts(newParams, true); |
|
|
|
}, [loading, hasMore, loadingMore, searchParams, searchProducts]); |
|
|
|
}, [loading, hasMore, loadingMore, searchParams, searchProducts]); |
|
|
|
|
|
|
|
|
|
|
|
// 渲染底部加载指示器
|
|
|
|
// 渲染底部加载指示器
|
|
|
|
const renderFooter = useCallback(() => { |
|
|
|
const renderFooter = useCallback(() => { |
|
|
|
if (!hasMore) |
|
|
|
if (!hasMore) |
|
|
@ -408,7 +377,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
<Text style={styles.footerText}>{t("noMoreData")}</Text> |
|
|
|
<Text style={styles.footerText}>{t("noMoreData")}</Text> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (loadingMore) |
|
|
|
if (loadingMore) |
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<View style={styles.footerContainer}> |
|
|
|
<View style={styles.footerContainer}> |
|
|
@ -416,22 +384,18 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
<Text style={styles.footerText}>{t("loadingMore")}</Text> |
|
|
|
<Text style={styles.footerText}>{t("loadingMore")}</Text> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
return <View style={styles.footerSpace} />; |
|
|
|
return <View style={styles.footerSpace} />; |
|
|
|
}, [loadingMore, hasMore, t]); |
|
|
|
}, [loadingMore, hasMore, t]); |
|
|
|
|
|
|
|
|
|
|
|
// 处理滚动事件
|
|
|
|
// 处理滚动事件
|
|
|
|
const handleScroll = useCallback((event: any) => { |
|
|
|
const handleScroll = useCallback((event: any) => { |
|
|
|
const offsetY = event.nativeEvent.contentOffset.y; |
|
|
|
const offsetY = event.nativeEvent.contentOffset.y; |
|
|
|
// 当滚动超过屏幕高度的一半时显示回到顶部按钮
|
|
|
|
// 当滚动超过屏幕高度的一半时显示回到顶部按钮
|
|
|
|
setShowBackToTop(offsetY > 300); |
|
|
|
setShowBackToTop(offsetY > 300); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 回到顶部
|
|
|
|
// 回到顶部
|
|
|
|
const scrollToTop = useCallback(() => { |
|
|
|
const scrollToTop = useCallback(() => { |
|
|
|
flatListRef.current?.scrollToOffset({ offset: 0, animated: true }); |
|
|
|
flatListRef.current?.scrollToOffset({ offset: 0, animated: true }); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 处理标签切换
|
|
|
|
// 处理标签切换
|
|
|
|
const handleTabChange = useCallback( |
|
|
|
const handleTabChange = useCallback( |
|
|
|
(tab: "default" | "volume" | "price") => { |
|
|
|
(tab: "default" | "volume" | "price") => { |
|
|
@ -443,7 +407,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
scrollToTop(); |
|
|
|
scrollToTop(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
setActiveTab(tab); |
|
|
|
setActiveTab(tab); |
|
|
|
|
|
|
|
|
|
|
|
// 根据标签类型设置排序规则
|
|
|
|
// 根据标签类型设置排序规则
|
|
|
|
if (tab === "price") { |
|
|
|
if (tab === "price") { |
|
|
|
// 默认价格从低到高
|
|
|
|
// 默认价格从低到高
|
|
|
@ -468,7 +431,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
}, |
|
|
|
}, |
|
|
|
[handleSort, activeTab, sortOrder, originalProducts, scrollToTop] |
|
|
|
[handleSort, activeTab, sortOrder, originalProducts, scrollToTop] |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 渲染骨架屏网格
|
|
|
|
// 渲染骨架屏网格
|
|
|
|
const renderSkeletonGrid = useCallback(() => { |
|
|
|
const renderSkeletonGrid = useCallback(() => { |
|
|
|
// Create an array of items for the skeleton grid
|
|
|
|
// Create an array of items for the skeleton grid
|
|
|
@ -487,7 +449,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
); |
|
|
|
); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<SafeAreaView style={styles.safeArea}> |
|
|
|
<SafeAreaView style={styles.safeArea}> |
|
|
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
|
|
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> |
|
|
@ -527,7 +488,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
)} |
|
|
|
)} |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
{/* 标签筛选 */} |
|
|
|
{/* 标签筛选 */} |
|
|
|
<View style={styles.tabContainer}> |
|
|
|
<View style={styles.tabContainer}> |
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
@ -590,7 +550,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
{/* 搜索结果 */} |
|
|
|
{/* 搜索结果 */} |
|
|
|
<View style={styles.resultsContainer}> |
|
|
|
<View style={styles.resultsContainer}> |
|
|
|
{/* 搜索结果标题栏和排序选项 */} |
|
|
|
{/* 搜索结果标题栏和排序选项 */} |
|
|
@ -660,9 +619,7 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
|
|
<View style={styles.sortDivider} /> |
|
|
|
<View style={styles.sortDivider} /> |
|
|
|
|
|
|
|
|
|
|
|
<View style={styles.sortGroup}> |
|
|
|
<View style={styles.sortGroup}> |
|
|
|
<Text style={styles.sortLabel}>{t('time')}:</Text> |
|
|
|
<Text style={styles.sortLabel}>{t('time')}:</Text> |
|
|
|
<View style={styles.sortButtons}> |
|
|
|
<View style={styles.sortButtons}> |
|
|
@ -725,7 +682,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
</ScrollView> |
|
|
|
</ScrollView> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{/* 加载指示器或产品列表 */} |
|
|
|
{/* 加载指示器或产品列表 */} |
|
|
|
{loading && showSkeleton ? ( |
|
|
|
{loading && showSkeleton ? ( |
|
|
|
renderSkeletonGrid() |
|
|
|
renderSkeletonGrid() |
|
|
@ -768,7 +724,6 @@ export const SearchResultScreen = ({ route, navigation }: SearchResultScreenProp |
|
|
|
</SafeAreaView> |
|
|
|
</SafeAreaView> |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({ |
|
|
|
const styles = StyleSheet.create({ |
|
|
|
safeArea: { |
|
|
|
safeArea: { |
|
|
|
flex: 1, |
|
|
|
flex: 1, |
|
|
@ -1075,7 +1030,6 @@ const styles = StyleSheet.create({ |
|
|
|
width: widthUtils(30, 66).width, |
|
|
|
width: widthUtils(30, 66).width, |
|
|
|
height: widthUtils(30, 66).height, |
|
|
|
height: widthUtils(30, 66).height, |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
vipButtonText: { |
|
|
|
vipButtonText: { |
|
|
|
fontStyle: "italic", |
|
|
|
fontStyle: "italic", |
|
|
|
fontWeight: "900", |
|
|
|
fontWeight: "900", |
|
|
|