Browse Source

手机支付问题

main
unknown 2 weeks ago
parent
commit
da76833f8e
  1. 58
      app/screens/BalanceScreen/PhoneNumberInputModal.tsx
  2. 268
      app/screens/BalanceScreen/RechargeScreen.tsx
  3. 71
      app/screens/previewOrder/perviewOrder.tsx
  4. 203
      app/screens/productStatus/OrderDatails.tsx

58
app/screens/BalanceScreen/PhoneNumberInputModal.tsx

@ -32,6 +32,8 @@ interface PhoneNumberInputModalProps {
} | null;
onSubmit: (phoneNumber: string) => Promise<void>;
onCloses?: () => void;
displayCountryCode?: string;
onCountrySelect?: () => void;
}
type RootStackParamList = {
@ -44,6 +46,8 @@ const PhoneNumberInputModal = ({
paymentParams,
onSubmit,
onCloses,
displayCountryCode,
onCountrySelect,
}: PhoneNumberInputModalProps) => {
const { t } = useTranslation();
const [phoneNumber, setPhoneNumber] = useState("");
@ -69,14 +73,28 @@ const PhoneNumberInputModal = ({
const handlePaySubmit = async () => {
if (!paymentParams) return;
setIsSubmitting(true)
// 验证电话号码(对于mobile_money支付)
if (paymentParams.payment_method === "mobile_money" && !phoneNumber) {
Alert.alert("Error", t('balance.phone_modal.phone_required') || "Phone number is required");
return;
}
setIsSubmitting(true);
try {
// 如果有onSubmit函数,说明是从订单页面调用的,需要传递电话号码
if (onSubmit) {
await onSubmit(phoneNumber);
} else {
// 原来的充值逻辑
const data = {
amount: paymentParams.amount,
currency: paymentParams.currency,
payment_method: paymentParams.payment_method,
}
};
payApi.initiateRecharge(data).then((res) => {
const res = await payApi.initiateRecharge(data);
console.log(res);
// 成功后关闭所有模态窗口
@ -90,12 +108,13 @@ const PhoneNumberInputModal = ({
method: paymentParams.payment_method,
order_id: res.payment.order_id.toString(),
});
setIsSubmitting(false)
}).catch((err) => {
Alert.alert("Error", t('balance.phone_modal.payment_failed'));
setIsSubmitting(false)
})
}
} catch (error) {
console.error("Payment error:", error);
Alert.alert("Error", t('balance.phone_modal.payment_failed') || "Payment failed");
} finally {
setIsSubmitting(false);
}
};
return (
@ -173,9 +192,15 @@ const PhoneNumberInputModal = ({
{t('balance.phone_modal.phone_number')}
</Text>
<View style={styles.phoneInputWrapper}>
<View style={styles.countryCodeContainer}>
<Text style={styles.countryCodeText}>+89</Text>
</View>
<TouchableOpacity
style={styles.countryCodeContainer}
onPress={onCountrySelect}
>
<Text style={styles.countryCodeText}>
{displayCountryCode || '+243'}
</Text>
<Text style={styles.countryCodeArrow}></Text>
</TouchableOpacity>
<TextInput
style={styles.phoneInput}
value={phoneNumber}
@ -213,10 +238,10 @@ const PhoneNumberInputModal = ({
<TouchableOpacity
style={[
styles.payButton,
isSubmitting && styles.payButtonDisabled,
(isSubmitting || (paymentParams?.payment_method === "mobile_money" && !phoneNumber)) && styles.payButtonDisabled,
]}
onPress={handlePaySubmit}
disabled={isSubmitting}
disabled={isSubmitting || (paymentParams?.payment_method === "mobile_money" && !phoneNumber)}
>
{isSubmitting ? (
<ActivityIndicator size="small" color="#fff" />
@ -350,6 +375,11 @@ const styles = StyleSheet.create({
fontSize: fontSize(16),
color: "#333",
},
countryCodeArrow: {
fontSize: fontSize(12),
color: "#999",
marginLeft: 5,
},
phoneInput: {
flex: 1,
height: 50,

268
app/screens/BalanceScreen/RechargeScreen.tsx

@ -11,6 +11,8 @@ import {
ActivityIndicator,
Alert,
TextInput,
Modal,
FlatList,
} from "react-native";
import fontSize from "../../utils/fontsizeUtils";
import widthUtils from "../../utils/widthUtils";
@ -20,15 +22,27 @@ import CheckIcon from "../../components/CheckIcon";
import PhoneNumberInputModal from "./PhoneNumberInputModal";
import useUserStore from "../../store/user";
// 添加导航相关导入
import { useNavigation } from "@react-navigation/native";
import { useNavigation, CommonActions } from "@react-navigation/native";
// 添加API服务
import {
payApi,
RechargeRecommendAmountResponse,
PaymentMethod,
} from "../../services/api/payApi";
import { settingApi } from "../../services/api/setting";
import payMap from "../../utils/payMap";
import { useTranslation } from "react-i18next";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { CountryList } from "../../constants/countries";
// 定义本地存储的国家数据类型
interface LocalCountryData {
code: string;
flag: string;
name: string;
phoneCode: string;
userCount: number;
}
interface RechargeScreenProps {
onClose: () => void;
@ -75,6 +89,13 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
// 添加Wave展开视图的状态
const [isWaveExpanded, setIsWaveExpanded] = useState(false);
// 添加国家选择相关状态
const [countryList, setCountryList] = useState<CountryList[]>([]);
const [selectedCountry, setSelectedCountry] = useState<CountryList | null>(null);
const [localSelectedCountry, setLocalSelectedCountry] = useState<LocalCountryData | null>(null);
const [showCountryModal, setShowCountryModal] = useState(false);
const [loadingCountries, setLoadingCountries] = useState(false);
useEffect(() => {
payApi.getRechargeRecommendAmount().then((res) => {
setRecommendedAmounts(res);
@ -92,6 +113,86 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
});
}, []);
// 获取国家列表
const loadCountryList = async () => {
setLoadingCountries(true);
try {
// 首先尝试读取本地存储的国家数据
const savedLocalCountry = await AsyncStorage.getItem("@selected_country");
if (savedLocalCountry) {
try {
const parsedLocalCountry: LocalCountryData = JSON.parse(savedLocalCountry);
setLocalSelectedCountry(parsedLocalCountry);
console.log('使用本地存储的国家:', parsedLocalCountry);
} catch (e) {
console.error("解析本地存储国家数据失败:", e);
}
}
const response = await settingApi.getSendSmsCountryList();
if (response && Array.isArray(response)) {
setCountryList(response);
// 如果没有本地存储的国家,则使用API返回的数据进行匹配
if (!savedLocalCountry) {
// 如果用户有国家信息,自动选择对应的国家
if (user?.country_en) {
const userCountry = response.find((country: CountryList) =>
country.name_en.toLowerCase() === user.country_en.toLowerCase()
);
if (userCountry) {
setSelectedCountry(userCountry);
}
}
}
}
} catch (error) {
console.error('获取国家列表失败:', error);
} finally {
setLoadingCountries(false);
}
};
// 格式化电话号码
const formatPhoneNumber = (phone: string, localCountry: LocalCountryData | null, apiCountry: CountryList | null): string => {
if (!phone) return phone;
// 移除电话号码中的空格、破折号等
const cleanPhone = phone.replace(/[\s\-\(\)]/g, '');
// 如果已经有+号开头,直接返回
if (cleanPhone.startsWith('+')) {
return cleanPhone;
}
// 优先使用本地存储的国家数据的 phoneCode
let countryCode = '';
if (localCountry?.phoneCode) {
countryCode = localCountry.phoneCode;
} else if (apiCountry?.country) {
countryCode = `+${apiCountry.country}`;
} else {
return phone; // 如果都没有,返回原始电话号码
}
// 如果电话号码以0开头,移除0
const phoneWithoutLeadingZero = cleanPhone.startsWith('0') ? cleanPhone.substring(1) : cleanPhone;
return `${countryCode}${phoneWithoutLeadingZero}`;
};
// 获取显示的国家代码
const getDisplayCountryCode = () => {
if (loadingCountries) return "...";
if (localSelectedCountry?.phoneCode) {
return localSelectedCountry.phoneCode;
}
if (selectedCountry?.country) {
return `+${selectedCountry.country}`;
}
return '+243'; // 默认值,刚果民主共和国
};
const handlePriceSelect = (price: string) => {
setSelectedPrice(price);
setShowCustomAmountInput(false);
@ -170,6 +271,11 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
handleCurrencyConversion(amountToConvert, "FCFA");
}
}
// 如果是mobile_money,先加载国家列表
else if (selectedMethod.key === "mobile_money") {
// 先加载国家列表
loadCountryList();
}
} else if (operator === "currency" && operator !== selectedOperator) {
// 旧的逻辑保留作为备用
handleCurrencySelect("USD");
@ -276,6 +382,11 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
// selectedPriceLabel 保持显示原始美元金额
// params.selectedPriceLabel 已经在上面设置为原始金额,不需要修改
}
// 如果是mobile_money,先加载国家列表
else if (selectedMethod.key === "mobile_money") {
// 先加载国家列表
loadCountryList();
}
} else if (selectedOperator === "balance") {
params.payment_method = "Balance";
} else if (selectedOperator === "currency") {
@ -413,7 +524,7 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
}
// 验证电话号码(添加更严格的验证)
if (!phoneNumber || phoneNumber.length < 8) {
if (paymentParams.payment_method === "mobile_money" && (!phoneNumber || phoneNumber.length < 8)) {
Alert.alert(
"Erreur",
"Veuillez entrer un numéro de téléphone valide (au moins 8 chiffres)"
@ -425,38 +536,75 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
setIsSubmitting(true);
try {
// 准备请求数据,添加电话号码
const rechargeData = {
// 格式化电话号码,添加国家前缀(仅对mobile_money支付)
let formattedPhone = phoneNumber;
if (paymentParams.payment_method === "mobile_money") {
formattedPhone = formatPhoneNumber(phoneNumber, localSelectedCountry, selectedCountry);
console.log('发送的电话号码:', formattedPhone);
}
// 准备请求数据
const rechargeData: any = {
amount: paymentParams.amount,
currency: paymentParams.currency,
payment_method: paymentParams.payment_method,
phone: phoneNumber,
};
// 如果是mobile_money支付,添加extra字段
if (paymentParams.payment_method === "mobile_money") {
rechargeData.extra = {
phone_number: formattedPhone
};
}
console.log("Submitting recharge request:", rechargeData);
// 调用充值接口(使用可选链避免错误)
// 调用充值接口
const response = await payApi.initiateRecharge(rechargeData);
if (response && response.success) {
const paymentInfo = response.payment;
// 检查是否有支付URL
if (paymentInfo && paymentInfo.payment_url) {
// 关闭模态框
setShowPhoneModal(false);
onClose();
// 打开支付页面
// 检查是否有支付URL
if (paymentInfo && paymentInfo.payment_url) {
// 有支付URL,跳转到支付页面
setTimeout(() => {
navigation.navigate("Pay", {
payUrl: paymentInfo.payment_url,
method: paymentParams.payment_method,
order_id: paymentInfo.order_id?.toString() || "",
});
}, 1000);
}, 500);
} else {
// 没有支付URL,说明支付已完成,跳转到成功页面或主页
Alert.alert("Succès", "Votre recharge a été traitée avec succès!", [
{
text: "OK",
onPress: () => {
setShowPhoneModal(false);
onClose();
// 跳转到主页或余额页面
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'MainTabs',
state: {
routes: [
{ name: 'Home' },
{ name: 'productCollection' },
{ name: 'Chat' },
{ name: 'Cart' },
{ name: 'Profile' },
],
index: 4, // Profile tab 的索引
},
},
],
})
);
},
},
]);
@ -1033,7 +1181,57 @@ const RechargeScreen = ({ onClose }: RechargeScreenProps) => {
paymentParams={paymentParams}
onSubmit={handlePaySubmit}
onCloses={onClose}
displayCountryCode={getDisplayCountryCode()}
onCountrySelect={() => setShowCountryModal(true)}
/>
{/* 国家选择模态框 */}
<Modal
visible={showCountryModal}
animationType="slide"
transparent={true}
onRequestClose={() => setShowCountryModal(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}></Text>
<TouchableOpacity
onPress={() => setShowCountryModal(false)}
style={styles.closeButtonContainer}
>
<Text style={styles.closeButtonText}></Text>
</TouchableOpacity>
</View>
<FlatList
data={countryList}
keyExtractor={(item) => item.country.toString()}
renderItem={({ item }) => (
<TouchableOpacity
style={[
styles.countryItem,
selectedCountry?.country === item.country && styles.currencyButtonActive
]}
onPress={() => {
setSelectedCountry(item);
setLocalSelectedCountry(null); // 清除本地存储的选择,使用API的数据
setShowCountryModal(false);
}}
>
<Text style={[
styles.countryItemText,
selectedCountry?.country === item.country && styles.currencyButtonTextActive
]}>
{item.name_en} (+{item.country})
</Text>
</TouchableOpacity>
)}
style={styles.countryList}
/>
</View>
</View>
</Modal>
</SafeAreaView>
);
};
@ -1930,6 +2128,52 @@ const styles = StyleSheet.create({
marginTop: 5,
textAlign: "center",
},
modalOverlay: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.5)",
},
modalContent: {
backgroundColor: "white",
padding: 20,
borderRadius: 10,
width: "80%",
maxHeight: "80%",
},
modalHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 20,
},
modalTitle: {
fontSize: 18,
fontWeight: "700",
color: "black",
},
closeButtonContainer: {
padding: 5,
},
closeButtonText: {
fontSize: 16,
fontWeight: "700",
color: "#007AFF",
},
countryItem: {
padding: 10,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 5,
},
countryItemText: {
fontSize: 16,
fontWeight: "500",
color: "#333",
},
countryList: {
flex: 1,
},
});
export default RechargeScreen;

71
app/screens/previewOrder/perviewOrder.tsx

@ -35,6 +35,16 @@ import { useTranslation } from "react-i18next";
import fontSize from "../../utils/fontsizeUtils";
import { getBurialPointData } from "../../store/burialPoint";
import useBurialPointStore from "../../store/burialPoint";
import AsyncStorage from "@react-native-async-storage/async-storage";
// 定义本地存储的国家数据类型
interface LocalCountryData {
code: string;
flag: string;
name: string;
phoneCode: string;
userCount: number;
}
// Define the param list for navigation
type RootStackParamList = {
@ -58,6 +68,7 @@ export const PreviewOrder = () => {
const [showPhoneInput, setShowPhoneInput] = useState(false);
const [countryList, setCountryList] = useState<CountryList[]>([]);
const [selectedCountry, setSelectedCountry] = useState<CountryList | null>(null);
const [localSelectedCountry, setLocalSelectedCountry] = useState<LocalCountryData | null>(null);
const [showCountryModal, setShowCountryModal] = useState(false);
const [loadingCountries, setLoadingCountries] = useState(false);
const route = useRoute<RouteProp<RootStackParamList, "PreviewOrder">>();
@ -65,6 +76,7 @@ export const PreviewOrder = () => {
const { user } = useUserStore();
const { t } = useTranslation();
const { logPreviewOrder } = useBurialPointStore();
useEffect(() => {
if (!user.user_id) {
return Alert.alert(t("order.preview.login_required"));
@ -82,9 +94,24 @@ export const PreviewOrder = () => {
const loadCountryList = async () => {
setLoadingCountries(true);
try {
// 首先尝试读取本地存储的国家数据
const savedLocalCountry = await AsyncStorage.getItem("@selected_country");
if (savedLocalCountry) {
try {
const parsedLocalCountry: LocalCountryData = JSON.parse(savedLocalCountry);
setLocalSelectedCountry(parsedLocalCountry);
console.log('使用本地存储的国家:', parsedLocalCountry);
} catch (e) {
console.error("解析本地存储国家数据失败:", e);
}
}
const response = await settingApi.getSendSmsCountryList();
if (response && Array.isArray(response)) {
setCountryList(response);
// 如果没有本地存储的国家,则使用API返回的数据进行匹配
if (!savedLocalCountry) {
// 如果用户有国家信息,自动选择对应的国家
if (user?.country_en) {
const userCountry = response.find((country: CountryList) =>
@ -95,6 +122,7 @@ export const PreviewOrder = () => {
}
}
}
}
} catch (error) {
console.error('获取国家列表失败:', error);
} finally {
@ -103,8 +131,8 @@ export const PreviewOrder = () => {
};
// 格式化电话号码
const formatPhoneNumber = (phone: string, country: CountryList | null): string => {
if (!phone || !country) return phone;
const formatPhoneNumber = (phone: string, localCountry: LocalCountryData | null, apiCountry: CountryList | null): string => {
if (!phone) return phone;
// 移除电话号码中的空格、破折号等
const cleanPhone = phone.replace(/[\s\-\(\)]/g, '');
@ -114,8 +142,15 @@ export const PreviewOrder = () => {
return cleanPhone;
}
// 使用 country 字段作为国家代码
const countryCode = `+${country.country}`;
// 优先使用本地存储的国家数据的 phoneCode
let countryCode = '';
if (localCountry?.phoneCode) {
countryCode = localCountry.phoneCode;
} else if (apiCountry?.country) {
countryCode = `+${apiCountry.country}`;
} else {
return phone; // 如果都没有,返回原始电话号码
}
// 如果电话号码以0开头,移除0
const phoneWithoutLeadingZero = cleanPhone.startsWith('0') ? cleanPhone.substring(1) : cleanPhone;
@ -146,7 +181,7 @@ export const PreviewOrder = () => {
return;
}
if (showPhoneInput && !selectedCountry) {
if (showPhoneInput && !localSelectedCountry && !selectedCountry) {
Alert.alert(t("error"), "请选择国家");
return;
}
@ -155,7 +190,7 @@ export const PreviewOrder = () => {
// 格式化电话号码,添加国家前缀
const formattedPhone = showPhoneInput && phoneNumber
? formatPhoneNumber(phoneNumber, selectedCountry)
? formatPhoneNumber(phoneNumber, localSelectedCountry, selectedCountry)
: '';
const data = {
@ -223,6 +258,18 @@ export const PreviewOrder = () => {
});
};
// 获取显示的国家代码
const getDisplayCountryCode = () => {
if (loadingCountries) return "...";
if (localSelectedCountry?.phoneCode) {
return localSelectedCountry.phoneCode;
}
if (selectedCountry?.country) {
return `+${selectedCountry.country}`;
}
return '+86'; // 默认值
};
return (
<SafeAreaView style={[styles.safeArea]}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
@ -268,12 +315,7 @@ export const PreviewOrder = () => {
disabled={loadingCountries}
>
<Text style={styles.countryCodeText}>
{loadingCountries
? "..."
: selectedCountry
? `+${selectedCountry.country}`
: '+86'
}
{getDisplayCountryCode()}
</Text>
<Text style={styles.countryCodeArrow}></Text>
</TouchableOpacity>
@ -386,12 +428,12 @@ export const PreviewOrder = () => {
<TouchableOpacity
style={[
styles.primaryButtonStyle,
(!showPhoneInput || (showPhoneInput && phoneNumber && selectedCountry)) && !loading
(!showPhoneInput || (showPhoneInput && phoneNumber && (localSelectedCountry || selectedCountry))) && !loading
? {}
: styles.disabledButtonStyle,
]}
onPress={handleSubmit}
disabled={(showPhoneInput && (!phoneNumber || !selectedCountry)) || loading}
disabled={(showPhoneInput && (!phoneNumber || (!localSelectedCountry && !selectedCountry))) || loading}
>
{loading ? (
<ActivityIndicator size="small" color="#ffffff" />
@ -435,6 +477,7 @@ export const PreviewOrder = () => {
]}
onPress={() => {
setSelectedCountry(item);
setLocalSelectedCountry(null); // 清除本地存储的选择,使用API的数据
setShowCountryModal(false);
}}
>

203
app/screens/productStatus/OrderDatails.tsx

@ -17,12 +17,13 @@ import {
TextStyle,
ImageStyle,
StyleProp,
FlatList,
} from "react-native";
import { useTranslation } from "react-i18next";
import BackIcon from "../../components/BackIcon";
import MassageIcon from "../../components/MassageIcon";
import fontSize from "../../utils/fontsizeUtils";
import { useNavigation } from "@react-navigation/native";
import { useNavigation, CommonActions } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useRoute, RouteProp } from "@react-navigation/native";
import {
@ -31,6 +32,7 @@ import {
OrderItemDetails,
} from "../../services/api/orders";
import { payApi, PaymentMethod } from "../../services/api/payApi";
import { settingApi } from "../../services/api/setting";
import useUserStore from "../../store/user";
import OrderIcon from "../../components/OrderIcon";
import InfoIcon from "../../components/InfoIcon";
@ -50,6 +52,18 @@ import payMap from "../../utils/payMap";
import PhoneNumberInputModal from "../../screens/BalanceScreen/PhoneNumberInputModal";
import { cartApi } from "../../services/api/cart";
import IconComponent from "../../components/IconComponent";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { CountryList } from "../../constants/countries";
// 定义本地存储的国家数据类型
interface LocalCountryData {
code: string;
flag: string;
name: string;
phoneCode: string;
userCount: number;
}
// 定义选项类型
interface PaymentOption {
id: string;
@ -244,6 +258,13 @@ export const OrderDetails = () => {
const [showCancelModal, setShowCancelModal] = useState(false);
const [isCancelling, setIsCancelling] = useState(false);
// 添加国家选择相关状态
const [countryList, setCountryList] = useState<CountryList[]>([]);
const [selectedCountry, setSelectedCountry] = useState<CountryList | null>(null);
const [localSelectedCountry, setLocalSelectedCountry] = useState<LocalCountryData | null>(null);
const [showCountryModal, setShowCountryModal] = useState(false);
const [loadingCountries, setLoadingCountries] = useState(false);
const getOrderDetails = async () => {
try {
setIsLoading(true);
@ -256,6 +277,86 @@ export const OrderDetails = () => {
}
};
// 获取国家列表
const loadCountryList = async () => {
setLoadingCountries(true);
try {
// 首先尝试读取本地存储的国家数据
const savedLocalCountry = await AsyncStorage.getItem("@selected_country");
if (savedLocalCountry) {
try {
const parsedLocalCountry: LocalCountryData = JSON.parse(savedLocalCountry);
setLocalSelectedCountry(parsedLocalCountry);
console.log('使用本地存储的国家:', parsedLocalCountry);
} catch (e) {
console.error("解析本地存储国家数据失败:", e);
}
}
const response = await settingApi.getSendSmsCountryList();
if (response && Array.isArray(response)) {
setCountryList(response);
// 如果没有本地存储的国家,则使用API返回的数据进行匹配
if (!savedLocalCountry) {
// 如果用户有国家信息,自动选择对应的国家
if (user?.country_en) {
const userCountry = response.find((country: CountryList) =>
country.name_en.toLowerCase() === user.country_en.toLowerCase()
);
if (userCountry) {
setSelectedCountry(userCountry);
}
}
}
}
} catch (error) {
console.error('获取国家列表失败:', error);
} finally {
setLoadingCountries(false);
}
};
// 格式化电话号码
const formatPhoneNumber = (phone: string, localCountry: LocalCountryData | null, apiCountry: CountryList | null): string => {
if (!phone) return phone;
// 移除电话号码中的空格、破折号等
const cleanPhone = phone.replace(/[\s\-\(\)]/g, '');
// 如果已经有+号开头,直接返回
if (cleanPhone.startsWith('+')) {
return cleanPhone;
}
// 优先使用本地存储的国家数据的 phoneCode
let countryCode = '';
if (localCountry?.phoneCode) {
countryCode = localCountry.phoneCode;
} else if (apiCountry?.country) {
countryCode = `+${apiCountry.country}`;
} else {
return phone; // 如果都没有,返回原始电话号码
}
// 如果电话号码以0开头,移除0
const phoneWithoutLeadingZero = cleanPhone.startsWith('0') ? cleanPhone.substring(1) : cleanPhone;
return `${countryCode}${phoneWithoutLeadingZero}`;
};
// 获取显示的国家代码
const getDisplayCountryCode = () => {
if (loadingCountries) return "...";
if (localSelectedCountry?.phoneCode) {
return localSelectedCountry.phoneCode;
}
if (selectedCountry?.country) {
return `+${selectedCountry.country}`;
}
return '+243'; // 默认值,刚果民主共和国
};
useEffect(() => {
getOrderDetails();
@ -399,6 +500,9 @@ export const OrderDetails = () => {
// 如果是mobile_money支付方式,显示电话号码输入模态框
if (selectedPayment === "mobile_money") {
// 先加载国家列表
await loadCountryList();
// 准备支付参数
const params = {
originalAmount: orderDetails.total_amount,
@ -514,9 +618,19 @@ export const OrderDetails = () => {
return;
}
// 验证国家选择
if (!localSelectedCountry && !selectedCountry) {
Alert.alert(t("error"), "请选择国家");
return;
}
setIsPaymentLoading(true);
try {
// 格式化电话号码,添加国家前缀
const formattedPhone = formatPhoneNumber(phoneNumber, localSelectedCountry, selectedCountry);
console.log('发送的电话号码:', formattedPhone);
// 准备请求数据
const paymentData = {
order_id: orderDetails?.order_id || "",
@ -526,7 +640,6 @@ export const OrderDetails = () => {
actual_amount: paymentParams.amount,
shipping_fee: 0,
domestic_shipping_fee: 0,
phone: phoneNumber,
};
// 更新订单支付方式
@ -538,19 +651,35 @@ export const OrderDetails = () => {
method: paymentParams.payment_method,
currency: paymentParams.currency,
amount: paymentParams.amount,
phone: phoneNumber,
extra: { phone_number: formattedPhone },
};
const response = await payApi.getPayInfo(payData);
if (response.success) {
setShowPhoneModal(false);
setShowPaymentModal(false);
// 打开支付页面
navigation.navigate("Pay", {
payUrl: response.payment_url,
method: paymentParams.payment_method,
order_id: orderDetails?.order_id || "",
});
// 支付成功后跳转到 ProfileScreen
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'MainTabs',
state: {
routes: [
{ name: 'Home' },
{ name: 'productCollection' },
{ name: 'Chat' },
{ name: 'Cart' },
{ name: 'Profile' },
],
index: 4, // Profile tab 的索引
},
},
],
})
);
} else {
Alert.alert(t("error"), t("order.error.payment_update"));
}
@ -801,7 +930,7 @@ export const OrderDetails = () => {
<View style={styles.recipientPhoneContainer}>
<PhoneIcon size={16} color="#3D3D3D" />
<Text style={styles.recipientPhone}>
{orderDetails.receiver_phone}
{formatPhoneNumber(orderDetails.receiver_phone, localSelectedCountry, selectedCountry)}
</Text>
</View>
</View>
@ -811,7 +940,7 @@ export const OrderDetails = () => {
<WhatsAppIcon size={16} />
<Text style={styles.recipientPhone}>WhatsApp:</Text>
<Text style={styles.recipientPhone}>
{orderDetails.receiver_phone}
{formatPhoneNumber(orderDetails.receiver_phone, localSelectedCountry, selectedCountry)}
</Text>
</View>
</View>
@ -972,7 +1101,7 @@ export const OrderDetails = () => {
<TouchableOpacity
style={styles.bottomButton1}
onPress={() => {
callPhone(orderDetails.whatsapp_number);
callPhone(formatPhoneNumber(orderDetails.receiver_phone, localSelectedCountry, selectedCountry));
}}
>
<Text style={styles.bottomButtonText1}>
@ -1445,8 +1574,58 @@ export const OrderDetails = () => {
paymentParams={paymentParams}
onSubmit={handlePhoneSubmit}
onCloses={() => setShowPaymentModal(false)}
displayCountryCode={getDisplayCountryCode()}
onCountrySelect={() => setShowCountryModal(true)}
/>
{/* 国家选择模态框 */}
<Modal
visible={showCountryModal}
animationType="slide"
transparent={true}
onRequestClose={() => setShowCountryModal(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}></Text>
<TouchableOpacity
onPress={() => setShowCountryModal(false)}
style={styles.closeButtonContainer}
>
<Text style={styles.closeButtonText}></Text>
</TouchableOpacity>
</View>
<FlatList
data={countryList}
keyExtractor={(item) => item.country.toString()}
renderItem={({ item }) => (
<TouchableOpacity
style={[
styles.cardContainer,
selectedCountry?.country === item.country && styles.currencyButtonActive
]}
onPress={() => {
setSelectedCountry(item);
setLocalSelectedCountry(null); // 清除本地存储的选择,使用API的数据
setShowCountryModal(false);
}}
>
<Text style={[
styles.buttonTextDark,
selectedCountry?.country === item.country && styles.currencyButtonTextActive
]}>
{item.name_en} (+{item.country})
</Text>
</TouchableOpacity>
)}
style={styles.paymentOptions}
/>
</View>
</View>
</Modal>
{/* 取消订单确认弹窗 */}
<Modal
visible={showCancelModal}

Loading…
Cancel
Save