mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
支持插件扩展仪表板
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "moviepilot",
|
"name": "moviepilot",
|
||||||
"version": "1.8.6-2",
|
"version": "1.8.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"bin": "dist/service.js",
|
"bin": "dist/service.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -445,6 +445,20 @@ export interface Plugin {
|
|||||||
add_time?: number
|
add_time?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 插件仪表板
|
||||||
|
export interface PluginDashboard {
|
||||||
|
// 插件ID
|
||||||
|
id: string
|
||||||
|
// 插件名称
|
||||||
|
name: string
|
||||||
|
// 全局配置
|
||||||
|
attrs: { [key: string]: any }
|
||||||
|
// col列数
|
||||||
|
cols: { [key: string]: number }
|
||||||
|
// 页面元素
|
||||||
|
elements: { [key: string]: any }[]
|
||||||
|
}
|
||||||
|
|
||||||
// 种子信息
|
// 种子信息
|
||||||
export interface TorrentInfo {
|
export interface TorrentInfo {
|
||||||
// 站点ID
|
// 站点ID
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { type PropType } from 'vue'
|
||||||
|
|
||||||
|
// 组件接口
|
||||||
|
interface RenderProps {
|
||||||
|
component: string
|
||||||
|
text: string
|
||||||
|
html: string
|
||||||
|
content?: any
|
||||||
|
slots?: any
|
||||||
|
props?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const elementProps = defineProps({
|
||||||
|
config: Object as PropType<RenderProps>,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(elementProps.config)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Component :is="elementProps.config?.component" v-if="!elementProps.config?.html" v-bind="elementProps.config?.props">
|
||||||
|
{{ elementProps.config?.text }}
|
||||||
|
<template v-for="(content, name) in elementProps.config?.slots || []" :key="name" v-slot:[name]="{ _props }">
|
||||||
|
<slot :name="name" v-bind="_props">
|
||||||
|
<DashboardRender v-for="(slotItem, slotIndex) in content || []" :key="slotIndex" :config="slotItem" />
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<DashboardRender
|
||||||
|
v-for="(innerItem, innerIndex) in elementProps.config?.content || []"
|
||||||
|
:key="innerIndex"
|
||||||
|
:config="innerItem"
|
||||||
|
/>
|
||||||
|
</Component>
|
||||||
|
<Component
|
||||||
|
:is="elementProps.config?.component"
|
||||||
|
v-if="elementProps.config?.html"
|
||||||
|
v-bind="elementProps.config?.props"
|
||||||
|
v-html="elementProps.config?.html"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
+74
-28
@@ -9,30 +9,15 @@ import AnalyticsMemory from '@/views/dashboard/AnalyticsMemory.vue'
|
|||||||
import MediaServerLatest from '@/views/dashboard/MediaServerLatest.vue'
|
import MediaServerLatest from '@/views/dashboard/MediaServerLatest.vue'
|
||||||
import MediaServerLibrary from '@/views/dashboard/MediaServerLibrary.vue'
|
import MediaServerLibrary from '@/views/dashboard/MediaServerLibrary.vue'
|
||||||
import MediaServerPlaying from '@/views/dashboard/MediaServerPlaying.vue'
|
import MediaServerPlaying from '@/views/dashboard/MediaServerPlaying.vue'
|
||||||
|
import DashboardRender from '@/components/render/DashboardRender.vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
import { PluginDashboard } from '@/api/types'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
|
||||||
// 仪表盘配置
|
|
||||||
const dashboard_names = {
|
|
||||||
storage: '存储空间',
|
|
||||||
mediaStatistic: '媒体统计',
|
|
||||||
weeklyOverview: '最近入库',
|
|
||||||
speed: '实时速率',
|
|
||||||
scheduler: '后台任务',
|
|
||||||
cpu: 'CPU',
|
|
||||||
memory: '内存',
|
|
||||||
library: '我的媒体库',
|
|
||||||
playing: '继续观看',
|
|
||||||
latest: '最近添加',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 弹窗
|
|
||||||
const dialog = ref(false)
|
|
||||||
|
|
||||||
// 从localStorage中获取数据
|
// 从localStorage中获取数据
|
||||||
const default_config = {
|
const default_config = {
|
||||||
mediaStatistic: true,
|
mediaStatistic: true,
|
||||||
@@ -47,6 +32,29 @@ const default_config = {
|
|||||||
latest: true,
|
latest: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 仪表盘字典
|
||||||
|
const dashboard_names = ref<{ [key: string]: string }>({
|
||||||
|
storage: '存储空间',
|
||||||
|
mediaStatistic: '媒体统计',
|
||||||
|
weeklyOverview: '最近入库',
|
||||||
|
speed: '实时速率',
|
||||||
|
scheduler: '后台任务',
|
||||||
|
cpu: 'CPU',
|
||||||
|
memory: '内存',
|
||||||
|
library: '我的媒体库',
|
||||||
|
playing: '继续观看',
|
||||||
|
latest: '最近添加',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 有仪表板的插件
|
||||||
|
const dashboard_plugins = ref<any[]>([])
|
||||||
|
|
||||||
|
// 插件仪表板配置
|
||||||
|
const plugin_dashboards = ref<PluginDashboard[]>([])
|
||||||
|
|
||||||
|
// 弹窗
|
||||||
|
const dialog = ref(false)
|
||||||
|
|
||||||
// 初始化默认值
|
// 初始化默认值
|
||||||
const config = ref(JSON.parse(localStorage.getItem('MP_DASHBOARD') || '{}'))
|
const config = ref(JSON.parse(localStorage.getItem('MP_DASHBOARD') || '{}'))
|
||||||
if (isNullOrEmptyObject(config.value)) {
|
if (isNullOrEmptyObject(config.value)) {
|
||||||
@@ -65,52 +73,90 @@ function setDashboardConfig() {
|
|||||||
})
|
})
|
||||||
dialog.value = false
|
dialog.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调用API获取有仪表板的插件
|
||||||
|
async function getDashboardPlugins() {
|
||||||
|
try {
|
||||||
|
dashboard_plugins.value = await api.get('/plugin/dashboards')
|
||||||
|
if (!isNullOrEmptyObject(dashboard_plugins.value)) {
|
||||||
|
// 获取id和name补充到 dashboard_names 中
|
||||||
|
dashboard_plugins.value.forEach((plugin: { [key: string]: string }) => {
|
||||||
|
dashboard_names.value[plugin.id] = plugin.name
|
||||||
|
})
|
||||||
|
// 下载插件仪表板配置
|
||||||
|
dashboard_plugins.value.forEach(async (plugin: { id: string }) => {
|
||||||
|
await getPluginDashboard(plugin.id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取一个插件的仪表板配置项
|
||||||
|
async function getPluginDashboard(id: string) {
|
||||||
|
try {
|
||||||
|
api.get(`/plugin/dashboard/${id}`).then(res => {
|
||||||
|
if (res) plugin_dashboards.value.push(res)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getDashboardPlugins()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
<VFab icon="mdi-view-dashboard-edit" location="bottom end" size="x-large" fixed app appear @click="dialog = true" />
|
<VFab icon="mdi-view-dashboard-edit" location="bottom end" size="x-large" fixed app appear @click="dialog = true" />
|
||||||
|
<!-- 仪表板 -->
|
||||||
<VRow class="match-height">
|
<VRow class="match-height">
|
||||||
|
<!-- 系统内置的仪表板 -->
|
||||||
<VCol v-if="config.storage" cols="12" md="4">
|
<VCol v-if="config.storage" cols="12" md="4">
|
||||||
<AnalyticsStorage />
|
<AnalyticsStorage />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.mediaStatistic" cols="12" md="8">
|
<VCol v-if="config.mediaStatistic" cols="12" md="8">
|
||||||
<AnalyticsMediaStatistic />
|
<AnalyticsMediaStatistic />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.weeklyOverview" cols="12" md="4">
|
<VCol v-if="config.weeklyOverview" cols="12" md="4">
|
||||||
<AnalyticsWeeklyOverview />
|
<AnalyticsWeeklyOverview />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.speed" cols="12" md="4">
|
<VCol v-if="config.speed" cols="12" md="4">
|
||||||
<AnalyticsSpeed />
|
<AnalyticsSpeed />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.scheduler" cols="12" md="4">
|
<VCol v-if="config.scheduler" cols="12" md="4">
|
||||||
<AnalyticsScheduler />
|
<AnalyticsScheduler />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.cpu" cols="12" md="6">
|
<VCol v-if="config.cpu" cols="12" md="6">
|
||||||
<AnalyticsCpu />
|
<AnalyticsCpu />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.memory" cols="12" md="6">
|
<VCol v-if="config.memory" cols="12" md="6">
|
||||||
<AnalyticsMemory />
|
<AnalyticsMemory />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.library" cols="12">
|
<VCol v-if="config.library" cols="12">
|
||||||
<MediaServerLibrary />
|
<MediaServerLibrary />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.playing" cols="12">
|
<VCol v-if="config.playing" cols="12">
|
||||||
<MediaServerPlaying />
|
<MediaServerPlaying />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<VCol v-if="config.latest" cols="12">
|
<VCol v-if="config.latest" cols="12">
|
||||||
<MediaServerLatest />
|
<MediaServerLatest />
|
||||||
</VCol>
|
</VCol>
|
||||||
|
<!-- 插件仪表板 -->
|
||||||
|
<template v-for="plugin in plugin_dashboards" :key="plugin.id">
|
||||||
|
<VCol v-if="config[plugin.id]" v-bind="plugin.cols">
|
||||||
|
<VCard :title="plugin.name">
|
||||||
|
<VCardItem>
|
||||||
|
<DashboardRender v-for="(item, index) in plugin.elements" :key="index" :config="item" />
|
||||||
|
</VCardItem>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</template>
|
||||||
</VRow>
|
</VRow>
|
||||||
|
|
||||||
<!-- 弹窗,根据配置生成选项 -->
|
<!-- 弹窗,根据配置生成选项 -->
|
||||||
<VDialog v-model="dialog" max-width="35rem" scrollable :fullscreen="!display.mdAndUp.value">
|
<VDialog v-model="dialog" max-width="35rem" scrollable :fullscreen="!display.mdAndUp.value">
|
||||||
<VCard>
|
<VCard>
|
||||||
@@ -120,8 +166,8 @@ function setDashboardConfig() {
|
|||||||
<VDivider />
|
<VDivider />
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="(item, key) in dashboard_names" :key="key" cols="12" md="4" sm="4">
|
<VCol v-for="(name, key) in dashboard_names" :key="key" cols="12" md="4" sm="4">
|
||||||
<VCheckbox v-model="config[key]" :label="dashboard_names[key]" />
|
<VCheckbox v-model="config[key]" :label="name" />
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
|
|||||||
Reference in New Issue
Block a user