React Native 支付弹窗组件 - PayModal:实现支付宝和微信支付功能
import React, { Component } from 'react'; import { StyleSheet, View, Text, Image, AppState, Linking } from 'react-native'; import BottomSheet from '../BottomSheet'; import LColors from '@assets/Strings/LColors'; import { bottomSpace, scaleSize, screenHeight } from '@utils/layout'; import { UIActivityIndicator } from 'react-native-indicators'; import { getList, doPayment, checkPay } from '@api/Order'; import ACTION_TYPE from '../Order/OrderAction'; import LTouchableOpacity from '../TouchAble/LTouchableOpacity'; import { aliPay, wxPay } from '@utils/native'; import TimerText from './TimerText'; import { Base64 } from 'js-base64'; import DialogContainer from '@common/UIComponents/Dialog/DialogContainer'; import { track } from '@utils/dataAnalytics'; import IconFont from '@assets/iconfont'; import LNumberText from 'imou-rn/dist/components/LNumberText'; import LToast from 'imou-rn/dist/components/LToast'; import { getImageUrlForPath } from '@utils/layout'; import LNetImage from '../LNetImage'; import { log, toast } from '@common/Utils/LogUtil';
export default class PayModal extends Component { constructor(props) { super(props); this.state = { data: null, selPayWayIndex: 0, time: '', isLoading: true, isNetError: false, leftTime: 10000, confirmModalVisible: true, appState: AppState.currentState, paymentId: '', }; this.isGoToSuccess = false; this.onBack = this._handleBack.bind(this); }
componentDidMount() { AppState.addEventListener('change', this._handleAppStateChange); }
componentWillUnmount() { AppState.removeEventListener('change', this._handleAppStateChange); }
_handleAppStateChange = (nextAppState) => { if ( this.state.appState && this.state.appState.match(/inactive|background/) && nextAppState === 'active' ) { this.doWhileGetPayResult(); } this.setState({ appState: nextAppState }); };
doWhileGetPayResult() { const { paying, visible } = this.state; if (!paying || this.isChecking || !visible) return; this.isChecking = true; LToast.loading('加载中', 0); let times = 0; const interval = setInterval(() => { if (times === 6) { LToast.removeAll(); clearInterval(interval); this.isChecking = false; return; } this._checkPay(interval); times++; }, 500); }
_checkPay(interval) { const { paymentId, visible } = this.state; if (!visible) return; console.log('_checkPay2222'); if (!paymentId) { this._fetchData(); return; } const json = { paymentId: paymentId, }; checkPay(json) .then((res) => { const { code, data, desc } = res; this.isChecking = false;
if (code === 10000) {
const { payStatus, promotionType, preparePayType } = data || {};
if (
payStatus === '1' ||
(promotionType === 'prepare' && payStatus === '3' && preparePayType === 'deposit')
) {
if (interval) {
LToast.removeAll();
interval && clearInterval(interval);
AppState.removeEventListener('change', (state) => {
// this._handleAppStateChange(state);
});
}
this.isGoToSuccess = true;
const from = this.props.from;
this.timerText && this.timerText.stop();
if (from && from === 'orderList') {
this.updateCallback && this.updateCallback(ACTION_TYPE.PAY);
this.setState(
{
visible: false,
},
() => {
this.props.navigation &&
this.props.navigation.navigate('PaySuccessScreen', {
data: { orderInfo: data },
});
this.updateCallback = null;
},
);
return;
}
this.setState(
{
visible: false,
},
() => {
this.props.navigation &&
this.props.navigation.replace('PaySuccessScreen', {
data: { orderInfo: data },
});
},
);
} else {
this._fetchData();
}
} else {
LToast.removeAll();
interval && clearInterval(interval);
this.isChecking = false;
toast('服务器开小差啦~');
}
})
.catch(() => {
LToast.removeAll();
interval && clearInterval(interval);
AppState.removeEventListener('change', (state) => {
this._handleAppStateChange(state);
});
this.isChecking = false;
toast('服务器开小差啦~');
});
} _handleBack() { this._handleOnClose(); if (this.props.from === 'confirm') { const { data } = this.state; this.props.navigation && this.props.navigation.replace('OrderDtlScreen', { orderID: data?.orderId, }); } else if (this.props.from === 'orderDtl') { this.props.onRefresh && this.props.onRefresh(); } track('$AppClick', 'PayScreen', { $element_id: 'click_cancel_pay', }); } _handleOnClose() { AppState.removeEventListener('change', (state) => { this._handleAppStateChange(state); }); this.props.onClose && this.props.onClose(); if (this.props.from === 'orderList') { this.updateCallback && this.updateCallback(ACTION_TYPE.PAY); } this.timerText && this.timerText.stop(); this.isGoToSuccess = false; this.setState({ visible: false, isLoading: false, paying: false, }); } show(data) { if (!data) return; AppState.addEventListener('change', (state) => { this._handleAppStateChange(state); }); this.isGoToSuccess = false; this.setState( { visible: true, data: data, isLoading: true, paying: true, paymentId: '', }, () => { this.updateCallback = data.updateCallback; this._fetchData(); }, ); } _fetchData() { if (!this.state.data) return; const { orderId } = this.state.data || {}; const json = { orderId: orderId, endPay: 0, platform: 'appnative', version: '5.5.0', }; getList(json) .then((data) => { if (data.code === 10000) { this._handleNetResult(data); } else { toast('服务器开小差啦~'); this.setState({ data: { orderId: orderId }, }); } }) .catch(() => { toast('服务器开小差啦~'); }); } _handleNetResult(result) { console.log('this.isGoToSuccess', this.isGoToSuccess); if (this.isGoToSuccess) return; const data = result?.data; if (data?.payStatus == 1) { this.comfirmModal && this.comfirmModal.hide(); this.isGoToSuccess = true; const from = this.props.from; this.timerText && this.timerText.stop(); if (from && from === 'orderList') { console.log('this.state.data.updateCallback', this.updateCallback); this.updateCallback && this.updateCallback(ACTION_TYPE.PAY); this.setState( { visible: false, }, () => { this.props.navigation && this.props.navigation.navigate('PaySuccessScreen', { data: data }); this.updateCallback = null; }, ); return; } this.setState( { visible: false, }, () => { this.props.navigation && this.props.navigation.replace('PaySuccessScreen', { data: data }); }, ); return; } this.timerText && this.timerText.stop(); this.setState({ isLoading: false, isNetError: false, data: data, leftTime: data?.leftTime, }); this.timerText && this.timerText.start(data?.leftTime); }
_handlePayResult(result) { const code = result?.code; if (JSON.stringify(result) === '{}' || !result) { this.doWhileGetPayResult(); return; } else if (code === 6001) { const timer = setTimeout(() => { clearTimeout(timer); this._fetchData(); }, 500);
toast('取消支付');
} else if (code === -1) {
const timer = setTimeout(() => {
clearTimeout(timer);
this._fetchData();
}, 500);
toast('其他错误');
} else if (code === 8000) {
const timer = setTimeout(() => {
clearTimeout(timer);
this._fetchData();
}, 500);
return;
}
this.comfirmModal && this.comfirmModal.hide();
}
_renderPayWayRow({ title, appId, index }) {
const { data } = this.state;
return (
click_pay_${appId},
},
}}
sensorsDataParams={{ $element_id: m_orderDtl_payWayBy${appId}_rpckn }}
onPress={() => {
this._doPayment({ appId });
}}>
doPayment(req)
.then(async (res) => {
const { code, desc } = res;
if (code === 10000) {
const html = res.data?.html;
this.setState({
paymentId: res.data?.paymentId,
});
if (!html) return;
const base64Str = Base64.encode(html, false);
if (infoItem?.appId === 'alipayapp') {
const canOpenAlipay = await Linking.canOpenURL('alipays://');
log('canOpenAlipay', canOpenAlipay);
aliPay(base64Str)
.then((data) => {
this._handlePayResult(data);
})
.catch((e) => {
this._handlePayResult(e);
});
if (canOpenAlipay) {
this.comfirmModal && this.comfirmModal.show();
}
} else if (infoItem?.appId === 'wxpayapp') {
wxPay(base64Str)
.then((data) => {
this._handlePayResult(data);
})
.catch((e) => {
this._handlePayResult(e);
});
this.comfirmModal && this.comfirmModal.show();
}
} else if (code === 20001) {
toast('请勿重复支付');
this._fetchData();
} else if (code === 21000) {
toast(desc);
} else {
toast('服务器开小差啦~');
}
})
.catch((e) => {
toast(e);
});
}
render() {
const { visible, data, leftTime, isLoading } = this.state;
return (
<BottomSheet
modalVisible={visible}
maxHeight={screenHeight * 0.4}
title={'确认付款'}
onClose={() => {
if (leftTime > 0) {
this.backAlert && this.backAlert.show();
} else {
AppState.removeEventListener('change', (state) => {
this._handleAppStateChange(state);
});
this._handleBack();
}
}}>
{!visible ? null : isLoading ? (
const styles = StyleSheet.create({ container: { position: 'relative', paddingBottom: bottomSpace + 180, }, rowBack: { alignItems: 'stretch', }, row: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', height: 60, }, payWarp: { marginTop: 16, }, priceLarge: { textAlign: 'center', fontSize: 32, color: LColors.C2, lineHeight: 35, }, rowRight: { flexDirection: 'row', alignItems: 'center' }, payName: { marginLeft: 17, fontSize: 18, color: LColors.N1 }, timerText: { marginTop: 5, textAlign: 'center', marginRight: 12, fontSize: 15, color: LColors.N1, }, outBigImg: { width: scaleSize(90), height: scaleSize(112), }, loading: { justifyContent: 'center', alignItems: 'center', height: 255 }, priceSmall: { fontSize: 12, fontWeight: 'bold' }, outTimeText: { fontSize: 15, color: LColors.N15, lineHeight: 21, marginTop: 15, textAlign: 'center', }, outWarp: { alignItems: 'center' }, });
原文地址: https://www.cveoy.top/t/topic/f3DR 著作权归作者所有。请勿转载和采集!