Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
46ea9170
Commit
46ea9170
authored
Mar 04, 2026
by
shaw
Browse files
fix: 修复自定义菜单页面管理员视角菜单不生效问题
parent
7d318aee
Changes
6
Hide whitespace changes
Inline
Side-by-side
frontend/src/components/layout/AppHeader.vue
View file @
46ea9170
...
@@ -211,6 +211,7 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
...
@@ -211,6 +211,7 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import
{
useRouter
,
useRoute
}
from
'
vue-router
'
import
{
useRouter
,
useRoute
}
from
'
vue-router
'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useAppStore
,
useAuthStore
,
useOnboardingStore
}
from
'
@/stores
'
import
{
useAppStore
,
useAuthStore
,
useOnboardingStore
}
from
'
@/stores
'
import
{
useAdminSettingsStore
}
from
'
@/stores/adminSettings
'
import
LocaleSwitcher
from
'
@/components/common/LocaleSwitcher.vue
'
import
LocaleSwitcher
from
'
@/components/common/LocaleSwitcher.vue
'
import
SubscriptionProgressMini
from
'
@/components/common/SubscriptionProgressMini.vue
'
import
SubscriptionProgressMini
from
'
@/components/common/SubscriptionProgressMini.vue
'
import
AnnouncementBell
from
'
@/components/common/AnnouncementBell.vue
'
import
AnnouncementBell
from
'
@/components/common/AnnouncementBell.vue
'
...
@@ -221,6 +222,7 @@ const route = useRoute()
...
@@ -221,6 +222,7 @@ const route = useRoute()
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
const
appStore
=
useAppStore
()
const
appStore
=
useAppStore
()
const
authStore
=
useAuthStore
()
const
authStore
=
useAuthStore
()
const
adminSettingsStore
=
useAdminSettingsStore
()
const
onboardingStore
=
useOnboardingStore
()
const
onboardingStore
=
useOnboardingStore
()
const
user
=
computed
(()
=>
authStore
.
user
)
const
user
=
computed
(()
=>
authStore
.
user
)
...
@@ -257,8 +259,9 @@ const pageTitle = computed(() => {
...
@@ -257,8 +259,9 @@ const pageTitle = computed(() => {
// For custom pages, use the menu item's label instead of generic "自定义页面"
// For custom pages, use the menu item's label instead of generic "自定义页面"
if
(
route
.
name
===
'
CustomPage
'
)
{
if
(
route
.
name
===
'
CustomPage
'
)
{
const
id
=
route
.
params
.
id
as
string
const
id
=
route
.
params
.
id
as
string
const
items
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
const
publicItems
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
const
menuItem
=
items
.
find
((
item
)
=>
item
.
id
===
id
)
const
menuItem
=
publicItems
.
find
((
item
)
=>
item
.
id
===
id
)
??
(
authStore
.
isAdmin
?
adminSettingsStore
.
customMenuItems
.
find
((
item
)
=>
item
.
id
===
id
)
:
undefined
)
if
(
menuItem
?.
label
)
return
menuItem
.
label
if
(
menuItem
?.
label
)
return
menuItem
.
label
}
}
const
titleKey
=
route
.
meta
.
titleKey
as
string
const
titleKey
=
route
.
meta
.
titleKey
as
string
...
...
frontend/src/components/layout/AppSidebar.vue
View file @
46ea9170
...
@@ -579,8 +579,7 @@ const customMenuItemsForUser = computed(() => {
...
@@ -579,8 +579,7 @@ const customMenuItemsForUser = computed(() => {
})
})
const
customMenuItemsForAdmin
=
computed
(()
=>
{
const
customMenuItemsForAdmin
=
computed
(()
=>
{
const
items
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
return
adminSettingsStore
.
customMenuItems
return
items
.
filter
((
item
)
=>
item
.
visibility
===
'
admin
'
)
.
filter
((
item
)
=>
item
.
visibility
===
'
admin
'
)
.
sort
((
a
,
b
)
=>
a
.
sort_order
-
b
.
sort_order
)
.
sort
((
a
,
b
)
=>
a
.
sort_order
-
b
.
sort_order
)
})
})
...
...
frontend/src/router/index.ts
View file @
46ea9170
...
@@ -6,6 +6,7 @@
...
@@ -6,6 +6,7 @@
import
{
createRouter
,
createWebHistory
,
type
RouteRecordRaw
}
from
'
vue-router
'
import
{
createRouter
,
createWebHistory
,
type
RouteRecordRaw
}
from
'
vue-router
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
useAdminSettingsStore
}
from
'
@/stores/adminSettings
'
import
{
useNavigationLoadingState
}
from
'
@/composables/useNavigationLoading
'
import
{
useNavigationLoadingState
}
from
'
@/composables/useNavigationLoading
'
import
{
useRoutePrefetch
}
from
'
@/composables/useRoutePrefetch
'
import
{
useRoutePrefetch
}
from
'
@/composables/useRoutePrefetch
'
import
{
resolveDocumentTitle
}
from
'
./title
'
import
{
resolveDocumentTitle
}
from
'
./title
'
...
@@ -431,8 +432,10 @@ router.beforeEach((to, _from, next) => {
...
@@ -431,8 +432,10 @@ router.beforeEach((to, _from, next) => {
// For custom pages, use menu item label as document title
// For custom pages, use menu item label as document title
if
(
to
.
name
===
'
CustomPage
'
)
{
if
(
to
.
name
===
'
CustomPage
'
)
{
const
id
=
to
.
params
.
id
as
string
const
id
=
to
.
params
.
id
as
string
const
items
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
const
publicItems
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
const
menuItem
=
items
.
find
((
item
)
=>
item
.
id
===
id
)
const
adminSettingsStore
=
useAdminSettingsStore
()
const
menuItem
=
publicItems
.
find
((
item
)
=>
item
.
id
===
id
)
??
(
authStore
.
isAdmin
?
adminSettingsStore
.
customMenuItems
.
find
((
item
)
=>
item
.
id
===
id
)
:
undefined
)
if
(
menuItem
?.
label
)
{
if
(
menuItem
?.
label
)
{
const
siteName
=
appStore
.
siteName
||
'
Sub2API
'
const
siteName
=
appStore
.
siteName
||
'
Sub2API
'
document
.
title
=
`
${
menuItem
.
label
}
-
${
siteName
}
`
document
.
title
=
`
${
menuItem
.
label
}
-
${
siteName
}
`
...
...
frontend/src/stores/adminSettings.ts
View file @
46ea9170
import
{
defineStore
}
from
'
pinia
'
import
{
defineStore
}
from
'
pinia
'
import
{
ref
}
from
'
vue
'
import
{
ref
}
from
'
vue
'
import
{
adminAPI
}
from
'
@/api
'
import
{
adminAPI
}
from
'
@/api
'
import
type
{
CustomMenuItem
}
from
'
@/types
'
export
const
useAdminSettingsStore
=
defineStore
(
'
adminSettings
'
,
()
=>
{
export
const
useAdminSettingsStore
=
defineStore
(
'
adminSettings
'
,
()
=>
{
const
loaded
=
ref
(
false
)
const
loaded
=
ref
(
false
)
...
@@ -47,6 +48,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
...
@@ -47,6 +48,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
const
opsMonitoringEnabled
=
ref
(
readCachedBool
(
'
ops_monitoring_enabled_cached
'
,
true
))
const
opsMonitoringEnabled
=
ref
(
readCachedBool
(
'
ops_monitoring_enabled_cached
'
,
true
))
const
opsRealtimeMonitoringEnabled
=
ref
(
readCachedBool
(
'
ops_realtime_monitoring_enabled_cached
'
,
true
))
const
opsRealtimeMonitoringEnabled
=
ref
(
readCachedBool
(
'
ops_realtime_monitoring_enabled_cached
'
,
true
))
const
opsQueryModeDefault
=
ref
(
readCachedString
(
'
ops_query_mode_default_cached
'
,
'
auto
'
))
const
opsQueryModeDefault
=
ref
(
readCachedString
(
'
ops_query_mode_default_cached
'
,
'
auto
'
))
const
customMenuItems
=
ref
<
CustomMenuItem
[]
>
([])
async
function
fetch
(
force
=
false
):
Promise
<
void
>
{
async
function
fetch
(
force
=
false
):
Promise
<
void
>
{
if
(
loaded
.
value
&&
!
force
)
return
if
(
loaded
.
value
&&
!
force
)
return
...
@@ -64,6 +66,8 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
...
@@ -64,6 +66,8 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
opsQueryModeDefault
.
value
=
settings
.
ops_query_mode_default
||
'
auto
'
opsQueryModeDefault
.
value
=
settings
.
ops_query_mode_default
||
'
auto
'
writeCachedString
(
'
ops_query_mode_default_cached
'
,
opsQueryModeDefault
.
value
)
writeCachedString
(
'
ops_query_mode_default_cached
'
,
opsQueryModeDefault
.
value
)
customMenuItems
.
value
=
Array
.
isArray
(
settings
.
custom_menu_items
)
?
settings
.
custom_menu_items
:
[]
loaded
.
value
=
true
loaded
.
value
=
true
}
catch
(
err
)
{
}
catch
(
err
)
{
// Keep cached/default value: do not "flip" the UI based on a transient fetch failure.
// Keep cached/default value: do not "flip" the UI based on a transient fetch failure.
...
@@ -122,6 +126,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
...
@@ -122,6 +126,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', () => {
opsMonitoringEnabled
,
opsMonitoringEnabled
,
opsRealtimeMonitoringEnabled
,
opsRealtimeMonitoringEnabled
,
opsQueryModeDefault
,
opsQueryModeDefault
,
customMenuItems
,
fetch
,
fetch
,
setOpsMonitoringEnabledLocal
,
setOpsMonitoringEnabledLocal
,
setOpsRealtimeMonitoringEnabledLocal
,
setOpsRealtimeMonitoringEnabledLocal
,
...
...
frontend/src/views/admin/SettingsView.vue
View file @
46ea9170
...
@@ -1363,9 +1363,11 @@ import Toggle from '@/components/common/Toggle.vue'
...
@@ -1363,9 +1363,11 @@ import Toggle from '@/components/common/Toggle.vue'
import
ImageUpload
from
'
@/components/common/ImageUpload.vue
'
import
ImageUpload
from
'
@/components/common/ImageUpload.vue
'
import
{
useClipboard
}
from
'
@/composables/useClipboard
'
import
{
useClipboard
}
from
'
@/composables/useClipboard
'
import
{
useAppStore
}
from
'
@/stores
'
import
{
useAppStore
}
from
'
@/stores
'
import
{
useAdminSettingsStore
}
from
'
@/stores/adminSettings
'
const
{
t
}
=
useI18n
()
const
{
t
}
=
useI18n
()
const
appStore
=
useAppStore
()
const
appStore
=
useAppStore
()
const
adminSettingsStore
=
useAdminSettingsStore
()
const
{
copyToClipboard
}
=
useClipboard
()
const
{
copyToClipboard
}
=
useClipboard
()
const
loading
=
ref
(
true
)
const
loading
=
ref
(
true
)
...
@@ -1661,8 +1663,9 @@ async function saveSettings() {
...
@@ -1661,8 +1663,9 @@ async function saveSettings() {
form
.
smtp_password
=
''
form
.
smtp_password
=
''
form
.
turnstile_secret_key
=
''
form
.
turnstile_secret_key
=
''
form
.
linuxdo_connect_client_secret
=
''
form
.
linuxdo_connect_client_secret
=
''
// Refresh cached
public
settings so sidebar/header update immediately
// Refresh cached settings so sidebar/header update immediately
await
appStore
.
fetchPublicSettings
(
true
)
await
appStore
.
fetchPublicSettings
(
true
)
await
adminSettingsStore
.
fetch
(
true
)
appStore
.
showSuccess
(
t
(
'
admin.settings.settingsSaved
'
))
appStore
.
showSuccess
(
t
(
'
admin.settings.settingsSaved
'
))
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
appStore
.
showError
(
appStore
.
showError
(
...
...
frontend/src/views/user/CustomPageView.vue
View file @
46ea9170
...
@@ -70,6 +70,7 @@ import { useRoute } from 'vue-router'
...
@@ -70,6 +70,7 @@ import { useRoute } from 'vue-router'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useI18n
}
from
'
vue-i18n
'
import
{
useAppStore
}
from
'
@/stores
'
import
{
useAppStore
}
from
'
@/stores
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAdminSettingsStore
}
from
'
@/stores/adminSettings
'
import
AppLayout
from
'
@/components/layout/AppLayout.vue
'
import
AppLayout
from
'
@/components/layout/AppLayout.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
Icon
from
'
@/components/icons/Icon.vue
'
import
{
buildEmbeddedUrl
,
detectTheme
}
from
'
@/utils/embedded-url
'
import
{
buildEmbeddedUrl
,
detectTheme
}
from
'
@/utils/embedded-url
'
...
@@ -78,6 +79,7 @@ const { t } = useI18n()
...
@@ -78,6 +79,7 @@ const { t } = useI18n()
const
route
=
useRoute
()
const
route
=
useRoute
()
const
appStore
=
useAppStore
()
const
appStore
=
useAppStore
()
const
authStore
=
useAuthStore
()
const
authStore
=
useAuthStore
()
const
adminSettingsStore
=
useAdminSettingsStore
()
const
loading
=
ref
(
false
)
const
loading
=
ref
(
false
)
const
pageTheme
=
ref
<
'
light
'
|
'
dark
'
>
(
'
light
'
)
const
pageTheme
=
ref
<
'
light
'
|
'
dark
'
>
(
'
light
'
)
...
@@ -86,12 +88,16 @@ let themeObserver: MutationObserver | null = null
...
@@ -86,12 +88,16 @@ let themeObserver: MutationObserver | null = null
const
menuItemId
=
computed
(()
=>
route
.
params
.
id
as
string
)
const
menuItemId
=
computed
(()
=>
route
.
params
.
id
as
string
)
const
menuItem
=
computed
(()
=>
{
const
menuItem
=
computed
(()
=>
{
const
items
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
const
id
=
menuItemId
.
value
const
found
=
items
.
find
((
item
)
=>
item
.
id
===
menuItemId
.
value
)
??
null
// Try public settings first (contains user-visible items)
if
(
found
&&
found
.
visibility
===
'
admin
'
&&
!
authStore
.
isAdmin
)
{
const
publicItems
=
appStore
.
cachedPublicSettings
?.
custom_menu_items
??
[]
return
null
const
found
=
publicItems
.
find
((
item
)
=>
item
.
id
===
id
)
??
null
if
(
found
)
return
found
// For admin users, also check admin settings (contains admin-only items)
if
(
authStore
.
isAdmin
)
{
return
adminSettingsStore
.
customMenuItems
.
find
((
item
)
=>
item
.
id
===
id
)
??
null
}
}
return
found
return
null
})
})
const
embeddedUrl
=
computed
(()
=>
{
const
embeddedUrl
=
computed
(()
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment