diff --git a/App.tsx b/App.tsx index 176c6cb..b201024 100644 --- a/App.tsx +++ b/App.tsx @@ -22,6 +22,9 @@ import { AddRess } from "./app/screens/Recipient/Address"; import { SettingList } from "./app/screens/setting/SettingList"; import { CountrySetting } from "./app/screens/setting/CountrySetting"; import { MySetting } from "./app/services/api/setting"; +import { MyAddress } from "./app/screens/setting/MyAddress"; +import { CartScreen } from "./app/screens/CartScreen"; +import { PaymentSuccessScreen } from "./app/screens/pay/PaySuccess"; export type RootStackParamList = { CountrySelect: undefined; MainApp: undefined; @@ -38,6 +41,9 @@ export type RootStackParamList = { AddRess:undefined; SettingList:undefined; CountrySetting: { mySetting?: MySetting }; + MyAddress:undefined; + CartScreen:undefined; + PaymentSuccessScreen:undefined; }; const Stack = createNativeStackNavigator(); @@ -174,6 +180,33 @@ export default function App() { gestureDirection: "horizontal", }} /> + + + diff --git a/app/components/LocationPinIcon.tsx b/app/components/LocationPinIcon.tsx new file mode 100644 index 0000000..c037724 --- /dev/null +++ b/app/components/LocationPinIcon.tsx @@ -0,0 +1,23 @@ +// 推荐图标 + +import React from 'react'; +import Svg, { Path } from 'react-native-svg'; + +const LocationPinIcon = ({size = 20}:{size?:number}) => ( + + + + +); + +export default LocationPinIcon; \ No newline at end of file diff --git a/app/navigation/types.ts b/app/navigation/types.ts index 12d0d31..07fa610 100644 --- a/app/navigation/types.ts +++ b/app/navigation/types.ts @@ -11,4 +11,5 @@ export type RootStackParamList = { Recipient: undefined; SettingList: undefined; CountrySetting: { mySetting?: MySetting | undefined }; + MyAddress: undefined; }; diff --git a/app/screens/CartScreen.tsx b/app/screens/CartScreen.tsx index 4cd5375..987b9f1 100644 --- a/app/screens/CartScreen.tsx +++ b/app/screens/CartScreen.tsx @@ -6,7 +6,6 @@ import { StyleSheet, TouchableOpacity, ScrollView, - Alert, Modal, } from "react-native"; import BackIcon from "../components/BackIcon"; @@ -23,7 +22,8 @@ import { Swipeable } from "react-native-gesture-handler"; import OrangeCircleIcon from "../components/OrangeCircleIcon"; import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; - +import { useFocusEffect } from "@react-navigation/native"; +import { useCallback } from "react"; export const CartScreen = () => { const [cartList, setCartList] = useState([]); const [selectedItems, setSelectedItems] = useState<{ @@ -39,11 +39,11 @@ export const CartScreen = () => { const navigation = useNavigation>(); const changeAllSelected = () => { - const allSkusSelected = cartList.every(item => - item.skus.every(sku => sku.selected === 1) + const allSkusSelected = cartList.every((item) => + item.skus.every((sku) => sku.selected === 1) ); setAllSelected(!allSkusSelected); - } + }; const toggleSelection = async ( cartItemId: string, index1: number, @@ -94,16 +94,16 @@ export const CartScreen = () => { } // 检查所有商品的 skus 数组中的 selected 属性是否都为 1 - - changeAllSelected() + + changeAllSelected(); }; const getCart = async () => { const res = await getCartList(); setCartList(res.items); // 检查所有商品的 skus 数组中的 selected 属性是否都为 1 - const allSkusSelected = res.items.every(item => - item.skus.every(sku => sku.selected === 1) + const allSkusSelected = res.items.every((item) => + item.skus.every((sku) => sku.selected === 1) ); setAllSelected(allSkusSelected); }; @@ -112,9 +112,13 @@ export const CartScreen = () => { setAllSelected(!allSelected); setCartList((prev) => { return prev.map((item) => { - return { ...item, selected: allSelected ? 0 : 1,skus:item.skus.map((sku)=>{ - return { ...sku, selected: allSelected ? 0 : 1 }; - }) }; + return { + ...item, + selected: allSelected ? 0 : 1, + skus: item.skus.map((sku) => { + return { ...sku, selected: allSelected ? 0 : 1 }; + }), + }; }); }); }; @@ -132,7 +136,7 @@ export const CartScreen = () => { const confirmDelete = () => { if (itemToDelete) { const { cartId, cartItemId, cartId1 } = itemToDelete; - + console.log(itemToDelete); setCartList((prev) => { // 先找到要删除的商品 const itemToUpdate = prev.find((item) => item.cart_id === cartId); @@ -162,8 +166,11 @@ export const CartScreen = () => { }); } }); + deleteCartItem(cartId, cartItemId).then((res) => { + console.log(res); + }); } - + // 关闭确认对话框 setDeleteModalVisible(false); setItemToDelete(null); @@ -175,9 +182,31 @@ export const CartScreen = () => { setItemToDelete(null); }; - useEffect(() => { - getCart(); - }, []); + // useEffect(() => { + // getCart(); + // }, []); + useFocusEffect( + useCallback(() => { + getCart(); + }, []) + ); + + const gotoOrder = () => { + const items:{cart_item_id:number}[] = [] + cartList.forEach((item) => { + item.skus.forEach((sku) => { + if (sku.selected === 1) { + if (sku.cart_item_id) { + items.push({ + cart_item_id: sku.cart_item_id, + }) + } + } + }); + + }); + navigation.navigate("Recipient",{items}); + }; return ( { ) } > - + {sku.selected === 1 ? ( - + ) : ( )} @@ -385,9 +409,10 @@ export const CartScreen = () => { 24928 FCFA - { - navigation.navigate("Recipient") - }}> + { - - - {/* + + + {/* */} - Supprimer l'article ? - - - Non - - - Oui - + Supprimer l'article ? + + + Non + + + Oui + + - - - - + ); }; @@ -928,54 +957,54 @@ const styles = StyleSheet.create({ }, modalOverlay: { flex: 1, - backgroundColor: 'rgba(0, 0, 0, 0.5)', - justifyContent: 'center', - alignItems: 'center', + backgroundColor: "rgba(0, 0, 0, 0.5)", + justifyContent: "center", + alignItems: "center", }, modalContent: { - backgroundColor: 'white', + backgroundColor: "white", borderRadius: 10, padding: 20, - width: '80%', - alignItems: 'center', + width: "80%", + alignItems: "center", }, modalTitle: { fontSize: fontSize(18), - fontWeight: 'bold', + fontWeight: "bold", marginBottom: 10, }, modalMessage: { fontSize: fontSize(16), marginBottom: 20, - textAlign: 'center', + textAlign: "center", }, modalButtons: { - flexDirection: 'row', - justifyContent: 'space-between', - width: '100%', + flexDirection: "row", + justifyContent: "space-between", + width: "100%", }, modalButton: { paddingVertical: 10, paddingHorizontal: 20, borderRadius: 5, - width: '45%', - alignItems: 'center', + width: "45%", + alignItems: "center", }, cancelButton: { - backgroundColor: '#f0f0f0', + backgroundColor: "#f0f0f0", }, deleteButton: { - backgroundColor: '#ff5217', + backgroundColor: "#ff5217", }, cancelButtonText: { - color: '#333', + color: "#333", fontSize: fontSize(16), - fontWeight: '500', + fontWeight: "500", }, deleteButtonText: { - color: 'white', + color: "white", fontSize: fontSize(16), - fontWeight: '500', + fontWeight: "500", }, overlay: { flex: 1, diff --git a/app/screens/ChatScreen.tsx b/app/screens/ChatScreen.tsx index 261943f..f289c2d 100644 --- a/app/screens/ChatScreen.tsx +++ b/app/screens/ChatScreen.tsx @@ -32,6 +32,17 @@ export const ChatScreen = () => { 运费计算 + + + + Chat Screen + navigation.navigate("PaymentSuccessScreen")} + > + 付款成功 + + ); }; diff --git a/app/screens/ProductCard.tsx b/app/screens/ProductCard.tsx index 6348959..eef76d8 100644 --- a/app/screens/ProductCard.tsx +++ b/app/screens/ProductCard.tsx @@ -6,6 +6,7 @@ import { StyleSheet, TouchableOpacity, ScrollView, + Modal } from "react-native"; import widthUtils from "../utils/widthUtils"; import fontSize from "../utils/fontsizeUtils"; @@ -18,6 +19,8 @@ import { } from "../services/api/productApi"; import { cartApi } from "../services/api/cart"; import { useState } from "react"; +import { useNavigation } from "@react-navigation/native"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; interface ProductCardProps { onClose: () => void; product: ProductDetailParams; @@ -33,6 +36,7 @@ const ProductCard: React.FC = ({ product: ProductDetailParams; groupList: ProductGroupList[]; }) => { + const navigation = useNavigation>(); const [groupList, setGroupList] = useState(localGroupList); const [product, setProduct] = useState(localProduct); @@ -46,6 +50,7 @@ const ProductCard: React.FC = ({ const [selectedSize, setSelectedSize] = useState(0); const [totalPrice, setTotalPrice] = useState(0); const [flag, setFlag] = useState(false); + const [deleteModalVisible, setDeleteModalVisible] = useState(false); useEffect(() => { setPrice(product.price as number); const imageItem = groupList.filter((item) => item.has_image); @@ -107,6 +112,7 @@ const ProductCard: React.FC = ({ } }); }); + console.log(processedImg); setHasImg(processedImg); } else { @@ -127,7 +133,6 @@ const ProductCard: React.FC = ({ const handleColorSelect = (colorId: string, index: number) => { if (!hasImg) return; - // setPrice(price ?? 0); // 创建attributes的深拷贝 @@ -156,7 +161,12 @@ const ProductCard: React.FC = ({ }); }; - const handleSizeSelect = (value: string, type: string, index: number) => { + const handleSizeSelect = ( + value: string, + type: string, + index: number, + amount_on_sale: number + ) => { if (!hasImg) return; const data = hasImg.attributes.find((item) => item.has_color); @@ -192,8 +202,18 @@ const ProductCard: React.FC = ({ if (type === "+") { newHasImg.attributes[colorIndex].size = (newHasImg.attributes[colorIndex].size ?? 0) + 1; + if (newHasImg.attributes[colorIndex].size > amount_on_sale) { + newHasImg.attributes[colorIndex].size = amount_on_sale; + } newHasImg.attributes[colorIndex].list[index].size = (newHasImg.attributes[colorIndex].list[index].size ?? 0) + 1; + + if ( + newHasImg.attributes[colorIndex].list[index].size > amount_on_sale + ) { + newHasImg.attributes[colorIndex].list[index].size = + amount_on_sale; + } } else { newHasImg.attributes[colorIndex].size = (newHasImg.attributes[colorIndex].size ?? 0) - 1; @@ -220,13 +240,17 @@ const ProductCard: React.FC = ({ const handleNoImgSizeSelect = ( value: string, type: string, - index: number + index: number, + amount_on_sale: number ) => { if (!noImgList) return; console.log(noImgList); if (type === "+") { noImgList[index].size = (noImgList[index].size ?? 0) + 1; + if (noImgList[index].size > amount_on_sale) { + noImgList[index].size = amount_on_sale; + } } else { noImgList[index].size = (noImgList[index].size ?? 0) - 1; } @@ -238,11 +262,7 @@ const ProductCard: React.FC = ({ let total = 0; let priceSum = 0; - console.log(product); - noImgList.forEach((item) => { - console.log(item.size); - console.log(item.offer_price); total += item.size ?? 0; priceSum += (item.offer_price ?? @@ -318,6 +338,12 @@ const ProductCard: React.FC = ({ console.log(res); }); } + setDeleteModalVisible(true); + }; + + const cancelDelete = () => { + // 关闭确认对话框 + setDeleteModalVisible(false); }; return ( @@ -485,7 +511,7 @@ const ProductCard: React.FC = ({ x{list?.size} )} - = ({ handleSizeSelect( list?.attributes[0]?.value, "-", - index1 + index1, + list.amount_on_sale ) } > @@ -518,7 +545,8 @@ const ProductCard: React.FC = ({ handleSizeSelect( list?.attributes[0]?.value, "+", - index1 + index1, + list.amount_on_sale ) } > @@ -533,6 +561,114 @@ const ProductCard: React.FC = ({ )} + {hasImg && groupList.length > 1 && !hasImg.has_image && ( + + + {hasImg?.attribute_name}: {size} + + + + {hasImg.attributes.map((item, index) => ( + handleColorSelect(item.value, index)} + > + + {item.size && ( + + x{item.size} + + )} + + + {item.value} + + + ))} + + + {sizeTitle} + + {hasImg.attributes + .find((item) => item.has_color) + ?.list.map((list, index1) => ( + + + + {(list?.size ?? 0) > 0 && ( + + x{list?.size} + + )} + + {list?.attributes[0]?.value} + + + + 库存 {list?.amount_on_sale} + + + + + + handleSizeSelect( + list?.attributes[0]?.value, + "-", + index1, + list.amount_on_sale + ) + } + > + - + + + {list?.size ?? 0} + + + handleSizeSelect( + list?.attributes[0]?.value, + "+", + index1, + list.amount_on_sale + ) + } + > + + + + + + ))} + + + + + + )} + {noImgList && groupList.length === 1 && !flag && ( @@ -563,7 +699,7 @@ const ProductCard: React.FC = ({ x{list?.size} )} - = ({ handleNoImgSizeSelect( list?.attributes[0]?.value, "-", - index1 + index1, + list.amount_on_sale ) } > @@ -594,7 +731,8 @@ const ProductCard: React.FC = ({ handleNoImgSizeSelect( list?.attributes[0]?.value, "+", - index1 + index1, + list.amount_on_sale ) } > @@ -634,8 +772,8 @@ const ProductCard: React.FC = ({ > = ({ uri: list?.attributes[0]?.sku_image_url, }} style={{ - width: 50, - height: 50, + width: widthUtils(50,50).width, + height: widthUtils(50,50).height, borderRadius: 5, }} /> @@ -658,7 +796,6 @@ const ProductCard: React.FC = ({ flexDirection: "row", alignItems: "center", justifyContent: "space-between", - width: 250, }} > {(list?.size ?? 0) > 0 && ( @@ -666,7 +803,7 @@ const ProductCard: React.FC = ({ x{list?.size} )} - = ({ handleNoImgSizeSelect( list?.attributes[0]?.value, "-", - index1 + index1, + list.amount_on_sale ) } > @@ -701,7 +839,8 @@ const ProductCard: React.FC = ({ handleNoImgSizeSelect( list?.attributes[0]?.value, "+", - index1 + index1, + list.amount_on_sale ) } > @@ -744,6 +883,31 @@ const ProductCard: React.FC = ({ + + + + + {/* */} + Supprimer l'article ? + + + Non + + navigation.navigate("MainTabs", { screen: "Cart" })}> + Voir le panier + + + + + ); }; @@ -830,7 +994,7 @@ const styles = StyleSheet.create({ paddingBottom: 14, margin: 0, fontWeight: "700", - fontSize: 14, + fontSize: fontSize(14), fontFamily: "Segoe UI", color: "#ff5100", }, @@ -845,7 +1009,7 @@ const styles = StyleSheet.create({ margin: 0, fontStyle: "italic", fontWeight: "900", - fontSize: 11, + fontSize: fontSize(11), fontFamily: "Segoe UI", color: "#4e2000", }, @@ -856,7 +1020,7 @@ const styles = StyleSheet.create({ marginLeft: 1.25, }, vipButton: { - width: 55, + width: widthUtils(55,55).width, minWidth: 55, height: 21, marginLeft: -2.5, @@ -868,7 +1032,7 @@ const styles = StyleSheet.create({ italicBoldSegoeVip: { fontStyle: "italic", fontWeight: "900", - fontSize: 14, + fontSize: fontSize(14), fontFamily: "Segoe UI", }, pricingCardContainer: { @@ -923,8 +1087,8 @@ const styles = StyleSheet.create({ padding: 0, margin: 0, fontWeight: "600", - fontSize: 16, - lineHeight: 20, + fontSize: fontSize(16), + lineHeight: fontSize(20), fontFamily: "Segoe UI", color: "black", }, @@ -935,8 +1099,8 @@ const styles = StyleSheet.create({ flexDirection: "column", alignItems: "stretch", justifyContent: "flex-start", - width: 90, - height: 116, + width: widthUtils(116,116).width, + height: widthUtils(116,116).height, paddingBottom: 5, backgroundColor: "#f4f4f4", borderRadius: 5, @@ -946,8 +1110,8 @@ const styles = StyleSheet.create({ alignItems: "flex-start", justifyContent: "flex-start", borderRadius: 5, - width: 90, - height: 90, + width: widthUtils(90,90).width, + height: widthUtils(90,90).height, }, imageContainer: { width: "100%", @@ -963,9 +1127,9 @@ const styles = StyleSheet.create({ fontWeight: "400", fontFamily: "Segoe UI", color: "black", - height: 26, textAlign: "center", - width: 90, + width: widthUtils(90,26).width, + height: widthUtils(90,26).height, fontSize: fontSize(18), }, closeIconContainer: { @@ -982,8 +1146,8 @@ const styles = StyleSheet.create({ position: "absolute", top: -6, left: -1, - width: 30, - height: 16, + width: widthUtils(16,30).width, + height: widthUtils(16,30).height, borderRadius: 8, backgroundColor: "#ff5323", zIndex: 1, @@ -992,16 +1156,42 @@ const styles = StyleSheet.create({ }, topLeftBadgeText: { color: "white", - fontSize: 10, + fontSize: fontSize(10), fontWeight: "400", fontFamily: "Segoe UI", textAlign: "center", - lineHeight: 16, + lineHeight: fontSize(16), }, specifications: { - width: "100%", flex: 1, - paddingVertical: 20, + paddingVertical: 10, + }, + sizeList: { + gap: 5, + }, + sizeItem: { + paddingHorizontal: 10, + paddingVertical: 8, + borderRadius: 5, + marginTop: 10, + backgroundColor: "#efefef", + }, + sizeActiveItem: { + backgroundColor: "#ff5323", + color: "#ffffff", + }, + sizeActiveItemText: { + color: "#ffffff", + }, + sizeTitle: { + marginTop: 5, + padding: 0, + margin: 0, + fontWeight: "600", + fontSize: fontSize(16), + lineHeight: fontSize(20), + fontFamily: "Segoe UI", + color: "black", }, specificationsList: { marginTop: 10, @@ -1013,27 +1203,27 @@ const styles = StyleSheet.create({ alignItems: "center", }, sizeText: { - fontSize: 16, + fontSize: fontSize(16), fontWeight: "600", fontFamily: "Segoe UI", color: "black", - width: "100%", + width: widthUtils(200,200).width, }, selectedNumText: { - width: 30, - height: 16, + width: widthUtils(16,30).width, + height: widthUtils(16,30).height, backgroundColor: "#ff5217", borderRadius: 5, color: "white", textAlign: "center", - fontSize: 12, + fontSize: fontSize(12), fontWeight: "600", fontFamily: "Segoe UI", marginRight: 5, lineHeight: 18, }, amountText: { - fontSize: 16, + fontSize: fontSize(16), fontWeight: "600", fontFamily: "Segoe UI", color: "#bdbdbd", @@ -1043,16 +1233,16 @@ const styles = StyleSheet.create({ alignItems: "center", }, numText: { - width: 40, - height: 24, + width: widthUtils(24,40).width, + height: widthUtils(24,40).height, textAlign: "center", - fontSize: 16, + fontSize: fontSize(16), fontWeight: "600", fontFamily: "Segoe UI", color: "black", backgroundColor: "#f4f4f4", borderRadius: 5, - lineHeight: 28, + lineHeight: fontSize(28), marginHorizontal: 5, }, bottomFixedContainer: { @@ -1060,7 +1250,7 @@ const styles = StyleSheet.create({ bottom: 0, left: 0, width: "100%", - height: 118, + height: widthUtils(118,118).height, backgroundColor: "white", borderTopWidth: 1, borderTopColor: "#f4f4f4", @@ -1080,25 +1270,104 @@ const styles = StyleSheet.create({ paddingBottom: 10, }, bottomFixedContainerText: { - fontSize: 14, + fontSize: fontSize(14), fontWeight: "600", fontFamily: "PingFang SC", color: "black", }, bottomFixedContainer2: { width: "100%", - height: 40, + height: widthUtils(40,40).height, backgroundColor: "#ff5217", borderRadius: 25, alignItems: "center", justifyContent: "center", }, bottomFixedContainerButtonText: { - fontSize: 14, + fontSize: fontSize(14), fontWeight: "600", fontFamily: "PingFang SC", color: "white", }, + fixedCornerView: { + position: "absolute", + top: -8, + left: 0, + width: widthUtils(16,30).width, + height: widthUtils(16,30).height, + zIndex: 10, + borderRadius: 5, + }, + fixedCornerText: { + fontSize: fontSize(12), + fontWeight: "600", + fontFamily: "Segoe UI", + color: "white", + textAlign: "center", + lineHeight: fontSize(18), + backgroundColor: "#ff5217", + borderRadius: 5, + }, + overlay: { + flex: 1, + backgroundColor: "rgba(0,0,0,0.4)", + justifyContent: "center", + alignItems: "center", + }, + popup: { + backgroundColor: "white", + borderRadius: 10, + paddingVertical: 27, + paddingHorizontal: 20, + alignItems: "center", + gap: 21, + }, + image: { + width: widthUtils(80,80).width, + height: widthUtils(80,80).height, + borderRadius: 5, + resizeMode: "cover", + }, + promptText: { + fontSize: fontSize(20), + fontWeight: "600", + color: "black", + fontFamily: "Segoe UI", // 注意要在项目中配置字体 + }, + buttonContainer: { + flexDirection: "row", + justifyContent: "center", + marginTop: 10, + }, + cancelButton1: { + width: widthUtils(50,160).width, + height: widthUtils(50,160).height, + borderRadius: 25, + backgroundColor: "#f2f3f5", + justifyContent: "center", + alignItems: "center", + }, + confirmButton: { + width: widthUtils(50,160).width, + height: widthUtils(50,160).height, + borderRadius: 25, + backgroundColor: "#002fa7", + justifyContent: "center", + alignItems: "center", + marginLeft: 20, + }, + cancelText: { + fontSize: fontSize(16), + fontWeight: "500", + color: "#333333", + fontFamily: "Source Han Sans CN", // 注意要在项目中配置字体 + }, + confirmText: { + fontSize: fontSize(16), + fontWeight: "500", + color: "#ffffff", + fontFamily: "Source Han Sans CN", // 同上 + }, }); export default ProductCard; diff --git a/app/screens/ProductDetailScreen.tsx b/app/screens/ProductDetailScreen.tsx index 2029ccd..372a95d 100644 --- a/app/screens/ProductDetailScreen.tsx +++ b/app/screens/ProductDetailScreen.tsx @@ -10,6 +10,7 @@ import { useWindowDimensions, Animated, BackHandler, + ActivityIndicator, } from "react-native"; import fontSize from "../utils/fontsizeUtils"; import widthUtils from "../utils/widthUtils"; @@ -31,7 +32,6 @@ import { RouteProp } from "@react-navigation/native"; import BackIcon from "../components/BackIcon"; import CameraIcon from "../components/CameraIcon"; import ProductCard from "./ProductCard"; -import CloseIcon from "../components/CloseIcon"; type ProductDetailRouteParams = { offer_id: string; searchKeyword?: string; @@ -53,6 +53,7 @@ export const ProductDetailScreen = () => { const [product, setProduct] = useState(); const [groupList, setGroupList] = useState([]); + const [isLoading, setIsLoading] = useState(true); const [similars, setSimilars] = useState(); const [isSimilarsFlag, setIsSimilarsFlag] = useState(false); @@ -234,7 +235,7 @@ export const ProductDetailScreen = () => { if(item.offer_price){ price = item.offer_price }else{ - price = product.sale_info.price_range_list[product.sale_info.price_range_list.length - 1].price + price = product?.sale_info?.price_range_list[product?.sale_info?.price_range_list?.length - 1]?.price } } }) @@ -248,44 +249,50 @@ export const ProductDetailScreen = () => { const getProductDetail = async () => { if (!route.params?.offer_id) return; - const res = await productApi.getProductDetail(route.params.offer_id); - if (res.skus != null) { - const priceSelectedSku = res.skus.find( - (item) => item.offer_price === route.params.price - ); + setIsLoading(true); + try { + const res = await productApi.getProductDetail(route.params.offer_id); + if (res.skus != null) { + const priceSelectedSku = res.skus.find( + (item) => item.offer_price === route.params.price + ); + if (priceSelectedSku) { + res.price = priceSelectedSku.offer_price; + } else { + res.price = res?.sale_info?.price_range_list[res?.sale_info?.price_range_list?.length - 1]?.price; + } + }else{ + res.price = route.params.price + } + if (res.skus != null) { + const priceSelectedSku = res.skus.find(item => item.offer_price === route.params.price) if (priceSelectedSku) { - res.price = priceSelectedSku.offer_price; - } else { - res.price = res.sale_info.price_range_list[res.sale_info.price_range_list.length - 1]?.price; + setPriceSelectedSku({ + price:route.params.price, + }) + } + } + setPriceSelectedSku(priceSelectedSku) + setProduct(res); + let list:ProductGroupList[] = [] + if(res.skus != null){ + list = groupData(res,priceSelectedSku?.attributes as SkuAttribute[]); + }else{ + list = [] } - }else{ - res.price = route.params.price - } - if (res.skus != null) { - const priceSelectedSku = res.skus.find(item => item.offer_price === route.params.price) - if (priceSelectedSku) { - setPriceSelectedSku({ - price:route.params.price, - }) - } - } - setPriceSelectedSku(priceSelectedSku) - setProduct(res); - let list:ProductGroupList[] = [] - if(res.skus != null){ - list = groupData(res,priceSelectedSku?.attributes as SkuAttribute[]); - }else{ - list = [] - } - const imageUrls = []; - const regex = /]+src="([^"]+)"/g; - let match; - - while ((match = regex.exec(res.description)) !== null) { - imageUrls.push(match[1]); // match[1] 是 src 属性的值 + const imageUrls = []; + const regex = /]+src="([^"]+)"/g; + let match; + while ((match = regex.exec(res.description)) !== null) { + imageUrls.push(match[1]); // match[1] 是 src 属性的值 + } + setImageUrls(imageUrls); + setGroupList(list); + } catch (error) { + console.error("Error fetching product details:", error); + } finally { + setIsLoading(false); } - setImageUrls(imageUrls); - setGroupList(list); }; const getSimilars = () => { @@ -323,364 +330,373 @@ export const ProductDetailScreen = () => { return ( - - - - - { - if (showBottomSheet) { - setShowBottomSheet(false); - } else { - navigation.goBack(); - } - }}> - - - - - - - Recherche - - - {/* Replace with your SVG component or icon */} - - - - - {/* Replace with your SVG component or icon */} - - - {/* Replace with your SVG component or icon */} + {isLoading ? ( + + + Loading product details... + + ) : ( + <> + + + + + { + if (showBottomSheet) { + setShowBottomSheet(false); + } else { + navigation.goBack(); + } + }}> + + + + + + + Recherche + + + {/* Replace with your SVG component or icon */} + + + + + {/* Replace with your SVG component or icon */} + + + {/* Replace with your SVG component or icon */} + + - - - - - setActiveIndex(index)} - modeConfig={{ - parallaxScrollingScale: 0.9, - parallaxScrollingOffset: 50, - }} - renderItem={({ item }) => ( + + + setActiveIndex(index)} + modeConfig={{ + parallaxScrollingScale: 0.9, + parallaxScrollingOffset: 50, + }} + renderItem={({ item }) => ( + + + + )} + /> + + {/* 底部指示灯 - 固定在右下角 */} - + + {activeIndex + 1}/{product?.product_image_urls.length} + - )} - /> - - {/* 底部指示灯 - 固定在右下角 */} - - - {activeIndex + 1}/{product?.product_image_urls.length} - + - - - - - {product?.subject} - - - - {product?.price} - FCFA - - 3000FCFA - - - + + + {product?.subject} + + + + {product?.price} + FCFA + + 3000FCFA + + + - - {product?.sold_out} ventes - - + + {product?.sold_out} ventes + + - - -5% - - {/* Replace with your SVG component or icon */} - - - - - {/* Replace with your SVG component or icon */} - - - - - - VIP - 1 - + + -5% + + {/* Replace with your SVG component or icon */} + + + + + {/* Replace with your SVG component or icon */} + + + + + + VIP + 1 + + + - - - - - - {groupList.map((item, index) => - item.has_image ? ( - - - {item.attribute_name} : {item.attributes.find(item => item.has_color)?.value} - - - {getDisplayAttributes( - item.attributes, - item.attribute_name - ).map((attribute) => ( - - handleColorSelect(attribute.value, index) - } - style={[ - styles.colorImageContainer, - attribute.has_color && - styles.selectedColorImageContainer, - ]} - > - - - ))} + + + + {groupList.map((item, index) => + item.has_image ? ( + + + {item.attribute_name} : {item.attributes.find(item => item.has_color)?.value} + + + {getDisplayAttributes( + item.attributes, + item.attribute_name + ).map((attribute) => ( + + handleColorSelect(attribute.value, index) + } + style={[ + styles.colorImageContainer, + attribute.has_color && + styles.selectedColorImageContainer, + ]} + > + + + ))} - {!expandedGroups[item.attribute_name] && - item.attributes.length > 6 && ( - - toggleExpand(item.attribute_name) - } - > - - 更多 - - - )} + {!expandedGroups[item.attribute_name] && + item.attributes.length > 6 && ( + + toggleExpand(item.attribute_name) + } + > + + 更多 + + + )} - {expandedGroups[item.attribute_name] && ( - toggleExpand(item.attribute_name)} - > - 收起 + {expandedGroups[item.attribute_name] && ( + toggleExpand(item.attribute_name)} + > + 收起 + + )} + + + { + groupList.length > 1 && index === 0 && ( + setShowBottomSheet(true)}> + + + - )} - - - { - groupList.length > 1 && index === 0 && ( - setShowBottomSheet(true)}> - - - - - ) - } - { - groupList.length === 1 && index === 0 && ( - setShowBottomSheet(true)}> - - + ) + } + { + groupList.length === 1 && index === 0 && ( + setShowBottomSheet(true)}> + + + + + ) + } - - ) - } - - ) : ( - - - {item.attribute_name} - + ) : ( + + + {item.attribute_name} + - - {getDisplayAttributes( - item.attributes, - item.attribute_name - ).map((attribute) => ( - - handleSizeSelect(attribute.value, index) - } - style={[ - styles.sizeButton, - attribute.has_color && - styles.selectedSizeButton, - ]} - > - - {attribute.value} - - - ))} + + {getDisplayAttributes( + item.attributes, + item.attribute_name + ).map((attribute) => ( + + handleSizeSelect(attribute.value, index) + } + style={[ + styles.sizeButton, + attribute.has_color && + styles.selectedSizeButton, + ]} + > + + {attribute.value} + + + ))} - {!expandedGroups[item.attribute_name] && - item.attributes.length > 6 && ( - - toggleExpand(item.attribute_name) - } - > - - 更多 - - - )} + {!expandedGroups[item.attribute_name] && + item.attributes.length > 6 && ( + + toggleExpand(item.attribute_name) + } + > + + 更多 + + + )} - {expandedGroups[item.attribute_name] && ( - toggleExpand(item.attribute_name)} - > - 收起 + {expandedGroups[item.attribute_name] && ( + toggleExpand(item.attribute_name)} + > + 收起 + + )} + + { + groupList.length === 1 && ( + setShowBottomSheet(true)}> + + + - )} - - { - groupList.length === 1 && ( - setShowBottomSheet(true)}> - - - - - ) - } + ) + } - { - groupList.length === 2 && index === 0 && ( - setShowBottomSheet(true)}> - - + { + groupList.length === 2 && index === 0 && ( + setShowBottomSheet(true)}> + + + + + ) + } - - ) - } - - ) - )} + ) + )} + + - - - - - - More from this store - - View All - + + + + More from this store + + View All + - - {isSimilarsFlag && - similars?.map((item) => ( - - - - - - - {item.max_price} - - - FCFA - - + + {isSimilarsFlag && + similars?.map((item) => ( + + + + + + + {item.max_price} + + + FCFA + + + + ))} + + + + {imageUrls.map((src, index) => ( + + handleImageLoad(src, event)} + /> ))} - - - - {imageUrls.map((src, index) => ( - - handleImageLoad(src, event)} - /> - ))} + + + + + + chatNow + + setShowBottomSheet(true)} + > + + addToCart + - - - - - - chatNow - - setShowBottomSheet(true)} - > - - addToCart - - - {showBottomSheet && product && ( - - - setShowBottomSheet(false)} product={product} groupList={groupList}> - - + {showBottomSheet && product && ( + + + setShowBottomSheet(false)} product={product} groupList={groupList}> + + + )} + )} ); @@ -1344,4 +1360,15 @@ const styles = StyleSheet.create({ height: "85%", zIndex: 1, }, + loadingContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'white', + }, + loadingText: { + marginTop: 10, + fontSize: fontSize(16), + color: '#666', + }, }); diff --git a/app/screens/ProfileScreen.tsx b/app/screens/ProfileScreen.tsx index 8356b46..621b1be 100644 --- a/app/screens/ProfileScreen.tsx +++ b/app/screens/ProfileScreen.tsx @@ -1,12 +1,15 @@ -import React from "react"; +import React, {useState, useEffect,useCallback} from "react"; import { View, Text, Image, StyleSheet, ImageBackground,TouchableOpacity } from "react-native"; import SettingsIcon from "../components/SettingsIcon"; import fontSize from "../utils/fontsizeUtils"; import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; -import { userApi } from '../services/api/userApi'; +import { userApi ,User} from '../services/api/userApi'; import { settingApi } from '../services/api/setting'; import AsyncStorage from '@react-native-async-storage/async-storage'; +import { useFocusEffect } from '@react-navigation/native'; +import { flagMap } from '../utils/flagMap'; + type RootStackParamList = { SettingList: undefined; Home: undefined; @@ -32,6 +35,18 @@ export const ProfileScreen = () => { } const navigation = useNavigation>(); + const [userInfo, setUserInfo] = useState(null); + + const getUserInfo = async () => { + const res = await userApi.getProfile(); + console.log(res); + setUserInfo(res); + } + useFocusEffect( + useCallback(() => { + getUserInfo(); + }, []) + ); return ( { /> - Bellael - ID: 11 + {userInfo?.username} + ID: {userInfo?.user_id} @@ -61,11 +76,11 @@ export const ProfileScreen = () => { - FCFA + {userInfo?.currency} navigation.navigate("SettingList")}> diff --git a/app/screens/Recipient/Recipient.tsx b/app/screens/Recipient/Recipient.tsx index 78e1e4a..c5148e2 100644 --- a/app/screens/Recipient/Recipient.tsx +++ b/app/screens/Recipient/Recipient.tsx @@ -6,9 +6,9 @@ import { TouchableOpacity, ScrollView, Modal, - Switch, StyleSheet, Platform, + Image, } from "react-native"; import { Picker } from "@react-native-picker/picker"; import AddressIcon from "../../components/AddressIcon"; @@ -24,9 +24,14 @@ import { import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { eventBus } from "../../utils/eventBus"; -export function Recipient() { +import LocationPinIcon from "../../components/LocationPinIcon"; +import fontSize from "../../utils/fontsizeUtils"; +import { ordersApi,OrderData } from "../../services/api/orders"; + +export function Recipient({ route }:{route:{params:{items:{cart_item_id:number}[]}}}) { const navigation = useNavigation>(); const [showModal, setShowModal] = useState(false); + const [orderData, setOrderData] = useState(); const [formData, setFormData] = useState({ firstName: "", lastName: "", @@ -36,7 +41,7 @@ export function Recipient() { setDefault: false, }); - const [shippingMethod, setShippingMethod] = useState(null); + const [shippingMethod, setShippingMethod] = useState('sea'); const [warehouse, setWarehouse] = useState(""); const [arrival, setArrival] = useState("-"); const [shippingFee, setShippingFee] = useState("-"); @@ -53,9 +58,19 @@ export function Recipient() { const response = await addressApi.getAddress(); setAddressList(response.items); }; + + const getOrders = async () => { + const params = route.params; + const data = { + "items": params.items, + } + const response = await ordersApi.getOrders(data); + setOrderData(response); + }; useEffect(() => { getAddress(); getAddressList(); + getOrders(); const listener = (data: any) => { if (data.type === "add") { data.address_id = new Date().getTime(); @@ -207,35 +222,7 @@ export function Recipient() { } }; const [expanded, setExpanded] = useState(false); - const [orderItems] = useState([ - { - id: 1, - name: "Wireless Bluetooth Speaker Portable Outdoor Mini", - variant: "Color: Black | Size: Medium", - quantity: 1, - price: 29.99, - shipping: 8.5, - image: null, - }, - { - id: 2, - name: "Wireless Charging Pad for iPhone and Android Devices", - variant: "Color: White", - quantity: 2, - price: 31.98, - shipping: 5.0, - image: null, - }, - { - id: 3, - name: "Kitchen Multifunctional Food Slicer with 8 Blades", - variant: "Type: Stainless Steel", - quantity: 1, - price: 34.5, - shipping: 12.0, - image: null, - }, - ]); + const toggleExpanded = () => { setExpanded(!expanded); @@ -269,14 +256,14 @@ export function Recipient() { - + {defaultAddress?.receiver_first_name} .{" "} {defaultAddress?.receiver_last_name} - + {defaultAddress?.country} - + {defaultAddress?.receiver_phone} @@ -305,7 +292,7 @@ export function Recipient() { detail: "Economical", }, { id: "air", label: "Air Shipping", icon: "✈️", detail: "Express" }, - ].map((option) => ( + ].map((option, index) => ( { setShippingMethod(option.id); - updateShippingInfo(option.id, warehouse); // 👈 这就是"再加一句"的地方 + updateShippingInfo(option.id, warehouse); }} > + {index === 0 && ( + + + + )} {option.icon} {option.label} {option.detail} @@ -469,7 +461,7 @@ export function Recipient() { - Products(3 items) + Products({orderData?.items.length} items) {expanded ? "Hide Details" : "View Details"} @@ -479,11 +471,11 @@ export function Recipient() { - {orderItems.map((item) => ( - - {item.image ? ( + {orderData?.items.map((item) => ( + + {item.sku_image_url ? ( ) : ( @@ -492,16 +484,21 @@ export function Recipient() { - {item.name} + {item.product_name} - {item.variant} + {item.attributes.map((attribute) => ( + + {attribute?.attribute_name}: {attribute?.value} + + + ))} Qty: {item.quantity} - ${item.price.toFixed(2)} + ${item?.total_price} - +${item.shipping.toFixed(2)} domestic + {/* +${item?.shipping.toFixed(2)} domestic */} Supplier to warehouse shipping @@ -548,7 +545,7 @@ export function Recipient() { Subtotal - $231.00 + {orderData?.total_amount} Domestic Shipping @@ -562,18 +559,15 @@ export function Recipient() { {/* 实际支付金额 */} - {actualPayment && ( - - Actual Payment: - - - {actualPayment} - + + Total + {orderData?.total_amount} + + + 1 + - )} {/* Coupon Modal */} { + return ( + + + + + + 支付成功 + + + 73800FCFA + + + + + + 现代电话 + 17088752341 + + + 地址 + 河南省 + + + + 货到仓库后,打电话联系您 + + + + 查看订单 + + + 订单详情 + + + + + + 1234567890 + + + + + + + 商品名称 + ¥199 + + + + + + + 商品名称 + ¥299 + + + + + + + + + 商品名称 + ¥399 + + + + + + + 商品名称 + ¥499 + + + + + + + + + 商品名称 + ¥599 + + + + + + + 商品名称 + ¥699 + + + + + + + + + 商品名称 + ¥799 + + + + + + + 商品名称 + ¥899 + + + + + + + + + 商品名称 + ¥999 + + + + + + + 商品名称 + ¥1099 + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#f1f5f9", + }, + header: { + padding: 30, + backgroundColor: "white", + }, + headerSuccess: { + width: "100%", + marginBottom: 5, + }, + headerSuccessImg: { + width: 60, + height: 60, + alignSelf: "center", + }, + headerSuccessText: { + fontSize: 20, + color: "#000000", + alignSelf: "center", + marginTop: 10, + }, + headerSuccessTextTitle: { + fontSize: 16, + color: "#000000", + alignSelf: "center", + }, + headerPriceText: { + fontSize: 20, + color: "#000000", + alignSelf: "center", + }, + headerPriceTextTitle: { + fontSize: 20, + color: "#000000", + alignSelf: "center", + marginTop: 10, + }, + headerSuccessInfo: { + width: "100%", + backgroundColor: "#f0f6ff", + borderRadius: 5, + borderWidth: 1, + borderColor: "#dafcff", + marginTop: 10, + padding: 10, + }, + headerSuccessInfoItem: { + flexDirection: "row", + fontSize: 16, + color: "#0046bf", + fontWeight: "600", + alignItems: "center", + }, + headerSuccessInfoItem1: { + flexDirection: "row", + fontSize: 16, + color: "#0046bf", + fontWeight: "600", + alignItems: "center", + marginTop: 5, + }, + headerSuccessInfoItemText: { + fontSize: 16, + color: "#0046bf", + width: "20%", + fontWeight: "600", + alignItems: "center", + }, + headerSuccessInfoItemText1: { + fontSize: 16, + color: "#0046bf", + marginLeft: 10, + fontWeight: "600", + alignItems: "center", + }, + headerSuccessInfoItem2: { + marginTop: 5, + flexDirection: "row", + }, + button: { + flex: 1, + flexDirection: "row", + justifyContent: "space-between", + paddingLeft: 20, + paddingRight: 20, + marginTop: 20, + }, + buttonItem: { + width: "40%", + height: 40, + backgroundColor: "#0030a7", + borderRadius: 20, + justifyContent: "center", + alignItems: "center", + }, + buttonText: { + fontSize: 16, + color: "white", + }, + recommend: { + padding: 20, + }, + footerItemText1: { + fontSize: 16, + color: "#000000", + fontWeight: "600", + marginBottom: 15, + }, + productContainer: { + marginTop: 10, + }, + productRow: { + flexDirection: "row", + justifyContent: "space-between", + marginBottom: 15, + }, + productItem: { + width: "48%", + backgroundColor: "white", + borderRadius: 8, + padding: 10, + }, + productImageContainer: { + alignItems: "center", + marginBottom: 8, + width: "100%", + }, + productImage: { + width: "100%", + height: 120, + backgroundColor: "#f1f5f9", + borderRadius: 4, + }, + productName: { + fontSize: 14, + color: "#333", + marginTop: 5, + marginBottom: 5, + }, + productPrice: { + fontSize: 16, + color: "#E53935", + fontWeight: "bold", + }, +}); diff --git a/app/screens/setting/MyAddress.tsx b/app/screens/setting/MyAddress.tsx new file mode 100644 index 0000000..6047126 --- /dev/null +++ b/app/screens/setting/MyAddress.tsx @@ -0,0 +1,228 @@ +import { + View, + Text, + StyleSheet, + ScrollView, + TouchableOpacity, +} from "react-native"; +import BackIcon from "../../components/BackIcon"; +import FileEditIcon from "../../components/FileEditIcon"; +import { useNavigation } from "@react-navigation/native"; +import { addressApi, AddressItem, } from "../../services/api/addressApi"; +import { useState ,useEffect,useCallback} from "react"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; +import { useFocusEffect } from '@react-navigation/native'; +import fontSize from "../../utils/fontsizeUtils"; +import widthUtils from "../../utils/widthUtils"; +export function MyAddress() { + const navigation = useNavigation>(); + const [addressList, setAddressList] = useState(); + const [address, setAddress] = useState(); + const getAddress = async () => { + const response = await addressApi.getAddress(); + setAddressList(response.items); + }; + useEffect(() => { + getAddress(); + }, []); + const deleteAddress = async (address_id: number) => { + setAddressList(addressList?.filter((item) => item.address_id !== address_id)); + addressApi.deleteAddress(address_id) + } + useFocusEffect( + useCallback(() => { + getAddress(); + }, []) + ); + + const setAddressId = (address_id: number) => { + setAddress(address_id); + } + return ( + + + navigation.goBack()}> + + + + + { + addressList?.map((item) => ( + { + setAddressId(item.address_id); + }} + > + + + + + {item.receiver_first_name} .{" "} + {item.receiver_last_name} + + + {item.receiver_phone} + + + 设置默认地址 + deleteAddress(item.address_id)} + > + 删除 + + + + {item.is_default === 1 && ( + + 默认 + + )} + + { + navigation.navigate("AddRess", { + address: item, + }); + }} + > + + + + + + + )) + } + + + navigation.navigate("AddRess")} + > + 添加新地址 + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + backgroundColor: "#f8f8f8", + }, + header: { + paddingVertical: 16, + }, + userCardContainer1: { + marginTop: 20, + }, + addressItemSelected: { + borderColor: "#002fa7", + borderWidth: 2, + }, + addressItemNoSelected: { + borderColor: "#d0d0d0", + borderWidth: 2, + }, + userCardContainer: { + flexDirection: "row", + gap: 8, + alignItems: "flex-start", + justifyContent: "space-between", + width: "100%", + paddingTop: 15, + paddingRight: 10, + paddingBottom: 10, + paddingLeft: 11, + backgroundColor: "white", + borderRadius: 5, + marginBottom: 10, + }, + userInfoCard: { + flexDirection: "row", + alignItems: "flex-start", + justifyContent: "flex-start", + flex: 1, + marginRight: 8, + }, + userCardInfo2: { + flex: 1, + marginRight: 8, + }, + userCardInfo: { + fontSize: fontSize(18), + lineHeight: 22, + fontFamily: "PingFang SC", + fontWeight: "500", + color: "black", + flex: 1, + }, + userCardInfo1: { + fontSize: fontSize(18), + lineHeight: 22, + fontFamily: "PingFang SC", + fontWeight: "500", + color: "#6b7280", + marginTop: 10, + flex: 1, + width: "100%", + }, + centeredBoxWithText: { + flexDirection: "column", + alignItems: "stretch", + justifyContent: "center", + height: 26, + paddingRight: 11, + paddingLeft: 11, + marginLeft: 8, + backgroundColor: "#edf3ff", + borderRadius: 5, + }, + blueHeadingTextStyle: { + fontSize: fontSize(13), + fontFamily: "PingFang SC", + fontWeight: "500", + color: "#002fa7", + }, + svgContainer: { + width: widthUtils(24,24).width, + height: widthUtils(24,24).height, + color: "#0051ff", + marginLeft: "auto", + }, + addressEmit: { + paddingTop: 10, + flexDirection: "row", + gap: 10, + }, + addButton: { + width: "100%", + height: widthUtils(60,60).height, + backgroundColor: "#002fa7", + justifyContent: "center", + alignItems: "center", + borderRadius: 5, + marginTop: 10, + }, + addButtonText: { + color: "white", + fontSize: fontSize(16), + fontWeight: "500", + }, +}); diff --git a/app/screens/setting/SettingList.tsx b/app/screens/setting/SettingList.tsx index 426016b..9ab3869 100644 --- a/app/screens/setting/SettingList.tsx +++ b/app/screens/setting/SettingList.tsx @@ -14,7 +14,6 @@ export const SettingList = () => { const getMySetting = async () => { const res = await settingApi.getMySetting() console.log(res); - setMySetting(res); } @@ -61,12 +60,19 @@ export const SettingList = () => { - - 我的地址 - - - - + { + if (mySetting?.language && mySetting?.currency) { + navigation.navigate("MyAddress"); + } + }} + style={styles.item} + > + 我的地址 + + + + 反馈 diff --git a/app/services/api/orders.ts b/app/services/api/orders.ts new file mode 100644 index 0000000..dc95210 --- /dev/null +++ b/app/services/api/orders.ts @@ -0,0 +1,75 @@ +import apiService from './apiClient'; + + +// 地址类型 +interface Address { + address_id: number; + user_id: number; + receiver_first_name: string; + receiver_last_name: string; + country: string; + receiver_phone: string; + whatsapp_phone: string; + province: string | null; + city: string | null; + district: string | null; + detail_address: string | null; + is_default: number; + create_time: string; + update_time: string; + } + + // 订单商品项类型 + interface OrderItem { + offer_id: number; + sku_id: number; + product_name: string; + sku_image_url: string; + product_name_en: string; + product_name_fr: string; + product_name_ar: string; + quantity: number; + unit_price: number; + total_price: number; + attributes:{ + attribute_name:string; + attribute_name_trans:string, + attribute_value:string, + attribute_value_trans:string, + value:string, + value_trans:string, + value_trans_ar:string, + value_trans_fr:string, + }[] + } + + // 订单汇总类型 + interface OrderSummary { + total_amount: number; + shipping_fee: number; + discount_amount: number; + actual_amount: number; + currency: string; + } + + // 完整订单数据类型 + export interface OrderData { + address: Address; + items: OrderItem[]; + total_amount: number; + shipping_fee: number; + discount_amount: number; + actual_amount: number; + currency: string; + } + + export interface OrderPreviewData { + "items": + { + "cart_item_id": number + }[], + } + + export const ordersApi = { + getOrders: (data:OrderPreviewData) => apiService.post("/api/orders/preview",data), + }; \ No newline at end of file diff --git a/app/services/api/userApi.ts b/app/services/api/userApi.ts index ea3282b..8446822 100644 --- a/app/services/api/userApi.ts +++ b/app/services/api/userApi.ts @@ -2,11 +2,18 @@ import apiService from './apiClient'; // 用户接口定义 export interface User { - id: string; - username: string; - email: string; - avatar?: string; - createdAt: string; + "username": string, + "email": string, + "phone": string, + "avatar_url": string, + "status": number, + "user_id": number, + "last_login": string, + "create_time": string, + "update_time": string + currency:string, + country:string, + country_en:string, } // 登录参数 @@ -61,7 +68,7 @@ export const userApi = { // 获取用户信息 getProfile: () => { - return apiService.get('/user/profile'); + return apiService.get('/api/users/me'); }, // 更新用户信息 diff --git a/assets/img/image_1c498f1f.jpeg b/assets/img/image_1c498f1f.jpeg new file mode 100644 index 0000000..89dd32b Binary files /dev/null and b/assets/img/image_1c498f1f.jpeg differ diff --git a/assets/img/image_637dba57.png b/assets/img/image_637dba57.png new file mode 100644 index 0000000..753ee5b Binary files /dev/null and b/assets/img/image_637dba57.png differ diff --git a/assets/img/image_946febdc.png b/assets/img/image_946febdc.png new file mode 100644 index 0000000..a419421 Binary files /dev/null and b/assets/img/image_946febdc.png differ diff --git a/assets/img/image_b1c2e380.jpeg b/assets/img/image_b1c2e380.jpeg new file mode 100644 index 0000000..bd11975 Binary files /dev/null and b/assets/img/image_b1c2e380.jpeg differ diff --git a/assets/img/image_d9359f45.jpeg b/assets/img/image_d9359f45.jpeg new file mode 100644 index 0000000..ca05fb6 Binary files /dev/null and b/assets/img/image_d9359f45.jpeg differ diff --git a/assets/img/image_f5a80fba.jpeg b/assets/img/image_f5a80fba.jpeg new file mode 100644 index 0000000..a23b525 Binary files /dev/null and b/assets/img/image_f5a80fba.jpeg differ