refactor(auth): 管理端清除多身份残留(identities/currentIdentity/selectIdentity/Identity)

- auth.tsx/type 去 identities/currentIdentity 状态与 Identity 类型,role 恒取 user.role
- api/auth.ts 删 selectIdentity、getSavedUser/saveUser 去 identity 字段
- types.ts LoginResponse 去 identities/identity_id/port/identity_name 字段

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Pine
2026-08-26 19:16:14 +08:00
parent 40176d2149
commit fc1841dfe6
3 changed files with 7 additions and 50 deletions
+3 -11
View File
@@ -1,5 +1,5 @@
import { api, setToken } from "@/api/client";
import type { Identity, LoginResponse } from "@/types";
import type { LoginResponse } from "@/types";
export async function login(username: string, password: string): Promise<LoginResponse> {
const res = await api.post<LoginResponse>("/auth/login", { username, password });
@@ -7,14 +7,6 @@ export async function login(username: string, password: string): Promise<LoginRe
return res;
}
export async function selectIdentity(identityId: string): Promise<LoginResponse> {
const res = await api.post<LoginResponse>("/auth/select-identity", {
identity_id: identityId,
});
setToken(res.token);
return res;
}
// ---- 四种登录:短信验证码 / 微信扫码 / 小程序扫码 ----
export async function sendCode(phone: string): Promise<{ sent: boolean; message: string; stub_code?: string }> {
@@ -64,7 +56,7 @@ export async function fetchMe(): Promise<Record<string, unknown>> {
return api.get("/auth/me");
}
export function getSavedUser(): { username?: string; role?: string; identity?: Identity } | null {
export function getSavedUser(): { username?: string; role?: string } | null {
try {
return JSON.parse(localStorage.getItem("@cloud-opc-admin/user") || "null");
} catch {
@@ -72,7 +64,7 @@ export function getSavedUser(): { username?: string; role?: string; identity?: I
}
}
export function saveUser(user: { username?: string; role?: string; identity?: Identity } | null) {
export function saveUser(user: { username?: string; role?: string } | null) {
if (user) localStorage.setItem("@cloud-opc-admin/user", JSON.stringify(user));
else localStorage.removeItem("@cloud-opc-admin/user");
}
+4 -22
View File
@@ -2,13 +2,11 @@ import * as React from "react";
import { api, setToken as persistToken } from "@/api/client";
import * as authApi from "@/api/auth";
import { clearParkAuth } from "@/lib/parkAuth";
import type { Identity, LoginResponse } from "@/types";
import type { LoginResponse } from "@/types";
interface AuthState {
token: string | null;
user: LoginResponse | null;
identities: Identity[];
currentIdentity: Identity | null;
}
interface AuthContextValue extends AuthState {
@@ -28,29 +26,20 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
typeof window === "undefined" ? null : (localStorage.getItem("cloud_opc_admin_token") ?? null),
);
const [user, setUser] = React.useState<LoginResponse | null>(null);
const [identities, setIdentities] = React.useState<Identity[]>([]);
const [currentIdentity, setCurrentIdentity] = React.useState<Identity | null>(null);
// 启动/刷新时若有 token:先本地还原 saved user(立即有 role,避免「无权限」闪屏),
// 再调 /auth/me 从后端还原权威身份(identities / 当前身份 / permissions)。
// 再调 /auth/me 从后端还原权威身份(role / permissions,账号单一角色)。
React.useEffect(() => {
if (!token) return;
const saved = authApi.getSavedUser();
if (saved?.username) {
setUser((u) => ({ ...(u ?? {}), username: saved.username, role: saved.role } as LoginResponse));
if (saved.identity) setCurrentIdentity(saved.identity);
}
authApi
.fetchMe()
.then((res) => {
const r = res as unknown as LoginResponse;
const identities = r.identities ?? [];
setUser((u) => ({ ...(u ?? {}), username: r.username ?? u?.username, role: r.role ?? u?.role, ...r }));
if (identities.length) setIdentities(identities);
const current = identities.find((i) => i.id === r.identity_id);
if (current) setCurrentIdentity(current);
else if (saved?.identity) setCurrentIdentity(saved.identity);
else if (identities[0]) setCurrentIdentity(identities[0]);
})
.catch(() => { /* 401 时 api client 已触发 auth:expired → 登出 */ });
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -81,17 +70,12 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
if (res.token) persistToken(res.token);
setToken(res.token);
setUser(res);
setIdentities(res.identities ?? []);
const current = res.identities?.find((i) => i.id === res.identity_id) || null;
setCurrentIdentity(current || (res.identities?.[0] ?? null));
authApi.saveUser({ username: res.username, role: current?.role || res.role, identity: current || undefined });
authApi.saveUser({ username: res.username, role: res.role });
}
function logout() {
setToken(null);
setUser(null);
setIdentities([]);
setCurrentIdentity(null);
localStorage.removeItem("cloud_opc_admin_token");
authApi.saveUser(null);
clearParkAuth(); // 一并清除园区端(园区账密)登录态,避免回跳 /park 死循环
@@ -101,10 +85,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const value: AuthContextValue = {
token,
user,
identities,
currentIdentity,
isAuthed: !!token,
// 账号单一角色:role 恒取账号真实类型(user.role),不再多身份/currentIdentity
// 账号单一角色:role 恒取账号真实类型(user.role)。
role: user?.role || null,
permissions: user?.permissions ?? [],
username: user?.username ?? null,
-17
View File
@@ -1,19 +1,5 @@
export interface Identity {
id: string;
port: string;
role: string;
sub_role?: string | null;
name?: string;
org_id?: string | null;
region_id?: string | null;
org_name?: string | null;
region_name?: string | null;
status: string;
}
export interface LoginResponse {
token: string;
identities: Identity[];
username?: string;
nickname?: string;
avatar?: string;
@@ -24,9 +10,6 @@ export interface LoginResponse {
permissions?: string[];
scope_region_ids?: string[];
scope_level?: string;
identity_id?: string;
port?: string;
identity_name?: string;
}
// ---- 管理业务模型(server-core /admin/* 端点,部分端点尚未实现)----