diff --git a/apps/h5-partner/src/App.tsx b/apps/h5-partner/src/App.tsx
index d9d6182..af7de6e 100644
--- a/apps/h5-partner/src/App.tsx
+++ b/apps/h5-partner/src/App.tsx
@@ -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 ;
+ }
+ return ;
+}
+
+function AppRoutes() {
+ const location = useLocation();
-export default function App() {
return (
- } />
- : } />
+ } />
+ : }
+ />
);
}
+
+export default function App() {
+ return ;
+}
diff --git a/apps/h5-partner/src/PartnerAppRoutes.tsx b/apps/h5-partner/src/PartnerAppRoutes.tsx
index 89f1b55..71f60f3 100644
--- a/apps/h5-partner/src/PartnerAppRoutes.tsx
+++ b/apps/h5-partner/src/PartnerAppRoutes.tsx
@@ -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 ;
}
- if (loading) {
+ if (loading && !account) {
return ;
}
if (isSubAccount(account)) {
diff --git a/apps/h5-partner/src/contexts/PartnerSessionContext.tsx b/apps/h5-partner/src/contexts/PartnerSessionContext.tsx
index b772723..a64faaa 100644
--- a/apps/h5-partner/src/contexts/PartnerSessionContext.tsx
+++ b/apps/h5-partner/src/contexts/PartnerSessionContext.tsx
@@ -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;
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 => {
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 (
{children}
diff --git a/apps/h5-partner/src/lib/api.ts b/apps/h5-partner/src/lib/api.ts
index b1f18d4..5bc722b 100644
--- a/apps/h5-partner/src/lib/api.ts
+++ b/apps/h5-partner/src/lib/api.ts
@@ -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;
+export type PartnerSessionProfile = Pick & {
+ isPrimary?: PartnerMe['isPrimary'];
+ staffRole?: PartnerStaffRole;
+};
export type PartnerAuthPayload = {
accessToken: string;
diff --git a/apps/h5-partner/src/lib/wechat-auth.ts b/apps/h5-partner/src/lib/wechat-auth.ts
index ab434ab..c32cd01 100644
--- a/apps/h5-partner/src/lib/wechat-auth.ts
+++ b/apps/h5-partner/src/lib/wechat-auth.ts
@@ -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;
}
diff --git a/apps/h5-partner/src/pages/LoginPage.tsx b/apps/h5-partner/src/pages/LoginPage.tsx
index fce59d0..bcc662d 100644
--- a/apps/h5-partner/src/pages/LoginPage.tsx
+++ b/apps/h5-partner/src/pages/LoginPage.tsx
@@ -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): 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));
diff --git a/scripts/test-partner-auth.mjs b/scripts/test-partner-auth.mjs
index 25ba9ed..94c394e 100644
--- a/scripts/test-partner-auth.mjs
+++ b/scripts/test-partner-auth.mjs
@@ -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({