合伙人端验证是否已经绑定手机号,否则不支持微信一键登录

This commit is contained in:
2026-07-12 21:18:10 +08:00
parent b5235dedef
commit 236a2a87a5
7 changed files with 80 additions and 9 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ export default function AuthGate({ children }: { children: React.ReactNode }) {
if (!authenticated && !PUBLIC_PATHS.has(location.pathname)) { if (!authenticated && !PUBLIC_PATHS.has(location.pathname)) {
const profile = getPartnerProfile(); const profile = getPartnerProfile();
if (profile && hasPartnerWxSession()) { if (profile && hasPartnerWxSession() && profile.hasWechat) {
return <Navigate to="/login?quick=1" replace state={{ from: location }} />; return <Navigate to="/login?quick=1" replace state={{ from: location }} />;
} }
return <Navigate to="/login" replace state={{ from: location }} />; return <Navigate to="/login" replace state={{ from: location }} />;
+6
View File
@@ -111,6 +111,12 @@ export function clearStoreDraft(accountId?: string) {
localStorage.removeItem(storeDraftKey(accountId)); localStorage.removeItem(storeDraftKey(accountId));
} }
/** 清除当前账号及遗留的全局录店草稿 */
export function clearAllStoreDrafts(accountId?: string) {
clearStoreDraft(accountId);
localStorage.removeItem(STORE_DRAFT_KEY);
}
const PHONE_RE = /^1\d{10}$/; const PHONE_RE = /^1\d{10}$/;
const BANK_RE = /^\d{16,19}$/; const BANK_RE = /^\d{16,19}$/;
+34 -1
View File
@@ -1,8 +1,12 @@
import type { ClientRuntimeConfig, WechatLoginResult } from '@dukang/shared-types'; import type { ClientRuntimeConfig, WechatLoginResult } from '@dukang/shared-types';
import type { PartnerPhoneCheckResponse } from '@dukang/shared-types';
import { isWxAuthorizeEnabled } from '@dukang/shared-types'; import { isWxAuthorizeEnabled } from '@dukang/shared-types';
import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk'; import { WECHAT_INAPP_REQUIRED_MSG } from '@dukang/weixin-sdk';
import { isWechatEnv, weixinSdk } from './weixin'; import { isWechatEnv, weixinSdk } from './weixin';
import { request, saveWechatSession, type PartnerSessionPayload } from './api'; import { getPartnerProfile, request, saveWechatSession, type PartnerSessionPayload, type PartnerSessionProfile } from './api';
export const PARTNER_WECHAT_LOGIN_HINT =
'请先使用手机验证码登录,登录后将自动关联微信';
export type PartnerProfile = { export type PartnerProfile = {
id: string; id: string;
@@ -13,6 +17,35 @@ export type PartnerProfile = {
isPrimary?: boolean; 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<boolean> {
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<PartnerPhoneCheckResponse>('PARTNER_H5', '/partner/auth/phone/check', {
method: 'POST',
body: JSON.stringify({ phone: normalized }),
silent: true,
});
return !!res.hasWechat;
} catch {
return false;
}
}
export async function fetchClientConfig(): Promise<ClientRuntimeConfig> { export async function fetchClientConfig(): Promise<ClientRuntimeConfig> {
return request<ClientRuntimeConfig>('PARTNER_H5', '/common/client-config'); return request<ClientRuntimeConfig>('PARTNER_H5', '/common/client-config');
} }
+17 -2
View File
@@ -14,8 +14,10 @@ import { usePartnerSession } from '../contexts/PartnerSessionContext';
import { partnerHomePath } from '../lib/partnerAccess'; import { partnerHomePath } from '../lib/partnerAccess';
import { import {
bindPartnerWechatAfterSmsLogin, bindPartnerWechatAfterSmsLogin,
canPartnerUseWechatLogin,
fetchClientConfig, fetchClientConfig,
loginPartnerWithWechat, loginPartnerWithWechat,
PARTNER_WECHAT_LOGIN_HINT,
} from '../lib/wechat-auth'; } from '../lib/wechat-auth';
import { isWechatEnv } from '../lib/weixin'; import { isWechatEnv } from '../lib/weixin';
@@ -168,6 +170,14 @@ export default function LoginPage() {
setMsg(WECHAT_INAPP_REQUIRED_MSG); setMsg(WECHAT_INAPP_REQUIRED_MSG);
return; return;
} }
const canUseWechat = await canPartnerUseWechatLogin({
profile: savedProfile,
phone,
});
if (!canUseWechat) {
setMsg(PARTNER_WECHAT_LOGIN_HINT);
return;
}
setWxLoading(true); setWxLoading(true);
try { try {
const session = await loginPartnerWithWechat(); const session = await loginPartnerWithWechat();
@@ -183,7 +193,12 @@ export default function LoginPage() {
} }
if (quick) { if (quick) {
const canWechatQuick = wxAuthorize && isWechatEnv() && hasPartnerWxSession() && !!savedProfile; const canWechatQuick =
wxAuthorize &&
isWechatEnv() &&
hasPartnerWxSession() &&
!!savedProfile &&
savedProfile.hasWechat === true;
return ( return (
<div className="partner-auth-page partner-auth-page--quick"> <div className="partner-auth-page partner-auth-page--quick">
@@ -334,7 +349,7 @@ export default function LoginPage() {
</div> </div>
</main> </main>
{hasPartnerWxSession() && savedProfile && ( {hasPartnerWxSession() && savedProfile?.hasWechat && (
<Link to="/login?quick=1" className="partner-link"></Link> <Link to="/login?quick=1" className="partner-link"></Link>
)} )}
+12 -5
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom'; import { useNavigate, useSearchParams } from 'react-router-dom';
@@ -24,7 +24,7 @@ import { isSubAccount } from '../lib/partnerAccess';
import { import {
clearStoreDraft, clearAllStoreDrafts,
defaultStoreForm, defaultStoreForm,
@@ -114,6 +114,8 @@ export default function StoreCreatePage() {
const [smsHint, setSmsHint] = useState(''); const [smsHint, setSmsHint] = useState('');
const draftSaveDisabledRef = useRef(false);
function reportFormError(message: string) { function reportFormError(message: string) {
setSubmitError(message); setSubmitError(message);
} }
@@ -137,9 +139,8 @@ export default function StoreCreatePage() {
useEffect(() => { useEffect(() => {
if (draftSaveDisabledRef.current) return;
saveStoreDraft({ step, form }, accountId); saveStoreDraft({ step, form }, accountId);
}, [step, form, accountId]); }, [step, form, accountId]);
@@ -569,7 +570,13 @@ export default function StoreCreatePage() {
}); });
clearStoreDraft(accountId); draftSaveDisabledRef.current = true;
clearAllStoreDrafts(accountId);
setForm(defaultStoreForm());
setFieldErrors({});
setSubmitError('');
setSmsHint('');
setParams({ step: '1' }, { replace: true });
toastSuccess('门店录入成功'); toastSuccess('门店录入成功');
navigate(`/stores/${result.store.id}`); navigate(`/stores/${result.store.id}`);
} catch (e) { } catch (e) {
+9
View File
@@ -73,6 +73,15 @@ export interface PartnerStorePhoneAvailableResponse {
needConfirm?: boolean; needConfirm?: boolean;
} }
/** 合伙人登录前手机号校验 */
export interface PartnerPhoneCheckResponse {
ok: boolean;
maskedPhone: string;
name: string;
companyName?: string;
hasWechat?: boolean;
}
export interface PartnerWeeklyReportPeriod { export interface PartnerWeeklyReportPeriod {
startDate: string; startDate: string;
endDate: string; endDate: string;
@@ -264,6 +264,7 @@ export class AuthService {
maskedPhone: this.maskPhone(normalizedPhone), maskedPhone: this.maskPhone(normalizedPhone),
name: account.name, name: account.name,
companyName: primary.companyName, companyName: primary.companyName,
hasWechat: !!account.wxOpenId,
}; };
} }