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