From 38949ec757a0aa07db36f11afcdbbe96ece3d62b Mon Sep 17 00:00:00 2001
From: sion123 <450702724@qq.com>
Date: Sun, 16 Nov 2025 23:19:44 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/app/web-gold/src/App.vue | 8 +
.../web-gold/src/components/SidebarNav.vue | 146 ++++++++++++++++++
frontend/app/web-gold/src/main.js | 2 +
frontend/app/web-gold/src/router/index.js | 125 +++++++++++++++
.../src/views/content-style/Benchmark.vue | 6 +-
5 files changed, 285 insertions(+), 2 deletions(-)
create mode 100644 frontend/app/web-gold/src/components/SidebarNav.vue
create mode 100644 frontend/app/web-gold/src/router/index.js
diff --git a/frontend/app/web-gold/src/App.vue b/frontend/app/web-gold/src/App.vue
index d582252823..f9ec623447 100644
--- a/frontend/app/web-gold/src/App.vue
+++ b/frontend/app/web-gold/src/App.vue
@@ -1,5 +1,7 @@
+
+
+
+
+
+
+
+
diff --git a/frontend/app/web-gold/src/main.js b/frontend/app/web-gold/src/main.js
index 83d3974222..ce1f643532 100644
--- a/frontend/app/web-gold/src/main.js
+++ b/frontend/app/web-gold/src/main.js
@@ -6,12 +6,14 @@ import 'ant-design-vue/dist/reset.css'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue'
+import router from './router'
import './style.css'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
+app.use(router)
app.use(Antd)
app.mount('#app')
diff --git a/frontend/app/web-gold/src/router/index.js b/frontend/app/web-gold/src/router/index.js
new file mode 100644
index 0000000000..95bae9a27a
--- /dev/null
+++ b/frontend/app/web-gold/src/router/index.js
@@ -0,0 +1,125 @@
+import { createRouter, createWebHistory } from 'vue-router'
+import { useUserStore } from '@/stores/user'
+import { getToken } from '@gold/utils/token-manager'
+
+const routes = [
+ {
+ path: '/',
+ redirect: '/content-style/benchmark'
+ },
+ // { path: '/home', name: '首页', component: () => import('../views/home/Home.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: '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: '/realtime-hot', name: '实时热点推送', component: () => import('../views/realtime/RealtimeHot.vue') },
+ { path: '/mix-editor', name: '素材混剪', component: () => import('../views/mix/MixEditor.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({
+ history: createWebHistory(import.meta.env.BASE_URL),
+ routes,
+})
+
+// 用户信息初始化标志(确保只初始化一次)
+let userInfoInitialized = false
+
+/**
+ * 路由导航守卫:初始化用户信息 + 登录验证
+ * 在首次路由跳转时,如果已登录(有 token),则获取用户信息
+ * 如果未登录访问系统相关路由,则重定向到首页
+ */
+router.beforeEach(async (to, from, next) => {
+ const userStore = useUserStore()
+
+ // 只在首次路由跳转时初始化用户信息
+ if (!userInfoInitialized) {
+ userInfoInitialized = true
+
+ const token = getToken()
+ if (token) {
+ try {
+ // 如果 store 中已标记为登录,则获取用户信息
+ if (userStore.isLoggedIn) {
+ userStore.fetchUserInfo()
+ } else {
+ // 如果有 token 但 store 中未标记为登录,可能是刷新页面
+ // 先标记为已登录,然后获取用户信息
+ userStore.isLoggedIn = true
+ userStore.fetchUserInfo()
+ }
+ } catch (error) {
+ console.error('初始化用户信息失败:', error)
+ // 不阻止路由跳转,继续执行
+ }
+ }
+ }
+
+ // 检查访问系统相关路由时是否已登录
+ if (to.path.startsWith('/system')) {
+ // 等待 store 从本地存储恢复完成(最多等待500ms)
+ let waitCount = 0
+ while (!userStore.isHydrated && waitCount < 50) {
+ await new Promise(resolve => setTimeout(resolve, 10))
+ waitCount++
+ }
+
+ // 如果未登录,重定向到首页
+ if (!userStore.isLoggedIn) {
+ next({ path: '/content-style/benchmark', replace: true })
+ return
+ }
+ }
+
+ // 继续路由跳转
+ next()
+})
+
+export default router
+
diff --git a/frontend/app/web-gold/src/views/content-style/Benchmark.vue b/frontend/app/web-gold/src/views/content-style/Benchmark.vue
index 50a6a3ee19..cb5927814f 100644
--- a/frontend/app/web-gold/src/views/content-style/Benchmark.vue
+++ b/frontend/app/web-gold/src/views/content-style/Benchmark.vue
@@ -1,6 +1,7 @@