refactor: 抽离独立Layout,实现路由分层
优化内容: 1. 新增 MainLayout.vue 独立布局组件 - 封装 TopNav、SidebarNav、主内容区域 - 独立的页面脚注 2. 简化 App.vue - 只负责主题配置和SvgSprite - 只渲染 RouterView - 移除所有布局相关代码 3. 重构路由配置 - 登录页 /login:独立渲染,不使用Layout - 根路由 /:使用 MainLayout,渲染所有需要布局的页面 - 所有业务页面都作为根路由的子路由嵌套渲染 架构优势: - 登录页独立,不受主布局影响 - 主布局统一管理,减少重复代码 - 路由结构清晰,易于维护 - 符合Vue最佳实践 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
<script setup>
|
||||
import { RouterView } from 'vue-router'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import SidebarNav from './components/SidebarNav.vue'
|
||||
import TopNav from './components/TopNav.vue'
|
||||
import { theme } from 'ant-design-vue'
|
||||
import SvgSprite from '@/components/icons/SvgSprite.vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
@@ -73,49 +71,11 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<a-config-provider :theme="themeToken">
|
||||
<div class="app-shell">
|
||||
<SvgSprite />
|
||||
<TopNav />
|
||||
<div class="app-body">
|
||||
<SidebarNav />
|
||||
<div class="app-content">
|
||||
<main class="content-scroll">
|
||||
<keep-alive>
|
||||
<RouterView />
|
||||
</keep-alive>
|
||||
</main>
|
||||
<footer class="py-6 text-xs text-center text-gray-500">
|
||||
v0.1 · API 正常 · © 2025 金牌内容大师
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SvgSprite />
|
||||
<RouterView />
|
||||
</a-config-provider>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
/* 顶部固定,下面主体需要留出空间 */
|
||||
.app-body {
|
||||
padding-top: 70px; /* 与 TopNav 高度对齐 */
|
||||
display: grid;
|
||||
grid-template-columns: 220px 1fr; /* 左侧固定宽度侧边栏 */
|
||||
}
|
||||
|
||||
.app-content {
|
||||
min-height: calc(100vh - 70px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto; /* 右侧内容区域滚动 */
|
||||
padding: 0 16px 0 16px;
|
||||
}
|
||||
<style>
|
||||
/* 全局样式保持不变 */
|
||||
</style>
|
||||
|
||||
49
frontend/app/web-gold/src/layouts/MainLayout.vue
Normal file
49
frontend/app/web-gold/src/layouts/MainLayout.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<script setup>
|
||||
import TopNav from '@/components/TopNav.vue'
|
||||
import SidebarNav from '@/components/SidebarNav.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-shell">
|
||||
<TopNav />
|
||||
<div class="app-body">
|
||||
<SidebarNav />
|
||||
<div class="app-content">
|
||||
<main class="content-scroll">
|
||||
<keep-alive>
|
||||
<RouterView />
|
||||
</keep-alive>
|
||||
</main>
|
||||
<footer class="py-6 text-xs text-center text-gray-500">
|
||||
v0.1 · API 正常 · © 2025 金牌内容大师
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
/* 顶部固定,下面主体需要留出空间 */
|
||||
.app-body {
|
||||
padding-top: 70px; /* 与 TopNav 高度对齐 */
|
||||
display: grid;
|
||||
grid-template-columns: 220px 1fr; /* 左侧固定宽度侧边栏 */
|
||||
}
|
||||
|
||||
.app-content {
|
||||
min-height: calc(100vh - 70px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto; /* 右侧内容区域滚动 */
|
||||
padding: 0 16px 0 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,10 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import tokenManager from '@gold/utils/token-manager'
|
||||
import MainLayout from '@/layouts/MainLayout.vue'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/content-style/benchmark'
|
||||
},
|
||||
// 登录页面
|
||||
// 登录页面 - 独立渲染,不使用Layout
|
||||
{
|
||||
path: '/login',
|
||||
name: '登录',
|
||||
@@ -16,62 +13,72 @@ const routes = [
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
// { path: '/home', name: '首页', component: () => import('../views/home/Home.vue') },
|
||||
// 主布局路由 - 所有需要Layout的页面都在这里
|
||||
{
|
||||
path: '/content-style',
|
||||
name: '内容风格分析',
|
||||
path: '/',
|
||||
component: MainLayout,
|
||||
redirect: '/content-style/benchmark',
|
||||
children: [
|
||||
{ path: '', redirect: '/content-style/benchmark' },
|
||||
{ path: 'benchmark', name: '对标分析', component: () => import('../views/content-style/Benchmark.vue') },
|
||||
{ path: 'copywriting', name: '文案创作', component: () => import('../views/content-style/Copywriting.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/trends',
|
||||
name: '热点趋势分析',
|
||||
children: [
|
||||
{ path: '', redirect: '/trends/heat' },
|
||||
{ path: 'heat', name: '热度分析', component: () => import('../views/trends/Heat.vue') },
|
||||
{ path: 'forecast', name: '热点预测', component: () => import('../views/trends/Forecast.vue') },
|
||||
{ path: 'copywriting', name: '趋势文案创作', component: () => import('../views/trends/Copywriting.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/digital-human',
|
||||
name: '数字人',
|
||||
children: [
|
||||
{ path: '', redirect: '/digital-human/voice-copy' },
|
||||
{ path: 'voice-copy', name: '人声克隆', component: () => import('../views/dh/VoiceCopy.vue') },
|
||||
{ path: 'avatar', name: '生成数字人', component: () => import('../views/dh/Avatar.vue') },
|
||||
{ path: 'video', name: '数字人视频', component: () => import('../views/dh/Video.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/material',
|
||||
name: '素材库',
|
||||
children: [
|
||||
{ path: '', redirect: '/material/list' },
|
||||
{ path: 'list', name: '素材列表', component: () => import('../views/material/MaterialList.vue') },
|
||||
{ path: 'mix-task', name: '混剪任务', component: () => import('../views/material/MixTaskList.vue') },
|
||||
{ path: 'group', name: '素材分组', component: () => import('../views/material/MaterialGroup.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/system',
|
||||
name: '系统',
|
||||
children: [
|
||||
{ path: '', redirect: '/system/style-settings' },
|
||||
{ path: 'style-settings', name: '风格设置', component: () => import('../views/system/StyleSettings.vue') },
|
||||
{
|
||||
path: 'content-style',
|
||||
name: '内容风格分析',
|
||||
children: [
|
||||
{ path: '', redirect: '/content-style/benchmark' },
|
||||
{ path: 'benchmark', name: '对标分析', component: () => import('../views/content-style/Benchmark.vue') },
|
||||
{ path: 'copywriting', name: '文案创作', component: () => import('../views/content-style/Copywriting.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'trends',
|
||||
name: '热点趋势分析',
|
||||
children: [
|
||||
{ path: '', redirect: '/trends/heat' },
|
||||
{ path: 'heat', name: '热度分析', component: () => import('../views/trends/Heat.vue') },
|
||||
{ path: 'forecast', name: '热点预测', component: () => import('../views/trends/Forecast.vue') },
|
||||
{ path: 'copywriting', name: '趋势文案创作', component: () => import('../views/trends/Copywriting.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'digital-human',
|
||||
name: '数字人',
|
||||
children: [
|
||||
{ path: '', redirect: '/digital-human/voice-copy' },
|
||||
{ path: 'voice-copy', name: '人声克隆', component: () => import('../views/dh/VoiceCopy.vue') },
|
||||
{ path: 'avatar', name: '生成数字人', component: () => import('../views/dh/Avatar.vue') },
|
||||
{ path: 'video', name: '数字人视频', component: () => import('../views/dh/Video.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'material',
|
||||
name: '素材库',
|
||||
children: [
|
||||
{ path: '', redirect: '/material/list' },
|
||||
{ path: 'list', name: '素材列表', component: () => import('../views/material/MaterialList.vue') },
|
||||
{ path: 'mix-task', name: '混剪任务', component: () => import('../views/material/MixTaskList.vue') },
|
||||
{ path: 'group', name: '素材分组', component: () => import('../views/material/MaterialGroup.vue') },
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'system',
|
||||
name: '系统',
|
||||
children: [
|
||||
{ path: '', redirect: '/system/style-settings' },
|
||||
{ path: 'style-settings', name: '风格设置', component: () => import('../views/system/StyleSettings.vue') },
|
||||
],
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{ path: 'realtime-hot', name: '实时热点推送', component: () => import('../views/realtime/RealtimeHot.vue') },
|
||||
{ path: 'capcut-import', name: '剪映导入', component: () => import('../views/capcut/CapcutImport.vue') },
|
||||
{ path: 'help', name: '帮助', component: () => import('../views/misc/Help.vue') },
|
||||
{ path: 'download', name: '下载', component: () => import('../views/misc/Download.vue') },
|
||||
{ path: 'settings/theme', name: '主题设置', component: () => import('../views/misc/Theme.vue') },
|
||||
],
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{ path: '/realtime-hot', name: '实时热点推送', component: () => import('../views/realtime/RealtimeHot.vue') },
|
||||
{ path: '/capcut-import', name: '剪映导入', component: () => import('../views/capcut/CapcutImport.vue') },
|
||||
{ path: '/help', name: '帮助', component: () => import('../views/misc/Help.vue') },
|
||||
{ path: '/download', name: '下载', component: () => import('../views/misc/Download.vue') },
|
||||
{ path: '/settings/theme', name: '主题设置', component: () => import('../views/misc/Theme.vue') },
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
|
||||
Reference in New Issue
Block a user