import { Image } from "expo-image"; import Alipay from "expo-native-alipay"; import { useRouter } from "expo-router"; import React, { useEffect, useState } from "react"; import { ActivityIndicator, Alert, AppState, ImageBackground, Modal, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Images } from "@/constants/images"; import { Address, getDefaultAddress } from "@/services/address"; import { takeApply, takePreview } from "@/services/award"; interface GroupedGoods { total: number; data: { id: string; cover: string; spuId: string; level: string; name?: string; }; } interface CheckoutModalProps { visible: boolean; selectedItems: Array<{ id: string; spu: { id: string; name: string; cover: string }; level: string; }>; onClose: () => void; onSuccess: () => void; } export default function CheckoutModal({ visible, selectedItems, onClose, onSuccess, }: CheckoutModalProps) { const router = useRouter(); const insets = useSafeAreaInsets(); const [loading, setLoading] = useState(false); const [submitting, setSubmitting] = useState(false); const [address, setAddress] = useState
(null); const [expressAmount, setExpressAmount] = useState(0); const [goodsList, setGoodsList] = useState([]); const [verifyLoading, setVerifyLoading] = useState(false); const showAlert = (msg: string) => { if (Platform.OS === "web") window.alert(msg); else Alert.alert("提示", msg); }; useEffect(() => { if (visible && selectedItems.length > 0) { loadData(); } }, [visible, selectedItems]); const loadData = async () => { setLoading(true); try { // 获取默认地址 const addr = await getDefaultAddress(); setAddress(addr); // 获取提货预览 const ids = selectedItems.map((item) => item.id); const res = await takePreview(ids, addr?.id || ""); if (res) { setExpressAmount(res.expressAmount || 0); } // 合并相同商品 const goodsMap: Record = {}; selectedItems.forEach((item) => { const key = `${item.spu.id}_${item.level}`; if (goodsMap[key]) { goodsMap[key].total += 1; } else { goodsMap[key] = { total: 1, data: { id: item.id, cover: item.spu.cover, spuId: item.spu.id, level: item.level, name: item.spu.name, }, }; } }); setGoodsList(Object.values(goodsMap)); } catch (e) { console.error("加载提货信息失败:", e); } setLoading(false); }; const goToAddress = () => { onClose(); router.push("/address?type=1" as any); }; /* * Handle Submit with Payment Choice */ const handleSubmit = async () => { if (!address) { showAlert("请选择收货地址"); return; } if (expressAmount > 0) { Alert.alert("支付运费", `需支付运费 ¥${expressAmount}`, [ { text: "取消", style: "cancel" }, { text: "钱包支付", onPress: () => processTakeApply("WALLET") }, { text: "支付宝支付", onPress: () => processTakeApply("ALIPAY_APP") }, ]); } else { processTakeApply("WALLET"); } }; const processTakeApply = async (paymentType: string) => { if (submitting) return; setSubmitting(true); try { const ids = selectedItems.map((item) => item.id); const res: any = await takeApply(ids, address!.id, paymentType); console.log("Take Apply Res:", res, paymentType); if (paymentType === "ALIPAY_APP" && res?.payInfo) { let appStateSub: any = null; let isResolved = false; try { if (Platform.OS === "ios") Alipay.setAlipayScheme("alipay2021005175632205"); appStateSub = AppState.addEventListener( "change", async (nextAppState) => { if (nextAppState === "active" && !isResolved) { setTimeout(async () => { if (!isResolved) { isResolved = true; setVerifyLoading(false); showAlert("支付完成正在核实"); onSuccess(); } }, 500); } }, ); const result = await Alipay.pay(res.payInfo); if (isResolved) return; isResolved = true; setVerifyLoading(false); console.log("Alipay Result:", result); if (result?.resultStatus === "9000") { showAlert("提货成功"); onSuccess(); } else { showAlert("支付未完成"); } } catch (e) { isResolved = true; setVerifyLoading(false); console.error("Alipay Error:", e); showAlert("调用支付宝失败"); } finally { setVerifyLoading(false); if (appStateSub) { appStateSub.remove(); } } } else if (res) { // Wallet payment or free success showAlert("提货成功"); onSuccess(); } } catch (e) { console.error("提货失败:", e); // Usually axios interceptor handles error alerts, but just in case // showAlert('提货失败'); } setSubmitting(false); }; return ( {/* 标题 */} 提货 × {loading ? ( ) : ( <> {/* 商品列表 */} {goodsList.map((goods, idx) => ( x{goods.total} ))} {/* 运费 */} {expressAmount > 0 && ( 运费 ¥{expressAmount} )} {/* 收货地址 */} {!address ? ( 请填写收货地址 ) : ( {address.contactName} {address.contactNo} {address.province} {address.city} {address.district} {address.address} )} {/* 提交按钮 */} {submitting ? "提交中..." : "确定发货"} )} {/* 支付结果轮询确认加载中 */} {}} > 正在确认支付结果... ); } const styles = StyleSheet.create({ verifyLoadingOverlay: { ...StyleSheet.absoluteFillObject, backgroundColor: "rgba(0,0,0,0.4)", justifyContent: "center", alignItems: "center", zIndex: 9999, }, verifyLoadingBox: { backgroundColor: "rgba(0,0,0,0.8)", padding: 20, borderRadius: 12, alignItems: "center", }, verifyLoadingText: { color: "#fff", marginTop: 10, fontSize: 14, }, overlay: { flex: 1, justifyContent: "flex-end" }, overlayBg: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0,0,0,0.5)", }, container: { backgroundColor: "#fff", borderTopLeftRadius: 15, borderTopRightRadius: 15, paddingHorizontal: 14, }, header: { flexDirection: "row", alignItems: "center", justifyContent: "center", paddingVertical: 20, position: "relative", }, title: { fontSize: 16, fontWeight: "bold", color: "#000" }, closeBtn: { position: "absolute", right: 0, top: 15, width: 24, height: 24, backgroundColor: "#ebebeb", borderRadius: 12, justifyContent: "center", alignItems: "center", }, closeBtnText: { fontSize: 18, color: "#a2a2a2", lineHeight: 20 }, loadingBox: { height: 200, justifyContent: "center", alignItems: "center" }, goodsSection: { paddingVertical: 10 }, goodsItem: { width: 79, height: 103, backgroundColor: "#fff", borderRadius: 6, marginRight: 8, alignItems: "center", justifyContent: "center", position: "relative", borderWidth: 1, borderColor: "#eaeaea", }, goodsImg: { width: 73, height: 85 }, goodsCount: { position: "absolute", top: 0, right: 0, backgroundColor: "#ff6b00", borderRadius: 2, paddingHorizontal: 4, paddingVertical: 2, }, goodsCountText: { color: "#fff", fontSize: 10, fontWeight: "bold" }, feeRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingVertical: 8, }, feeLabel: { fontSize: 14, color: "#333" }, feeValue: { fontSize: 14, color: "#ff6b00", fontWeight: "bold" }, addressSection: { flexDirection: "row", alignItems: "center", paddingVertical: 10, borderTopWidth: 1, borderTopColor: "#f0f0f0", }, noAddress: { flex: 1, fontSize: 16, fontWeight: "bold", color: "#333" }, addressInfo: { flex: 1 }, addressName: { fontSize: 14, color: "#333", fontWeight: "bold" }, addressDetail: { fontSize: 12, color: "#666", marginTop: 4 }, arrowIcon: { fontSize: 20, color: "#999", marginLeft: 10 }, submitBtn: { alignItems: "center", marginTop: 15 }, submitBtnBg: { width: 260, height: 60, justifyContent: "center", alignItems: "center", }, submitBtnText: { color: "#000", fontSize: 16, fontWeight: "bold" }, });