245 lines
7.4 KiB
TypeScript
245 lines
7.4 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { View, Text } from '@tarojs/components';
|
|
import Taro, { useDidShow, useRouter } from '@tarojs/taro';
|
|
import PageShell from '../../components/PageShell';
|
|
import SubPageHeader from '../../components/SubPageHeader';
|
|
import WechatLoginButton from '../../components/WechatLoginButton';
|
|
import { ensurePayReady } from '../../lib/pay-ready';
|
|
import {
|
|
authorizeWechatForPay,
|
|
fetchClientConfig,
|
|
fetchUserProfile,
|
|
isWechatAuthRequiredError,
|
|
needsWechatAuthForPay,
|
|
payOrder,
|
|
saveWechatLoginResult,
|
|
} from '../../lib/pay-wechat';
|
|
import { applyWechatLoginResult } from '../../lib/wechat-auth';
|
|
import { isWechatEnv } from '../../lib/weixin';
|
|
import { goLogin } from '../../lib/auth-nav';
|
|
import { request, toast } from '../../lib/api';
|
|
|
|
export default function PayPage() {
|
|
const router = useRouter();
|
|
const orderId = router.params.orderId ?? '';
|
|
const [loading, setLoading] = useState(false);
|
|
const [authLoading, setAuthLoading] = useState(false);
|
|
const [mockMode, setMockMode] = useState(true);
|
|
const [needsWechatAuth, setNeedsWechatAuth] = useState(false);
|
|
const [msg, setMsg] = useState('');
|
|
const [orderNo, setOrderNo] = useState('');
|
|
const [payAmount, setPayAmount] = useState('—');
|
|
const [deliveryType, setDeliveryType] = useState('');
|
|
|
|
const returnPath = orderId
|
|
? `/pages/pay/index?orderId=${orderId}`
|
|
: '/pages/pay/index';
|
|
|
|
const refreshPayReadiness = useCallback(async () => {
|
|
try {
|
|
const [config, profile] = await Promise.all([fetchClientConfig(), fetchUserProfile()]);
|
|
setMockMode(config.mockPay);
|
|
setNeedsWechatAuth(needsWechatAuthForPay(config, profile));
|
|
return profile;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
useDidShow(() => {
|
|
void refreshPayReadiness();
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!orderId) return;
|
|
if (process.env.TARO_ENV === 'weapp') {
|
|
void ensurePayReady(returnPath);
|
|
}
|
|
}, [orderId, returnPath]);
|
|
|
|
useEffect(() => {
|
|
if (!orderId) {
|
|
setOrderNo('');
|
|
setPayAmount('—');
|
|
return;
|
|
}
|
|
request<{
|
|
orderNo?: string;
|
|
payAmount?: number | string;
|
|
totalAmount?: number | string;
|
|
deliveryType?: string;
|
|
}>(`/trade/orders/${orderId}`)
|
|
.then((order) => {
|
|
setOrderNo(order.orderNo || '');
|
|
setDeliveryType(order.deliveryType || '');
|
|
const amount = Number(order.payAmount ?? order.totalAmount ?? 0);
|
|
if (Number.isFinite(amount) && amount > 0) {
|
|
setPayAmount(amount.toFixed(2));
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
setOrderNo('');
|
|
setDeliveryType('');
|
|
toast(e instanceof Error ? e.message : '加载订单失败');
|
|
});
|
|
}, [orderId]);
|
|
|
|
async function wechatAuthorize() {
|
|
setAuthLoading(true);
|
|
setMsg('');
|
|
try {
|
|
if (!isWechatEnv()) {
|
|
setMsg('请在微信内打开以授权微信支付');
|
|
return;
|
|
}
|
|
if (process.env.TARO_ENV === 'weapp') {
|
|
const ready = await ensurePayReady(returnPath);
|
|
if (ready) await refreshPayReadiness();
|
|
return;
|
|
}
|
|
const result = await authorizeWechatForPay();
|
|
if (result) {
|
|
if (result.needBindPhone && result.wxSessionKey) {
|
|
goLogin(returnPath, { bindMode: '1', wxSessionKey: result.wxSessionKey });
|
|
return;
|
|
}
|
|
if (saveWechatLoginResult(result) || applyWechatLoginResult(result)) {
|
|
setMsg('');
|
|
await refreshPayReadiness();
|
|
toast('微信授权成功', 'success');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
setMsg(e instanceof Error ? e.message : '微信授权失败');
|
|
} finally {
|
|
setAuthLoading(false);
|
|
}
|
|
}
|
|
|
|
async function pay() {
|
|
if (!orderId) {
|
|
toast('订单不存在');
|
|
return;
|
|
}
|
|
if (needsWechatAuth) {
|
|
setMsg('请先完成微信授权后再支付');
|
|
if (process.env.TARO_ENV === 'h5') {
|
|
await wechatAuthorize();
|
|
} else {
|
|
await ensurePayReady(returnPath);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const ready = await ensurePayReady(returnPath);
|
|
if (!ready) return;
|
|
|
|
setLoading(true);
|
|
setMsg('');
|
|
try {
|
|
const status = await payOrder(orderId);
|
|
if (status === 'pending') {
|
|
toast('支付结果确认中,请稍后在订单列表查看');
|
|
} else {
|
|
toast('支付成功', 'success');
|
|
}
|
|
if (deliveryType === 'ON_SITE_PICKUP') {
|
|
Taro.redirectTo({ url: `/pages/pickup-receive/index?id=${orderId}` });
|
|
} else {
|
|
Taro.redirectTo({ url: '/pages/orders/index?tab=paid' });
|
|
}
|
|
} catch (e) {
|
|
if (isWechatAuthRequiredError(e)) {
|
|
setNeedsWechatAuth(true);
|
|
setMsg('微信支付需要先完成微信授权');
|
|
return;
|
|
}
|
|
const message = e instanceof Error ? e.message : '支付失败';
|
|
if (message.includes('取消')) {
|
|
setMsg('已取消支付');
|
|
return;
|
|
}
|
|
setMsg(message);
|
|
toast(message);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<PageShell variant="sub" className="pay-page" hasFixedFooter>
|
|
<SubPageHeader title="收银台" />
|
|
<View className="sub-page-body">
|
|
<View className="pay-status">
|
|
<View className="pay-status-icon">
|
|
<Text>¥</Text>
|
|
</View>
|
|
<Text className="pay-status-title">
|
|
{needsWechatAuth ? '需完成微信授权' : '待支付'}
|
|
</Text>
|
|
<Text className="pay-status-amount">¥{payAmount}</Text>
|
|
</View>
|
|
|
|
{needsWechatAuth ? (
|
|
<View className="pay-wechat-auth-card">
|
|
<Text className="pay-wechat-auth-title">尚未授权微信</Text>
|
|
<Text className="pay-wechat-auth-desc">
|
|
授权后可安全调起微信支付,不会重复扣款
|
|
</Text>
|
|
<WechatLoginButton
|
|
loading={authLoading}
|
|
onClick={() => void wechatAuthorize()}
|
|
/>
|
|
</View>
|
|
) : null}
|
|
|
|
<View className="order-card">
|
|
<View className="order-row">
|
|
<Text className="order-row-label">订单号</Text>
|
|
<Text className="order-row-value">{orderNo || '—'}</Text>
|
|
</View>
|
|
<View className="order-row">
|
|
<Text className="order-row-label">支付方式</Text>
|
|
<Text className="order-row-value">微信支付</Text>
|
|
</View>
|
|
<View className="order-row">
|
|
<Text className="order-row-label">说明</Text>
|
|
<Text className="order-row-value">
|
|
{mockMode ? 'Mock 模式由服务端直接标记已付款' : '将调起微信收银台'}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
{msg ? (
|
|
<Text className="pay-wechat-auth-msg" style={{ marginTop: 12 }}>
|
|
{msg}
|
|
</Text>
|
|
) : null}
|
|
</View>
|
|
<View className="pay-bar">
|
|
<View
|
|
className="order-confirm-submit"
|
|
style={{ flex: 1, opacity: loading || needsWechatAuth ? 0.7 : 1 }}
|
|
onClick={() => {
|
|
if (loading) return;
|
|
if (needsWechatAuth) {
|
|
void wechatAuthorize();
|
|
return;
|
|
}
|
|
void pay();
|
|
}}
|
|
>
|
|
<Text>
|
|
{loading
|
|
? '支付中…'
|
|
: needsWechatAuth
|
|
? authLoading
|
|
? '授权中…'
|
|
: '微信一键授权'
|
|
: '立即支付'}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</PageShell>
|
|
);
|
|
}
|