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 { request, saveAuth, type UserProfile } from './api'; import { isWechatEnv, weixinSdk } from './weixin'; export function isMiniWechatEnv(): boolean { return process.env.TARO_ENV === 'weapp'; } export function isWechatAuthRequiredError(err: unknown): boolean { return err instanceof Error && err.message === WECHAT_AUTH_REQUIRED; } export async function fetchClientConfig(): Promise { return request('/common/client-config'); } export async function fetchUserProfile(): Promise { return request('/auth/me'); } /** 真实微信支付且未绑定微信时需要授权(小程序 / H5 微信内) */ export function needsWechatAuthForPay( config: ClientRuntimeConfig, profile: UserProfile | null, ): boolean { if (!isWxAuthorizeEnabled(config)) return false; 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 { 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) { return new Promise((resolve) => setTimeout(resolve, ms)); } export async function waitOrderPaid(orderId: string, maxAttempts = 15): Promise { for (let i = 0; i < maxAttempts; i += 1) { const order = await request<{ payStatus?: string }>(`/trade/orders/${orderId}`); if (order.payStatus === 'PAID') return true; await sleep(2000); } return false; } export async function payOrder(orderId: string): Promise<'paid' | 'pending'> { const result = await request(`/trade/orders/${orderId}/pay`, { method: 'POST', }); if (result.mode === 'jsapi' && result.prepay) { 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'; } return 'paid'; } export type WechatBindResult = | { ok: true; profile?: UserProfile } | { ok: false; needBindPhone: true; wxSessionKey: string } | { ok: false; redirecting: true };