本地环境不验证手机号和微信登录授权

This commit is contained in:
2026-07-07 21:42:56 +08:00
parent ec748335bf
commit e32ccebc80
14 changed files with 132 additions and 24 deletions
@@ -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<PartnerProfile | null>(null);
const [clientConfig, setClientConfig] = useState<ClientRuntimeConfig | null>(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(() => {
+24 -2
View File
@@ -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<ClientRuntimeConfig> {
return request<ClientRuntimeConfig>('PARTNER_H5', '/common/client-config');
}
export async function fetchPartnerProfile(): Promise<PartnerProfile> {
return request<PartnerProfile>('PARTNER_H5', '/partner/me');
}
/** 微信内上传照片前需完成公众号授权绑定 */
export function needsWechatAuth(profile: PartnerProfile | null): boolean {
export function needsWechatAuth(
profile: PartnerProfile | null,
config?: Pick<ClientRuntimeConfig, 'wxAuthorize'> | null,
): boolean {
if (config && !isWxAuthorizeEnabled(config)) return false;
return isWechatEnv() && !!profile && !profile.hasWechat;
}
export async function checkNeedsWechatAuth(profile: PartnerProfile | null): Promise<boolean> {
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<WechatLoginResult | null> {
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<WechatLoginResult |
* 返回 true = 已登录;void = 已跳转授权页等待回调。
*/
export async function loginPartnerWithWechat(): Promise<boolean | void> {
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<boolean | void> {
* 短信登录成功后于微信内自动发起 OAuth,将 openId 绑定到当前合伙人账号(便于同一微信后续免登)。
*/
export async function bindPartnerWechatAfterSmsLogin(): Promise<void> {
const config = await fetchClientConfig();
if (!isWxAuthorizeEnabled(config)) return;
if (!isWechatEnv()) return;
await weixinSdk.login();
}
export async function authorizePartnerWechat(): Promise<WechatLoginResult | void> {
const config = await fetchClientConfig();
if (!isWxAuthorizeEnabled(config)) return;
if (!isWechatEnv()) {
throw new Error(WECHAT_INAPP_REQUIRED_MSG);
}
+16 -3
View File
@@ -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 && <span className="material-symbols-outlined">arrow_forward</span>}
</button>
{wxAuthorize && (
<>
<div className="partner-auth-divider"><span></span></div>
<button type="button" className="partner-btn-wechat" onClick={wechatLogin} disabled={wxLoading}>
<svg viewBox="0 0 24 24" fill="#07C160" aria-hidden>
@@ -271,6 +282,8 @@ export default function LoginPage() {
</svg>
<span>{wxLoading ? '登录中...' : '微信一键授权'}</span>
</button>
</>
)}
<label className="partner-checkbox-row">
<input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />