mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-08 01:06:41 +08:00
refactor: 将订阅和插件过滤弹窗改为站点管理风格的下拉列表菜单
This commit is contained in:
+47
-33
@@ -82,14 +82,25 @@ const filterOptions = computed(() => {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// 计算筛选按钮颜色
|
// 当前选中的筛选选项
|
||||||
|
const currentFilter = computed(() => {
|
||||||
|
return filterOptions.value.find(option => option.value === (subscribeStatusFilter.value || 'all'))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算筛选按钮颜色 - 有名称筛选或状态筛选时高亮
|
||||||
const filterButtonColor = computed(() => {
|
const filterButtonColor = computed(() => {
|
||||||
if (subscribeFilter.value || (subscribeStatusFilter.value && subscribeStatusFilter.value !== 'all')) {
|
if (subscribeFilter.value || (subscribeStatusFilter.value && subscribeStatusFilter.value !== 'all')) {
|
||||||
return 'primary'
|
return currentFilter.value?.color || 'primary'
|
||||||
}
|
}
|
||||||
return 'gray'
|
return 'gray'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 选择筛选选项
|
||||||
|
function selectFilter(value: string) {
|
||||||
|
subscribeStatusFilter.value = value
|
||||||
|
filterSubscribeDialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
// VMenu activator选择器
|
// VMenu activator选择器
|
||||||
const filterActivator = computed(() => '[data-menu-activator="filter-btn"]')
|
const filterActivator = computed(() => '[data-menu-activator="filter-btn"]')
|
||||||
const searchActivator = computed(() => '[data-menu-activator="search-btn"]')
|
const searchActivator = computed(() => '[data-menu-activator="search-btn"]')
|
||||||
@@ -200,44 +211,47 @@ onMounted(() => {
|
|||||||
</VWindowItem>
|
</VWindowItem>
|
||||||
</VWindow>
|
</VWindow>
|
||||||
|
|
||||||
<!-- 订阅过滤弹窗 -->
|
<!-- 订阅过滤下拉菜单 -->
|
||||||
<Teleport to="body" v-if="filterSubscribeDialog">
|
<Teleport to="body" v-if="filterSubscribeDialog">
|
||||||
<VMenu
|
<VMenu
|
||||||
v-model="filterSubscribeDialog"
|
v-model="filterSubscribeDialog"
|
||||||
width="25rem"
|
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
:activator="filterActivator"
|
:activator="filterActivator"
|
||||||
location="bottom end"
|
location="bottom end"
|
||||||
>
|
>
|
||||||
<VCard>
|
<VCard min-width="220">
|
||||||
<VCardItem>
|
<!-- 名称搜索 -->
|
||||||
<VCardTitle>
|
<div class="px-3 pt-3 pb-1">
|
||||||
<VIcon icon="mdi-filter-multiple-outline" class="mr-2" />
|
<VTextField
|
||||||
{{ t('subscribe.filterSubscriptions') }}
|
v-model="subscribeFilter"
|
||||||
</VCardTitle>
|
:placeholder="t('subscribe.name')"
|
||||||
<VDialogCloseBtn @click="filterSubscribeDialog = false" />
|
prepend-inner-icon="mdi-magnify"
|
||||||
</VCardItem>
|
density="compact"
|
||||||
<VCardText>
|
variant="outlined"
|
||||||
<VRow>
|
hide-details
|
||||||
<!-- 名称筛选 -->
|
clearable
|
||||||
<VCol cols="6">
|
/>
|
||||||
<VTextField v-model="subscribeFilter" :label="t('subscribe.name')" clearable density="comfortable" />
|
</div>
|
||||||
</VCol>
|
<VDivider class="mt-2" />
|
||||||
|
<!-- 状态筛选列表 -->
|
||||||
<!-- 状态筛选 -->
|
<VList density="compact" class="px-2 py-1">
|
||||||
<VCol cols="6">
|
<VListSubheader>{{ t('common.status') }}</VListSubheader>
|
||||||
<VSelect
|
<VListItem
|
||||||
v-model="subscribeStatusFilter"
|
v-for="option in filterOptions"
|
||||||
:items="filterOptions"
|
:key="option.value"
|
||||||
item-title="label"
|
:active="(subscribeStatusFilter || 'all') === option.value"
|
||||||
item-value="value"
|
@click="selectFilter(option.value)"
|
||||||
:label="t('common.status')"
|
density="compact"
|
||||||
density="comfortable"
|
>
|
||||||
clearable
|
<template #prepend>
|
||||||
/>
|
<VIcon :icon="option.icon" :color="option.color" size="small" />
|
||||||
</VCol>
|
</template>
|
||||||
</VRow>
|
<VListItemTitle>{{ option.label }}</VListItemTitle>
|
||||||
</VCardText>
|
<template #append>
|
||||||
|
<VIcon v-if="(subscribeStatusFilter || 'all') === option.value" icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|||||||
@@ -219,6 +219,16 @@ const isFilterFormEmpty = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 切换市场过滤器多选项
|
||||||
|
function toggleMarketFilter(field: 'author' | 'label' | 'repo', value: string) {
|
||||||
|
const index = filterForm[field].indexOf(value)
|
||||||
|
if (index > -1) {
|
||||||
|
filterForm[field].splice(index, 1)
|
||||||
|
} else {
|
||||||
|
filterForm[field].push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 插件过滤条件
|
// 插件过滤条件
|
||||||
const installedFilter = ref(null)
|
const installedFilter = ref(null)
|
||||||
|
|
||||||
@@ -1289,113 +1299,159 @@ function onDragStartPlugin(evt: any) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- 过滤弹窗 -->
|
<!-- 已安装插件过滤下拉菜单 -->
|
||||||
<Teleport to="body" v-if="filterInstalledPluginDialog">
|
<Teleport to="body" v-if="filterInstalledPluginDialog">
|
||||||
<VMenu
|
<VMenu
|
||||||
v-model="filterInstalledPluginDialog"
|
v-model="filterInstalledPluginDialog"
|
||||||
width="20rem"
|
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
:activator="'[data-menu-activator=installed-filter-btn]'"
|
:activator="'[data-menu-activator=installed-filter-btn]'"
|
||||||
location="bottom end"
|
location="bottom end"
|
||||||
>
|
>
|
||||||
<VCard>
|
<VCard min-width="220">
|
||||||
<VCardItem>
|
<!-- 名称搜索 -->
|
||||||
<VCardTitle>
|
<div class="px-3 pt-3 pb-1">
|
||||||
<VIcon icon="mdi-filter-multiple-outline" class="mr-2" />
|
<VCombobox
|
||||||
{{ t('plugin.filterPlugins') }}
|
v-model="installedFilter"
|
||||||
</VCardTitle>
|
:items="installedPluginNames"
|
||||||
<VDialogCloseBtn @click="filterInstalledPluginDialog = false" />
|
:placeholder="t('plugin.name')"
|
||||||
</VCardItem>
|
prepend-inner-icon="mdi-magnify"
|
||||||
<VCardText>
|
density="compact"
|
||||||
<VRow>
|
variant="outlined"
|
||||||
<VCol cols="12">
|
hide-details
|
||||||
<VCombobox
|
clearable
|
||||||
v-model="installedFilter"
|
/>
|
||||||
:items="installedPluginNames"
|
</div>
|
||||||
:label="t('plugin.name')"
|
<VDivider class="mt-2" />
|
||||||
density="comfortable"
|
<!-- 快捷筛选 -->
|
||||||
clearable
|
<VList density="compact" class="px-2 py-1">
|
||||||
/>
|
<VListSubheader>{{ t('common.filter') }}</VListSubheader>
|
||||||
</VCol>
|
<VListItem
|
||||||
<VCol cols="6">
|
:active="enabledFilter"
|
||||||
<VSwitch v-model="enabledFilter" :label="t('plugin.running')" />
|
@click="enabledFilter = !enabledFilter"
|
||||||
</VCol>
|
density="compact"
|
||||||
<VCol cols="6">
|
>
|
||||||
<VSwitch v-model="hasUpdateFilter" :label="t('plugin.hasNewVersion')" />
|
<template #prepend>
|
||||||
</VCol>
|
<VIcon icon="mdi-play-circle" color="success" size="small" />
|
||||||
</VRow>
|
</template>
|
||||||
</VCardText>
|
<VListItemTitle>{{ t('plugin.running') }}</VListItemTitle>
|
||||||
|
<template #append>
|
||||||
|
<VIcon v-if="enabledFilter" icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem
|
||||||
|
:active="hasUpdateFilter"
|
||||||
|
@click="hasUpdateFilter = !hasUpdateFilter"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-arrow-up-circle" color="info" size="small" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>{{ t('plugin.hasNewVersion') }}</VListItemTitle>
|
||||||
|
<template #append>
|
||||||
|
<VIcon v-if="hasUpdateFilter" icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- 插件市场过滤下拉菜单 -->
|
||||||
<Teleport to="body" v-if="filterMarketPluginDialog">
|
<Teleport to="body" v-if="filterMarketPluginDialog">
|
||||||
<VMenu
|
<VMenu
|
||||||
v-model="filterMarketPluginDialog"
|
v-model="filterMarketPluginDialog"
|
||||||
width="25rem"
|
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
:activator="'[data-menu-activator=market-filter-btn]'"
|
:activator="'[data-menu-activator=market-filter-btn]'"
|
||||||
location="bottom end"
|
location="bottom end"
|
||||||
|
max-height="80vh"
|
||||||
>
|
>
|
||||||
<VCard>
|
<VCard min-width="240" max-width="300">
|
||||||
<VCardItem>
|
<!-- 名称搜索 -->
|
||||||
<VCardTitle>
|
<div class="px-3 pt-3 pb-1">
|
||||||
<VIcon icon="mdi-filter-multiple-outline" class="mr-2" />
|
<VTextField
|
||||||
{{ t('plugin.filterPlugins') }}
|
v-model="filterForm.name"
|
||||||
</VCardTitle>
|
:placeholder="t('plugin.name')"
|
||||||
<VDialogCloseBtn @click="filterMarketPluginDialog = false" />
|
prepend-inner-icon="mdi-magnify"
|
||||||
</VCardItem>
|
density="compact"
|
||||||
<VCardText>
|
variant="outlined"
|
||||||
<!-- 过滤表单 -->
|
hide-details
|
||||||
<div v-if="isAppMarketLoaded">
|
clearable
|
||||||
<VRow>
|
/>
|
||||||
<VCol cols="6">
|
</div>
|
||||||
<VTextField v-model="filterForm.name" density="comfortable" :label="t('plugin.name')" clearable />
|
<VDivider class="mt-2" />
|
||||||
</VCol>
|
<!-- 排序 -->
|
||||||
<VCol v-if="authorFilterOptions.length > 0" cols="6">
|
<VList v-if="sortOptions.length > 0" density="compact" class="px-2 py-1">
|
||||||
<VSelect
|
<VListSubheader>{{ t('plugin.sortTitle') }}</VListSubheader>
|
||||||
v-model="filterForm.author"
|
<VListItem
|
||||||
:items="authorFilterOptions"
|
v-for="option in sortOptions"
|
||||||
density="comfortable"
|
:key="option.value"
|
||||||
chips
|
:active="(activeSort || 'count') === option.value"
|
||||||
:label="t('plugin.author')"
|
@click="activeSort = option.value"
|
||||||
multiple
|
density="compact"
|
||||||
clearable
|
>
|
||||||
/>
|
<VListItemTitle>{{ option.title }}</VListItemTitle>
|
||||||
</VCol>
|
<template #append>
|
||||||
<VCol v-if="labelFilterOptions.length > 0" cols="6">
|
<VIcon v-if="(activeSort || 'count') === option.value" icon="mdi-check" color="primary" size="small" />
|
||||||
<VSelect
|
</template>
|
||||||
v-model="filterForm.label"
|
</VListItem>
|
||||||
:items="labelFilterOptions"
|
</VList>
|
||||||
density="comfortable"
|
<!-- 作者筛选 -->
|
||||||
chips
|
<template v-if="authorFilterOptions.length > 0">
|
||||||
:label="t('plugin.label')"
|
<VDivider />
|
||||||
multiple
|
<VList density="compact" class="px-2 py-1">
|
||||||
clearable
|
<VListSubheader>{{ t('plugin.author') }}</VListSubheader>
|
||||||
/>
|
<VListItem
|
||||||
</VCol>
|
v-for="author in authorFilterOptions"
|
||||||
<VCol v-if="repoFilterOptions.length > 0" cols="6">
|
:key="author"
|
||||||
<VSelect
|
:active="filterForm.author.includes(author)"
|
||||||
v-model="filterForm.repo"
|
@click="toggleMarketFilter('author', author)"
|
||||||
:items="repoFilterOptions"
|
density="compact"
|
||||||
density="comfortable"
|
>
|
||||||
chips
|
<VListItemTitle>{{ author }}</VListItemTitle>
|
||||||
:label="t('plugin.repository')"
|
<template #append>
|
||||||
multiple
|
<VIcon v-if="filterForm.author.includes(author)" icon="mdi-check" color="primary" size="small" />
|
||||||
clearable
|
</template>
|
||||||
/>
|
</VListItem>
|
||||||
</VCol>
|
</VList>
|
||||||
<VCol v-if="sortOptions.length > 0" cols="6">
|
</template>
|
||||||
<VSelect
|
<!-- 标签筛选 -->
|
||||||
v-model="activeSort"
|
<template v-if="labelFilterOptions.length > 0">
|
||||||
:items="sortOptions"
|
<VDivider />
|
||||||
density="comfortable"
|
<VList density="compact" class="px-2 py-1">
|
||||||
:label="t('plugin.sortTitle')"
|
<VListSubheader>{{ t('plugin.label') }}</VListSubheader>
|
||||||
/>
|
<VListItem
|
||||||
</VCol>
|
v-for="label in labelFilterOptions"
|
||||||
</VRow>
|
:key="label"
|
||||||
</div>
|
:active="filterForm.label.includes(label)"
|
||||||
</VCardText>
|
@click="toggleMarketFilter('label', label)"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<VListItemTitle>{{ label }}</VListItemTitle>
|
||||||
|
<template #append>
|
||||||
|
<VIcon v-if="filterForm.label.includes(label)" icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</template>
|
||||||
|
<!-- 仓库筛选 -->
|
||||||
|
<template v-if="repoFilterOptions.length > 0">
|
||||||
|
<VDivider />
|
||||||
|
<VList density="compact" class="px-2 py-1">
|
||||||
|
<VListSubheader>{{ t('plugin.repository') }}</VListSubheader>
|
||||||
|
<VListItem
|
||||||
|
v-for="repo in repoFilterOptions"
|
||||||
|
:key="repo"
|
||||||
|
:active="filterForm.repo.includes(repo)"
|
||||||
|
@click="toggleMarketFilter('repo', repo)"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
|
<VListItemTitle class="text-truncate" style="max-width: 220px">{{ repo }}</VListItemTitle>
|
||||||
|
<template #append>
|
||||||
|
<VIcon v-if="filterForm.repo.includes(repo)" icon="mdi-check" color="primary" size="small" />
|
||||||
|
</template>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</template>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|||||||
Reference in New Issue
Block a user