import { ref, computed } from 'vue'; export type StaffUserType = 'ADMIN' | 'AGENT'; export interface StaffUser { id: string; username: string; userType: StaffUserType; locale?: string; role?: string; agentLevel?: number | null; maxAgentLevel?: number | null; canManageSubAgents?: boolean; } const TOKEN_KEY = 'manage_token'; const USER_KEY = 'manage_user'; function decodeJwtStaffClaims(rawToken: string): Partial | null { try { const segment = rawToken.split('.')[1]; if (!segment) return null; const padded = segment.replace(/-/g, '+').replace(/_/g, '/'); const payload = JSON.parse(atob(padded)) as { sub?: string; username?: string; userType?: string; role?: string; }; if (payload.userType !== 'ADMIN' && payload.userType !== 'AGENT') return null; if (!payload.sub || !payload.username) return null; return { id: payload.sub, username: payload.username, userType: payload.userType as StaffUserType, role: payload.role, }; } catch { return null; } } function loadUser(): StaffUser | null { try { const raw = localStorage.getItem(USER_KEY); if (!raw) return null; const parsed = JSON.parse(raw) as Partial; if (!parsed.id || !parsed.username || !parsed.userType) return null; return parsed as StaffUser; } catch { return null; } } function migrateLegacyTokens() { if (localStorage.getItem(TOKEN_KEY)) return; const legacyAdmin = localStorage.getItem('admin_token'); const legacyAgent = localStorage.getItem('agent_token'); if (legacyAdmin) { localStorage.setItem(TOKEN_KEY, legacyAdmin); localStorage.removeItem('admin_token'); localStorage.removeItem(USER_KEY); return; } if (legacyAgent) { localStorage.setItem(TOKEN_KEY, legacyAgent); localStorage.removeItem('agent_token'); localStorage.removeItem(USER_KEY); } } migrateLegacyTokens(); const token = ref(localStorage.getItem(TOKEN_KEY) || ''); const user = ref(loadUser()); /** Align manage_user.userType with JWT when localStorage is stale (common after account switch). */ export function reconcileStaffSessionFromToken(): boolean { if (!token.value) return false; const claims = decodeJwtStaffClaims(token.value); if (!claims?.userType || !claims.id || !claims.username) return false; if ( user.value?.id === claims.id && user.value.username === claims.username && user.value.userType === claims.userType ) { return true; } const next: StaffUser = { id: claims.id, username: claims.username, userType: claims.userType, locale: user.value?.locale, role: claims.role ?? user.value?.role, }; user.value = next; localStorage.setItem(USER_KEY, JSON.stringify(next)); return true; } reconcileStaffSessionFromToken(); if (typeof window !== 'undefined') { window.addEventListener('storage', () => { token.value = localStorage.getItem(TOKEN_KEY) || ''; user.value = loadUser(); reconcileStaffSessionFromToken(); }); } export function clearStaffSession() { token.value = ''; user.value = null; localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY); localStorage.removeItem('admin_token'); localStorage.removeItem('agent_token'); void import('../utils/session-hydrate').then((m) => m.resetStaffSessionHydration()); } function resolveUserType(): StaffUserType | null { return user.value?.userType ?? decodeJwtStaffClaims(token.value)?.userType ?? null; } export function useAuthStore() { const isAdmin = computed(() => resolveUserType() === 'ADMIN'); const isAgent = computed(() => resolveUserType() === 'AGENT'); const isTier1Agent = computed(() => isAgent.value && user.value?.agentLevel === 1); const isTier2Agent = computed(() => isAgent.value && user.value?.agentLevel === 2); const canManageSubAgents = computed(() => { if (!isAgent.value) return false; if (user.value?.canManageSubAgents != null) return user.value.canManageSubAgents; const level = user.value?.agentLevel; const max = user.value?.maxAgentLevel; if (level == null || level < 1) return false; if (max == null || max === 0) return true; return level < max; }); const portalLabel = computed(() => (isAdmin.value ? '平台后台' : '代理后台')); function setSession(newToken: string, newUser: StaffUser) { token.value = newToken; user.value = newUser; localStorage.setItem(TOKEN_KEY, newToken); localStorage.setItem(USER_KEY, JSON.stringify(newUser)); localStorage.removeItem('admin_token'); localStorage.removeItem('agent_token'); } function logout() { clearStaffSession(); } return { token, user, isAdmin, isAgent, isTier1Agent, isTier2Agent, canManageSubAgents, portalLabel, setSession, logout, clearStaffSession, reconcileStaffSessionFromToken, }; }