fix(h5-shop): tip unbound WeChat login to use phone first
This commit is contained in:
@@ -20,6 +20,9 @@ import {
|
|||||||
fetchClientConfig,
|
fetchClientConfig,
|
||||||
handleShopWechatCallback,
|
handleShopWechatCallback,
|
||||||
handleShopWechatLoginResult,
|
handleShopWechatLoginResult,
|
||||||
|
isShopWechatUnboundError,
|
||||||
|
SHOP_WX_NEED_PHONE_LOGIN_MSG,
|
||||||
|
stashShopWechatLoginHint,
|
||||||
} from '../lib/wechat-auth';
|
} from '../lib/wechat-auth';
|
||||||
import { isWechatEnv } from '../lib/weixin';
|
import { isWechatEnv } from '../lib/weixin';
|
||||||
|
|
||||||
@@ -83,7 +86,11 @@ export function StoreSessionProvider({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
stripOAuthParamsFromLocation();
|
stripOAuthParamsFromLocation();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
const raw = e instanceof Error ? e.message : '';
|
||||||
|
if (isShopWechatUnboundError(raw)) {
|
||||||
|
stashShopWechatLoginHint(SHOP_WX_NEED_PHONE_LOGIN_MSG);
|
||||||
|
}
|
||||||
stripOAuthParamsFromLocation();
|
stripOAuthParamsFromLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,40 @@ export type ShopAccountProfile = {
|
|||||||
store?: { name: string };
|
store?: { name: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 微信未绑定门店账号时的登录提示 */
|
||||||
|
export const SHOP_WX_NEED_PHONE_LOGIN_MSG = '请先用手机号登录';
|
||||||
|
|
||||||
|
const SHOP_WX_LOGIN_HINT_KEY = 'shop_wx_login_hint';
|
||||||
|
|
||||||
|
export function isShopWechatUnboundError(message: string): boolean {
|
||||||
|
return message.includes('首次登录') || message.includes('手机验证码') || message.includes('请先用手机号');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatShopWechatError(e: unknown): string {
|
||||||
|
const text = e instanceof Error ? e.message : '微信登录失败';
|
||||||
|
if (isShopWechatUnboundError(text)) return SHOP_WX_NEED_PHONE_LOGIN_MSG;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** OAuth 在启动层失败时暂存提示,供登录页展示 */
|
||||||
|
export function stashShopWechatLoginHint(message: string): void {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(SHOP_WX_LOGIN_HINT_KEY, message);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function consumeShopWechatLoginHint(): string | null {
|
||||||
|
try {
|
||||||
|
const hint = sessionStorage.getItem(SHOP_WX_LOGIN_HINT_KEY);
|
||||||
|
if (hint) sessionStorage.removeItem(SHOP_WX_LOGIN_HINT_KEY);
|
||||||
|
return hint;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchClientConfig(): Promise<ClientRuntimeConfig> {
|
export async function fetchClientConfig(): Promise<ClientRuntimeConfig> {
|
||||||
return request<ClientRuntimeConfig>('SHOP_H5', '/common/client-config');
|
return request<ClientRuntimeConfig>('SHOP_H5', '/common/client-config');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ import {
|
|||||||
import { routeAfterShopLogin } from './SelectStorePage';
|
import { routeAfterShopLogin } from './SelectStorePage';
|
||||||
import {
|
import {
|
||||||
bindShopWechatAfterSmsLogin,
|
bindShopWechatAfterSmsLogin,
|
||||||
|
consumeShopWechatLoginHint,
|
||||||
fetchClientConfig,
|
fetchClientConfig,
|
||||||
|
formatShopWechatError,
|
||||||
handleShopWechatCallback,
|
handleShopWechatCallback,
|
||||||
handleShopWechatLoginResult,
|
handleShopWechatLoginResult,
|
||||||
loginShopWithWechat,
|
loginShopWithWechat,
|
||||||
@@ -27,14 +29,6 @@ function maskPhone(phone: string) {
|
|||||||
return `${phone.slice(0, 3)} **** ${phone.slice(-4)}`;
|
return `${phone.slice(0, 3)} **** ${phone.slice(-4)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatWechatError(e: unknown): string {
|
|
||||||
const text = e instanceof Error ? e.message : '微信登录失败';
|
|
||||||
if (text.includes('首次登录') || text.includes('手机验证码')) {
|
|
||||||
return '该微信尚未绑定门店账号,请先使用手机验证码登录,登录后将自动关联微信';
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ShopAgreementCheckbox({
|
function ShopAgreementCheckbox({
|
||||||
agreed,
|
agreed,
|
||||||
onChange,
|
onChange,
|
||||||
@@ -76,7 +70,7 @@ export default function LoginPage() {
|
|||||||
const [agreed, setAgreed] = useState(false);
|
const [agreed, setAgreed] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [wxLoading, setWxLoading] = useState(false);
|
const [wxLoading, setWxLoading] = useState(false);
|
||||||
const [msg, setMsg] = useState('');
|
const [msg, setMsg] = useState(() => consumeShopWechatLoginHint() ?? '');
|
||||||
const [codeCooldown, setCodeCooldown] = useState(0);
|
const [codeCooldown, setCodeCooldown] = useState(0);
|
||||||
const [wxAuthorize, setWxAuthorize] = useState(false);
|
const [wxAuthorize, setWxAuthorize] = useState(false);
|
||||||
const agreementRef = useRef<HTMLLabelElement>(null);
|
const agreementRef = useRef<HTMLLabelElement>(null);
|
||||||
@@ -87,6 +81,11 @@ export default function LoginPage() {
|
|||||||
.catch(() => setWxAuthorize(false));
|
.catch(() => setWxAuthorize(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const hint = consumeShopWechatLoginHint();
|
||||||
|
if (hint) setMsg(hint);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isWechatEnv() || !wxAuthorize || !params.get('code')) return;
|
if (!isWechatEnv() || !wxAuthorize || !params.get('code')) return;
|
||||||
void handleShopWechatCallback()
|
void handleShopWechatCallback()
|
||||||
@@ -100,7 +99,7 @@ export default function LoginPage() {
|
|||||||
routeAfterShopLogin(session, navigate);
|
routeAfterShopLogin(session, navigate);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => setMsg(formatWechatError(e)));
|
.catch((e) => setMsg(formatShopWechatError(e)));
|
||||||
}, [applySession, navigate, params, setSearchParams, wxAuthorize]);
|
}, [applySession, navigate, params, setSearchParams, wxAuthorize]);
|
||||||
|
|
||||||
const quickStoreName = savedProfile?.storeName ?? '门店管理中心';
|
const quickStoreName = savedProfile?.storeName ?? '门店管理中心';
|
||||||
@@ -178,7 +177,7 @@ export default function LoginPage() {
|
|||||||
routeAfterShopLogin(session, navigate);
|
routeAfterShopLogin(session, navigate);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setMsg(formatWechatError(e));
|
setMsg(formatShopWechatError(e));
|
||||||
} finally {
|
} finally {
|
||||||
setWxLoading(false);
|
setWxLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1538,7 +1538,7 @@ export class AuthService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
throw new BadRequestException('首次登录请使用手机验证码,登录后将自动关联微信');
|
throw new BadRequestException('请先用手机号登录');
|
||||||
}
|
}
|
||||||
|
|
||||||
account = await this.prisma.storeAccount.update({
|
account = await this.prisma.storeAccount.update({
|
||||||
|
|||||||
Reference in New Issue
Block a user