import type { ClientRuntimeConfig, WechatLoginResult } from '@dukang/shared-types'; import type { PartnerPhoneCheckResponse } from '@dukang/shared-types'; import { isWxAuthorizeEnabled } from '@dukang/shared-types'; import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk'; import { isWechatEnv, weixinSdk } from './weixin'; import { getPartnerProfile, request, saveWechatSession, type PartnerSessionPayload, type PartnerSessionProfile } from './api'; export const PARTNER_WECHAT_LOGIN_HINT = '请先使用手机验证码登录,登录后将自动关联微信'; export type PartnerProfile = { id: string; name: string; phone: string; companyName?: string; hasWechat?: boolean; wxNickname?: string | null; wxAvatarUrl?: string | null; isPrimary?: boolean; }; export function partnerHasWechatBinding( profile: PartnerProfile | PartnerSessionProfile | null | undefined, ): boolean { return !!profile?.hasWechat; } /** 微信一键登录前:账号须已绑定 wxOpenId(本地缓存或手机号校验) */ export async function canPartnerUseWechatLogin(options: { profile?: PartnerProfile | PartnerSessionProfile | null; phone?: string; }): Promise { const cached = options.profile ?? getPartnerProfile(); if (partnerHasWechatBinding(cached)) return true; const normalized = options.phone?.trim() ?? ''; if (!/^1\d{10}$/.test(normalized)) return false; try { const res = await request('PARTNER_H5', '/partner/auth/phone/check', { method: 'POST', body: JSON.stringify({ phone: normalized }), silent: true, }); return !!res.hasWechat; } catch { return false; } } /** 短信登录/发码前:校验手机号对应合伙人存在且未暂停 */ export async function checkPartnerPhoneForLogin(phone: string): Promise { const normalized = phone.trim(); if (!/^1\d{10}$/.test(normalized)) { throw new Error('请输入正确的手机号'); } return request('PARTNER_H5', '/partner/auth/phone/check', { method: 'POST', body: JSON.stringify({ phone: normalized }), silent: true, }); } export async function fetchClientConfig(): Promise { return request('PARTNER_H5', '/common/client-config'); } export async function fetchPartnerProfile(): Promise { return request('PARTNER_H5', '/partner/me'); } /** 微信内上传照片前需完成公众号 OAuth 绑定 */ export function needsWechatAuth( profile: PartnerProfile | null, config?: Pick | null, ): boolean { if (config && !isWxAuthorizeEnabled(config)) return false; return isWechatEnv() && !!profile && !profile.hasWechat; } export async function checkNeedsWechatAuth(profile: PartnerProfile | null): Promise { const config = await fetchClientConfig(); return needsWechatAuth(profile, config); } export function sessionFromWechatLogin(result: WechatLoginResult): PartnerSessionPayload | null { if (!result.accessToken || !result.refreshToken) return null; const partner = result.partner; return { accessToken: result.accessToken, refreshToken: result.refreshToken, partner: partner ? { id: String(partner.id ?? ''), name: String(partner.name ?? ''), phone: String(partner.phone ?? ''), companyName: partner.companyName ? String(partner.companyName) : undefined, isPrimary: partner.isPrimary !== false, hasWechat: true, wxNickname: partner.wxNickname ? String(partner.wxNickname) : undefined, wxAvatarUrl: partner.wxAvatarUrl ? String(partner.wxAvatarUrl) : undefined, } : undefined, }; } /** 处理微信登录/绑定结果,写入 7 天免登录 session */ export function handlePartnerWechatLoginResult(result: WechatLoginResult): PartnerSessionPayload | null { const session = sessionFromWechatLogin(result); if (!session) return null; saveWechatSession(session); return session; } export async function handlePartnerWechatCallback(): Promise { if (!isWechatEnv()) return null; const config = await fetchClientConfig(); if (!isWxAuthorizeEnabled(config)) return null; return weixinSdk.handleOAuthCallback(); } /** * 微信一键登录(已绑定微信的合伙人账号免验证码)。 * 返回 session = 已登录;void = 已跳转授权页等待回调。 */ export async function loginPartnerWithWechat(): Promise { const config = await fetchClientConfig(); if (!isWxAuthorizeEnabled(config)) return null; if (!isWechatEnv()) { throw new Error(WECHAT_INAPP_REQUIRED_MSG); } const result = await weixinSdk.login(); if (result) return handlePartnerWechatLoginResult(result); } /** 短信登录成功后于微信内自动发起 OAuth,绑定 openId 便于后续免登 */ export async function bindPartnerWechatAfterSmsLogin(): Promise { const config = await fetchClientConfig(); if (!isWxAuthorizeEnabled(config)) return; if (!isWechatEnv()) return; await weixinSdk.login(); } export async function authorizePartnerWechat(): Promise { const config = await fetchClientConfig(); if (!isWxAuthorizeEnabled(config)) return; if (!isWechatEnv()) { throw new Error(WECHAT_INAPP_REQUIRED_MSG); } return weixinSdk.login(); } /** OAuth 回跳统一处理(登录页 / 录店页等) */ export async function processPartnerWechatOAuthCallback(): Promise { const result = await handlePartnerWechatCallback(); if (!result) return null; return handlePartnerWechatLoginResult(result); } /** @deprecated 使用 handlePartnerWechatLoginResult */ export function savePartnerWechatAuth(result: WechatLoginResult): PartnerSessionPayload | null { return handlePartnerWechatLoginResult(result); }