forked from gxwebsoft/mp-10550
fix(payment): 修复微信支付时openid绑定问题
- 新增确保支付前openid正确绑定的方法,解决支付账号不一致问题 - 在创建微信支付订单前强制刷新openid,防止旧微信账号导致支付失败 - 在自动登录后补充openid绑定步骤,确保支付所需的openid存在 - 设计为非阻塞流程,避免网络异常导致支付阻塞 - 仅针对微信支付触发,其他支付方式不受影响
This commit is contained in:
16
.workbuddy/memory/2026-04-25.md
Normal file
16
.workbuddy/memory/2026-04-25.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 2026-04-25 工作日志
|
||||
|
||||
## 微信支付"下单账号与支付账号不一致"问题修复
|
||||
|
||||
**问题**:用户支付时微信提示「下单账号与支付账号不一致,请核实后再支付」
|
||||
|
||||
**根因**:下单时后端使用的 openid 与当前实际支付的微信用户 openid 不匹配。前端在创建订单前没有刷新 openid,依赖登录/注册时的旧绑定。
|
||||
|
||||
**修改文件**:
|
||||
1. `src/utils/payment.ts` — 新增 `ensureOpenIdBeforePay()` 方法,在 `pay()` 方法中、微信支付创建订单前强制调用 `Taro.login()` + `getWxOpenId()` 刷新绑定当前用户的 openid
|
||||
2. `src/hooks/useUser.ts` — 在 `autoLoginByOpenId()` 登录成功后补充 openid 绑定逻辑(之前只调了 loginByOpenId 没有调 getWxOpenId)
|
||||
|
||||
**方案特点**:
|
||||
- 非阻塞设计:openid 刷新失败不阻止支付(网络波动时兼容)
|
||||
- 仅微信支付触发:余额支付/支付宝不受影响
|
||||
- 兼容已有 openid 的场景:即使已有 openid 也会刷新(防止切号)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { User } from '@/api/system/user/model';
|
||||
import { getUserInfo, updateUserInfo, loginByOpenId } from '@/api/layout';
|
||||
import { getUserInfo, updateUserInfo, loginByOpenId, getWxOpenId } from '@/api/layout';
|
||||
import { TenantId } from '@/config/app';
|
||||
import { handleInviteRelation } from '@/utils/invite';
|
||||
|
||||
@@ -27,6 +27,24 @@ export const useUser = () => {
|
||||
setUser(data.user);
|
||||
setIsLoggedIn(true);
|
||||
|
||||
// 自动登录成功后,补齐 openid(JSAPI 微信支付必需)
|
||||
// 防止后续支付时报"下单账号与支付账号不一致"
|
||||
if (!data.user?.openid) {
|
||||
try {
|
||||
const freshCode = await new Promise<string | undefined>((resolve, reject) => {
|
||||
Taro.login({
|
||||
success: (r) => resolve(r.code as string),
|
||||
fail: () => resolve(undefined),
|
||||
});
|
||||
});
|
||||
if (freshCode) {
|
||||
await getWxOpenId({ code: freshCode });
|
||||
}
|
||||
} catch (_e) {
|
||||
console.warn('自动登录后绑定 openid 失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 处理邀请关系
|
||||
if (data.user?.userId) {
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getSelectedStoreFromStorage, getSelectedStoreIdFromStorage } from '@/ut
|
||||
import type { ShopStoreRider } from '@/api/shop/shopStoreRider/model';
|
||||
import type { ShopStoreWarehouse } from '@/api/shop/shopStoreWarehouse/model';
|
||||
import request from '@/utils/request';
|
||||
import { getWxOpenId, getUserInfo } from '@/api/layout';
|
||||
|
||||
/**
|
||||
* 支付类型枚举
|
||||
@@ -33,6 +34,74 @@ export class PaymentHandler {
|
||||
private static storeRidersCache = new Map<number, ShopStoreRider[]>();
|
||||
private static warehousesCache: ShopStoreWarehouse[] | null = null;
|
||||
|
||||
/**
|
||||
* 【关键修复】支付前确保当前微信用户的 openid 已正确绑定到后端
|
||||
*
|
||||
* 问题场景:
|
||||
* 1. 用户通过手机号注册 → openid 未绑定 → 后端用空 openid 创建预支付单 → 支付时报"账号不一致"
|
||||
* 2. 用户切换了微信账号 → 本地缓存的用户信息是旧账号的 → openid 与当前支付人不匹配
|
||||
* 3. 自动登录(loginByOpenId)未触发 getWxOpenId 绑定流程
|
||||
*
|
||||
* 解决方案:每次微信支付前,重新获取 wx.login code 并调用 getWxOpenId 绑定,
|
||||
* 确保后端记录的 openid = 当前实际支付人的 openid
|
||||
*/
|
||||
private static async ensureOpenIdBeforePay(): Promise<void> {
|
||||
try {
|
||||
// 非微信环境跳过(如 H5 开发调试)
|
||||
let isWeapp = false;
|
||||
try {
|
||||
isWeapp = Taro.getEnv() === Taro.ENV_TYPE.WEAPP;
|
||||
} catch (_e) {
|
||||
isWeapp = process.env.TARO_ENV === 'weapp';
|
||||
}
|
||||
if (!isWeapp) return;
|
||||
|
||||
// 获取当前登录用户的最新信息(检查是否已有 openid)
|
||||
let currentUser = null;
|
||||
try {
|
||||
currentUser = await getUserInfo();
|
||||
} catch (_e) {
|
||||
// getUserInfo 失败时不阻塞支付(可能是 token 过期等),让后续接口自行报错
|
||||
console.warn('[ensureOpenId] 获取用户信息失败,跳过 openid 校验');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果用户已有 openid,仍然需要刷新:因为用户可能切换了微信账号
|
||||
// 每次都重新获取 code + 绑定,确保 openid 是当前微信会话的
|
||||
|
||||
const code = await new Promise<string | undefined>((resolve, reject) => {
|
||||
Taro.login({
|
||||
success: (res) => resolve(res.code as string),
|
||||
fail: (e) => reject(e),
|
||||
timeout: 5000, // 5秒超时
|
||||
});
|
||||
});
|
||||
|
||||
if (!code) {
|
||||
console.warn('[ensureOpenId] wx.login 未返回 code');
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用后端绑定/更新 openid
|
||||
await getWxOpenId({ code });
|
||||
console.log('[ensureOpenId] openid 刷新/绑定成功');
|
||||
|
||||
// 同步本地 User 缓存,确保后续逻辑能读到最新 openid
|
||||
try {
|
||||
const freshUser = await getUserInfo();
|
||||
if (freshUser) {
|
||||
Taro.setStorageSync('User', freshUser);
|
||||
}
|
||||
} catch (_e) {
|
||||
// ignore: 服务端已更新 openid,本地缓存不同步也不影响本次支付
|
||||
}
|
||||
} catch (error) {
|
||||
// openid 刷新失败不阻塞支付流程(可能网络波动),
|
||||
// 但记录日志方便排查;若确实不一致,微信支付侧会报错
|
||||
console.warn('[ensureOpenId] openid 刷新失败(非阻塞):', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行支付
|
||||
* @param orderData 订单数据
|
||||
@@ -80,6 +149,12 @@ export class PaymentHandler {
|
||||
// 设置支付类型
|
||||
orderData.payType = paymentType;
|
||||
|
||||
// 【关键修复】微信支付前,强制刷新/绑定当前微信用户的 openid
|
||||
// 防止"下单账号与支付账号不一致"错误
|
||||
if (paymentType === PaymentType.WECHAT) {
|
||||
await this.ensureOpenIdBeforePay();
|
||||
}
|
||||
|
||||
console.log('创建订单请求:', orderData);
|
||||
|
||||
// 创建订单
|
||||
|
||||
Reference in New Issue
Block a user