From 4ba51c502b0e78bd73c9ec425e95030ca45149dd Mon Sep 17 00:00:00 2001
From: jacy <18049821889@163.com>
Date: Sun, 2 Aug 2026 13:28:09 +0800
Subject: [PATCH] fix(proxy-order): remove mock pay button, use real WeChat pay
---
.../src/components/ProxyOrderModal.tsx | 26 +--
.../src/pages/ProxyOrderDetailPage.tsx | 200 ++++++++++++++++--
apps/h5-partner/src/pages/ProxyOrderPage.tsx | 38 +---
3 files changed, 183 insertions(+), 81 deletions(-)
diff --git a/apps/admin-web/src/components/ProxyOrderModal.tsx b/apps/admin-web/src/components/ProxyOrderModal.tsx
index 55ef4df..66f5ccb 100644
--- a/apps/admin-web/src/components/ProxyOrderModal.tsx
+++ b/apps/admin-web/src/components/ProxyOrderModal.tsx
@@ -63,7 +63,6 @@ export default function ProxyOrderModal({ open, onClose, onSuccess }: ProxyOrder
const [created, setCreated] = useState(null);
const [codeUrl, setCodeUrl] = useState(null);
const [payLoading, setPayLoading] = useState(false);
- const [mockConfirming, setMockConfirming] = useState(false);
const pollRef = useRef(null);
const region = useMemo(() => parseRegionCodes(regionCodes), [regionCodes]);
@@ -215,26 +214,6 @@ export default function ProxyOrderModal({ open, onClose, onSuccess }: ProxyOrder
}
}
- async function handleMockConfirm() {
- if (!created) return;
- setMockConfirming(true);
- try {
- const st = await request(`/admin/proxy-orders/${created.id}/pay/mock-confirm`, {
- method: 'POST',
- body: '{}',
- });
- stopPoll();
- message.success(`支付成功:${st.orderNo}`);
- const payload = { id: st.id, orderNo: st.orderNo };
- resetForm();
- onSuccess(payload);
- } catch (e) {
- message.error(e instanceof Error ? e.message : '模拟支付失败');
- } finally {
- setMockConfirming(false);
- }
- }
-
const deliveryLabel =
preview?.deliveryType === 'ON_SITE_PICKUP'
? '现场提货'
@@ -253,9 +232,6 @@ export default function ProxyOrderModal({ open, onClose, onSuccess }: ProxyOrder
step === 'pay' ? (
-
) : (
@@ -285,7 +261,7 @@ export default function ProxyOrderModal({ open, onClose, onSuccess }: ProxyOrder
) : codeUrl ? (
- 请使用微信扫一扫完成支付(本地可用下方模拟支付)
+ 请使用微信扫一扫完成支付,成功后自动关闭
{codeUrl}
diff --git a/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx b/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx
index 83ab15b..49af50c 100644
--- a/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx
+++ b/apps/h5-partner/src/pages/ProxyOrderDetailPage.tsx
@@ -1,14 +1,18 @@
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
+import QRCode from 'qrcode';
import PageHeader from '@dukang/shared-ui/PageHeader';
-import type { PartnerProxyOrderListItem } from '@dukang/shared-types';
-import { request } from '../lib/api';
+import { invokeWechatPay } from '@dukang/weixin-sdk';
+import type { PartnerProxyOrderListItem, ProxyOrderPayResponse, ProxyPayMethod } from '@dukang/shared-types';
+import { getToken, request } from '../lib/api';
import {
proxyOrderPayLabel,
proxyOrderStatusColor,
proxyOrderStatusLabel,
} from '../lib/proxyOrderStatus';
import { toastError, toastSuccess } from '../lib/toast';
+import { isWechatEnv } from '../lib/weixin';
+import { fetchPartnerProfile, partnerHasWechatBinding } from '../lib/wechat-auth';
function fmtMoney(n: number) {
return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
@@ -51,6 +55,20 @@ export default function ProxyOrderDetailPage() {
const [track, setTrack] = useState(null);
const [trackError, setTrackError] = useState('');
const [paying, setPaying] = useState(false);
+ const [payMsg, setPayMsg] = useState('');
+ const [payMethod, setPayMethod] = useState('NATIVE');
+ const [codeUrl, setCodeUrl] = useState(null);
+ const [qrDataUrl, setQrDataUrl] = useState(null);
+ const pollRef = useRef(null);
+
+ function stopPoll() {
+ if (pollRef.current != null) {
+ window.clearInterval(pollRef.current);
+ pollRef.current = null;
+ }
+ }
+
+ useEffect(() => () => stopPoll(), []);
useEffect(() => {
document.title = '代下单详情';
@@ -75,28 +93,113 @@ export default function ProxyOrderDetailPage() {
.catch((e) => setTrackError(e instanceof Error ? e.message : '物流暂不可用'));
}, [id, order]);
- async function continuePay() {
+ useEffect(() => {
+ if (!codeUrl) {
+ setQrDataUrl(null);
+ return;
+ }
+ void QRCode.toDataURL(codeUrl, { width: 220, margin: 1 })
+ .then(setQrDataUrl)
+ .catch(() => setQrDataUrl(null));
+ }, [codeUrl]);
+
+ const unpaid = order?.payStatus === 'UNPAID' || order?.status === 'PENDING_PAY';
+
+ function startPoll(orderId: string) {
+ stopPoll();
+ pollRef.current = window.setInterval(() => {
+ void request<{ payStatus: string; orderNo: string }>(
+ 'PARTNER_H5',
+ `/partner/proxy-orders/${orderId}/pay-status`,
+ { silent: true },
+ )
+ .then((st) => {
+ if (st.payStatus === 'PAID') {
+ stopPoll();
+ toastSuccess(`支付成功:${st.orderNo}`);
+ void request('PARTNER_H5', `/partner/proxy-orders/${orderId}`)
+ .then(setOrder)
+ .catch(() => undefined);
+ setCodeUrl(null);
+ }
+ })
+ .catch(() => undefined);
+ }, 2000);
+ }
+
+ async function startPay(method: ProxyPayMethod) {
if (!id) return;
setPaying(true);
+ setPayMsg('');
+ setPayMethod(method);
try {
- await request('PARTNER_H5', `/partner/proxy-orders/${id}/pay/mock-confirm`, {
- method: 'POST',
- body: '{}',
- silent: true,
- });
- toastSuccess('支付成功');
- const refreshed = await request(
+ if (method === 'JSAPI') {
+ if (!isWechatEnv()) {
+ throw new Error('请在微信内打开合伙人端以使用微信代付');
+ }
+ const profile = await fetchPartnerProfile();
+ if (!partnerHasWechatBinding(profile)) {
+ throw new Error('请先绑定微信后再代付');
+ }
+ }
+
+ const pay = await request(
'PARTNER_H5',
- `/partner/proxy-orders/${id}`,
+ `/partner/proxy-orders/${id}/pay`,
+ {
+ method: 'POST',
+ body: JSON.stringify({ payMethod: method }),
+ silent: true,
+ },
);
- setOrder(refreshed);
+
+ if (pay.mode === 'mock') {
+ toastSuccess('支付成功');
+ const refreshed = await request(
+ 'PARTNER_H5',
+ `/partner/proxy-orders/${id}`,
+ );
+ setOrder(refreshed);
+ setCodeUrl(null);
+ return;
+ }
+
+ if (pay.mode === 'native' && pay.codeUrl) {
+ setCodeUrl(pay.codeUrl);
+ startPoll(id);
+ return;
+ }
+
+ if (pay.mode === 'jsapi' && pay.prepay) {
+ setCodeUrl(null);
+ await invokeWechatPay(pay.prepay, {
+ apiBase: '/api/v1',
+ clientApp: 'PARTNER_H5',
+ getAccessToken: getToken,
+ platform: 'wechat-h5',
+ });
+ startPoll(id);
+ return;
+ }
+
+ throw new Error('支付发起失败');
} catch (e) {
+ setPayMsg(e instanceof Error ? e.message : '支付失败');
toastError(e instanceof Error ? e.message : '支付失败');
} finally {
setPaying(false);
}
}
+ const autoPayStartedRef = useRef(false);
+ useEffect(() => {
+ if (!id || !unpaid || autoPayStartedRef.current) return;
+ autoPayStartedRef.current = true;
+ void startPay('NATIVE');
+ // 仅首次进入未支付详情时自动拉收款码
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [id, unpaid]);
+
const img = order?.imageResource?.url || '';
const isOnSite = String(order?.deliveryType || '').toUpperCase() === 'ON_SITE_PICKUP';
@@ -175,16 +278,67 @@ export default function ProxyOrderDetailPage() {
- {order.payStatus === 'UNPAID' || order.status === 'PENDING_PAY' ? (
-
+ {unpaid ? (
+
+ 继续支付
+
+
+
+
+
+ {payMethod === 'NATIVE' ? (
+
+ {qrDataUrl ? (
+

+ ) : (
+
{paying ? '生成收款码中…' : '暂无收款码'}
+ )}
+
+ 请使用微信扫码支付,支付成功后自动更新
+
+
+
+ ) : (
+
+
将调起微信支付,由合伙人微信完成代付
+
+
+ )}
+
+ {payMsg ? (
+
+ {payMsg}
+
+ ) : null}
+
) : null}
{!isOnSite && order.payStatus === 'PAID' ? (
diff --git a/apps/h5-partner/src/pages/ProxyOrderPage.tsx b/apps/h5-partner/src/pages/ProxyOrderPage.tsx
index 5a68563..9616fee 100644
--- a/apps/h5-partner/src/pages/ProxyOrderPage.tsx
+++ b/apps/h5-partner/src/pages/ProxyOrderPage.tsx
@@ -305,25 +305,6 @@ export default function ProxyOrderPage() {
}
}
- async function handleMockConfirm() {
- if (!created) return;
- setPaying(true);
- try {
- await request('PARTNER_H5', `/partner/proxy-orders/${created.id}/pay/mock-confirm`, {
- method: 'POST',
- body: '{}',
- silent: true,
- });
- stopPoll();
- toastSuccess('支付成功');
- navigate(`/center/proxy-orders/${created.id}`, { replace: true });
- } catch (e) {
- setMsg(e instanceof Error ? e.message : '模拟支付失败');
- } finally {
- setPaying(false);
- }
- }
-
const selectedProduct = options?.products.find((p) => p.id === productId);
const deliveryLabel =
preview?.deliveryType === 'ON_SITE_PICKUP'
@@ -382,21 +363,21 @@ export default function ProxyOrderPage() {
{paying ? '生成收款码中…' : '暂无收款码'}
)}
- 请使用微信扫码支付
+ 请使用微信扫码支付,支付成功后自动跳转
) : (
-
将调起微信支付(本地 Mock 可能直接入账)
+
将调起微信支付,由合伙人微信完成代付
-
)}