diff --git a/apps/h5-shop/src/lib/wechat-auth.ts b/apps/h5-shop/src/lib/wechat-auth.ts index a9c3f15..562bd3e 100644 --- a/apps/h5-shop/src/lib/wechat-auth.ts +++ b/apps/h5-shop/src/lib/wechat-auth.ts @@ -9,6 +9,8 @@ export type ShopAccountProfile = { storeId: string; name: string; phone: string; + /** 是否已绑定微信(来自 /shop/auth/me account.hasWechat) */ + hasWechat?: boolean; wxOpenId?: string | null; store?: { name: string }; }; @@ -18,7 +20,27 @@ export async function fetchClientConfig(): Promise { } export async function fetchShopAccount(): Promise { - return request('SHOP_H5', '/shop/auth/me'); + const me = await request<{ + id?: string; + storeId?: string; + name?: string; + phone?: string; + account?: { + id?: string; + name?: string; + phone?: string; + hasWechat?: boolean; + }; + store?: { name?: string } | null; + }>('SHOP_H5', '/shop/auth/me'); + return { + id: String(me.account?.id ?? me.id ?? ''), + storeId: String(me.storeId ?? ''), + name: String(me.account?.name ?? me.name ?? ''), + phone: String(me.account?.phone ?? me.phone ?? ''), + hasWechat: !!me.account?.hasWechat, + store: me.store?.name ? { name: String(me.store.name) } : undefined, + }; } export function needsWechatAuth( @@ -26,7 +48,8 @@ export function needsWechatAuth( config?: Pick | null, ): boolean { if (config && !isWxAuthorizeEnabled(config)) return false; - return isWechatEnv() && !!profile && !profile.wxOpenId; + const unbound = !!profile && !(profile.hasWechat || profile.wxOpenId); + return isWechatEnv() && unbound; } export async function checkNeedsWechatAuth(profile: ShopAccountProfile | null): Promise { diff --git a/apps/h5-shop/src/pages/MinePage.tsx b/apps/h5-shop/src/pages/MinePage.tsx index 1600bc4..e8b659e 100644 --- a/apps/h5-shop/src/pages/MinePage.tsx +++ b/apps/h5-shop/src/pages/MinePage.tsx @@ -1,21 +1,95 @@ import { useEffect, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { isWxAuthorizeEnabled } from '@dukang/shared-types'; +import { stripOAuthParamsFromLocation } from '@dukang/weixin-sdk'; import { useStoreSession } from '../contexts/StoreSessionContext'; import { getStoreProfile, request } from '../lib/api'; +import { + authorizeShopWechat, + fetchClientConfig, + fetchShopAccount, + handleShopWechatCallback, + handleShopWechatLoginResult, +} from '../lib/wechat-auth'; +import { isWechatEnv } from '../lib/weixin'; export default function MinePage() { const navigate = useNavigate(); - const { resetSession, store: sessionStore } = useStoreSession(); + const [searchParams, setSearchParams] = useSearchParams(); + const { resetSession, store: sessionStore, applySession } = useStoreSession(); const profile = sessionStore ?? getStoreProfile(); const [store, setStore] = useState | null>(null); + const [hasWechat, setHasWechat] = useState(null); + const [wxAuthorize, setWxAuthorize] = useState(false); + const [binding, setBinding] = useState(false); + const [bindMsg, setBindMsg] = useState(''); useEffect(() => { request('SHOP_H5', '/shop/store').then(setStore).catch(() => setStore(null)); }, []); + useEffect(() => { + fetchClientConfig() + .then((config) => setWxAuthorize(isWxAuthorizeEnabled(config))) + .catch(() => setWxAuthorize(false)); + }, []); + + useEffect(() => { + fetchShopAccount() + .then((me) => setHasWechat(!!(me.hasWechat || me.wxOpenId))) + .catch(() => setHasWechat(null)); + }, []); + + useEffect(() => { + if (!isWechatEnv() || !wxAuthorize || !searchParams.get('code')) return; + void handleShopWechatCallback() + .then((result) => { + if (!result) return; + const session = handleShopWechatLoginResult(result); + if (session) { + applySession(session); + setHasWechat(true); + setBindMsg('微信绑定成功'); + } + stripOAuthParamsFromLocation(); + setSearchParams({}, { replace: true }); + }) + .catch((e) => setBindMsg(e instanceof Error ? e.message : '微信绑定失败')); + }, [applySession, searchParams, setSearchParams, wxAuthorize]); + const openTime = String(store?.openTime || '09:30'); const closeTime = String(store?.closeTime || '22:00'); const multiStore = (profile?.stores?.length ?? 0) > 1; + const showBindWechat = wxAuthorize && hasWechat === false; + + async function bindWechat() { + if (binding) return; + setBindMsg(''); + if (!isWechatEnv()) { + setBindMsg('请在微信内打开门店端以绑定微信'); + return; + } + setBinding(true); + try { + const result = await authorizeShopWechat(); + if (!result) { + // 跳转公众号 OAuth,回跳后由上面 useEffect 处理 + return; + } + const session = handleShopWechatLoginResult(result); + if (session) { + applySession(session); + setHasWechat(true); + setBindMsg('微信绑定成功'); + } else { + setBindMsg('绑定未完成,请重试'); + } + } catch (e) { + setBindMsg(e instanceof Error ? e.message : '微信绑定失败'); + } finally { + setBinding(false); + } + } return (
@@ -77,6 +151,20 @@ export default function MinePage() {

如需修改信息请联系城市合伙人

+ {bindMsg ?

{bindMsg}

: null} + + {showBindWechat ? ( + + ) : null} +