feat(admin,api,player): 代理层级管理、额度上下分与玩家钱包详情
新增代理管理器与二级代理体系,完善信用额度/上下分上下文与冻结策略;代理端玩家与子代理管理增强;玩家端新增钱包详情页与交易筛选优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
79
apps/admin/src/utils/session-hydrate.ts
Normal file
79
apps/admin/src/utils/session-hydrate.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import {
|
||||
reconcileStaffSessionFromToken,
|
||||
useAuthStore,
|
||||
type StaffUser,
|
||||
type StaffUserType,
|
||||
} from '../stores/auth';
|
||||
|
||||
let hydratePromise: Promise<boolean> | null = null;
|
||||
|
||||
function isStaffUserType(value: unknown): value is StaffUserType {
|
||||
return value === 'ADMIN' || value === 'AGENT';
|
||||
}
|
||||
|
||||
export function resetStaffSessionHydration() {
|
||||
hydratePromise = null;
|
||||
}
|
||||
|
||||
function hasCompleteStaffUser(u: StaffUser | null | undefined): u is StaffUser {
|
||||
return !!(u?.id && u.username && u.userType);
|
||||
}
|
||||
|
||||
/** Sync manage_user from JWT + /manage/auth/me (fixes stale localStorage userType). */
|
||||
export async function hydrateStaffSession(): Promise<boolean> {
|
||||
const auth = useAuthStore();
|
||||
if (!auth.token.value) return false;
|
||||
if (hydratePromise) return hydratePromise;
|
||||
|
||||
hydratePromise = (async () => {
|
||||
reconcileStaffSessionFromToken();
|
||||
|
||||
if (!hasCompleteStaffUser(auth.user.value)) {
|
||||
auth.clearStaffSession();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const { default: api } = await import('../api');
|
||||
const { data } = await api.get('/manage/auth/me');
|
||||
const raw = data.data as Partial<StaffUser>;
|
||||
if (!raw?.id || !raw.username || !isStaffUserType(raw.userType)) {
|
||||
return true;
|
||||
}
|
||||
auth.setSession(auth.token.value, {
|
||||
id: raw.id,
|
||||
username: raw.username,
|
||||
userType: raw.userType,
|
||||
locale: raw.locale,
|
||||
role: raw.role,
|
||||
agentLevel: typeof raw.agentLevel === 'number' ? raw.agentLevel : null,
|
||||
});
|
||||
return true;
|
||||
} catch (e: unknown) {
|
||||
const status = (e as { response?: { status?: number } })?.response?.status;
|
||||
if (status === 401) {
|
||||
auth.clearStaffSession();
|
||||
return false;
|
||||
}
|
||||
return hasCompleteStaffUser(auth.user.value);
|
||||
} finally {
|
||||
hydratePromise = null;
|
||||
}
|
||||
})();
|
||||
|
||||
return hydratePromise;
|
||||
}
|
||||
|
||||
/** Run before any authenticated route — JWT reconcile + optional /me refresh. */
|
||||
export async function ensureStaffSession(): Promise<boolean> {
|
||||
reconcileStaffSessionFromToken();
|
||||
const auth = useAuthStore();
|
||||
if (!auth.token.value) return false;
|
||||
if (!hasCompleteStaffUser(auth.user.value)) {
|
||||
reconcileStaffSessionFromToken();
|
||||
}
|
||||
if (!hasCompleteStaffUser(auth.user.value)) {
|
||||
return false;
|
||||
}
|
||||
return hydrateStaffSession();
|
||||
}
|
||||
Reference in New Issue
Block a user