import Taro from '@tarojs/taro'; import { appEnv, ensureRuntimeConfigLoaded, isH5Runtime } from '@/env'; import type { ApiEnvelope, CurrentUser } from '@/types'; import { getTenantContext, resolveTenant } from './api'; import { loadCurrentUser } from './auth'; let pendingGuardPath = ''; function hostFromRuntime() { if (isH5Runtime() && typeof window !== 'undefined') return window.location.host; return ''; } export function safeRedirectPath(path: string) { if (!path.startsWith('/pages/') || path.startsWith('/pages/student/login/') || path.startsWith('/pages/bootstrap/')) return landingPath(); if (appEnv.portal === 'tenant-admin') return path.startsWith('/pages/tenant-admin/') ? path : landingPath(); if (appEnv.portal === 'platform-admin') return path.startsWith('/pages/platform-admin/') ? path : landingPath(); return path.startsWith('/pages/student/') ? path : landingPath(); } function loginUrl(redirectPath: string) { return `/pages/student/login/index?redirect=${encodeURIComponent(safeRedirectPath(redirectPath))}`; } function forbiddenUrl(reason: string, redirectPath: string) { return `/pages/student/login/index?reason=${encodeURIComponent(reason)}&redirect=${encodeURIComponent(safeRedirectPath(redirectPath))}`; } function redirectToAuthUrl(url: string) { if (isH5Runtime() && typeof window !== 'undefined') { window.location.replace(url); return; } Taro.redirectTo({ url }); } export function currentPagePath() { if (isH5Runtime() && typeof window !== 'undefined') { const pathname = window.location.pathname || ''; if (pathname.startsWith('/pages/')) return pathname; if (!pathname || pathname === '/' || pathname.endsWith('/index.html')) return landingPath(); } const instance = Taro.getCurrentInstance(); const path = instance.router?.path || ''; const normalizedPath = path.startsWith('/') ? path : `/${path}`; return normalizedPath; } function isPublicPath(path: string) { return path === '/pages/bootstrap/index' || path === '/pages/student/login/index'; } export function isPathAllowedForPortal(path: string) { if (isPublicPath(path)) return true; if (!path.startsWith('/pages/')) return true; if (appEnv.portal === 'tenant-admin') return path.startsWith('/pages/tenant-admin/'); if (appEnv.portal === 'platform-admin') return path.startsWith('/pages/platform-admin/'); return path.startsWith('/pages/student/'); } export function shouldGuardPath(path: string) { if (isPublicPath(path)) return false; if (!isPathAllowedForPortal(path)) return true; if (appEnv.portal === 'tenant-admin') return path.startsWith('/pages/tenant-admin/'); if (appEnv.portal === 'platform-admin') return path.startsWith('/pages/platform-admin/'); return path.startsWith('/pages/student/') && path !== '/pages/student/region/index'; } export function landingPath() { if (appEnv.portal === 'tenant-admin') return '/pages/tenant-admin/workbench/index'; if (appEnv.portal === 'platform-admin') return '/pages/platform-admin/workbench/index'; return '/pages/student/home/index'; } export async function ensureTenantResolved() { await ensureRuntimeConfigLoaded(); const current = getTenantContext(); if (current?.tenantId) return current; return resolveTenant({ host: hostFromRuntime() }); } export async function requireSignedIn(redirectPath: string): Promise | null> { await ensureTenantResolved(); try { return await loadCurrentUser(); } catch { redirectToAuthUrl(loginUrl(redirectPath)); return null; } } export async function requirePlatformAdmin(redirectPath: string) { const payload = await requireSignedIn(redirectPath); if (!payload) return null; const user = payload.user || payload.item; const roles = user?.roles || []; if (user?.primaryRole === 'platform_admin' || roles.includes('platform_admin')) return payload; redirectToAuthUrl(forbiddenUrl('当前账号不是平台管理员', redirectPath)); return null; } export async function requireTenantAdmin(redirectPath: string) { const payload = await requireSignedIn(redirectPath); if (!payload) return null; const user = payload.user || payload.item; const roles = user?.roles || []; const allowedRoles = new Set(['tenant_owner', 'tenant_admin', 'tenant_operator', 'teacher', 'sales', 'agent']); if (user?.primaryRole === 'platform_admin') return payload; if (user?.primaryRole && allowedRoles.has(user.primaryRole)) return payload; if (roles.some(role => allowedRoles.has(role) || role === 'platform_admin')) return payload; redirectToAuthUrl(forbiddenUrl('当前账号没有租户后台权限', redirectPath)); return null; } export async function guardCurrentRoute() { await ensureRuntimeConfigLoaded(); const path = currentPagePath(); if (!path || !shouldGuardPath(path)) return true; if (!isPathAllowedForPortal(path)) { redirectToAuthUrl(`/pages/bootstrap/index?redirect=${encodeURIComponent(landingPath())}`); return false; } if (pendingGuardPath === path) return false; pendingGuardPath = path; try { if (appEnv.portal === 'platform-admin') { const payload = await requirePlatformAdmin(path); return Boolean(payload); } if (appEnv.portal === 'tenant-admin') { const payload = await requireTenantAdmin(path); return Boolean(payload); } const payload = await requireSignedIn(path); return Boolean(payload); } finally { pendingGuardPath = ''; } } export function redirectAfterLogin(rawRedirect?: string) { const redirectPath = rawRedirect ? decodeURIComponent(rawRedirect) : landingPath(); Taro.redirectTo({ url: safeRedirectPath(redirectPath) }); }