From 7b88aecf8b894023aa64926ea8145ce5e0e82752 Mon Sep 17 00:00:00 2001 From: Mac Date: Mon, 26 May 2025 00:07:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=86=E5=93=81=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/screens/ProductDetailScreen.tsx | 14 +- app/screens/function/Collection.tsx | 339 +++++++++++++++++++++------- app/services/api/productApi.ts | 48 ++++ 3 files changed, 313 insertions(+), 88 deletions(-) diff --git a/app/screens/ProductDetailScreen.tsx b/app/screens/ProductDetailScreen.tsx index dacfc39..dff6dc3 100644 --- a/app/screens/ProductDetailScreen.tsx +++ b/app/screens/ProductDetailScreen.tsx @@ -29,7 +29,7 @@ import HeartRedIcon from "../components/HeartIconRed"; import ShareIcon from "../components/ShareIcon"; import { Image as ExpoImage, ImageBackground } from "expo-image"; import useUserStore from "../store/user"; -import { getSubjectTransLanguage,getSkuTransLanguage } from "../utils/languageUtils"; +import { getSubjectTransLanguage } from "../utils/languageUtils"; import { useTranslation } from "react-i18next"; import { getBurialPointData } from "../store/burialPoint"; import useBurialPointStore from "../store/burialPoint"; @@ -609,17 +609,7 @@ export const ProductDetailScreen = () => { { setIsHeartRed(!isHeartRed); - Alert.alert("收藏成功", "是否我的查看收藏", [ - { - text: "取消", - onPress: () => console.log("取消 pressed"), - style: "cancel", - }, - { - text: "确定", - onPress: () => console.log("确定 pressed"), - }, - ]); + productApi.collectProduct(route.params.offer_id); }} > {isHeartRed ? ( diff --git a/app/screens/function/Collection.tsx b/app/screens/function/Collection.tsx index 6815376..b9ddd01 100644 --- a/app/screens/function/Collection.tsx +++ b/app/screens/function/Collection.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect, useCallback } from "react"; import { View, Text, @@ -9,34 +9,52 @@ import { SafeAreaView, StatusBar, Platform, + ActivityIndicator, + RefreshControl, + Alert, } from "react-native"; import widthUtils from "../../utils/widthUtils"; import fontSize from "../../utils/fontsizeUtils"; import BackIcon from "../../components/BackIcon"; import { useNavigation } from "@react-navigation/native"; +import { productApi } from "../../services/api/productApi"; +// 收藏商品项组件 const FavoriteItem = ({ - image, - title, - price, + favoriteItem, + onDelete, }: { - image: string; - title: string; - price: number; + favoriteItem: any; + onDelete: (favoriteId: number) => void; }) => { + const product = favoriteItem.product; + return ( - + - {title} + {product.subject_trans || product.subject} + + + {product.currency}{product.min_price} + {product.vip_discount > 0 && ( + + {product.currency}{product.original_min_price} + + )} - ¥{price} 加入购物车 - + onDelete(favoriteItem.favorite_id)} + > 删除 @@ -47,57 +65,149 @@ const FavoriteItem = ({ export const Collection = () => { const navigation = useNavigation(); - const data = [ - { - id: "1", - image: "https://img.alicdn.com/imgextra/i1/1234567890/O1CN01Item1.jpg", - title: "韩版宽松休闲卫衣女春秋款薄款学生ins潮", - price: 89.0, - }, - { - id: "2", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - { - id: "3", - image: "https://img.alicdn.com/imgextra/i3/3234567890/O1CN01Item3.jpg", - title: "华为MateBook X Pro 2020款 13.9英寸全面屏笔记本电脑", - price: 10999.0, - }, - { - id: "4", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - { - id: "5", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - { - id: "6", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - { - id: "7", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - { - id: "82", - image: "https://img.alicdn.com/imgextra/i2/2234567890/O1CN01Item2.jpg", - title: "小米无线蓝牙耳机半入耳式 轻巧便携", - price: 129.0, - }, - // 可以继续添加更多商品 - ]; + + // 状态管理 + const [favorites, setFavorites] = useState([]); + const [loading, setLoading] = useState(true); + const [loadingMore, setLoadingMore] = useState(false); + const [refreshing, setRefreshing] = useState(false); + const [hasMore, setHasMore] = useState(true); + const [currentPage, setCurrentPage] = useState(1); + const [total, setTotal] = useState(0); + + const PAGE_SIZE = 10; + + // 获取收藏列表 + const fetchFavorites = useCallback(async (page: number = 1, isRefresh: boolean = false) => { + try { + if (!isRefresh && page === 1) { + setLoading(true); + } else if (!isRefresh && page > 1) { + setLoadingMore(true); + } + + const response = await productApi.getCollectProductList(page, PAGE_SIZE); + + if (isRefresh || page === 1) { + setFavorites(response.items); + setCurrentPage(1); + } else { + // 避免重复添加数据 + setFavorites(prev => { + const newItems = response.items.filter( + newItem => !prev.some(existingItem => existingItem.favorite_id === newItem.favorite_id) + ); + return [...prev, ...newItems]; + }); + } + + setTotal(response.total); + setHasMore(response.items.length === PAGE_SIZE && favorites.length + response.items.length < response.total); + + if (!isRefresh && page > 1) { + setCurrentPage(page); + } + + } catch (error) { + console.error("获取收藏列表失败:", error); + Alert.alert("错误", "获取收藏列表失败,请重试"); + } finally { + setLoading(false); + setLoadingMore(false); + setRefreshing(false); + } + }, [favorites.length]); + + // 初始化加载 + useEffect(() => { + fetchFavorites(1); + }, []); + + // 下拉刷新 + const handleRefresh = useCallback(() => { + if (refreshing) return; + setRefreshing(true); + fetchFavorites(1, true); + }, [refreshing, fetchFavorites]); + + // 触底加载更多 + const handleLoadMore = useCallback(() => { + if (!hasMore || loadingMore || loading) return; + fetchFavorites(currentPage + 1); + }, [hasMore, loadingMore, loading, currentPage, fetchFavorites]); + + // 删除收藏 + const handleDelete = useCallback(async (favoriteId: number) => { + Alert.alert( + "确认删除", + "确定要删除这个收藏吗?", + [ + { text: "取消", style: "cancel" }, + { + text: "删除", + style: "destructive", + onPress: async () => { + try { + // 这里需要调用删除收藏的API,如果API没有提供,先在前端删除 + setFavorites(prev => prev.filter(item => item.favorite_id !== favoriteId)); + setTotal(prev => prev - 1); + } catch (error) { + console.error("删除收藏失败:", error); + Alert.alert("错误", "删除失败,请重试"); + } + } + } + ] + ); + }, []); + + // 滚动事件处理 + const handleScroll = useCallback((event: any) => { + const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent; + const paddingToBottom = 20; + + if (layoutMeasurement.height + contentOffset.y >= contentSize.height - paddingToBottom) { + handleLoadMore(); + } + }, [handleLoadMore]); + + // 渲染加载指示器 + const renderLoadingIndicator = () => ( + + + 加载中... + + ); + + // 渲染底部加载更多指示器 + const renderFooter = () => { + if (loadingMore) { + return ( + + + 加载更多... + + ); + } + + if (!hasMore && favorites.length > 0) { + return ( + + 没有更多数据了 + + ); + } + + return null; + }; + + // 渲染空状态 + const renderEmptyState = () => ( + + 暂无收藏商品 + 去逛逛,收藏喜欢的商品吧 + + ); return ( @@ -110,14 +220,43 @@ export const Collection = () => { > - 我的收藏 + 我的收藏 ({total}) - - {data.map((item) => ( - - ))} - + + {loading ? ( + renderLoadingIndicator() + ) : ( + + } + onScroll={handleScroll} + scrollEventThrottle={16} + > + {favorites.length === 0 ? ( + renderEmptyState() + ) : ( + <> + {favorites.map((item) => ( + + ))} + {renderFooter()} + + )} + + )} ); @@ -172,6 +311,8 @@ const styles = StyleSheet.create({ backgroundColor: "#fff", borderBottomWidth: 1, borderBottomColor: "#eee", + marginBottom: 8, + borderRadius: 8, }, image: { width: widthUtils(100, 100).width, @@ -193,29 +334,75 @@ const styles = StyleSheet.create({ color: "#f40", fontSize: fontSize(16), marginBottom: 10, + fontWeight: "600", + }, + originalPrice: { + color: "#999", + fontSize: fontSize(14), + textDecorationLine: "line-through", + marginLeft: 8, }, actions: { flexDirection: "row", gap: 8, }, btn: { - paddingVertical: 4, - paddingHorizontal: 10, - borderRadius: 3, - borderWidth: 1, + flex: 1, + paddingVertical: 6, + paddingHorizontal: 12, + borderRadius: 4, + alignItems: "center", }, cart: { - borderColor: "#ff5000", + backgroundColor: "#ff5100", }, delete: { - borderColor: "#ccc", + backgroundColor: "#f5f5f5", + borderWidth: 1, + borderColor: "#ddd", }, cartText: { - fontSize: fontSize(12), - color: "#ff5000", + color: "#fff", + fontSize: fontSize(14), }, deleteText: { + color: "#666", + fontSize: fontSize(14), + }, + loadingContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + paddingTop: 100, + }, + loadingText: { + marginTop: 10, + color: "#666", + fontSize: fontSize(14), + }, + footerContainer: { + paddingVertical: 20, + alignItems: "center", + justifyContent: "center", + }, + footerText: { + color: "#999", fontSize: fontSize(12), + marginTop: 5, + }, + emptyContainer: { + flex: 1, + justifyContent: "center", + alignItems: "center", + paddingTop: 100, + }, + emptyText: { + fontSize: fontSize(16), + color: "#666", + marginBottom: 8, + }, + emptySubtext: { + fontSize: fontSize(14), color: "#999", }, }); diff --git a/app/services/api/productApi.ts b/app/services/api/productApi.ts index abd7f74..1931a6a 100644 --- a/app/services/api/productApi.ts +++ b/app/services/api/productApi.ts @@ -193,6 +193,40 @@ export interface HotTerms { terms: string[]; } + +interface SuccessfulResponse { + total: number; + page: number; + page_size: number; + items: FavoriteItem[]; +} + +interface FavoriteItem { + favorite_id: number; + user_id: number; + offer_id: number; + create_time: string; // ISO 8601 date string + product: Favorite; +} + +interface Favorite { + offer_id: number; + subject: string; + subject_trans: string; + subject_trans_en: string; + subject_trans_ar: string; + product_image_urls: string[]; + min_price: number; + max_price: number; + original_min_price: number; + original_max_price: number; + currency: string; + vip_discount: number; + vip_level: number; + discount_percent: number; + sold_out: number; +} + // 搜索商品 export const productApi = { // 搜索商品 @@ -218,6 +252,20 @@ export interface HotTerms { return apiService.post('/api/search/image_search/?user_id='+data.user_id,{ image_base64: data.image_base64 }); + }, + // 收藏商品 + collectProduct: (offer_id: string) => { + return apiService.post(`/api/favorites/`,{ + offer_id:offer_id + }); + }, + // 收藏商品列表 + getCollectProductList: (page:number,page_size:number) => { + return apiService.get(`/api/favorites/?page=${page}&page_size=${page_size}`); + }, + // 删除收藏商品 + deleteCollectProduct: (offer_id: number) => { + return apiService.delete(`/api/favorites/${offer_id}/`); } }