| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- import { Image } from 'expo-image';
- import { useRouter } from 'expo-router';
- import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
- import {
- ActivityIndicator,
- Alert,
- Dimensions,
- Modal,
- ScrollView,
- StyleSheet,
- Text,
- TouchableOpacity,
- View
- } from 'react-native';
- import { applyOrder, getApplyResult, previewOrder } from '@/services/award';
- import Alipay from 'expo-native-alipay';
- import { LotteryResultModal, LotteryResultModalRef } from './LotteryResultModal';
- const { width: SCREEN_WIDTH } = Dimensions.get('window');
- // 等级配置
- const LEVEL_MAP: Record<string, { title: string; color: string }> = {
- A: { title: '超神款', color: '#FF4444' },
- B: { title: '欧皇款', color: '#FF9600' },
- C: { title: '隐藏款', color: '#9B59B6' },
- D: { title: '普通款', color: '#666666' },
- };
- interface CheckoutModalProps {
- data: any;
- poolId: string;
- onSuccess: (param: { num: number; tradeNo: string }) => void;
- boxNumber?: string;
- }
- export interface CheckoutModalRef {
- show: (num: number, preview: any, boxNum?: string, seatNumbers?: number[], packFlag?: boolean) => void;
- showFreedom: () => void;
- close: () => void;
- }
- interface LotteryItem {
- id: string;
- name: string;
- cover: string;
- level: string;
- spu?: { marketPrice: number };
- }
- // 自由购买数量选项
- const FREEDOM_NUMS = [10, 20, 30, 40, 50];
- export const CheckoutModal = forwardRef<CheckoutModalRef, CheckoutModalProps>(
- ({ data, poolId, onSuccess, boxNumber }, ref) => {
- const router = useRouter();
- const lotteryResultRef = useRef<LotteryResultModalRef>(null);
- const [visible, setVisible] = useState(false);
- const [num, setNum] = useState(1);
- const [checked, setChecked] = useState(true);
- const [loading, setLoading] = useState(false);
- const [freedomNum, setFreedomNum] = useState(10);
- const [freedomSelectVisible, setFreedomSelectVisible] = useState(false);
- // 预览数据
- const [coin, setCoin] = useState<number | null>(null);
- const [couponAmount, setCouponAmount] = useState<number | null>(null);
- const [lastPrice, setLastPrice] = useState<number | null>(null);
- const [magic, setMagic] = useState<any>(null);
- const [cash, setCash] = useState<any>(null);
- const [cashChecked, setCashChecked] = useState(false);
- // 盒子相关
- const [boxNum, setBoxNum] = useState<string | undefined>(boxNumber);
- const [seatNumbers, setSeatNumbers] = useState<number[] | undefined>();
- const [packFlag, setPackFlag] = useState<boolean | undefined>();
- // 抽奖结果
- const [resultVisible, setResultVisible] = useState(false);
- const [resultLoading, setResultLoading] = useState(false);
- const [resultList, setResultList] = useState<LotteryItem[]>([]);
- // 设置预览数据
- const setPreviewData = (previewData: any) => {
- setCoin(previewData.magicAmount || null);
- setCouponAmount(previewData.couponAmount || null);
- setLastPrice(previewData.paymentAmount);
- setMagic(previewData.magic || null);
- if (previewData.cash && previewData.cash.balance > previewData.paymentAmount) {
- setCash(previewData.cash);
- setCashChecked(true);
- } else {
- setCash(previewData.cash || null);
- setCashChecked(false);
- }
- };
- // ... (Imports handled via separate edit or assume existing)
-
- const [payConfig, setPayConfig] = useState<any>(null);
- const [paymentMethod, setPaymentMethod] = useState<'ALIPAY' | 'WXPAY'>('ALIPAY');
-
- // ...
- useImperativeHandle(ref, () => ({
- show: (n: number, previewData: any = {}, bNum?: string, seats?: number[], pack?: boolean) => {
- setNum(n);
- setBoxNum(bNum);
- setSeatNumbers(seats);
- setPackFlag(pack || undefined);
- setPreviewData(previewData);
- setVisible(true);
- fetchPayConfig();
- },
- showFreedom: () => {
- setFreedomNum(10);
- setFreedomSelectVisible(true);
- },
- close: () => {
- setVisible(false);
- setFreedomSelectVisible(false);
- setResultVisible(false);
- },
- }));
- const handleFreedomSelect = async (selectedNum: number) => {
- setFreedomSelectVisible(false);
- setLoading(true);
- try {
- const preview = await previewOrder(poolId, selectedNum);
- if (preview) {
- setNum(selectedNum);
- setFreedomNum(selectedNum);
- setPreviewData(preview);
- setVisible(true);
- fetchPayConfig();
- }
- } catch (error: any) {
- Alert.alert('提示', error?.message || '获取订单信息失败');
- } finally {
- setLoading(false);
- }
- };
- const close = () => {
- setVisible(false);
- setFreedomSelectVisible(false);
- };
- const closeResult = () => {
- setResultVisible(false);
- setResultList([]);
- onSuccess({ tradeNo: '', num });
- };
- const fetchPayConfig = async () => {
- try {
- const res = await import('@/services/user').then(m => m.getParamConfig('wxpay_alipay'));
- if (res && res.data) {
- setPayConfig(JSON.parse(res.data));
- }
- } catch (e) {
- console.log('Fetch Pay Config Error', e);
- }
- };
-
- // ...
- const pay = async () => {
- if (loading) return;
- if (!checked) {
- Alert.alert('提示', '请同意《宝箱服务协议》');
- return;
- }
- setLoading(true);
- try {
- let paymentType = '';
-
- // Prioritize Wallet if checked
- if (cashChecked) {
- paymentType = 'WALLET';
- } else if (paymentMethod === 'ALIPAY') {
- // APP端固定使用 ALIPAY_APP,忽略后端配置的 CUSTOMER_SERVICE_LINK
- paymentType = 'ALIPAY_APP';
- } else {
- // 微信支付也固定使用 WXPAY_APP
- paymentType = 'WXPAY_APP';
- }
- const payNum = packFlag ? 1 : num;
- console.log('Submit Order Params:', {
- poolId,
- quantity: payNum,
- paymentType,
- boxNum,
- seatNumbers,
- packFlag,
- payConfig
- });
- const res = await applyOrder(poolId, payNum, paymentType, boxNum, seatNumbers, packFlag);
-
- console.log('Apply Order Result:', res);
- if (!res) {
- Alert.alert('提示', '订单创建失败');
- return;
- }
- if (res.paySuccess) {
- // Direct Success (Wallet)
- handleSuccess(res.bizTradeNo || res.tradeNo);
- } else if (res.payInfo) {
- // Handle Native Payment
- handleNativePay(res.payInfo, paymentType, res.bizTradeNo || res.tradeNo);
- } else {
- Alert.alert('提示', res?.message || '支付失败,请重试');
- }
- } catch (error: any) {
- Alert.alert('支付失败', error?.message || '请稍后重试');
- } finally {
- setLoading(false);
- }
- };
- const handleSuccess = (tradeNo: string) => {
- setVisible(false);
- router.push({
- pathname: '/lottery' as any,
- params: { tradeNo, num, poolId }
- });
- onSuccess({ tradeNo, num });
- };
- const handleNativePay = async (payInfo: string, type: string, tradeNo: string) => {
- if (type === 'ALIPAY' || type.includes('ALIPAY')) {
- try {
- // 设置支付宝 URL Scheme(用于支付完成后返回APP)
- Alipay.setAlipayScheme('alipay2021004126636720');
-
- // 使用 expo-native-alipay 调用支付宝
- const result = await Alipay.pay(payInfo);
- console.log('Alipay Result:', result);
-
- // resultStatus: '9000' 表示支付成功
- const status = result?.resultStatus;
-
- if (status === '9000') {
- // 支付成功,跳转到抽奖页面
- handleSuccess(tradeNo);
- } else if (status === '6001') {
- Alert.alert('提示', '用户取消支付');
- } else {
- Alert.alert('支付中断', `状态码: ${status}`);
- }
- } catch (e: any) {
- console.log('Alipay Error:', e);
- Alert.alert('支付异常', e.message || '调用支付宝失败');
- }
- } else {
- Alert.alert('提示', '微信支付暂未实现');
- }
- };
- // 获取抽奖结果(10发以下用弹窗)
- const fetchLotteryResult = async (tradeNo: string) => {
- setResultLoading(true);
- setResultVisible(true);
- setResultList([]);
- let attempts = 0;
- const maxAttempts = 5;
- const poll = async () => {
- try {
- const res = await getApplyResult(tradeNo);
- if (res?.inventoryList && res.inventoryList.length > 0) {
- setResultList(res.inventoryList);
- setResultLoading(false);
- // 不在这里调用 onSuccess,等用户关闭弹窗时再调用
- } else if (attempts < maxAttempts) {
- attempts++;
- setTimeout(poll, 1000);
- } else {
- setResultLoading(false);
- Alert.alert('提示', '获取结果超时,请在仓库中查看');
- }
- } catch {
- if (attempts < maxAttempts) {
- attempts++;
- setTimeout(poll, 1000);
- } else {
- setResultLoading(false);
- Alert.alert('提示', '获取结果失败,请在仓库中查看');
- }
- }
- };
- poll();
- };
- const displayPrice = lastPrice ?? (data?.price || 0) * num;
- return (
- <>
- {/* 10发以上的全屏抽奖结果弹窗 */}
- <LotteryResultModal
- ref={lotteryResultRef}
- onClose={() => {
- // 抽奖结果弹窗关闭后刷新数据
- onSuccess({ tradeNo: '', num });
- }}
- onGoStore={() => {
- onSuccess({ tradeNo: '', num });
- router.replace('/store' as any);
- }}
- />
- {/* 自由购买数量选择弹窗 */}
- <Modal visible={freedomSelectVisible} transparent animationType="fade" onRequestClose={() => setFreedomSelectVisible(false)}>
- <View style={styles.overlay}>
- <TouchableOpacity style={styles.mask} activeOpacity={1} onPress={() => setFreedomSelectVisible(false)} />
- <View style={styles.freedomContainer}>
- <View style={styles.header}>
- <Text style={styles.title}>购买多盒</Text>
- <TouchableOpacity onPress={() => setFreedomSelectVisible(false)} style={styles.closeBtn}>
- <Text style={styles.closeText}>×</Text>
- </TouchableOpacity>
- </View>
- <View style={styles.freedomContent}>
- <View style={styles.freedomBtnList}>
- {FREEDOM_NUMS.map((item) => (
- <TouchableOpacity
- key={item}
- style={[styles.freedomBtn, freedomNum === item && styles.freedomBtnActive]}
- onPress={() => setFreedomNum(item)}
- >
- <Text style={[styles.freedomBtnText, freedomNum === item && styles.freedomBtnTextActive]}>
- {item}<Text style={styles.freedomUnit}>盒</Text>
- </Text>
- {freedomNum === item && <Text style={styles.checkIcon}>✓</Text>}
- </TouchableOpacity>
- ))}
- </View>
- <TouchableOpacity
- style={[styles.freedomSubmitBtn, loading && styles.payBtnDisabled]}
- onPress={() => handleFreedomSelect(freedomNum)}
- disabled={loading}
- >
- {loading ? (
- <ActivityIndicator color="#fff" size="small" />
- ) : (
- <Text style={styles.freedomSubmitText}>确认 ¥{(data?.price || 0) * freedomNum}</Text>
- )}
- </TouchableOpacity>
- </View>
- </View>
- </View>
- </Modal>
- {/* 支付确认弹窗 */}
- <Modal visible={visible} transparent animationType="slide" onRequestClose={close}>
- <View style={styles.overlay}>
- <TouchableOpacity style={styles.mask} activeOpacity={1} onPress={close} />
- <View style={styles.container}>
- <View style={styles.header}>
- <Text style={styles.title}>{data?.name}</Text>
- <TouchableOpacity onPress={close} style={styles.closeBtn}>
- <Text style={styles.closeText}>×</Text>
- </TouchableOpacity>
- </View>
- <View style={styles.content}>
- <View style={styles.row}>
- <Text style={styles.label}>购买件数</Text>
- <Text style={styles.priceText}>¥{data?.price} x {num}</Text>
- </View>
- <View style={styles.row}>
- <Text style={styles.label}>优惠券</Text>
- <Text style={[styles.valueText, couponAmount ? styles.themeColor : {}]}>
- {couponAmount ? `已使用优惠¥${couponAmount}` : '暂无优惠券可选'}
- </Text>
- </View>
- {magic && magic.balance > 0 && (
- <View style={styles.row}>
- <View style={styles.rowLeft}>
- <Text style={styles.label}>果实</Text>
- <Text style={styles.balanceText}>(剩余:{magic.balance})</Text>
- </View>
- <Text style={styles.balanceText}>
- 已抵扣 <Text style={styles.themeColor}>¥{coin || 0}</Text>
- </Text>
- </View>
- )}
- {cash && (
- <View style={styles.row}>
- <View style={styles.rowLeft}>
- <Text style={styles.label}>钱包支付</Text>
- <Text style={styles.themeColor}>(余额:¥{cash.balance})</Text>
- </View>
- <TouchableOpacity
- style={[styles.radio, cashChecked && styles.radioChecked]}
- onPress={() => setCashChecked(!cashChecked)}
- >
- {cashChecked && <View style={styles.radioInner} />}
- </TouchableOpacity>
- </View>
- )}
-
- {/* Payment Methods Section */}
- {(!cashChecked || (cash && cash.balance < (lastPrice || (data?.price || 0) * num))) && payConfig ? (
- <View style={styles.paymentSection}>
- <Text style={styles.sectionTitle}>支付方式</Text>
-
- {payConfig?.alipay?.enabled ? (
- <TouchableOpacity
- style={styles.payOption}
- onPress={() => setPaymentMethod('ALIPAY')}
- >
- <View style={styles.rowLeft}>
- <Text style={styles.payLabel}>支付宝支付</Text>
- </View>
- <View style={[styles.radio, paymentMethod === 'ALIPAY' && styles.radioChecked]}>
- {paymentMethod === 'ALIPAY' ? <View style={styles.radioInner} /> : null}
- </View>
- </TouchableOpacity>
- ) : null}
- {payConfig?.wxpay?.enabled ? (
- <TouchableOpacity
- style={styles.payOption}
- onPress={() => setPaymentMethod('WXPAY')}
- >
- <View style={styles.rowLeft}>
- <Text style={styles.payLabel}>微信支付</Text>
- </View>
- <View style={[styles.radio, paymentMethod === 'WXPAY' && styles.radioChecked]}>
- {paymentMethod === 'WXPAY' ? <View style={styles.radioInner} /> : null}
- </View>
- </TouchableOpacity>
- ) : null}
- </View>
- ) : null}
- <View style={styles.agreementRow}>
- <View style={styles.agreementLeft}>
- <Text style={styles.agreementText}>
- 我已满18周岁,已阅读并同意<Text style={styles.link}>《宝箱服务协议》</Text>
- </Text>
- <Text style={styles.tips}>宝箱商品存在概率性,请谨慎消费</Text>
- </View>
- <TouchableOpacity
- style={[styles.radio, checked && styles.radioChecked]}
- onPress={() => setChecked(!checked)}
- >
- {checked && <View style={styles.radioInner} />}
- </TouchableOpacity>
- </View>
- </View>
- <View style={styles.footer}>
- <View style={styles.priceInfo}>
- <Text style={styles.totalLabel}>实付:</Text>
- <Text style={styles.totalPrice}>¥{displayPrice.toFixed(2)}</Text>
- </View>
- <TouchableOpacity
- style={[styles.payBtn, loading && styles.payBtnDisabled]}
- onPress={pay}
- disabled={loading}
- >
- {loading ? <ActivityIndicator color="#fff" size="small" /> : <Text style={styles.payBtnText}>立即支付</Text>}
- </TouchableOpacity>
- </View>
- </View>
- </View>
- </Modal>
- {/* 抽奖结果弹窗 */}
- <Modal visible={resultVisible} transparent animationType="fade" onRequestClose={closeResult}>
- <View style={styles.resultOverlay}>
- <View style={styles.resultContainer}>
- <View style={styles.resultHeader}>
- <Text style={styles.resultTitle}>🎉 恭喜您获得 🎉</Text>
- <TouchableOpacity onPress={closeResult} style={styles.resultCloseBtn}>
- <Text style={styles.closeText}>×</Text>
- </TouchableOpacity>
- </View>
- {resultLoading ? (
- <View style={styles.resultLoading}>
- <ActivityIndicator size="large" color="#ff9600" />
- <Text style={styles.resultLoadingText}>正在开启宝箱...</Text>
- </View>
- ) : (
- <ScrollView style={styles.resultScroll} showsVerticalScrollIndicator={false}>
- <View style={styles.resultList}>
- {resultList.map((item, index) => (
- <View key={item.id || index} style={styles.resultItem}>
- <View style={[styles.levelBadge, { backgroundColor: LEVEL_MAP[item.level]?.color || '#666' }]}>
- <Text style={styles.levelText}>{LEVEL_MAP[item.level]?.title || item.level}</Text>
- </View>
- <View style={styles.resultImageBox}>
- <Image source={{ uri: item.cover }} style={styles.resultImage} contentFit="contain" />
- </View>
- <Text style={styles.resultName} numberOfLines={2}>{item.name}</Text>
- {item.spu?.marketPrice && (
- <Text style={styles.resultPrice}>参考价:¥{item.spu.marketPrice}</Text>
- )}
- </View>
- ))}
- </View>
- </ScrollView>
- )}
- <View style={styles.resultFooter}>
- <TouchableOpacity style={styles.resultBtn} onPress={closeResult}>
- <Text style={styles.resultBtnText}>继续抽奖</Text>
- </TouchableOpacity>
- </View>
- </View>
- </View>
- </Modal>
- </>
- );
- }
- );
- const styles = StyleSheet.create({
- overlay: {
- flex: 1,
- backgroundColor: 'rgba(0,0,0,0.5)',
- justifyContent: 'flex-end',
- },
- mask: { flex: 1 },
- container: {
- backgroundColor: '#fff',
- borderTopLeftRadius: 20,
- borderTopRightRadius: 20,
- paddingBottom: 34,
- },
- header: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- padding: 15,
- borderBottomWidth: 1,
- borderBottomColor: '#eee',
- position: 'relative',
- },
- title: { fontSize: 16, fontWeight: '600', color: '#333' },
- closeBtn: { position: 'absolute', right: 15, top: 10 },
- closeText: { fontSize: 24, color: '#999' },
- content: { padding: 15 },
- row: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- paddingVertical: 10,
- },
- rowLeft: { flexDirection: 'row', alignItems: 'center', flex: 1 },
- label: { fontSize: 14, color: '#333' },
- priceText: { fontSize: 14, color: '#ff9600', fontWeight: '600' },
- valueText: { fontSize: 12, color: '#999' },
- themeColor: { color: '#ff9600' },
- balanceText: { fontSize: 12, color: '#999', marginLeft: 5 },
- radio: {
- width: 20,
- height: 20,
- borderRadius: 10,
- borderWidth: 2,
- borderColor: '#ddd',
- justifyContent: 'center',
- alignItems: 'center',
- },
- radioChecked: { borderColor: '#ff9600' },
- radioInner: { width: 10, height: 10, borderRadius: 5, backgroundColor: '#ff9600' },
- agreementRow: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'flex-start',
- paddingVertical: 10,
- marginTop: 10,
- },
- agreementLeft: { flex: 1, marginRight: 10 },
- agreementText: { fontSize: 12, color: '#333', lineHeight: 18 },
- link: { color: '#ff9600' },
- tips: { fontSize: 11, color: '#999', marginTop: 5 },
- footer: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-between',
- paddingHorizontal: 15,
- paddingTop: 15,
- borderTopWidth: 1,
- borderTopColor: '#eee',
- },
- priceInfo: { flexDirection: 'row', alignItems: 'center' },
- totalLabel: { fontSize: 14, color: '#333' },
- totalPrice: { fontSize: 20, color: '#ff9600', fontWeight: 'bold' },
- payBtn: {
- backgroundColor: '#ff9600',
- paddingHorizontal: 30,
- paddingVertical: 12,
- borderRadius: 25,
- },
- payBtnDisabled: { opacity: 0.6 },
- payBtnText: { color: '#fff', fontSize: 16, fontWeight: '600' },
- // 自由购买弹窗
- freedomContainer: {
- backgroundColor: '#fff',
- borderTopLeftRadius: 20,
- borderTopRightRadius: 20,
- paddingBottom: 34,
- },
- freedomContent: { padding: 20 },
- freedomBtnList: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between' },
- freedomBtn: {
- width: '48%',
- height: 50,
- backgroundColor: '#fff',
- borderRadius: 8,
- justifyContent: 'center',
- alignItems: 'center',
- marginBottom: 12,
- borderWidth: 1,
- borderColor: '#eee',
- position: 'relative',
- },
- freedomBtnActive: { backgroundColor: '#F1423D', borderColor: '#F1423D' },
- freedomBtnText: { fontSize: 18, fontWeight: 'bold', color: '#333' },
- freedomBtnTextActive: { color: '#fff' },
- freedomUnit: { fontSize: 12, fontWeight: '500' },
- checkIcon: {
- position: 'absolute',
- bottom: 0,
- right: 0,
- backgroundColor: '#fff',
- color: '#F1423D',
- fontSize: 12,
- paddingHorizontal: 6,
- paddingVertical: 2,
- borderTopLeftRadius: 8,
- borderBottomRightRadius: 8,
- },
- freedomSubmitBtn: {
- backgroundColor: '#ff9600',
- height: 50,
- borderRadius: 25,
- justifyContent: 'center',
- alignItems: 'center',
- marginTop: 20,
- },
- freedomSubmitText: { color: '#fff', fontSize: 16, fontWeight: '600' },
- // 抽奖结果弹窗
- resultOverlay: {
- flex: 1,
- backgroundColor: 'rgba(0,0,0,0.7)',
- justifyContent: 'center',
- alignItems: 'center',
- padding: 20,
- },
- resultContainer: {
- width: '100%',
- maxHeight: '80%',
- backgroundColor: '#fff',
- borderRadius: 16,
- overflow: 'hidden',
- },
- resultHeader: {
- alignItems: 'center',
- padding: 20,
- backgroundColor: '#ff9600',
- position: 'relative',
- },
- resultTitle: {
- fontSize: 20,
- fontWeight: 'bold',
- color: '#fff',
- },
- resultCloseBtn: {
- position: 'absolute',
- right: 15,
- top: 15,
- width: 30,
- height: 30,
- backgroundColor: 'rgba(255,255,255,0.3)',
- borderRadius: 15,
- justifyContent: 'center',
- alignItems: 'center',
- },
- resultLoading: {
- padding: 60,
- alignItems: 'center',
- },
- resultLoadingText: {
- marginTop: 15,
- fontSize: 14,
- color: '#666',
- },
- resultScroll: {
- maxHeight: 400,
- },
- resultList: {
- flexDirection: 'row',
- flexWrap: 'wrap',
- padding: 10,
- justifyContent: 'space-between',
- },
- resultItem: {
- width: (SCREEN_WIDTH - 80) / 2,
- backgroundColor: '#f9f9f9',
- borderRadius: 10,
- padding: 10,
- marginBottom: 10,
- alignItems: 'center',
- },
- levelBadge: {
- paddingHorizontal: 10,
- paddingVertical: 3,
- borderRadius: 10,
- marginBottom: 8,
- },
- levelText: {
- color: '#fff',
- fontSize: 11,
- fontWeight: 'bold',
- },
- resultImageBox: {
- width: '100%',
- aspectRatio: 1,
- backgroundColor: '#fff',
- borderRadius: 8,
- overflow: 'hidden',
- },
- resultImage: {
- width: '100%',
- height: '100%',
- },
- resultName: {
- fontSize: 12,
- color: '#333',
- textAlign: 'center',
- marginTop: 8,
- lineHeight: 16,
- },
- resultPrice: {
- fontSize: 10,
- color: '#999',
- marginTop: 4,
- },
- resultFooter: {
- padding: 15,
- borderTopWidth: 1,
- borderTopColor: '#eee',
- },
- resultBtn: {
- backgroundColor: '#ff9600',
- height: 46,
- borderRadius: 23,
- justifyContent: 'center',
- alignItems: 'center',
- },
- resultBtnText: {
- color: '#fff',
- fontSize: 16,
- fontWeight: '600',
- },
- paymentSection: {
- marginTop: 20,
- borderTopWidth: 1,
- borderTopColor: '#f0f0f0',
- paddingTop: 10,
- },
- sectionTitle: {
- fontSize: 14,
- fontWeight: 'bold',
- marginBottom: 10,
- color: '#333',
- },
- payOption: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- paddingVertical: 12,
- borderBottomWidth: 1,
- borderBottomColor: '#f9f9f9',
- },
- payLabel: {
- fontSize: 14,
- color: '#333',
- marginLeft: 10,
- },
- });
|