mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-28 11:37:29 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
236440be52 | ||
|
|
6f7e4bb272 | ||
|
|
38dcd3635a | ||
|
|
a3f3330dad | ||
|
|
bbc6c57c08 | ||
|
|
2f36a8edef | ||
|
|
df637fb887 | ||
|
|
be74c92a35 | ||
|
|
a219a64e20 | ||
|
|
25c22a276a | ||
|
|
6e6be057ca | ||
|
|
af69efa48b | ||
|
|
c551083fa4 | ||
|
|
9767feed29 | ||
|
|
4392818e92 | ||
|
|
8d22bafeb6 | ||
|
|
89ddd1fb78 | ||
|
|
24513fa22b | ||
|
|
cddde0c2a0 | ||
|
|
9c674e0018 | ||
|
|
0c6476d283 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "moviepilot",
|
"name": "moviepilot",
|
||||||
"version": "1.6.4-3",
|
"version": "1.6.8-1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"bin": "dist/service.js",
|
"bin": "dist/service.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -121,7 +121,11 @@ function themeTransition() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<IconBtn @click="changeTheme">
|
<IconBtn @click="changeTheme">
|
||||||
<VIcon :icon="props.themes[currentThemeIndex].icon" />
|
<VTooltip text="切换主题">
|
||||||
|
<template #activator="{ props: _props }">
|
||||||
|
<VIcon v-bind="_props" :icon="props.themes[currentThemeIndex].icon" />
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -877,6 +877,9 @@ export interface ScheduleInfo {
|
|||||||
// 名称
|
// 名称
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
|
// 提供者
|
||||||
|
provider: string
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
status: string
|
status: string
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import PageRender from '@/components/render/PageRender.vue'
|
|||||||
import { isNullOrEmptyObject } from '@core/utils'
|
import { isNullOrEmptyObject } from '@core/utils'
|
||||||
import noImage from '@images/logos/plugin.png'
|
import noImage from '@images/logos/plugin.png'
|
||||||
import { getDominantColor } from '@/@core/utils/image'
|
import { getDominantColor } from '@/@core/utils/image'
|
||||||
|
import store from '@/store'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -225,6 +226,13 @@ function visitAuthorPage() {
|
|||||||
window.open(props.plugin?.author_url, '_blank')
|
window.open(props.plugin?.author_url, '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查看日志URL
|
||||||
|
function openLoggerWindow() {
|
||||||
|
const token = store.state.auth.token
|
||||||
|
const url = `${import.meta.env.VITE_API_BASE_URL}system/logging?token=${token}&length=-1&logfile=plugins/${props.plugin?.id?.toLowerCase()}.log`
|
||||||
|
window.open(url, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
// 弹出菜单
|
// 弹出菜单
|
||||||
const dropdownItems = ref([
|
const dropdownItems = ref([
|
||||||
{
|
{
|
||||||
@@ -265,9 +273,20 @@ const dropdownItems = ref([
|
|||||||
click: uninstallPlugin,
|
click: uninstallPlugin,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '查看日志',
|
||||||
|
value: 5,
|
||||||
|
show: true,
|
||||||
|
props: {
|
||||||
|
prependIcon: 'mdi-file-document-outline',
|
||||||
|
click: () => {
|
||||||
|
openLoggerWindow()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '作者主页',
|
title: '作者主页',
|
||||||
value: 4,
|
value: 5,
|
||||||
show: true,
|
show: true,
|
||||||
props: {
|
props: {
|
||||||
prependIcon: 'mdi-home-circle-outline',
|
prependIcon: 'mdi-home-circle-outline',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang='ts' setup>
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import SubscribeEditForm from '../form/SubscribeEditForm.vue'
|
import SubscribeEditForm from '../form/SubscribeEditForm.vue'
|
||||||
import { calculateTimeDifference } from '@/@core/utils'
|
import { calculateTimeDifference } from '@/@core/utils'
|
||||||
import { formatSeason } from '@/@core/utils/formatters'
|
import { formatSeason } from '@/@core/utils/formatters'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import type { Subscribe } from '@/api/types'
|
import type { Subscribe } from '@/api/types'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -55,7 +56,7 @@ function getPercentage() {
|
|||||||
return Math.round(
|
return Math.round(
|
||||||
(((props.media?.total_episode ?? 0) - (props.media?.lack_episode ?? 0))
|
(((props.media?.total_episode ?? 0) - (props.media?.lack_episode ?? 0))
|
||||||
/ (props.media?.total_episode ?? 1))
|
/ (props.media?.total_episode ?? 1))
|
||||||
* 100,
|
* 100,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,8 +127,28 @@ const dropdownItems = ref([
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '取消订阅',
|
title: '查看详情',
|
||||||
value: 3,
|
value: 3,
|
||||||
|
props: {
|
||||||
|
prependIcon: 'mdi-open-in-new',
|
||||||
|
click: () => {
|
||||||
|
router.push({
|
||||||
|
path: '/media',
|
||||||
|
query: {
|
||||||
|
mediaid: `${
|
||||||
|
props.media?.tmdbid
|
||||||
|
? `tmdb:${props.media?.tmdbid}`
|
||||||
|
: `douban:${props.media?.doubanid}`
|
||||||
|
}`,
|
||||||
|
type: props.media?.type,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '取消订阅',
|
||||||
|
value: 4,
|
||||||
props: {
|
props: {
|
||||||
prependIcon: 'mdi-trash-can-outline',
|
prependIcon: 'mdi-trash-can-outline',
|
||||||
color: 'error',
|
color: 'error',
|
||||||
@@ -162,7 +183,7 @@ const dropdownItems = ref([
|
|||||||
</template>
|
</template>
|
||||||
<VCardTitle :class="getTextClass()">
|
<VCardTitle :class="getTextClass()">
|
||||||
{{ props.media?.name }}
|
{{ props.media?.name }}
|
||||||
{{ formatSeason(props.media?.season ? props.media?.season.toString() : "") }}
|
{{ formatSeason(props.media?.season ? props.media?.season.toString() : '') }}
|
||||||
</VCardTitle>
|
</VCardTitle>
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="me-n3">
|
<div class="me-n3">
|
||||||
@@ -252,7 +273,8 @@ const dropdownItems = ref([
|
|||||||
<VIcon
|
<VIcon
|
||||||
icon="mdi-download"
|
icon="mdi-download"
|
||||||
class="me-1"
|
class="me-1"
|
||||||
/> {{ lastUpdateText }}
|
/>
|
||||||
|
{{ lastUpdateText }}
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VProgressLinear
|
<VProgressLinear
|
||||||
v-if="getPercentage() > 0"
|
v-if="getPercentage() > 0"
|
||||||
|
|||||||
@@ -416,21 +416,41 @@ onMounted(() => {
|
|||||||
</VMenu>
|
</VMenu>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
<span v-show="hover.isHovering" class="flex">
|
<span v-show="hover.isHovering" class="flex">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="recognize(item.path)">
|
<VTooltip text="识别">
|
||||||
<VIcon icon="mdi-text-recognition" />
|
<template #activator="{ props }">
|
||||||
</IconBtn>
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="recognize(item.path)">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="scrape(item.path)">
|
<VIcon icon="mdi-text-recognition" />
|
||||||
<VIcon icon="mdi-auto-fix" />
|
</IconBtn>
|
||||||
</IconBtn>
|
</template>
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="showRenmae(item)">
|
</VTooltip>
|
||||||
<VIcon icon="mdi-rename" />
|
<VTooltip text="刮削">
|
||||||
</IconBtn>
|
<template #activator="{ props }">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="showTransfer(item)">
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="scrape(item.path)">
|
||||||
<VIcon icon="mdi-folder-arrow-right" />
|
<VIcon icon="mdi-auto-fix" />
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="deleteItem(item)">
|
</template>
|
||||||
<VIcon icon="mdi-delete-outline" />
|
</VTooltip>
|
||||||
</IconBtn>
|
<VTooltip text="重命名">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showRenmae(item)">
|
||||||
|
<VIcon icon="mdi-rename" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="整理">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showTransfer(item)">
|
||||||
|
<VIcon icon="mdi-folder-arrow-right" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="删除">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="deleteItem(item)">
|
||||||
|
<VIcon icon="mdi-delete-outline" color="error" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
@@ -483,21 +503,41 @@ onMounted(() => {
|
|||||||
</VMenu>
|
</VMenu>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
<span v-show="hover.isHovering" class="flex">
|
<span v-show="hover.isHovering" class="flex">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="recognize(item.path)">
|
<VTooltip text="识别">
|
||||||
<VIcon icon="mdi-text-recognition" />
|
<template #activator="{ props }">
|
||||||
</IconBtn>
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="recognize(item.path)">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="scrape(item.path)">
|
<VIcon icon="mdi-text-recognition" />
|
||||||
<VIcon icon="mdi-auto-fix" />
|
</IconBtn>
|
||||||
</IconBtn>
|
</template>
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="showRenmae(item)">
|
</VTooltip>
|
||||||
<VIcon icon="mdi-rename" />
|
<VTooltip text="刮削">
|
||||||
</IconBtn>
|
<template #activator="{ props }">
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="showTransfer(item)">
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="scrape(item.path)">
|
||||||
<VIcon icon="mdi-folder-arrow-right" />
|
<VIcon icon="mdi-auto-fix" />
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
<IconBtn class="d-none d-sm-block" @click.stop="deleteItem(item)">
|
</template>
|
||||||
<VIcon icon="mdi-delete-outline" />
|
</VTooltip>
|
||||||
</IconBtn>
|
<VTooltip text="重命名">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showRenmae(item)">
|
||||||
|
<VIcon icon="mdi-rename" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="整理">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="showTransfer(item)">
|
||||||
|
<VIcon icon="mdi-folder-arrow-right" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="删除">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" class="d-none d-sm-block" @click.stop="deleteItem(item)">
|
||||||
|
<VIcon icon="mdi-delete-outline" color="error" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
|||||||
@@ -144,19 +144,31 @@ const sortIcon = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
</VToolbarItems>
|
</VToolbarItems>
|
||||||
<div class="flex-grow-1" />
|
<div class="flex-grow-1" />
|
||||||
<IconBtn @click="changeSort">
|
<VTooltip text="调整排序">
|
||||||
<VIcon :icon="sortIcon" />
|
<template #activator="{ props }">
|
||||||
</IconBtn>
|
<IconBtn v-bind="props" @click="changeSort">
|
||||||
<IconBtn v-if="pathSegments.length > 0" @click="goUp">
|
<VIcon :icon="sortIcon" />
|
||||||
<VIcon icon="mdi-arrow-up-bold-outline" />
|
</IconBtn>
|
||||||
</IconBtn>
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="返回上一级" v-if="pathSegments.length > 0">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<IconBtn v-bind="props" @click="goUp">
|
||||||
|
<VIcon icon="mdi-arrow-up-bold-outline" />
|
||||||
|
</IconBtn>
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
<VDialog
|
<VDialog
|
||||||
v-model="newFolderPopper"
|
v-model="newFolderPopper"
|
||||||
max-width="50rem"
|
max-width="50rem"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<IconBtn title="新建文件夹" v-bind="props">
|
<IconBtn v-bind="props">
|
||||||
<VIcon icon="mdi-folder-plus-outline" />
|
<VTooltip text="新建文件夹">
|
||||||
|
<template #activator="{ props: _props }">
|
||||||
|
<VIcon v-bind="_props" icon="mdi-folder-plus-outline" />
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
<VCard title="新建文件夹">
|
<VCard title="新建文件夹">
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ function allLoggingUrl() {
|
|||||||
class="me-2"
|
class="me-2"
|
||||||
v-bind="props"
|
v-bind="props"
|
||||||
>
|
>
|
||||||
<VIcon icon="mdi-checkbox-multiple-blank-outline" />
|
<VTooltip text="捷径">
|
||||||
|
<template #activator="{ props: _props }">
|
||||||
|
<VIcon v-bind="_props" icon="mdi-checkbox-multiple-blank-outline" />
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
<!-- Menu Content -->
|
<!-- Menu Content -->
|
||||||
|
|||||||
@@ -5,25 +5,21 @@ import NoDataFound from '@/components/NoDataFound.vue'
|
|||||||
import PluginAppCard from '@/components/cards/PluginAppCard.vue'
|
import PluginAppCard from '@/components/cards/PluginAppCard.vue'
|
||||||
import PluginCard from '@/components/cards/PluginCard.vue'
|
import PluginCard from '@/components/cards/PluginCard.vue'
|
||||||
|
|
||||||
// 数据列表
|
// 已安装插件列表
|
||||||
const dataList = ref<Plugin[]>([])
|
const dataList = ref<Plugin[]>([])
|
||||||
|
|
||||||
|
// 未安装插件列表
|
||||||
|
const uninstalledList = ref<Plugin[]>([])
|
||||||
|
|
||||||
// 是否刷新过
|
// 是否刷新过
|
||||||
const isRefreshed = ref(false)
|
const isRefreshed = ref(false)
|
||||||
|
|
||||||
|
// APP市场是否加载完成
|
||||||
|
const isAppMarketLoaded = ref(false)
|
||||||
|
|
||||||
// APP市场窗口
|
// APP市场窗口
|
||||||
const PluginAppDialog = ref(false)
|
const PluginAppDialog = ref(false)
|
||||||
|
|
||||||
// 获取已安装的插件列表
|
|
||||||
const getInstalledPluginList = computed(() => {
|
|
||||||
return dataList.value.filter(item => item.installed)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取未安装或者有更新的插件列表
|
|
||||||
const getUninstalledPluginList = computed(() => {
|
|
||||||
return dataList.value.filter(item => !item.installed || item.has_update)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 关闭插件市场窗口
|
// 关闭插件市场窗口
|
||||||
function pluginDialogClose() {
|
function pluginDialogClose() {
|
||||||
PluginAppDialog.value = false
|
PluginAppDialog.value = false
|
||||||
@@ -31,14 +27,19 @@ function pluginDialogClose() {
|
|||||||
|
|
||||||
// 新安装了插件
|
// 新安装了插件
|
||||||
function pluginInstalled() {
|
function pluginInstalled() {
|
||||||
fetchData()
|
fetchInstalledPlugins()
|
||||||
pluginDialogClose()
|
pluginDialogClose()
|
||||||
|
fetchUninstalledPlugins()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取插件列表数据
|
// 获取插件列表数据
|
||||||
async function fetchData() {
|
async function fetchInstalledPlugins() {
|
||||||
try {
|
try {
|
||||||
dataList.value = await api.get('plugin/')
|
dataList.value = await api.get('plugin/', {
|
||||||
|
params: {
|
||||||
|
state: 'installed',
|
||||||
|
},
|
||||||
|
})
|
||||||
isRefreshed.value = true
|
isRefreshed.value = true
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@@ -46,8 +47,26 @@ async function fetchData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取未安装插件列表数据
|
||||||
|
async function fetchUninstalledPlugins() {
|
||||||
|
try {
|
||||||
|
uninstalledList.value = await api.get('plugin/', {
|
||||||
|
params: {
|
||||||
|
state: 'market',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
isAppMarketLoaded.value = true
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 加载时获取数据
|
// 加载时获取数据
|
||||||
onBeforeMount(fetchData)
|
onBeforeMount(() => {
|
||||||
|
fetchInstalledPlugins()
|
||||||
|
fetchUninstalledPlugins()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -63,19 +82,19 @@ onBeforeMount(fetchData)
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="getInstalledPluginList.length > 0"
|
v-if="dataList.length > 0"
|
||||||
class="grid gap-4 grid-plugin-card"
|
class="grid gap-4 grid-plugin-card"
|
||||||
>
|
>
|
||||||
<PluginCard
|
<PluginCard
|
||||||
v-for="data in getInstalledPluginList"
|
v-for="data in dataList"
|
||||||
:key="data.id"
|
:key="data.id"
|
||||||
:plugin="data"
|
:plugin="data"
|
||||||
@remove="fetchData"
|
@remove="fetchInstalledPlugins"
|
||||||
@save="fetchData"
|
@save="fetchInstalledPlugins"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="getInstalledPluginList.length === 0 && isRefreshed"
|
v-if="dataList.length === 0 && isRefreshed"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
error-title="没有安装插件"
|
error-title="没有安装插件"
|
||||||
error-description="点击右下角按钮,前往插件市场安装插件。"
|
error-description="点击右下角按钮,前往插件市场安装插件。"
|
||||||
@@ -121,16 +140,27 @@ onBeforeMount(fetchData)
|
|||||||
</VToolbar>
|
</VToolbar>
|
||||||
</div>
|
</div>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<div class="grid gap-4 grid-plugin-card">
|
<div
|
||||||
|
v-if="!isAppMarketLoaded"
|
||||||
|
class="mt-12 w-full text-center text-gray-500 text-sm flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<VProgressCircular
|
||||||
|
v-if="!isAppMarketLoaded"
|
||||||
|
size="48"
|
||||||
|
indeterminate
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="isAppMarketLoaded" class="grid gap-4 grid-plugin-card">
|
||||||
<PluginAppCard
|
<PluginAppCard
|
||||||
v-for="data in getUninstalledPluginList"
|
v-for="data in uninstalledList"
|
||||||
:key="data.id"
|
:key="data.id"
|
||||||
:plugin="data"
|
:plugin="data"
|
||||||
@install="pluginInstalled"
|
@install="pluginInstalled"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="getUninstalledPluginList.length === 0 && isRefreshed"
|
v-if="uninstalledList.length === 0 && isAppMarketLoaded"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
error-title="没有未安装插件"
|
error-title="没有未安装插件"
|
||||||
error-description="所有可用插件均已安装。"
|
error-description="所有可用插件均已安装。"
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ const dropdownItems = ref([
|
|||||||
<VIcon :icon="getIcon(item.value.type || '')" />
|
<VIcon :icon="getIcon(item.value.type || '')" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
<div class="d-flex flex-column ms-1">
|
<div class="d-flex flex-column ms-1">
|
||||||
<span class="d-block whitespace-nowrap text-high-emphasis">
|
<span class="d-block text-high-emphasis">
|
||||||
{{ item.value.title }} {{ item.value.seasons }}{{ item.value.episodes }}
|
{{ item.value.title }} {{ item.value.seasons }}{{ item.value.episodes }}
|
||||||
</span>
|
</span>
|
||||||
<small>{{ item.value.category }}</small>
|
<small>{{ item.value.category }}</small>
|
||||||
@@ -415,8 +415,16 @@ const dropdownItems = ref([
|
|||||||
</VCard>
|
</VCard>
|
||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
<span v-if="selected.length > 0" class="fixed right-5 bottom-5">
|
<span v-if="selected.length > 0" class="fixed right-5 bottom-5">
|
||||||
<VBtn icon="mdi-redo-variant" class="me-2" color="primary" size="x-large" @click="retransferBatch" />
|
<VTooltip text="批量重新整理">
|
||||||
<VBtn icon="mdi-trash-can-outline" color="error" size="x-large" @click="removeHistoryBatch" />
|
<template #activator="{ props }">
|
||||||
|
<VBtn v-bind="props" icon="mdi-redo-variant" class="me-2" color="primary" size="x-large" @click="retransferBatch" />
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
|
<VTooltip text="批量删除">
|
||||||
|
<template #activator="{ props }">
|
||||||
|
<VBtn v-bind="props" icon="mdi-trash-can-outline" color="error" size="x-large" @click="removeHistoryBatch" />
|
||||||
|
</template>
|
||||||
|
</VTooltip>
|
||||||
</span>
|
</span>
|
||||||
<!-- 底部弹窗 -->
|
<!-- 底部弹窗 -->
|
||||||
<VBottomSheet v-model="deleteConfirmDialog" inset>
|
<VBottomSheet v-model="deleteConfirmDialog" inset>
|
||||||
|
|||||||
@@ -78,11 +78,14 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VCard title="定时作业">
|
<VCard title="定时作业">
|
||||||
<VCardSubtitle> 手动执行不会影响作业正常的时间表。 </VCardSubtitle>
|
<VCardSubtitle> 包含系统内置服务以及插件提供的服务,手动执行不会影响作业正常的时间表。 </VCardSubtitle>
|
||||||
|
|
||||||
<VTable class="text-no-wrap">
|
<VTable class="text-no-wrap">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th scope="col">
|
||||||
|
提供者
|
||||||
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
任务名称
|
任务名称
|
||||||
</th>
|
</th>
|
||||||
@@ -100,6 +103,9 @@ onUnmounted(() => {
|
|||||||
v-for="scheduler in schedulerList"
|
v-for="scheduler in schedulerList"
|
||||||
:key="scheduler.id"
|
:key="scheduler.id"
|
||||||
>
|
>
|
||||||
|
<td>
|
||||||
|
{{ scheduler.provider }}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ scheduler.name }}
|
{{ scheduler.name }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang='ts' setup>
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
|
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
|
||||||
@@ -94,7 +94,7 @@ async function saveSelectedRssSites() {
|
|||||||
|
|
||||||
const result2: { [key: string]: any } = await api.post(
|
const result2: { [key: string]: any } = await api.post(
|
||||||
'system/setting/SUBSCRIBE_SEARCH',
|
'system/setting/SUBSCRIBE_SEARCH',
|
||||||
enableIntervalSearch.value,
|
enableIntervalSearch.value ? 'True' : 'False',
|
||||||
)
|
)
|
||||||
|
|
||||||
const result3: { [key: string]: any } = await api.post(
|
const result3: { [key: string]: any } = await api.post(
|
||||||
@@ -469,7 +469,7 @@ onMounted(() => {
|
|||||||
</VMenu>
|
</VMenu>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
<VCardSubtitle> 设置在正常订阅时默认使用的优先级,未在优先级中的资源将不会自动下载。 </VCardSubtitle>
|
<VCardSubtitle> 设置在正常订阅时默认使用的优先级,未在优先级中的资源将不会自动下载。</VCardSubtitle>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<div class="grid gap-3 grid-filterrule-card">
|
<div class="grid gap-3 grid-filterrule-card">
|
||||||
<FilterRuleCard
|
<FilterRuleCard
|
||||||
@@ -535,7 +535,7 @@ onMounted(() => {
|
|||||||
</VMenu>
|
</VMenu>
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
</template>
|
</template>
|
||||||
<VCardSubtitle> 设置在订阅洗版时使用的优先级,匹配优先级1时洗版完成。 </VCardSubtitle>
|
<VCardSubtitle> 设置在订阅洗版时使用的优先级,匹配优先级1时洗版完成。</VCardSubtitle>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<div class="grid gap-3 grid-filterrule-card">
|
<div class="grid gap-3 grid-filterrule-card">
|
||||||
<FilterRuleCard
|
<FilterRuleCard
|
||||||
@@ -571,7 +571,7 @@ onMounted(() => {
|
|||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12">
|
<VCol cols="12">
|
||||||
<VCard title="默认过滤规则">
|
<VCard title="默认过滤规则">
|
||||||
<VCardSubtitle> 设置在订阅时默认使用的过滤规则。 </VCardSubtitle>
|
<VCardSubtitle> 设置在订阅时默认使用的过滤规则。</VCardSubtitle>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<VForm>
|
<VForm>
|
||||||
<VRow>
|
<VRow>
|
||||||
@@ -638,7 +638,7 @@ onMounted(() => {
|
|||||||
</VDialog>
|
</VDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang='scss'>
|
||||||
.grid-filterrule-card {
|
.grid-filterrule-card {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
padding-block-end: 1rem;
|
padding-block-end: 1rem;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import { VRow } from 'vuetify/lib/components/index.mjs'
|
import { VRow } from 'vuetify/lib/components/index.mjs'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
|
import { requiredValidator } from '@/@validators'
|
||||||
|
|
||||||
// 选中的媒体服务器
|
// 选中的媒体服务器
|
||||||
const selectedMediaServers = ref([])
|
const selectedMediaServers = ref([])
|
||||||
@@ -532,8 +533,8 @@ onMounted(() => {
|
|||||||
<VCol cols="12" md="4">
|
<VCol cols="12" md="4">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="mediaServerSettings.EMBY_PLAY_HOST"
|
v-model="mediaServerSettings.EMBY_PLAY_HOST"
|
||||||
label="播放地址"
|
label="外网播放地址"
|
||||||
placeholder="IP:PORT"
|
placeholder="http(s)://domain:port"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="4">
|
<VCol cols="12" md="4">
|
||||||
@@ -559,7 +560,7 @@ onMounted(() => {
|
|||||||
<VTextField
|
<VTextField
|
||||||
v-model="mediaServerSettings.JELLYFIN_PLAY_HOST"
|
v-model="mediaServerSettings.JELLYFIN_PLAY_HOST"
|
||||||
label="外网播放地址"
|
label="外网播放地址"
|
||||||
placeholder="IP:PORT"
|
placeholder="http(s)://domain:port"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="4">
|
<VCol cols="12" md="4">
|
||||||
@@ -585,7 +586,7 @@ onMounted(() => {
|
|||||||
<VTextField
|
<VTextField
|
||||||
v-model="mediaServerSettings.PLEX_PLAY_HOST"
|
v-model="mediaServerSettings.PLEX_PLAY_HOST"
|
||||||
label="外网播放地址"
|
label="外网播放地址"
|
||||||
placeholder="IP:PORT"
|
placeholder="http(s)://domain:port"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="4">
|
<VCol cols="12" md="4">
|
||||||
@@ -628,6 +629,7 @@ onMounted(() => {
|
|||||||
<VTextField
|
<VTextField
|
||||||
v-model="mediaSettings.DOWNLOAD_PATH"
|
v-model="mediaSettings.DOWNLOAD_PATH"
|
||||||
label="下载目录"
|
label="下载目录"
|
||||||
|
:rules="[requiredValidator]"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
@@ -682,6 +684,8 @@ onMounted(() => {
|
|||||||
<VTextField
|
<VTextField
|
||||||
v-model="mediaSettings.LIBRARY_PATH"
|
v-model="mediaSettings.LIBRARY_PATH"
|
||||||
label="媒体库目录"
|
label="媒体库目录"
|
||||||
|
placeholder="多个目录使用,分隔"
|
||||||
|
:rules="[requiredValidator]"
|
||||||
/>
|
/>
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
|
|||||||
Reference in New Issue
Block a user