699ea6e8
杨鑫
完善打印逻辑
|
1
2
3
4
5
6
7
8
9
10
11
|
import React from "react";
import { toast } from "sonner";
import { ApiError } from "../../lib/apiClient";
import { clearTokens, getAccessToken } from "../../lib/authStorage";
import type { CurrentUserMenuNodeDto, CurrentUserBriefDto } from "../../types/authSession";
import { getMyMenus, logout as logoutApi } from "../../services/authSessionService";
export type AuthState = {
token: string | null;
user: CurrentUserBriefDto | null;
|
ef6b3255
杨鑫
修改BUG
|
12
13
|
/** `/auth-session/my-menus` 根级 `role`:人类可读角色名,用于顶栏/欢迎语等 */
roleDisplay: string | null;
|
699ea6e8
杨鑫
完善打印逻辑
|
14
15
16
|
menus: CurrentUserMenuNodeDto[];
permissionCodes: string[];
roleCodes: string[];
|
540ac0e3
杨鑫
前端修改bug
|
17
18
|
/** 角色勾选的访问权限(manage_people 等) */
roleAccessPermissionCodes: string[];
|
699ea6e8
杨鑫
完善打印逻辑
|
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
loading: boolean;
};
type AuthContextValue = AuthState & {
refresh: () => Promise<void>;
clearLocalAuth: () => void;
logout: () => Promise<void>;
};
const AuthContext = React.createContext<AuthContextValue | null>(null);
export function useAuth() {
const ctx = React.useContext(AuthContext);
if (!ctx) throw new Error("useAuth must be used within AuthProvider");
return ctx;
}
function normalizeId(x: any): string {
return String(x?.id ?? x?.Id ?? "");
}
function normalizeMenuNode(n: any): CurrentUserMenuNodeDto {
const childrenRaw = n?.children ?? n?.Children;
const children = Array.isArray(childrenRaw) ? childrenRaw.map(normalizeMenuNode) : undefined;
return {
id: normalizeId(n),
parentId: (n?.parentId ?? n?.ParentId ?? null) as any,
menuName: (n?.menuName ?? n?.MenuName ?? null) as any,
routerName: (n?.routerName ?? n?.RouterName ?? null) as any,
// doc: rbac-menu 新增 router;平台端历史字段为 routeUrl
routeUrl: (n?.routeUrl ?? n?.RouteUrl ?? n?.router ?? n?.Router ?? null) as any,
menuIcon: (n?.menuIcon ?? n?.MenuIcon ?? null) as any,
menuType: (n?.menuType ?? n?.MenuType ?? null) as any,
permissionCode: (n?.permissionCode ?? n?.PermissionCode ?? null) as any,
orderNum: (n?.orderNum ?? n?.OrderNum ?? null) as any,
state: (n?.state ?? n?.State ?? null) as any,
component: (n?.component ?? n?.Component ?? null) as any,
isCache: (n?.isCache ?? n?.IsCache ?? null) as any,
isShow: (n?.isShow ?? n?.IsShow ?? null) as any,
query: (n?.query ?? n?.Query ?? null) as any,
remark: (n?.remark ?? n?.Remark ?? null) as any,
link: (n?.link ?? n?.Link ?? null) as any,
menuSource: (n?.menuSource ?? n?.MenuSource ?? null) as any,
concurrencyStamp: (n?.concurrencyStamp ?? n?.ConcurrencyStamp ?? null) as any,
children,
};
}
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = React.useState<AuthState>(() => ({
token: getAccessToken(),
user: null,
|
ef6b3255
杨鑫
修改BUG
|
71
|
roleDisplay: null,
|
699ea6e8
杨鑫
完善打印逻辑
|
72
73
74
|
menus: [],
permissionCodes: [],
roleCodes: [],
|
540ac0e3
杨鑫
前端修改bug
|
75
|
roleAccessPermissionCodes: [],
|
699ea6e8
杨鑫
完善打印逻辑
|
76
77
78
79
80
81
|
loading: false,
}));
const refresh = React.useCallback(async () => {
const token = getAccessToken();
if (!token) {
|
ef6b3255
杨鑫
修改BUG
|
82
83
84
85
86
87
88
89
|
setState((s) => ({
...s,
token: null,
user: null,
roleDisplay: null,
menus: [],
permissionCodes: [],
roleCodes: [],
|
540ac0e3
杨鑫
前端修改bug
|
90
|
roleAccessPermissionCodes: [],
|
ef6b3255
杨鑫
修改BUG
|
91
92
|
loading: false,
}));
|
699ea6e8
杨鑫
完善打印逻辑
|
93
94
95
96
97
98
99
100
101
|
return;
}
setState((s) => ({ ...s, token, loading: true }));
try {
const res = await getMyMenus();
const menus = Array.isArray((res as any)?.menus) ? (res as any).menus.map(normalizeMenuNode) : [];
const permissionCodes = Array.isArray((res as any)?.permissionCodes) ? (res as any).permissionCodes : [];
const roleCodes = Array.isArray((res as any)?.roleCodes) ? (res as any).roleCodes : [];
|
540ac0e3
杨鑫
前端修改bug
|
102
103
104
105
106
|
const roleAccessRaw =
(res as any)?.accessPermissionCodes ?? (res as any)?.AccessPermissionCodes ?? [];
const roleAccessPermissionCodes = Array.isArray(roleAccessRaw)
? roleAccessRaw.map((x: unknown) => String(x ?? "").trim()).filter(Boolean)
: [];
|
699ea6e8
杨鑫
完善打印逻辑
|
107
|
const u0 = (res as any)?.user ?? null;
|
ef6b3255
杨鑫
修改BUG
|
108
109
110
111
112
113
|
const roleRaw = (res as any)?.role ?? (res as any)?.Role ?? null;
const roleDisplay =
roleRaw != null && String(roleRaw).trim() ? String(roleRaw).trim() : null;
// 后端常把 fullName / lastUpdated 放在与 user 同级(与抓包 data 下结构一致),需与 user 内字段合并
const rootFullName = (res as any)?.fullName ?? (res as any)?.FullName ?? null;
const rootLastUpdated = (res as any)?.lastUpdated ?? (res as any)?.LastUpdated ?? null;
|
699ea6e8
杨鑫
完善打印逻辑
|
114
115
116
117
|
const user: CurrentUserBriefDto | null = u0
? {
id: String(u0.id ?? u0.Id ?? ""),
userName: String(u0.userName ?? u0.UserName ?? ""),
|
ef6b3255
杨鑫
修改BUG
|
118
|
fullName: (u0.fullName ?? u0.FullName ?? rootFullName ?? null) as any,
|
699ea6e8
杨鑫
完善打印逻辑
|
119
120
121
|
nick: (u0.nick ?? u0.Nick ?? null) as any,
email: (u0.email ?? u0.Email ?? null) as any,
icon: (u0.icon ?? u0.Icon ?? null) as any,
|
ef6b3255
杨鑫
修改BUG
|
122
|
lastUpdated: (u0.lastUpdated ?? u0.LastUpdated ?? rootLastUpdated ?? null) as any,
|
699ea6e8
杨鑫
完善打印逻辑
|
123
124
125
126
127
128
129
|
}
: null;
setState((s) => ({
...s,
token,
user,
|
ef6b3255
杨鑫
修改BUG
|
130
|
roleDisplay,
|
699ea6e8
杨鑫
完善打印逻辑
|
131
132
133
|
menus,
permissionCodes,
roleCodes,
|
540ac0e3
杨鑫
前端修改bug
|
134
|
roleAccessPermissionCodes,
|
699ea6e8
杨鑫
完善打印逻辑
|
135
136
137
138
139
140
141
142
|
loading: false,
}));
} catch (e: unknown) {
const isApi = e instanceof ApiError;
const status = isApi ? e.status : 0;
const isAuthFailure = isApi && (status === 401 || status === 403);
const description =
|
91821909
杨鑫
最新
|
143
144
|
e instanceof Error ? e.message : typeof e === "string" ? e : "Please try again later.";
toast.error("Failed to load menu permissions", { description });
|
699ea6e8
杨鑫
完善打印逻辑
|
145
146
147
148
149
150
151
152
|
if (isAuthFailure) {
clearTokens();
setState((s) => ({
...s,
loading: false,
token: null,
user: null,
|
ef6b3255
杨鑫
修改BUG
|
153
|
roleDisplay: null,
|
699ea6e8
杨鑫
完善打印逻辑
|
154
155
156
|
menus: [],
permissionCodes: [],
roleCodes: [],
|
540ac0e3
杨鑫
前端修改bug
|
157
|
roleAccessPermissionCodes: [],
|
699ea6e8
杨鑫
完善打印逻辑
|
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
}));
} else {
// 500/网络错误等:保留 token,不退出;menus 为空时 Sidebar 使用静态 fallback
setState((s) => ({ ...s, loading: false }));
}
}
}, []);
React.useEffect(() => {
refresh();
}, [refresh]);
const clearLocalAuth = React.useCallback(() => {
clearTokens();
|
ef6b3255
杨鑫
修改BUG
|
172
173
174
175
176
177
178
179
|
setState((s) => ({
...s,
token: null,
user: null,
roleDisplay: null,
menus: [],
permissionCodes: [],
roleCodes: [],
|
540ac0e3
杨鑫
前端修改bug
|
180
|
roleAccessPermissionCodes: [],
|
ef6b3255
杨鑫
修改BUG
|
181
|
}));
|
699ea6e8
杨鑫
完善打印逻辑
|
182
183
184
185
186
187
188
189
190
|
}, []);
const logout = React.useCallback(async () => {
try {
await logoutApi();
} catch {
// ignore: server-side cache clear best-effort
} finally {
clearLocalAuth();
|
ef6b3255
杨鑫
修改BUG
|
191
|
toast.success("Logged out");
|
699ea6e8
杨鑫
完善打印逻辑
|
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
}
}, [clearLocalAuth]);
const value: AuthContextValue = React.useMemo(
() => ({
...state,
refresh,
clearLocalAuth,
logout,
}),
[state, refresh, clearLocalAuth, logout],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
|