fix:登录跳转失败问题
This commit is contained in:
@@ -1,13 +1,32 @@
|
||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import PartnerAppRoutes from './PartnerAppRoutes';
|
||||
import { isLoggedIn } from './lib/api';
|
||||
import { usePartnerSession } from './contexts/PartnerSessionContext';
|
||||
import { partnerHomePath } from './lib/partnerAccess';
|
||||
|
||||
function LoginRoute() {
|
||||
const { account } = usePartnerSession();
|
||||
if (isLoggedIn()) {
|
||||
return <Navigate to={partnerHomePath(account)} replace />;
|
||||
}
|
||||
return <LoginPage />;
|
||||
}
|
||||
|
||||
function AppRoutes() {
|
||||
const location = useLocation();
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/*" element={isLoggedIn() ? <PartnerAppRoutes /> : <Navigate to="/login" replace />} />
|
||||
<Route path="/login" element={<LoginRoute />} />
|
||||
<Route
|
||||
path="/*"
|
||||
element={isLoggedIn() ? <PartnerAppRoutes /> : <Navigate to="/login" replace state={{ from: location }} />}
|
||||
/>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return <AppRoutes />;
|
||||
}
|
||||
|
||||
@@ -61,12 +61,12 @@ function SubAccountRoutes() {
|
||||
}
|
||||
|
||||
export default function PartnerAppRoutes() {
|
||||
const { account, loading, loggedIn } = usePartnerSession();
|
||||
const { account, loading } = usePartnerSession();
|
||||
|
||||
if (!loggedIn && !isLoggedIn()) {
|
||||
if (!isLoggedIn()) {
|
||||
return <Navigate to="/login" replace />;
|
||||
}
|
||||
if (loading) {
|
||||
if (loading && !account) {
|
||||
return <SessionLoading />;
|
||||
}
|
||||
if (isSubAccount(account)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from 'react';
|
||||
import { toAppPath } from '@dukang/weixin-sdk';
|
||||
import { clearAuth, isLoggedIn, request } from '../lib/api';
|
||||
import { clearAuth, isLoggedIn, request, saveAuth, type PartnerAuthPayload } from '../lib/api';
|
||||
|
||||
import type { PartnerMe, PartnerStaffRole } from '@dukang/shared-types';
|
||||
|
||||
@@ -12,6 +12,7 @@ type PartnerSessionValue = {
|
||||
account: PartnerAccount | null;
|
||||
loading: boolean;
|
||||
loggedIn: boolean;
|
||||
applySession: (session: PartnerAuthPayload) => void;
|
||||
refresh: () => Promise<PartnerAccount | null>;
|
||||
logout: () => void;
|
||||
};
|
||||
@@ -23,6 +24,15 @@ export function PartnerSessionProvider({ children }: { children: ReactNode }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loggedIn, setLoggedIn] = useState(() => isLoggedIn());
|
||||
|
||||
const applySession = useCallback((session: PartnerAuthPayload) => {
|
||||
saveAuth(session);
|
||||
setLoggedIn(true);
|
||||
setLoading(false);
|
||||
if (session.partner) {
|
||||
setAccount(session.partner as PartnerAccount);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const refresh = useCallback(async (): Promise<PartnerAccount | null> => {
|
||||
if (!isLoggedIn()) {
|
||||
setAccount(null);
|
||||
@@ -38,6 +48,9 @@ export function PartnerSessionProvider({ children }: { children: ReactNode }) {
|
||||
return data;
|
||||
} catch {
|
||||
setAccount(null);
|
||||
if (!isLoggedIn()) {
|
||||
setLoggedIn(false);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -57,7 +70,7 @@ export function PartnerSessionProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
return (
|
||||
<PartnerSessionContext.Provider
|
||||
value={{ account, loading, loggedIn, refresh, logout }}
|
||||
value={{ account, loading, loggedIn, applySession, refresh, logout }}
|
||||
>
|
||||
{children}
|
||||
</PartnerSessionContext.Provider>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PartnerMe } from '@dukang/shared-types';
|
||||
import type { PartnerMe, PartnerStaffRole } from '@dukang/shared-types';
|
||||
import { isOnAppPath, toAppPath } from '@dukang/weixin-sdk';
|
||||
|
||||
export const apiBase = '/api/v1';
|
||||
@@ -6,7 +6,10 @@ export const apiBase = '/api/v1';
|
||||
const LAST_PHONE = 'partnerLastPhone';
|
||||
const PARTNER_PROFILE = 'partnerProfile';
|
||||
|
||||
export type PartnerSessionProfile = Pick<PartnerMe, 'id' | 'name' | 'phone' | 'companyName'>;
|
||||
export type PartnerSessionProfile = Pick<PartnerMe, 'id' | 'name' | 'phone' | 'companyName'> & {
|
||||
isPrimary?: PartnerMe['isPrimary'];
|
||||
staffRole?: PartnerStaffRole;
|
||||
};
|
||||
|
||||
export type PartnerAuthPayload = {
|
||||
accessToken: string;
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ClientRuntimeConfig, WechatLoginResult } from '@dukang/shared-type
|
||||
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';
|
||||
import { request, saveAuth, type PartnerSessionProfile } from './api';
|
||||
|
||||
export type PartnerProfile = {
|
||||
id: string;
|
||||
@@ -37,7 +37,10 @@ export async function checkNeedsWechatAuth(profile: PartnerProfile | null): Prom
|
||||
/** 处理微信登录/绑定结果,返回是否已拿到 token 可进入首页 */
|
||||
export function handlePartnerWechatLoginResult(result: WechatLoginResult): boolean {
|
||||
if (!result.accessToken) return false;
|
||||
saveAuth({ accessToken: result.accessToken });
|
||||
saveAuth({
|
||||
accessToken: result.accessToken,
|
||||
partner: result.partner as PartnerSessionProfile | undefined,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { request, getLastPhone, getPartnerProfile, saveAuth } from '../lib/api';
|
||||
import { request, getLastPhone, getPartnerProfile, type PartnerAuthPayload } from '../lib/api';
|
||||
import { usePartnerSession } from '../contexts/PartnerSessionContext';
|
||||
import type { PartnerAccount } from '../contexts/PartnerSessionContext';
|
||||
import { partnerHomePath } from '../lib/partnerAccess';
|
||||
import type { PartnerMe } from '@dukang/shared-types';
|
||||
import {
|
||||
fetchClientConfig,
|
||||
handlePartnerWechatCallback,
|
||||
handlePartnerWechatLoginResult,
|
||||
loginPartnerWithWechat,
|
||||
} from '../lib/wechat-auth';
|
||||
import { isWechatEnv } from '../lib/weixin';
|
||||
@@ -43,9 +43,21 @@ function formatPartnerError(e: unknown): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
function toLoginSession(data: { accessToken: string; partner?: PartnerMe }): PartnerAuthPayload {
|
||||
return {
|
||||
accessToken: data.accessToken,
|
||||
partner: data.partner,
|
||||
};
|
||||
}
|
||||
|
||||
function toPartnerAccount(partner?: Record<string, unknown>): PartnerAccount | undefined {
|
||||
if (!partner || typeof partner.id !== 'string') return undefined;
|
||||
return partner as unknown as PartnerAccount;
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const navigate = useNavigate();
|
||||
const { refresh } = usePartnerSession();
|
||||
const { applySession } = usePartnerSession();
|
||||
const [params] = useSearchParams();
|
||||
const quick = params.get('quick') === '1';
|
||||
const savedProfile = getPartnerProfile();
|
||||
@@ -73,14 +85,17 @@ export default function LoginPage() {
|
||||
useEffect(() => {
|
||||
if (!isWechatEnv() || !wxAuthorize || !params.get('code')) return;
|
||||
void handlePartnerWechatCallback()
|
||||
.then(async (result) => {
|
||||
if (!result) return;
|
||||
if (!handlePartnerWechatLoginResult(result)) return;
|
||||
const account = await refresh();
|
||||
navigate(partnerHomePath(account ?? undefined));
|
||||
.then((result) => {
|
||||
if (!result?.accessToken) return;
|
||||
const session: PartnerAuthPayload = {
|
||||
accessToken: result.accessToken,
|
||||
partner: toPartnerAccount(result.partner),
|
||||
};
|
||||
applySession(session);
|
||||
navigate(partnerHomePath(session.partner), { replace: true });
|
||||
})
|
||||
.catch((e) => setMsg(formatWechatError(e)));
|
||||
}, [navigate, refresh, wxAuthorize, params]);
|
||||
}, [applySession, navigate, wxAuthorize, params]);
|
||||
|
||||
function formatWechatError(e: unknown): string {
|
||||
const text = e instanceof Error ? e.message : '微信登录失败';
|
||||
@@ -155,10 +170,10 @@ export default function LoginPage() {
|
||||
body: JSON.stringify({ phone: loginPhone, code }),
|
||||
silent: true,
|
||||
});
|
||||
saveAuth(data);
|
||||
const session = toLoginSession(data);
|
||||
applySession(session);
|
||||
persistRememberAccount(loginPhone);
|
||||
const account = await refresh();
|
||||
navigate(partnerHomePath(account ?? data.partner));
|
||||
navigate(partnerHomePath(session.partner), { replace: true });
|
||||
} catch (e) {
|
||||
setMsg(formatPartnerError(e));
|
||||
} finally {
|
||||
@@ -177,8 +192,11 @@ export default function LoginPage() {
|
||||
try {
|
||||
const ok = await loginPartnerWithWechat();
|
||||
if (ok) {
|
||||
const account = await refresh();
|
||||
navigate(partnerHomePath(account ?? undefined));
|
||||
applySession({
|
||||
accessToken: localStorage.getItem('accessToken') ?? '',
|
||||
partner: getPartnerProfile() ?? undefined,
|
||||
});
|
||||
navigate(partnerHomePath(getPartnerProfile()), { replace: true });
|
||||
}
|
||||
} catch (e) {
|
||||
setMsg(formatWechatError(e));
|
||||
|
||||
@@ -55,7 +55,11 @@ async function main() {
|
||||
);
|
||||
if (!login.accessToken) throw new Error('login missing token');
|
||||
|
||||
console.log('4. Admin partner logs list');
|
||||
console.log('4. PARTNER /partner/me after login');
|
||||
const me = await req('PARTNER_H5', '/partner/me', { token: login.accessToken });
|
||||
if (!me?.id || !me?.phone) throw new Error('partner/me missing profile');
|
||||
|
||||
console.log('5. Admin partner logs list');
|
||||
const admin = await req('HQ_WEB', '/admin/auth/login/password', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user