refactor: unify header tab menu definitions

This commit is contained in:
jxxghp
2026-06-03 07:21:34 +08:00
parent 8c3380e8f5
commit 841e9479af
9 changed files with 50 additions and 79 deletions

View File

@@ -121,11 +121,20 @@ export interface NavLink extends NavLinkProps, Partial<AclProperties> {
disable?: boolean
}
export interface NavMenuTabItem {
title: string
icon?: string
tab: string
description?: string
}
export interface NavMenu extends NavLink {
header: string
description?: string
admin?: boolean
footer?: boolean
// 水平三级菜单和页面动态标签页共用的静态标签定义。
tabs?: NavMenuTabItem[]
}
// 👉 Vertical nav group

View File

@@ -10,15 +10,7 @@ import UserProfile from '@/layouts/components/UserProfile.vue'
import QuickAccess from '@/layouts/components/QuickAccess.vue'
import HeaderTab from '@/layouts/components/HeaderTab.vue'
import { usePluginSidebarNavStore, useUserStore } from '@/stores'
import {
getDiscoverTabs,
getNavMenus,
getPluginTabs,
getSettingTabs,
getSubscribeMovieTabs,
getSubscribeTvTabs,
getWorkflowTabs,
} from '@/router/i18n-menu'
import { getNavMenus } from '@/router/i18n-menu'
import { filterPluginSidebarNavEntries } from '@/utils/pluginSidebarNav'
import { NavMenu } from '@/@layouts/types'
import { useDisplay } from 'vuetify'
@@ -210,20 +202,6 @@ const visibleHorizontalHeaderButtons = computed(() => {
return (dynamicHeaderTab.value?.appendButtons ?? []).filter(button => resolveMaybeRefValue(button.show, true) !== false)
})
const staticHorizontalNavTabs = computed<Record<string, DynamicHeaderTabItem[]>>(() => ({
'/recommend': getRecommendTabs(),
'/discover': getDiscoverTabs(t).map(tab => ({
title: tab.name,
icon: tab.icon,
tab: tab.tab,
})),
'/subscribe/movie': getSubscribeMovieTabs(t),
'/subscribe/tv': getSubscribeTvTabs(t),
'/workflow': getWorkflowTabs(t),
'/plugins': getPluginTabs(t),
'/setting': getSettingTabs(t),
}))
// 在组件销毁时清理
onUnmounted(() => {
dynamicHeaderTab.value = null
@@ -370,17 +348,7 @@ function getHorizontalNavTabs(item: NavMenu): DynamicHeaderTabItem[] {
return dynamicHeaderTab.value?.items ?? []
}
return staticHorizontalNavTabs.value[targetPath] ?? []
}
function getRecommendTabs(): DynamicHeaderTabItem[] {
return [
{ title: t('recommend.all'), icon: 'mdi-filmstrip-box-multiple', tab: t('recommend.all') },
{ title: t('recommend.categoryMovie'), icon: 'mdi-movie', tab: t('recommend.categoryMovie') },
{ title: t('recommend.categoryTV'), icon: 'mdi-television-classic', tab: t('recommend.categoryTV') },
{ title: t('recommend.categoryAnime'), icon: 'mdi-animation', tab: t('recommend.categoryAnime') },
{ title: t('recommend.categoryRankings'), icon: 'mdi-trophy', tab: t('recommend.categoryRankings') },
]
return item.tabs ?? []
}
function applyPendingHorizontalTab() {

View File

@@ -87,7 +87,7 @@ function initDiscoverTabs() {
const tabs = getDiscoverTabs(t)
for (const tab of tabs) {
discoverTabs.value.push({
name: tab.name,
name: tab.title,
mediaid_prefix: tab.tab,
api_path: '',
filter_params: {},

View File

@@ -8,6 +8,7 @@ import { useDynamicButton } from '@/composables/useDynamicButton'
import { usePWA } from '@/composables/usePWA'
import { getItemColor, initializeItemColors } from '@/utils/colorUtils'
import { openSharedDialog } from '@/composables/useSharedDialog'
import { getRecommendTabs } from '@/router/i18n-menu'
const ContentToggleSettingsDialog = defineAsyncComponent(() => import('@/components/dialog/ContentToggleSettingsDialog.vue'))
@@ -222,34 +223,8 @@ async function saveConfig(payload?: { enabled?: Record<string, boolean> }) {
settingsDialogController = null
}
// 标签图标映射
const categoryItems = computed(() => [
{
title: t('recommend.all'),
icon: 'mdi-filmstrip-box-multiple',
tab: t('recommend.all'),
},
{
title: t('recommend.categoryMovie'),
icon: 'mdi-movie',
tab: t('recommend.categoryMovie'),
},
{
title: t('recommend.categoryTV'),
icon: 'mdi-television-classic',
tab: t('recommend.categoryTV'),
},
{
title: t('recommend.categoryAnime'),
icon: 'mdi-animation',
tab: t('recommend.categoryAnime'),
},
{
title: t('recommend.categoryRankings'),
icon: 'mdi-trophy',
tab: t('recommend.categoryRankings'),
},
])
// 推荐分类标签与导航三级菜单共用同一份定义。
const categoryItems = computed(() => getRecommendTabs(t))
// 注册动态标签页
registerHeaderTab({

View File

@@ -44,7 +44,7 @@ const { registerHeaderTab } = useDynamicHeaderTab()
// 注册动态标签页
registerHeaderTab({
items: settingTabs.value,
items: settingTabs,
modelValue: activeTab,
})

View File

@@ -313,7 +313,7 @@ const { registerHeaderTab } = useDynamicHeaderTab()
// 注册动态标签页
registerHeaderTab({
items: subscribeTabs.value,
items: subscribeTabs,
modelValue: activeTab,
appendButtons: [
{

View File

@@ -69,7 +69,7 @@ const { registerHeaderTab } = useDynamicHeaderTab()
// 注册动态标签页
registerHeaderTab({
items: workflowTabs.value,
items: workflowTabs,
modelValue: activeTab,
appendButtons: [
{

View File

@@ -1,4 +1,5 @@
import { useGlobalSettingsStore } from '@/stores'
import type { NavMenuTabItem } from '@/@layouts/types'
import type { Composer } from 'vue-i18n'
// 构建路由菜单,每次调用时使用当前的语言环境
@@ -34,6 +35,7 @@ export function getNavMenus(t: Composer['t']) {
admin: false,
footer: true,
permission: 'discovery',
tabs: getRecommendTabs(t),
},
{
title: t('navItems.explore'),
@@ -43,6 +45,7 @@ export function getNavMenus(t: Composer['t']) {
admin: false,
footer: true,
permission: 'discovery',
tabs: getDiscoverTabs(t),
},
{
title: t('navItems.movie'),
@@ -53,6 +56,7 @@ export function getNavMenus(t: Composer['t']) {
admin: false,
footer: false,
permission: 'subscribe',
tabs: getSubscribeMovieTabs(t),
},
{
title: t('navItems.tv'),
@@ -63,6 +67,7 @@ export function getNavMenus(t: Composer['t']) {
admin: false,
footer: false,
permission: 'subscribe',
tabs: getSubscribeTvTabs(t),
},
{
title: t('navItems.workflow'),
@@ -73,6 +78,7 @@ export function getNavMenus(t: Composer['t']) {
admin: true,
footer: false,
permission: 'manage',
tabs: getWorkflowTabs(t),
},
{
title: t('navItems.calendar'),
@@ -114,6 +120,7 @@ export function getNavMenus(t: Composer['t']) {
header: t('menu.system'),
admin: true,
permission: 'manage',
tabs: getPluginTabs(t),
},
{
title: t('navItems.siteManager'),
@@ -140,14 +147,26 @@ export function getNavMenus(t: Composer['t']) {
header: t('menu.system'),
admin: true,
permission: 'admin',
tabs: getSettingTabs(t),
},
]
: []),
]
}
// 获取推荐标签页
export function getRecommendTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{ title: t('recommend.all'), icon: 'mdi-filmstrip-box-multiple', tab: t('recommend.all') },
{ title: t('recommend.categoryMovie'), icon: 'mdi-movie', tab: t('recommend.categoryMovie') },
{ title: t('recommend.categoryTV'), icon: 'mdi-television-classic', tab: t('recommend.categoryTV') },
{ title: t('recommend.categoryAnime'), icon: 'mdi-animation', tab: t('recommend.categoryAnime') },
{ title: t('recommend.categoryRankings'), icon: 'mdi-trophy', tab: t('recommend.categoryRankings') },
]
}
// 获取设置标签页
export function getSettingTabs(t: Composer['t']) {
export function getSettingTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
title: t('settingTabs.system.title'),
@@ -195,7 +214,7 @@ export function getSettingTabs(t: Composer['t']) {
}
// 获取电影订阅标签页
export function getSubscribeMovieTabs(t: Composer['t']) {
export function getSubscribeMovieTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
title: t('subscribeTabs.movie.mysub'),
@@ -211,7 +230,7 @@ export function getSubscribeMovieTabs(t: Composer['t']) {
}
// 获取电视剧订阅标签页
export function getSubscribeTvTabs(t: Composer['t']) {
export function getSubscribeTvTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
title: t('subscribeTabs.tv.mysub'),
@@ -232,7 +251,7 @@ export function getSubscribeTvTabs(t: Composer['t']) {
}
// 获取插件标签页
export function getPluginTabs(t: Composer['t']) {
export function getPluginTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
title: t('pluginTabs.installed'),
@@ -248,28 +267,28 @@ export function getPluginTabs(t: Composer['t']) {
}
// 获取发现标签页
export function getDiscoverTabs(t: Composer['t']) {
export function getDiscoverTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
name: t('discoverTabs.themoviedb'),
title: t('discoverTabs.themoviedb'),
tab: 'themoviedb',
icon: 'themoviedb',
icon: 'mdi-movie-search-outline',
},
{
name: t('discoverTabs.douban'),
title: t('discoverTabs.douban'),
tab: 'douban',
icon: 'douban',
icon: 'mdi-book-open-page-variant-outline',
},
{
name: t('discoverTabs.bangumi'),
title: t('discoverTabs.bangumi'),
tab: 'bangumi',
icon: 'bangumi',
icon: 'mdi-calendar-star-outline',
},
]
}
// 获取工作流标签页
export function getWorkflowTabs(t: Composer['t']) {
export function getWorkflowTabs(t: Composer['t']): NavMenuTabItem[] {
return [
{
title: t('workflowTabs.list'),

View File

@@ -50,7 +50,7 @@ const { registerHeaderTab } = useDynamicHeaderTab()
// 注册动态标签页在setup顶层立即执行
registerHeaderTab({
items: pluginTabs.value,
items: pluginTabs,
modelValue: activeTab,
appendButtons: [
{