mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
feat(plugin): 侧栏全页 AppPage、多 nav_key 联邦加载与 sidebar_nav 缓存
- 新增路由 plugin-app 与壳页,按 nav_key 尝试 AppPage{Pascal}/AppPage/Page
- DefaultLayout 与 appcenter 合并插件侧栏项;plugin/sidebar_nav 经 Pinia 去重缓存
- 工具 pluginSidebarNav、联邦 loader 与文档/示例更新;登出时清空侧栏缓存
Made-with: Cursor
This commit is contained in:
+17
-10
@@ -1,15 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { NavMenu } from '@/@layouts/types'
|
||||
import { getNavMenus } from '@/router/i18n-menu'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { usePluginSidebarNavStore, useUserStore } from '@/stores'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { filterPluginSidebarNavEntries } from '@/utils/pluginSidebarNav'
|
||||
import { filterMenusByPermission } from '@/utils/permission'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n()
|
||||
|
||||
// 从 Store 中获取用户信息
|
||||
const userStore = useUserStore()
|
||||
const pluginSidebarNavStore = usePluginSidebarNavStore()
|
||||
|
||||
// 获取用户权限信息
|
||||
const userPermissions = computed(() => ({
|
||||
@@ -20,14 +21,22 @@ const userPermissions = computed(() => ({
|
||||
// 应用分组(以header分组)
|
||||
const appGroups = ref<Record<string, NavMenu[]>>({})
|
||||
|
||||
// 根据header属性对应用进行分类
|
||||
function categorizeApps() {
|
||||
// 获取所有菜单并根据权限过滤
|
||||
// 根据header属性对应用进行分类(含插件侧栏项,与桌面端侧栏一致)
|
||||
async function categorizeApps() {
|
||||
const allMenus = getNavMenus(t)
|
||||
const filteredMenus = filterMenusByPermission(allMenus, userPermissions.value)
|
||||
const menus = filteredMenus.filter((item: NavMenu) => !item.footer)
|
||||
let menus = filteredMenus.filter((item: NavMenu) => !item.footer)
|
||||
|
||||
await pluginSidebarNavStore.ensureSidebarNav()
|
||||
if (pluginSidebarNavStore.items.length > 0) {
|
||||
const pluginNavMenus = filterPluginSidebarNavEntries(
|
||||
pluginSidebarNavStore.items,
|
||||
t,
|
||||
userPermissions.value,
|
||||
).map(e => e.navMenu)
|
||||
menus = [...menus, ...pluginNavMenus]
|
||||
}
|
||||
|
||||
// 按header属性分组
|
||||
const groupedMenus: Record<string, NavMenu[]> = {}
|
||||
|
||||
menus.forEach(menu => {
|
||||
@@ -38,11 +47,9 @@ function categorizeApps() {
|
||||
groupedMenus[header].push(menu)
|
||||
})
|
||||
|
||||
// 将分组结果赋值给响应式变量
|
||||
appGroups.value = groupedMenus
|
||||
}
|
||||
|
||||
// 页面加载时对应用进行分类
|
||||
onMounted(() => {
|
||||
categorizeApps()
|
||||
})
|
||||
@@ -60,7 +67,7 @@ onMounted(() => {
|
||||
<VList lines="one" class="settings-list">
|
||||
<VListItem
|
||||
v-for="(app, appIndex) in apps"
|
||||
:key="appIndex"
|
||||
:key="`${header}-${appIndex}-${String(app.to)}`"
|
||||
:to="app.to || ''"
|
||||
color="primary"
|
||||
class="settings-list-item"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import type { Component } from 'vue'
|
||||
import api from '@/api'
|
||||
import { loadRemoteAppPageComponent } from '@/utils/federationLoader'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const pluginId = computed(() => route.params.pluginId as string)
|
||||
const navKey = computed(() => (route.params.navKey as string) || 'main')
|
||||
|
||||
const RemoteView = shallowRef<Component | null>(null)
|
||||
const loadError = ref(false)
|
||||
|
||||
watch(
|
||||
[pluginId, navKey],
|
||||
async ([pid, nk]) => {
|
||||
loadError.value = false
|
||||
if (!pid) {
|
||||
RemoteView.value = null
|
||||
return
|
||||
}
|
||||
try {
|
||||
RemoteView.value = (await loadRemoteAppPageComponent(pid, nk)) as Component
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
RemoteView.value = null
|
||||
loadError.value = true
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="plugin-app-page">
|
||||
<VAlert v-if="loadError" type="error" class="ma-4" title="组件加载错误">
|
||||
无法加载插件全页组件。多入口时请暴露 AppPage 或 AppPage{Pascal}(见文档),并确认插件已启用。
|
||||
</VAlert>
|
||||
<VSkeletonLoader v-else-if="!RemoteView" class="ma-4" type="article, article, article" />
|
||||
<component
|
||||
v-else
|
||||
:is="RemoteView"
|
||||
:key="`${pluginId}-${navKey}`"
|
||||
:api="api"
|
||||
:nav-key="navKey"
|
||||
:plugin-id="pluginId"
|
||||
@action="() => {}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user