fix fix fix

This commit is contained in:
2026-03-25 21:19:58 +08:00
parent b63c00d251
commit 0d168c9046
10 changed files with 91 additions and 68 deletions

View File

@@ -40,7 +40,7 @@ import {
import Api, { WalletItem, loadServerDomain, saveServerDomain, getServerDomain } from '../services/api';
// key 与服务端 WalletType 字符串一致(见 types.go
// key matches server WalletType string (see types.go)
const WALLET_ICONS: Record<string, any> = {
'paytm': require('../res/paytm.png'),
'paytm business': require('../res/paytm-business.png'),
@@ -63,7 +63,7 @@ const WALLET_TYPE_COLORS: Record<string, string> = {
'freecharge': '#ff5722',
};
// 钱包类型展示信息walletType 与服务端一致)
// wallet type display info (walletType matches server)
const WALLET_TYPE_OPTIONS = [
{ key: 'paytm_personal_otp', walletType: 'paytm', label: 'Paytm Personal (OTP)', mode: 'otp' },
{ key: 'paytm_personal_token', walletType: 'paytm', label: 'Paytm Personal (Token)', mode: 'token' },
@@ -201,7 +201,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
onError: (error: string) => this.setState({ proxyStatus: 'error', proxyError: error }),
});
} catch (error) {
console.error('[Proxy] 初始化失败:', error);
console.error('[Proxy] init failed:', error);
}
}
@@ -252,7 +252,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
wallets: s.wallets.map(w => w.id === walletId ? { ...w, upi: vpa } : w),
}));
} catch (e) {
Alert.alert('设置失败', (e as Error).message);
Alert.alert('Set Failed', (e as Error).message);
}
};
@@ -273,11 +273,11 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
const wt = typeMap[key as string];
if (wt) await Api.instance.register(wt as WalletType, result);
this.setState({ [key]: false } as any);
Alert.alert('绑定成功', msg);
Alert.alert('Bind Success', msg);
this.fetchWallets();
} catch (error) {
this.setState({ [key]: false } as any);
Alert.alert('绑定失败', (error as Error).message);
Alert.alert('Bind Failed', (error as Error).message);
}
};
@@ -293,7 +293,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
if (showPaytmPersonalBind && paytmPersonalBindType === 'tokenMode') return (
<Modal visible transparent onRequestClose={close('showPaytmPersonalBind')}>
<PaytmPersonalBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showPaytmPersonalBind', 'Paytm Personal 绑定成功') as any} onError={(e: string) => { Alert.alert('绑定失败', e); close('showPaytmPersonalBind')(); }} />
<PaytmPersonalBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showPaytmPersonalBind', 'Paytm Personal bound successfully') as any} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPaytmPersonalBind')(); }} />
</Modal>
);
if (showPaytmPersonalBind) return (
@@ -301,14 +301,14 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<PayTmPersonalOTPBind isDebug
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile, {}); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { sessionId: p.sessionId }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={(r: PaytmPersonalBindResult) => { Alert.alert('绑定成功', 'Paytm Personal OTP'); this.setState({ showPaytmPersonalBind: false }); this.fetchWallets(); }}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showPaytmPersonalBind')(); }}
onSuccess={(r: PaytmPersonalBindResult) => { Alert.alert('Bind Success', 'Paytm Personal OTP'); this.setState({ showPaytmPersonalBind: false }); this.fetchWallets(); }}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPaytmPersonalBind')(); }}
/>
</Modal>
);
if (showPhonePePersonalBind && phonePePersonalBindType === 'tokenMode') return (
<Modal visible transparent onRequestClose={close('showPhonePePersonalBind')}>
<PhonePePersonalBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showPhonePePersonalBind', 'PhonePe Personal 绑定成功') as any} onError={(e: string) => { Alert.alert('绑定失败', e); close('showPhonePePersonalBind')(); }} />
<PhonePePersonalBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showPhonePePersonalBind', 'PhonePe Personal bound successfully') as any} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePePersonalBind')(); }} />
</Modal>
);
if (showPhonePePersonalBind) return (
@@ -316,8 +316,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<PhonePePersonalOTPBind isDebug
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile, {}); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { sessionId: p.sessionId }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={(r: PhonePePersonalBindResult) => { Alert.alert('绑定成功', 'PhonePe Personal OTP'); this.setState({ showPhonePePersonalBind: false }); this.fetchWallets(); }}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showPhonePePersonalBind')(); }}
onSuccess={(r: PhonePePersonalBindResult) => { Alert.alert('Bind Success', 'PhonePe Personal OTP'); this.setState({ showPhonePePersonalBind: false }); this.fetchWallets(); }}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePePersonalBind')(); }}
/>
</Modal>
);
@@ -326,16 +326,16 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<PaytmBusinessOTPBind isDebug
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile, { password: p.password }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { sessionId: p.sessionId }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={this.handleBindSuccess('showPaytmBusinessBind', 'Paytm Business 绑定成功') as any}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showPaytmBusinessBind')(); }}
onSuccess={this.handleBindSuccess('showPaytmBusinessBind', 'Paytm Business bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPaytmBusinessBind')(); }}
/>
</Modal>
);
if (showPhonePeBusinessBind) return (
<Modal visible transparent onRequestClose={close('showPhonePeBusinessBind')}>
<PhonePeBusinessBind processString="Processing..." isDebug
onSuccess={this.handleBindSuccess('showPhonePeBusinessBind', 'PhonePe Business 绑定成功') as any}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showPhonePeBusinessBind')(); }}
onSuccess={this.handleBindSuccess('showPhonePeBusinessBind', 'PhonePe Business bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePeBusinessBind')(); }}
onRenderBottomView={({ showOtpInput, loading, formError, phone, otp, onPhoneChange, onOtpChange, onGetOtp, onSubmitOtp }) => (
<View style={s.otpBar}>
{!showOtpInput ? (<>
@@ -354,7 +354,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
);
if (showGooglePayBusinessBind) return (
<Modal visible transparent onRequestClose={close('showGooglePayBusinessBind')}>
<GooglePayBusinessBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showGooglePayBusinessBind', 'GooglePay Business 绑定成功') as any} onError={(e: string) => { Alert.alert('绑定失败', e); close('showGooglePayBusinessBind')(); }} />
<GooglePayBusinessBind processString="Processing..." isDebug onSuccess={this.handleBindSuccess('showGooglePayBusinessBind', 'GooglePay Business bound successfully') as any} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showGooglePayBusinessBind')(); }} />
</Modal>
);
if (showBharatPeBusinessBind) return (
@@ -362,8 +362,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<BharatPeBusinessOTPBind isDebug
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { sessionId: p.sessionId }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={this.handleBindSuccess('showBharatPeBusinessBind', 'BharatPe Business 绑定成功') as any}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showBharatPeBusinessBind')(); }}
onSuccess={this.handleBindSuccess('showBharatPeBusinessBind', 'BharatPe Business bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showBharatPeBusinessBind')(); }}
/>
</Modal>
);
@@ -372,8 +372,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<MobikwikOTPBind isDebug deviceId={this.deviceId} tuneUserId={this.tuneUserId}
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile, { deviceId: p.deviceId, tuneUserId: p.tuneUserId }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { sessionId: p.sessionId, deviceId: p.deviceId, tuneUserId: p.tuneUserId, nid: p.nid }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={this.handleBindSuccess('showMobikwikPersonalBind', 'Mobikwik 绑定成功') as any}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showMobikwikPersonalBind')(); }}
onSuccess={this.handleBindSuccess('showMobikwikPersonalBind', 'Mobikwik bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showMobikwikPersonalBind')(); }}
/>
</Modal>
);
@@ -382,8 +382,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<FreeChargeBind isDebug
onRequestOTP={async (wt, p) => { try { return await Api.instance.requestOTP(wt, p.mobile); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onVerifyOTP={async (wt, p) => { try { return await Api.instance.verifyOTP(wt, p.mobile, p.otp, { otpId: p.otpId, deviceId: p.deviceId, csrfId: p.csrfId, appFc: p.appFc }); } catch (e) { return { success: false, message: (e as Error).message }; } }}
onSuccess={this.handleBindSuccess('showFreechargePersonalBind', 'Freecharge 绑定成功') as any}
onError={(e: string) => { Alert.alert('绑定失败', e); close('showFreechargePersonalBind')(); }}
onSuccess={this.handleBindSuccess('showFreechargePersonalBind', 'Freecharge bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showFreechargePersonalBind')(); }}
/>
</Modal>
);
@@ -420,7 +420,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
style={s.addModalBox}
>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<Text style={s.addModalTitle}></Text>
<Text style={s.addModalTitle}>Select Wallet Type</Text>
<TouchableOpacity onPress={() => this.setState({ showAddWallet: false })}>
<Text style={{ fontSize: 20, color: '#999' }}></Text>
</TouchableOpacity>
@@ -452,7 +452,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<Modal visible={showServerSettings} transparent animationType="fade">
<View style={s.modalOverlay}>
<View style={s.settingsBox}>
<Text style={s.settingsTitle}></Text>
<Text style={s.settingsTitle}>Server Settings</Text>
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 6, marginBottom: 14 }}>
{presets.map(p => (
<TouchableOpacity key={p.label} onPress={() => this.setState({ settingsHost: p.host, settingsPort: p.port })}
@@ -467,16 +467,16 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<TextInput style={[s.textInput, { marginBottom: 20 }]} value={settingsPort} onChangeText={t => this.setState({ settingsPort: t })} placeholder="16000" keyboardType="number-pad" />
<View style={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
<TouchableOpacity onPress={() => this.setState({ showServerSettings: false })} style={{ paddingHorizontal: 16, paddingVertical: 8, marginRight: 10 }}>
<Text style={{ color: '#666' }}></Text>
<Text style={{ color: '#666' }}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity onPress={async () => {
const { settingsHost, settingsPort } = this.state;
const domain = settingsPort ? `${settingsHost}:${settingsPort}` : settingsHost;
await saveServerDomain(domain, settingsPort === '443');
this.setState({ showServerSettings: false });
Alert.alert('已保存', '重启 App 后生效');
Alert.alert('Saved', 'Restart app to take effect');
}} style={s.saveBtn}>
<Text style={{ color: '#fff', fontWeight: 'bold' }}></Text>
<Text style={{ color: '#fff', fontWeight: 'bold' }}>Save</Text>
</TouchableOpacity>
</View>
</View>
@@ -522,14 +522,14 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
useNativeDriver
style={s.vpaModalBox}
>
<Text style={s.vpaModalTitle}> VPA</Text>
<Text style={s.vpaModalTitle}>Select VPA</Text>
<Text style={s.vpaModalSub}>{vpaModalWallet?.phone}</Text>
<ScrollView style={s.vpaModalList} bounces={false}>
{vpaModalLoading
? <ActivityIndicator size="large" color={color} style={{ marginVertical: 28 }} />
: vpaModalVpas.length === 0
? <Text style={{ color: '#aaa', textAlign: 'center', marginVertical: 28 }}> VPA </Text>
? <Text style={{ color: '#aaa', textAlign: 'center', marginVertical: 28 }}>No VPA data</Text>
: vpaModalVpas.map(vpa => {
const selected = vpa === vpaModalSelected;
return (
@@ -551,14 +551,14 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
<View style={s.vpaModalFooter}>
<TouchableOpacity style={s.vpaModalCancelBtn} onPress={this.closeVpaModal}>
<Text style={{ color: '#666', fontSize: 15 }}></Text>
<Text style={{ color: '#666', fontSize: 15 }}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[s.vpaModalConfirmBtn, { backgroundColor: vpaModalSelected ? color : '#ccc' }]}
onPress={this.confirmVpa}
disabled={!vpaModalSelected}
>
<Text style={{ color: '#fff', fontSize: 15, fontWeight: '600' }}></Text>
<Text style={{ color: '#fff', fontSize: 15, fontWeight: '600' }}>Confirm</Text>
</TouchableOpacity>
</View>
</Animatable.View>
@@ -570,22 +570,22 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
render() {
const { proxyStatus, proxyError, wallets, loadingWallets } = this.state;
const proxyCfg: Record<string, { label: string; color: string }> = {
idle: { label: '未连接', color: '#95a5a6' },
connecting: { label: '连接中…', color: '#f39c12' },
connected: { label: '已连接', color: '#2ecc71' },
disconnected: { label: '已断开', color: '#e74c3c' },
error: { label: '连接失败', color: '#e74c3c' },
idle: { label: 'Idle', color: '#95a5a6' },
connecting: { label: 'Connecting…', color: '#f39c12' },
connected: { label: 'Connected', color: '#2ecc71' },
disconnected: { label: 'Disconnected', color: '#e74c3c' },
error: { label: 'Error', color: '#e74c3c' },
};
const { label, color } = proxyCfg[proxyStatus];
return (
<View style={s.container}>
{/* 顶栏 */}
{/* top bar */}
<View style={s.topBar}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<View style={{ width: 8, height: 8, borderRadius: 4, backgroundColor: color, marginRight: 6 }} />
<Text style={{ color, fontSize: 13 }}>
Proxy {label}{proxyStatus === 'error' && proxyError ? `${proxyError}` : ''}
Proxy {label}{proxyStatus === 'error' && proxyError ? `: ${proxyError}` : ''}
</Text>
</View>
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
@@ -608,11 +608,11 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
</View>
</View>
{/* 钱包列表 */}
{/* wallet list */}
<View style={s.listHeader}>
<Text style={s.listHeaderText}></Text>
<Text style={s.listHeaderText}>Bound Wallets</Text>
<TouchableOpacity onPress={this.fetchWallets} disabled={loadingWallets}>
<Text style={{ fontSize: 13, color: '#3498db' }}>{loadingWallets ? '刷新中…' : '刷新'}</Text>
<Text style={{ fontSize: 13, color: '#3498db' }}>{loadingWallets ? 'Refreshing…' : 'Refresh'}</Text>
</TouchableOpacity>
</View>
@@ -624,7 +624,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
renderItem={this.renderWalletItem}
ListEmptyComponent={
<View style={{ alignItems: 'center', marginTop: 60 }}>
<Text style={{ color: '#aaa', fontSize: 14 }}>{loadingWallets ? '加载中…' : '暂无绑定钱包,点右上角 + Add 添加'}</Text>
<Text style={{ color: '#aaa', fontSize: 14 }}>{loadingWallets ? 'Loading…' : 'No wallets. Tap + Add to get started.'}</Text>
</View>
}
/>