diff --git a/frontend/src/main.ts b/frontend/src/main.ts index e1d6616..56d50e3 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -4,7 +4,50 @@ import router from './router' import App from './App.vue' import './assets/styles/global.css' +// 导入所有使用到的 Naive UI 组件 +import { + NConfigProvider, + NMessageProvider, + NDialogProvider, + NButton, + NInput, + NForm, + NFormItem, + NAvatar, + NBadge, + NCard, + NDataTable, + NSwitch, + NSelect, + NButtonGroup, +} from 'naive-ui' + const app = createApp(App) + app.use(createPinia()) app.use(router) + +// 全局注册 Naive UI 组件 +// 注意:必须用带 N 前缀的名字注册,因为模板中使用 等 +// Vue 会把 n-button 解析为 NButton,而 component.name 是 "Button"(无前缀),所以不能用 .name +const naiveComponents: Record = { + NConfigProvider, + NMessageProvider, + NDialogProvider, + NButton, + NInput, + NForm, + NFormItem, + NAvatar, + NBadge, + NCard, + NDataTable, + NSwitch, + NSelect, + NButtonGroup, +} +Object.entries(naiveComponents).forEach(([name, component]) => { + app.component(name, component) +}) + app.mount('#app') diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index b635e46..7c385e7 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -2,36 +2,30 @@ import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' import { useAuthStore } from '@/stores/auth' const routes: RouteRecordRaw[] = [ + // ==================== 认证页面(套用 AuthLayout)===================== { - path: '/login', - name: 'Login', - component: () => import('@/views/auth/LoginView.vue'), - meta: { requiresAuth: false, layout: 'auth' }, - }, - { - path: '/register', - name: 'Register', - component: () => import('@/views/auth/RegisterView.vue'), - meta: { requiresAuth: false, layout: 'auth' }, + path: '/auth', + component: () => import('@/layouts/AuthLayout.vue'), + meta: { requiresAuth: false }, + children: [ + { path: '/login', name: 'Login', component: () => import('@/views/auth/LoginView.vue') }, + { path: '/register', name: 'Register', component: () => import('@/views/auth/RegisterView.vue') }, + ], }, + + // ==================== 聊天主界面(套用 ChatLayout)===================== { path: '/', component: () => import('@/layouts/ChatLayout.vue'), meta: { requiresAuth: true }, children: [ { path: '', redirect: '/chat' }, - { - path: 'chat', - name: 'ChatList', - component: () => import('@/views/chat/ChatListView.vue'), - }, - { - path: 'chat/:id', - name: 'ChatRoom', - component: () => import('@/views/chat/ChatRoomView.vue'), - }, + { path: 'chat', name: 'ChatList', component: () => import('@/views/chat/ChatListView.vue') }, + { path: 'chat/:id', name: 'ChatRoom', component: () => import('@/views/chat/ChatRoomView.vue') }, ], }, + + // ==================== 通讯录(套用 MainLayout)===================== { path: '/contacts', component: () => import('@/layouts/MainLayout.vue'), @@ -41,6 +35,8 @@ const routes: RouteRecordRaw[] = [ { path: 'search', name: 'Search', component: () => import('@/views/contacts/SearchView.vue') }, ], }, + + // ==================== 个人中心 ===================== { path: '/profile', component: () => import('@/layouts/MainLayout.vue'), @@ -49,27 +45,24 @@ const routes: RouteRecordRaw[] = [ { path: '', name: 'Profile', component: () => import('@/views/profile/ProfileView.vue') }, ], }, + + // ==================== 管理后台 ===================== + { + path: '/admin/login', + name: 'AdminLogin', + component: () => import('@/views/admin/AdminLoginView.vue'), + meta: { requiresAuth: false }, + }, { path: '/admin', + component: () => import('@/layouts/AdminLayout.vue'), + meta: { requiresAuth: true }, children: [ - { - path: 'login', - name: 'AdminLogin', - component: () => import('@/views/admin/AdminLoginView.vue'), - meta: { layout: 'auth' }, - }, - { - path: '', - component: () => import('@/layouts/AdminLayout.vue'), - meta: { requiresAdmin: true }, - children: [ - { path: '', redirect: '/admin/dashboard' }, - { path: 'dashboard', name: 'AdminDashboard', component: () => import('@/views/admin/AdminDashboardView.vue') }, - { path: 'users', name: 'AdminUsers', component: () => import('@/views/admin/AdminUsersView.vue') }, - { path: 'messages', name: 'AdminMessages', component: () => import('@/views/admin/AdminMessagesView.vue') }, - { path: 'config', name: 'AdminConfig', component: () => import('@/views/admin/AdminConfigView.vue') }, - ], - }, + { path: '', redirect: '/admin/dashboard' }, + { path: 'dashboard', name: 'AdminDashboard', component: () => import('@/views/admin/AdminDashboardView.vue') }, + { path: 'users', name: 'AdminUsers', component: () => import('@/views/admin/AdminUsersView.vue') }, + { path: 'messages', name: 'AdminMessages', component: () => import('@/views/admin/AdminMessagesView.vue') }, + { path: 'config', name: 'AdminConfig', component: () => import('@/views/admin/AdminConfigView.vue') }, ], }, ] @@ -80,16 +73,22 @@ const router = createRouter({ }) // 路由守卫 -router.beforeEach((to, _from, next) => { +router.beforeEach(async (to, _from, next) => { const authStore = useAuthStore() - if (to.meta.requiresAuth && !authStore.isAuthenticated) { - next({ name: 'Login', query: { redirect: to.fullPath } }) - return + // 首次加载时尝试恢复登录状态 + if (!authStore.isAuthenticated && localStorage.getItem('access_token')) { + try { + await authStore.fetchProfile() + } catch { + authStore.logout() + } } - if (to.meta.requiresAuth === false && authStore.isAuthenticated) { - next({ name: 'ChatList' }) + const needsAuth = to.matched.some((record) => record.meta.requiresAuth) + + if (needsAuth && !authStore.isAuthenticated) { + next({ name: 'Login', query: { redirect: to.fullPath } }) return } diff --git a/提示词.md b/提示词.md index 265d85d..8a3ebfb 100644 --- a/提示词.md +++ b/提示词.md @@ -4,4 +4,6 @@ 基于当前的技术栈和项目环境,在.gitignore里补充适当的内容,忽视不必要追踪的文件 -前端的用户和管理员界面,都看不到登录界面。用户界面目前一片空白。请检查。此外,需要实现热挂载,即修改了前端或后端代码后,不需要重启docker(除非必要),刷新就能看到效果。 \ No newline at end of file +前端的用户和管理员界面,都看不到登录界面。用户界面目前一片空白。请检查。此外,需要实现热挂载,即修改了前端或后端代码后,不需要重启docker(除非必要),刷新就能看到效果。 + +这三个页面目前都变成一片空白了 \ No newline at end of file