/** * Vue 应用入口 * 侧边栏导航 + 内容区布局,数据驱动菜单渲染 * P1: 登录守卫 + 用户信息展示 + 新页面注册 */ import { createApp } from 'vue' import { store, MENU_ITEMS } from './store.js' import { isLoggedIn, clearTokens, getUserInfo, toast, getRefreshToken } from './utils.js' import { getCurrentUser, refreshToken } from './api.js' // 导入组件 import ChatPanel from '../components/ChatPanel.js' import DocStats from '../components/DocStats.js' import DocSearch from '../components/DocSearch.js' import CategoryManager from '../components/CategoryManager.js' import RoleManager from '../components/RoleManager.js' import DocList from '../components/DocList.js' import DocUpload from '../components/DocUpload.js' import DocDetail from '../components/DocDetail.js' import ConversationManager from '../components/ConversationManager.js' import ModelConfigManager from '../components/ModelConfigManager.js' import SensitiveWordManager from '../components/SensitiveWordManager.js' import FaqManager from '../components/FaqManager.js' import AuditLogManager from '../components/AuditLogManager.js' import LoginPage from '../components/LoginPage.js' import UserManager from '../components/UserManager.js' import DashboardPanel from '../components/DashboardPanel.js' import ApiKeyManager from '../components/ApiKeyManager.js' import WebhookManager from '../components/WebhookManager.js' import McpServerManager from '../components/McpServerManager.js' const app = createApp({ setup() { const menuItems = MENU_ITEMS /** 判断父菜单是否高亮(任一子页面激活时高亮父菜单) */ function isMenuActive(parentItem) { if (!parentItem.children) return store.activePage === parentItem.id return parentItem.children.some(c => c.id === store.activePage) } /** 判断菜单项是否对当前用户可见(roles 限制) */ function isMenuVisible(item) { if (!item.roles || !item.roles.length) return true return item.roles.some(r => store.hasRole(r)) } /** 登录成功回调 */ function onLoginSuccess(user) { store.currentUser = user || getUserInfo() store.isLoggedIn = true } /** 退出登录 */ function handleLogout() { clearTokens() store.isLoggedIn = false store.currentUser = {} store.activePage = 'chat' toast('已退出登录', 'info') } /** 尝试刷新 Token */ async function tryRefreshToken() { const rt = getRefreshToken() if (!rt) return false try { const res = await refreshToken(rt) if (res.success && res.data) { const { setToken: st, setRefreshToken: srt } = await import('./utils.js') st(res.data.accessToken) srt(res.data.refreshToken) return true } } catch (e) { /* 刷新失败 */ } return false } // 监听 401 未授权事件 window.addEventListener('auth:unauthorized', async () => { const refreshed = await tryRefreshToken() if (!refreshed) { store.isLoggedIn = false store.currentUser = {} toast('登录已过期,请重新登录', 'error') } }) // 启动时验证登录态 if (isLoggedIn()) { getCurrentUser().then(res => { if (res.success && res.data) { store.currentUser = res.data store.isLoggedIn = true } else { // 业务失败(如用户被禁用),尝试刷新 tryRefreshToken().then(ok => { if (!ok) { store.isLoggedIn = false clearTokens() } else { // 刷新成功后重新获取用户信息 getCurrentUser().then(r => { if (r.success && r.data) { store.currentUser = r.data store.isLoggedIn = true } else { store.isLoggedIn = false clearTokens() } }).catch(() => { store.isLoggedIn = false; clearTokens() }) } }) } }).catch(() => { // 401 等错误,尝试刷新(不要先清除 token!) tryRefreshToken().then(ok => { if (!ok) { store.isLoggedIn = false clearTokens() } else { // 刷新成功后重新获取用户信息 getCurrentUser().then(r => { if (r.success && r.data) { store.currentUser = r.data store.isLoggedIn = true } else { store.isLoggedIn = false clearTokens() } }).catch(() => { store.isLoggedIn = false; clearTokens() }) } }) }) } return { menuItems, isMenuActive, isMenuVisible, store, onLoginSuccess, handleLogout } }, template: `
` }) // 注册组件 app.component('chat-panel', ChatPanel) app.component('doc-stats', DocStats) app.component('doc-search', DocSearch) app.component('category-manager', CategoryManager) app.component('role-manager', RoleManager) app.component('doc-list', DocList) app.component('doc-upload', DocUpload) app.component('doc-detail', DocDetail) app.component('conversation-manager', ConversationManager) app.component('model-config-manager', ModelConfigManager) app.component('sensitive-word-manager', SensitiveWordManager) app.component('faq-manager', FaqManager) app.component('audit-log-manager', AuditLogManager) app.component('login-page', LoginPage) app.component('user-manager', UserManager) app.component('dashboard-panel', DashboardPanel) app.component('api-key-manager', ApiKeyManager) app.component('webhook-manager', WebhookManager) app.component('mcp-server-manager', McpServerManager) app.mount('#app')