import { computed, ref } from 'vue' import { defineStore } from 'pinia' import { loginApi, logoutApi, meApi } from '@/api/auth' import { listDictItemsApi } from '@/api/system/dict' import type { CurrentUserProfile, LoginRequest, MeResponse, MenuNode } from '@/types/auth' import type { DictItem } from '@/types/system/dict' const TOKEN_KEY = 'platform.token' export interface TabItem { name: string title: string path: string closable: boolean } function normalizeTabPath(path: string) { if (path === '/workbench') return '/dashboard' return path } export const useAuthStore = defineStore('auth', () => { const token = ref(localStorage.getItem(TOKEN_KEY) ?? '') const user = ref(null) const menus = ref([]) const permissions = ref([]) const layoutCollapsed = ref(false) const dictCache = ref>({}) const tabs = ref([ { name: 'workbench-home', title: '工作台', path: '/dashboard', closable: false } ]) const tabRefreshMarks = ref>({}) const loaded = ref(false) const isAuthed = computed(() => Boolean(token.value)) function setToken(nextToken: string) { token.value = nextToken localStorage.setItem(TOKEN_KEY, nextToken) } function clearAuth() { token.value = '' user.value = null menus.value = [] permissions.value = [] dictCache.value = {} loaded.value = false tabs.value = [{ name: 'workbench-home', title: '工作台', path: '/dashboard', closable: false }] tabRefreshMarks.value = {} localStorage.removeItem(TOKEN_KEY) } async function login(payload: LoginRequest) { const result = await loginApi(payload) setToken(result.accessToken) await loadProfile() } async function logout() { try { if (token.value) { await logoutApi() } } finally { clearAuth() } } async function loadProfile(force = false): Promise { if (!token.value) return null if (loaded.value && !force) { return { user: user.value!, menus: menus.value, permissions: permissions.value } } const profile = await meApi() user.value = profile.user menus.value = profile.menus permissions.value = [...profile.permissions] loaded.value = true return profile } function hasPermission(permission?: string | null) { if (!permission) return true return permissions.value.includes(permission) } async function loadDictByTypeId(typeId: string, force = false) { const cached = dictCache.value[typeId] if (cached && !force) return cached const result = await listDictItemsApi({ typeId, page: 1, pageSize: 200 }) dictCache.value[typeId] = result.items.filter((item) => item.status === 'ENABLED') return dictCache.value[typeId] } function getDictLabel(typeId: string, value: string) { const item = dictCache.value[typeId]?.find((entry) => entry.value === value) return item?.label ?? value } function getDictColor(typeId: string, value: string) { const item = dictCache.value[typeId]?.find((entry) => entry.value === value) return item?.color ?? undefined } function addTab(tab: TabItem) { const normalizedPath = normalizeTabPath(tab.path) if (tabs.value.some((item) => item.path === normalizedPath)) return tabs.value.push({ ...tab, path: normalizedPath }) } function closeTab(path: string) { const targetPath = normalizeTabPath(path) const fixed = tabs.value.filter((item) => !item.closable) tabs.value = [ ...fixed, ...tabs.value.filter((item) => item.closable && item.path !== targetPath) ] delete tabRefreshMarks.value[targetPath] } function closeOtherTabs(path: string) { const targetPath = normalizeTabPath(path) tabs.value = tabs.value.filter((item) => !item.closable || item.path === targetPath) Object.keys(tabRefreshMarks.value).forEach((tabPath) => { if (!tabs.value.some((item) => item.path === tabPath)) { delete tabRefreshMarks.value[tabPath] } }) } function closeAllTabs() { const fixedTabs = tabs.value.filter((item) => !item.closable) const fixedPaths = new Set(fixedTabs.map((item) => item.path)) Object.keys(tabRefreshMarks.value).forEach((path) => { if (!fixedPaths.has(path)) { delete tabRefreshMarks.value[path] } }) tabs.value = fixedTabs } function refreshTab(path: string) { const targetPath = normalizeTabPath(path) tabRefreshMarks.value[targetPath] = Date.now() } return { token, user, menus, permissions, layoutCollapsed, dictCache, tabs, tabRefreshMarks, loaded, isAuthed, setToken, clearAuth, login, logout, loadProfile, hasPermission, addTab, closeTab, closeOtherTabs, closeAllTabs, refreshTab, loadDictByTypeId, getDictLabel, getDictColor } })