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" },
});