能看到内容了
This commit is contained in:
@@ -4,7 +4,50 @@ import router from './router'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import './assets/styles/global.css'
|
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)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
|
// 全局注册 Naive UI 组件
|
||||||
|
// 注意:必须用带 N 前缀的名字注册,因为模板中使用 <n-button> 等
|
||||||
|
// Vue 会把 n-button 解析为 NButton,而 component.name 是 "Button"(无前缀),所以不能用 .name
|
||||||
|
const naiveComponents: Record<string, any> = {
|
||||||
|
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')
|
app.mount('#app')
|
||||||
|
|||||||
@@ -2,36 +2,30 @@ import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
|
|||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
|
// ==================== 认证页面(套用 AuthLayout)=====================
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/auth',
|
||||||
name: 'Login',
|
component: () => import('@/layouts/AuthLayout.vue'),
|
||||||
component: () => import('@/views/auth/LoginView.vue'),
|
meta: { requiresAuth: false },
|
||||||
meta: { requiresAuth: false, layout: 'auth' },
|
children: [
|
||||||
},
|
{ path: '/login', name: 'Login', component: () => import('@/views/auth/LoginView.vue') },
|
||||||
{
|
{ path: '/register', name: 'Register', component: () => import('@/views/auth/RegisterView.vue') },
|
||||||
path: '/register',
|
],
|
||||||
name: 'Register',
|
|
||||||
component: () => import('@/views/auth/RegisterView.vue'),
|
|
||||||
meta: { requiresAuth: false, layout: 'auth' },
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ==================== 聊天主界面(套用 ChatLayout)=====================
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@/layouts/ChatLayout.vue'),
|
component: () => import('@/layouts/ChatLayout.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
children: [
|
children: [
|
||||||
{ path: '', redirect: '/chat' },
|
{ path: '', redirect: '/chat' },
|
||||||
{
|
{ path: 'chat', name: 'ChatList', component: () => import('@/views/chat/ChatListView.vue') },
|
||||||
path: 'chat',
|
{ path: 'chat/:id', name: 'ChatRoom', component: () => import('@/views/chat/ChatRoomView.vue') },
|
||||||
name: 'ChatList',
|
|
||||||
component: () => import('@/views/chat/ChatListView.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'chat/:id',
|
|
||||||
name: 'ChatRoom',
|
|
||||||
component: () => import('@/views/chat/ChatRoomView.vue'),
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ==================== 通讯录(套用 MainLayout)=====================
|
||||||
{
|
{
|
||||||
path: '/contacts',
|
path: '/contacts',
|
||||||
component: () => import('@/layouts/MainLayout.vue'),
|
component: () => import('@/layouts/MainLayout.vue'),
|
||||||
@@ -41,6 +35,8 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'search', name: 'Search', component: () => import('@/views/contacts/SearchView.vue') },
|
{ path: 'search', name: 'Search', component: () => import('@/views/contacts/SearchView.vue') },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ==================== 个人中心 =====================
|
||||||
{
|
{
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
component: () => import('@/layouts/MainLayout.vue'),
|
component: () => import('@/layouts/MainLayout.vue'),
|
||||||
@@ -49,19 +45,18 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: '', name: 'Profile', component: () => import('@/views/profile/ProfileView.vue') },
|
{ path: '', name: 'Profile', component: () => import('@/views/profile/ProfileView.vue') },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ==================== 管理后台 =====================
|
||||||
{
|
{
|
||||||
path: '/admin',
|
path: '/admin/login',
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'login',
|
|
||||||
name: 'AdminLogin',
|
name: 'AdminLogin',
|
||||||
component: () => import('@/views/admin/AdminLoginView.vue'),
|
component: () => import('@/views/admin/AdminLoginView.vue'),
|
||||||
meta: { layout: 'auth' },
|
meta: { requiresAuth: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '/admin',
|
||||||
component: () => import('@/layouts/AdminLayout.vue'),
|
component: () => import('@/layouts/AdminLayout.vue'),
|
||||||
meta: { requiresAdmin: true },
|
meta: { requiresAuth: true },
|
||||||
children: [
|
children: [
|
||||||
{ path: '', redirect: '/admin/dashboard' },
|
{ path: '', redirect: '/admin/dashboard' },
|
||||||
{ path: 'dashboard', name: 'AdminDashboard', component: () => import('@/views/admin/AdminDashboardView.vue') },
|
{ path: 'dashboard', name: 'AdminDashboard', component: () => import('@/views/admin/AdminDashboardView.vue') },
|
||||||
@@ -70,8 +65,6 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'config', name: 'AdminConfig', component: () => import('@/views/admin/AdminConfigView.vue') },
|
{ path: 'config', name: 'AdminConfig', component: () => import('@/views/admin/AdminConfigView.vue') },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
@@ -80,16 +73,22 @@ const router = createRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 路由守卫
|
// 路由守卫
|
||||||
router.beforeEach((to, _from, next) => {
|
router.beforeEach(async (to, _from, next) => {
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
|
// 首次加载时尝试恢复登录状态
|
||||||
next({ name: 'Login', query: { redirect: to.fullPath } })
|
if (!authStore.isAuthenticated && localStorage.getItem('access_token')) {
|
||||||
return
|
try {
|
||||||
|
await authStore.fetchProfile()
|
||||||
|
} catch {
|
||||||
|
authStore.logout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.meta.requiresAuth === false && authStore.isAuthenticated) {
|
const needsAuth = to.matched.some((record) => record.meta.requiresAuth)
|
||||||
next({ name: 'ChatList' })
|
|
||||||
|
if (needsAuth && !authStore.isAuthenticated) {
|
||||||
|
next({ name: 'Login', query: { redirect: to.fullPath } })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,3 +5,5 @@
|
|||||||
基于当前的技术栈和项目环境,在.gitignore里补充适当的内容,忽视不必要追踪的文件
|
基于当前的技术栈和项目环境,在.gitignore里补充适当的内容,忽视不必要追踪的文件
|
||||||
|
|
||||||
前端的用户和管理员界面,都看不到登录界面。用户界面目前一片空白。请检查。此外,需要实现热挂载,即修改了前端或后端代码后,不需要重启docker(除非必要),刷新就能看到效果。
|
前端的用户和管理员界面,都看不到登录界面。用户界面目前一片空白。请检查。此外,需要实现热挂载,即修改了前端或后端代码后,不需要重启docker(除非必要),刷新就能看到效果。
|
||||||
|
|
||||||
|
这三个页面目前都变成一片空白了
|
||||||
Reference in New Issue
Block a user