From e32ccebc80f0e633a2d6ddfc7e9c0f64c8a1b876 Mon Sep 17 00:00:00 2001 From: jacy-dukang Date: Tue, 7 Jul 2026 21:42:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=8E=AF=E5=A2=83=E4=B8=8D?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=89=8B=E6=9C=BA=E5=8F=B7=E5=92=8C=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E7=99=BB=E5=BD=95=E6=8E=88=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/OssUploadField.tsx | 10 ++++--- apps/h5-partner/src/lib/wechat-auth.ts | 26 ++++++++++++++++-- apps/h5-partner/src/pages/LoginPage.tsx | 19 ++++++++++--- apps/h5-shop/src/lib/wechat-auth.ts | 22 +++++++++++++-- apps/h5-shop/src/pages/HomePage.tsx | 4 +-- apps/h5-shop/src/pages/LoginPage.tsx | 16 ++++++++++- apps/h5-user/src/lib/pay-wechat.ts | 4 +++ apps/h5-user/src/lib/wechat-auth.ts | 12 +++++++++ apps/h5-user/src/pages/LoginPage.tsx | 27 +++++++++++-------- packages/shared-types/src/config.ts | 3 +++ packages/shared-types/src/wechat.ts | 8 ++++++ server/dukang-api/.env.example | 2 ++ server/dukang-api/.env.production.example | 2 ++ .../common/client-config.controller.ts | 1 + 14 files changed, 132 insertions(+), 24 deletions(-) diff --git a/apps/h5-partner/src/components/OssUploadField.tsx b/apps/h5-partner/src/components/OssUploadField.tsx index a872634..fd2a959 100644 --- a/apps/h5-partner/src/components/OssUploadField.tsx +++ b/apps/h5-partner/src/components/OssUploadField.tsx @@ -2,11 +2,13 @@ import { useEffect, useId, useRef, useState } from 'react'; import { uploadFileToOss, type OssMediaType } from '../lib/upload'; import { authorizePartnerWechat, + fetchClientConfig, fetchPartnerProfile, needsWechatAuth, type PartnerProfile, } from '../lib/wechat-auth'; import { isWechatEnv, weixinSdk } from '../lib/weixin'; +import type { ClientRuntimeConfig } from '@dukang/shared-types'; type OssUploadFieldProps = { value?: string; @@ -42,17 +44,19 @@ export default function OssUploadField({ const [authorizing, setAuthorizing] = useState(false); const [error, setError] = useState(''); const [profile, setProfile] = useState(null); + const [clientConfig, setClientConfig] = useState(null); const resolvedAccept = accept ?? (mediaType === 'VIDEO' ? 'video/*' : mediaType === 'FILE' ? 'image/*,.pdf' : 'image/*'); const useWechatPicker = isWechatEnv() && mediaType !== 'VIDEO'; - const needsAuth = useWechatPicker && needsWechatAuth(profile) && wechatReady !== true; + const needsAuth = useWechatPicker && needsWechatAuth(profile, clientConfig) && wechatReady !== true; useEffect(() => { if (!useWechatPicker) return; - void fetchPartnerProfile() - .then((me) => { + void Promise.all([fetchPartnerProfile(), fetchClientConfig()]) + .then(([me, config]) => { setProfile(me); + setClientConfig(config); onWechatReadyChange?.(!!me.hasWechat); }) .catch(() => { diff --git a/apps/h5-partner/src/lib/wechat-auth.ts b/apps/h5-partner/src/lib/wechat-auth.ts index f1ba168..fc6fa8c 100644 --- a/apps/h5-partner/src/lib/wechat-auth.ts +++ b/apps/h5-partner/src/lib/wechat-auth.ts @@ -1,4 +1,5 @@ -import type { WechatLoginResult } from '@dukang/shared-types'; +import type { ClientRuntimeConfig, WechatLoginResult } 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 { request, saveAuth } from './api'; @@ -11,15 +12,28 @@ export type PartnerProfile = { hasWechat?: boolean; }; +export async function fetchClientConfig(): Promise { + return request('PARTNER_H5', '/common/client-config'); +} + export async function fetchPartnerProfile(): Promise { return request('PARTNER_H5', '/partner/me'); } /** 微信内上传照片前需完成公众号授权绑定 */ -export function needsWechatAuth(profile: PartnerProfile | null): boolean { +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); +} + /** 处理微信登录/绑定结果,返回是否已拿到 token 可进入首页 */ export function handlePartnerWechatLoginResult(result: WechatLoginResult): boolean { if (!result.accessToken) return false; @@ -29,6 +43,8 @@ export function handlePartnerWechatLoginResult(result: WechatLoginResult): boole export async function handlePartnerWechatCallback(): Promise { if (!isWechatEnv()) return null; + const config = await fetchClientConfig(); + if (!isWxAuthorizeEnabled(config)) return null; return weixinSdk.handleOAuthCallback(); } @@ -37,6 +53,8 @@ export async function handlePartnerWechatCallback(): Promise { + const config = await fetchClientConfig(); + if (!isWxAuthorizeEnabled(config)) return false; if (!isWechatEnv()) { throw new Error(WECHAT_INAPP_REQUIRED_MSG); } @@ -48,11 +66,15 @@ export async function loginPartnerWithWechat(): Promise { * 短信登录成功后于微信内自动发起 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); } diff --git a/apps/h5-partner/src/pages/LoginPage.tsx b/apps/h5-partner/src/pages/LoginPage.tsx index 07043eb..8bfa3f5 100644 --- a/apps/h5-partner/src/pages/LoginPage.tsx +++ b/apps/h5-partner/src/pages/LoginPage.tsx @@ -3,11 +3,13 @@ import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { request, saveAuth } from '../lib/api'; import { bindPartnerWechatAfterSmsLogin, + fetchClientConfig, handlePartnerWechatCallback, handlePartnerWechatLoginResult, loginPartnerWithWechat, } from '../lib/wechat-auth'; import { isWechatEnv } from '../lib/weixin'; +import { isWxAuthorizeEnabled } from '@dukang/shared-types'; import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk'; const REMEMBER_PHONE_KEY = 'partner_remember_phone'; @@ -47,16 +49,23 @@ export default function LoginPage() { const [wxLoading, setWxLoading] = useState(false); const [msg, setMsg] = useState(''); const [codeCooldown, setCodeCooldown] = useState(0); + const [wxAuthorize, setWxAuthorize] = useState(false); useEffect(() => { - if (!isWechatEnv()) return; + fetchClientConfig() + .then((config) => setWxAuthorize(isWxAuthorizeEnabled(config))) + .catch(() => setWxAuthorize(false)); + }, []); + + useEffect(() => { + if (!isWechatEnv() || !wxAuthorize) return; void handlePartnerWechatCallback() .then((result) => { if (!result) return; if (handlePartnerWechatLoginResult(result)) navigate('/'); }) .catch((e) => setMsg(formatWechatError(e))); - }, [navigate]); + }, [navigate, wxAuthorize]); function formatWechatError(e: unknown): string { const text = e instanceof Error ? e.message : '微信登录失败'; @@ -129,7 +138,7 @@ export default function LoginPage() { }); saveAuth(data); persistRememberAccount(phone); - if (isWechatEnv()) { + if (isWechatEnv() && wxAuthorize) { setMsg('登录成功,正在关联微信…'); await bindPartnerWechatAfterSmsLogin(); return; @@ -264,6 +273,8 @@ export default function LoginPage() { {!loading && arrow_forward} + {wxAuthorize && ( + <>
其他登录方式
+ + )}