h5微信授权
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-07-14 20:09:36 +08:00
parent 9b13d02dde
commit 1ad49f1acf
14 changed files with 569 additions and 79 deletions
+40 -29
View File
@@ -1,9 +1,13 @@
import type { ClientRuntimeConfig, WechatJsapiPrepayParams, WechatLoginResult, WechatPayOrderResult } from '@dukang/shared-types';
import type {
ClientRuntimeConfig,
WechatJsapiPrepayParams,
WechatLoginResult,
WechatPayOrderResult,
} from '@dukang/shared-types';
import { WECHAT_AUTH_REQUIRED, isWxAuthorizeEnabled } from '@dukang/shared-types';
import { invokeWechatPay } from '@dukang/weixin-sdk';
import Taro from '@tarojs/taro';
import { request, type UserProfile } from './api';
import { syncMiniWechatProfile } from './mini-wechat-profile';
import { request, saveAuth, type UserProfile } from './api';
import { isWechatEnv, weixinSdk } from './weixin';
export function isMiniWechatEnv(): boolean {
return process.env.TARO_ENV === 'weapp';
@@ -21,13 +25,35 @@ export async function fetchUserProfile(): Promise<UserProfile> {
return request<UserProfile>('/auth/me');
}
/** 真实微信支付且未绑定微信时需要授权 */
/** 真实微信支付且未绑定微信时需要授权(小程序 / H5 微信内) */
export function needsWechatAuthForPay(
config: ClientRuntimeConfig,
profile: UserProfile | null,
): boolean {
if (!isWxAuthorizeEnabled(config)) return false;
return !config.mockPay && config.wechatPayEnabled && isMiniWechatEnv() && !profile?.hasWechat;
return !config.mockPay && config.wechatPayEnabled && isWechatEnv() && !profile?.hasWechat;
}
export function saveWechatLoginResult(result: WechatLoginResult): boolean {
if (!result.accessToken) return false;
saveAuth({
accessToken: result.accessToken,
refreshToken: result.refreshToken,
});
return true;
}
/** H5:发起公众号 OAuth(可能直接跳转);小程序请用 bindWechatForUser */
export async function authorizeWechatForPay(): Promise<WechatLoginResult | void> {
const config = await fetchClientConfig();
if (!isWxAuthorizeEnabled(config)) return;
if (!isWechatEnv()) {
throw new Error('请在微信内打开以完成授权');
}
if (process.env.TARO_ENV === 'h5') {
return weixinSdk.login();
}
throw new Error('请使用小程序微信授权');
}
function sleep(ms: number) {
@@ -49,9 +75,12 @@ export async function payOrder(orderId: string): Promise<'paid' | 'pending'> {
});
if (result.mode === 'jsapi' && result.prepay) {
await invokeWechatPay(result.prepay as WechatJsapiPrepayParams, {
platform: isMiniWechatEnv() ? 'mini' : undefined,
});
const prepay = result.prepay as WechatJsapiPrepayParams;
if (process.env.TARO_ENV === 'h5') {
await weixinSdk.pay(prepay);
} else {
await invokeWechatPay(prepay, { platform: 'mini' });
}
const paid = await waitOrderPaid(orderId);
return paid ? 'paid' : 'pending';
}
@@ -61,23 +90,5 @@ export async function payOrder(orderId: string): Promise<'paid' | 'pending'> {
export type WechatBindResult =
| { ok: true; profile?: UserProfile }
| { ok: false; needBindPhone: true; wxSessionKey: string };
export async function bindWechatForUser(
prefetchedWxProfile?: { nickname?: string; avatarUrl?: string } | null,
): Promise<WechatBindResult> {
const res = await Taro.login();
if (!res.code) {
throw new Error(res.errMsg || '微信授权失败');
}
const data = await request<WechatLoginResult>('/auth/wechat/bind', {
method: 'POST',
data: { code: res.code, platform: 'mini' },
});
if (data.needBindPhone && data.wxSessionKey) {
return { ok: false, needBindPhone: true, wxSessionKey: data.wxSessionKey };
}
await syncMiniWechatProfile(prefetchedWxProfile);
const profile = await fetchUserProfile();
return { ok: true, profile };
}
| { ok: false; needBindPhone: true; wxSessionKey: string }
| { ok: false; redirecting: true };