mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 00:36:41 +08:00
新增订阅功能的状态筛选选项
This commit is contained in:
@@ -41,6 +41,7 @@ export default {
|
|||||||
details: 'Details',
|
details: 'Details',
|
||||||
files: 'Files',
|
files: 'Files',
|
||||||
share: 'Share',
|
share: 'Share',
|
||||||
|
subscribe: 'Subscribe',
|
||||||
unsubscribe: 'Unsubscribe',
|
unsubscribe: 'Unsubscribe',
|
||||||
media: 'Media',
|
media: 'Media',
|
||||||
unknown: 'Unknown',
|
unknown: 'Unknown',
|
||||||
@@ -60,6 +61,7 @@ export default {
|
|||||||
networkOffline: 'Network Offline',
|
networkOffline: 'Network Offline',
|
||||||
serviceAvailable: 'Service Available',
|
serviceAvailable: 'Service Available',
|
||||||
serviceUnavailable: 'Service Unavailable',
|
serviceUnavailable: 'Service Unavailable',
|
||||||
|
status: 'Status',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: 'Movie',
|
movie: 'Movie',
|
||||||
@@ -812,6 +814,12 @@ export default {
|
|||||||
totalReuseCount: 'Total Reuse Count',
|
totalReuseCount: 'Total Reuse Count',
|
||||||
ranking: 'Ranking',
|
ranking: 'Ranking',
|
||||||
noStatisticsData: 'No share statistics data available',
|
noStatisticsData: 'No share statistics data available',
|
||||||
|
bestVersion: 'Version Upgrading',
|
||||||
|
completed: 'Completed',
|
||||||
|
subscribing: 'Subscribing',
|
||||||
|
notStarted: 'Not Started',
|
||||||
|
pending: 'Pending',
|
||||||
|
paused: 'Paused',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: 'All',
|
all: 'All',
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default {
|
|||||||
details: '详情',
|
details: '详情',
|
||||||
files: '文件',
|
files: '文件',
|
||||||
share: '分享',
|
share: '分享',
|
||||||
|
subscribe: '订阅',
|
||||||
unsubscribe: '取消订阅',
|
unsubscribe: '取消订阅',
|
||||||
media: '媒体',
|
media: '媒体',
|
||||||
unknown: '未知',
|
unknown: '未知',
|
||||||
@@ -60,6 +61,7 @@ export default {
|
|||||||
networkOffline: '网络离线',
|
networkOffline: '网络离线',
|
||||||
serviceAvailable: '服务可用',
|
serviceAvailable: '服务可用',
|
||||||
serviceUnavailable: '服务不可用',
|
serviceUnavailable: '服务不可用',
|
||||||
|
status: '状态',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: '电影',
|
movie: '电影',
|
||||||
@@ -808,6 +810,12 @@ export default {
|
|||||||
totalReuseCount: '次复用',
|
totalReuseCount: '次复用',
|
||||||
ranking: '排名',
|
ranking: '排名',
|
||||||
noStatisticsData: '暂无分享统计数据',
|
noStatisticsData: '暂无分享统计数据',
|
||||||
|
bestVersion: '洗版中',
|
||||||
|
completed: '订阅完成',
|
||||||
|
subscribing: '订阅中',
|
||||||
|
notStarted: '未开始',
|
||||||
|
pending: '待定',
|
||||||
|
paused: '暂停',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: '全部',
|
all: '全部',
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export default {
|
|||||||
details: '詳情',
|
details: '詳情',
|
||||||
files: '文件',
|
files: '文件',
|
||||||
share: '分享',
|
share: '分享',
|
||||||
|
subscribe: '訂閱',
|
||||||
unsubscribe: '取消訂閱',
|
unsubscribe: '取消訂閱',
|
||||||
media: '媒體',
|
media: '媒體',
|
||||||
unknown: '未知',
|
unknown: '未知',
|
||||||
@@ -60,6 +61,7 @@ export default {
|
|||||||
networkOffline: '網絡離線',
|
networkOffline: '網絡離線',
|
||||||
serviceAvailable: '服務可用',
|
serviceAvailable: '服務可用',
|
||||||
serviceUnavailable: '服務不可用',
|
serviceUnavailable: '服務不可用',
|
||||||
|
status: '狀態',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: '電影',
|
movie: '電影',
|
||||||
@@ -806,6 +808,12 @@ export default {
|
|||||||
totalReuseCount: '次複用',
|
totalReuseCount: '次複用',
|
||||||
ranking: '排名',
|
ranking: '排名',
|
||||||
noStatisticsData: '暫無分享統計數據',
|
noStatisticsData: '暫無分享統計數據',
|
||||||
|
bestVersion: '洗版中',
|
||||||
|
completed: '訂閱完成',
|
||||||
|
subscribing: '訂閱中',
|
||||||
|
notStarted: '未開始',
|
||||||
|
pending: '待定',
|
||||||
|
paused: '暫停',
|
||||||
},
|
},
|
||||||
recommend: {
|
recommend: {
|
||||||
all: '全部',
|
all: '全部',
|
||||||
|
|||||||
+65
-4
@@ -43,6 +43,9 @@ const shareStatisticsDialog = ref(false)
|
|||||||
// 订阅过滤词
|
// 订阅过滤词
|
||||||
const subscribeFilter = ref('')
|
const subscribeFilter = ref('')
|
||||||
|
|
||||||
|
// 订阅状态筛选
|
||||||
|
const subscribeStatusFilter = ref<string | null>(null)
|
||||||
|
|
||||||
// 分享搜索词
|
// 分享搜索词
|
||||||
const shareKeyword = ref('')
|
const shareKeyword = ref('')
|
||||||
|
|
||||||
@@ -52,6 +55,41 @@ const searchShares = () => {
|
|||||||
shareViewKey.value++
|
shareViewKey.value++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 筛选选项
|
||||||
|
const filterOptions = computed(() => {
|
||||||
|
const baseOptions = [
|
||||||
|
{ value: 'all', label: t('common.all'), icon: 'mdi-format-list-bulleted' },
|
||||||
|
{ value: 'best_version', label: t('subscribe.bestVersion'), icon: 'mdi-refresh', color: 'warning' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 电影只显示基本选项和状态选项
|
||||||
|
if (subType === '电影') {
|
||||||
|
return [
|
||||||
|
...baseOptions,
|
||||||
|
{ value: 'pending', label: t('subscribe.pending'), icon: 'mdi-help-circle', color: 'secondary' },
|
||||||
|
{ value: 'paused', label: t('subscribe.paused'), icon: 'mdi-pause-circle', color: 'error' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 电视剧显示所有选项
|
||||||
|
return [
|
||||||
|
...baseOptions,
|
||||||
|
{ value: 'not_started', label: t('subscribe.notStarted'), icon: 'mdi-clock-outline', color: 'secondary' },
|
||||||
|
{ value: 'subscribing', label: t('subscribe.subscribing'), icon: 'mdi-download', color: 'info' },
|
||||||
|
{ value: 'pending', label: t('subscribe.pending'), icon: 'mdi-help-circle', color: 'secondary' },
|
||||||
|
{ value: 'paused', label: t('subscribe.paused'), icon: 'mdi-pause-circle', color: 'error' },
|
||||||
|
{ value: 'completed', label: t('subscribe.completed'), icon: 'mdi-check-circle', color: 'success' },
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算筛选按钮颜色
|
||||||
|
const filterButtonColor = computed(() => {
|
||||||
|
if (subscribeFilter.value || (subscribeStatusFilter.value && subscribeStatusFilter.value !== 'all')) {
|
||||||
|
return 'primary'
|
||||||
|
}
|
||||||
|
return 'gray'
|
||||||
|
})
|
||||||
|
|
||||||
// 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"]')
|
||||||
@@ -67,7 +105,7 @@ registerHeaderTab({
|
|||||||
{
|
{
|
||||||
icon: 'mdi-filter-multiple-outline',
|
icon: 'mdi-filter-multiple-outline',
|
||||||
variant: 'text',
|
variant: 'text',
|
||||||
color: computed(() => (subscribeFilter.value ? 'primary' : 'gray')),
|
color: filterButtonColor,
|
||||||
class: 'settings-icon-button',
|
class: 'settings-icon-button',
|
||||||
dataAttr: 'filter-btn',
|
dataAttr: 'filter-btn',
|
||||||
action: () => {
|
action: () => {
|
||||||
@@ -125,7 +163,12 @@ onMounted(() => {
|
|||||||
<VWindowItem value="mysub">
|
<VWindowItem value="mysub">
|
||||||
<transition name="fade-slide" appear>
|
<transition name="fade-slide" appear>
|
||||||
<div>
|
<div>
|
||||||
<SubscribeListView :type="subType" :subid="subId" :keyword="subscribeFilter" />
|
<SubscribeListView
|
||||||
|
:type="subType"
|
||||||
|
:subid="subId"
|
||||||
|
:keyword="subscribeFilter"
|
||||||
|
:status-filter="subscribeStatusFilter ?? ''"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</VWindowItem>
|
</VWindowItem>
|
||||||
@@ -149,7 +192,7 @@ onMounted(() => {
|
|||||||
<Teleport to="body" v-if="filterSubscribeDialog">
|
<Teleport to="body" v-if="filterSubscribeDialog">
|
||||||
<VMenu
|
<VMenu
|
||||||
v-model="filterSubscribeDialog"
|
v-model="filterSubscribeDialog"
|
||||||
width="20rem"
|
width="25rem"
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
:activator="filterActivator"
|
:activator="filterActivator"
|
||||||
location="bottom end"
|
location="bottom end"
|
||||||
@@ -163,7 +206,25 @@ onMounted(() => {
|
|||||||
<VDialogCloseBtn @click="filterSubscribeDialog = false" />
|
<VDialogCloseBtn @click="filterSubscribeDialog = false" />
|
||||||
</VCardItem>
|
</VCardItem>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<VTextField v-model="subscribeFilter" :label="t('subscribe.name')" clearable density="comfortable" />
|
<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>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VMenu>
|
</VMenu>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
subid: String,
|
subid: String,
|
||||||
keyword: String,
|
keyword: String,
|
||||||
|
statusFilter: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 是否刷新过
|
// 是否刷新过
|
||||||
@@ -51,22 +52,61 @@ const orderConfig = ref<{ id: number }[]>([])
|
|||||||
// 显示的订阅列表
|
// 显示的订阅列表
|
||||||
const displayList = ref<Subscribe[]>([])
|
const displayList = ref<Subscribe[]>([])
|
||||||
|
|
||||||
|
// 根据订阅数据判断订阅状态
|
||||||
|
function getSubscribeStatus(subscribe: Subscribe) {
|
||||||
|
// 洗版中
|
||||||
|
if (subscribe.best_version) {
|
||||||
|
return 'best_version'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据订阅状态判断
|
||||||
|
if (subscribe.state === 'P') {
|
||||||
|
return 'pending' // 待定
|
||||||
|
} else if (subscribe.state === 'S') {
|
||||||
|
return 'paused' // 暂停
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是电影,只有洗版和状态
|
||||||
|
if (subscribe.type === '电影') {
|
||||||
|
return 'all'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 电视剧根据集数情况判断
|
||||||
|
if (subscribe.total_episode && subscribe.total_episode > 0) {
|
||||||
|
const lackEpisode = subscribe.lack_episode || 0
|
||||||
|
const completedEpisode = subscribe.total_episode - lackEpisode
|
||||||
|
|
||||||
|
if (lackEpisode === 0) {
|
||||||
|
return 'completed' // 订阅完成
|
||||||
|
} else if (completedEpisode > 0) {
|
||||||
|
return 'subscribing' // 订阅中
|
||||||
|
} else {
|
||||||
|
return 'not_started' // 未开始
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'not_started' // 默认未开始
|
||||||
|
}
|
||||||
|
|
||||||
// API请求键值(计算属性)
|
// API请求键值(计算属性)
|
||||||
const orderRequestKey = computed(() => (props.type === '电影' ? 'SubscribeMovieOrder' : 'SubscribeTvOrder'))
|
const orderRequestKey = computed(() => (props.type === '电影' ? 'SubscribeMovieOrder' : 'SubscribeTvOrder'))
|
||||||
|
|
||||||
// 监听dataList变化,同步更新displayList
|
// 监听dataList变化,同步更新displayList
|
||||||
watch([dataList, () => props.keyword], () => {
|
watch([dataList, () => props.keyword, () => props.statusFilter], () => {
|
||||||
if (superUser)
|
if (superUser)
|
||||||
displayList.value = dataList.value.filter(
|
displayList.value = dataList.value.filter(
|
||||||
data =>
|
data =>
|
||||||
data.type === props.type && (!props.keyword || data.name.toLowerCase().includes(props.keyword.toLowerCase())),
|
data.type === props.type &&
|
||||||
|
(!props.keyword || data.name.toLowerCase().includes(props.keyword.toLowerCase())) &&
|
||||||
|
(!props.statusFilter || getSubscribeStatus(data) === props.statusFilter),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
displayList.value = dataList.value.filter(
|
displayList.value = dataList.value.filter(
|
||||||
data =>
|
data =>
|
||||||
data.type === props.type &&
|
data.type === props.type &&
|
||||||
data.username === userName &&
|
data.username === userName &&
|
||||||
(!props.keyword || data.name.toLowerCase().includes(props.keyword.toLowerCase())),
|
(!props.keyword || data.name.toLowerCase().includes(props.keyword.toLowerCase())) &&
|
||||||
|
(!props.statusFilter || getSubscribeStatus(data) === props.statusFilter),
|
||||||
)
|
)
|
||||||
// 排序
|
// 排序
|
||||||
sortSubscribeOrder()
|
sortSubscribeOrder()
|
||||||
@@ -133,6 +173,22 @@ function historyDone() {
|
|||||||
fetchData()
|
fetchData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 错误描述
|
||||||
|
const errorDescription = computed(() => {
|
||||||
|
if ((props.statusFilter && props.statusFilter !== 'all') || props.keyword) {
|
||||||
|
return t('common.tryChangingFilters')
|
||||||
|
}
|
||||||
|
return t('subscribe.noSubscribeData')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 错误标题
|
||||||
|
const errorTitle = computed(() => {
|
||||||
|
if ((props.statusFilter && props.statusFilter !== 'all') || props.keyword) {
|
||||||
|
return t('common.noMatchingData')
|
||||||
|
}
|
||||||
|
return t('common.noData')
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
if (props.subid) {
|
if (props.subid) {
|
||||||
@@ -161,7 +217,6 @@ useDynamicButton({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VPageContentTitle v-if="keyword" :title="`${t('subscribe.filterSubscriptions')}:${keyword}`" />
|
|
||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
<draggable
|
<draggable
|
||||||
v-if="displayList.length > 0"
|
v-if="displayList.length > 0"
|
||||||
@@ -171,6 +226,7 @@ useDynamicButton({
|
|||||||
item-key="id"
|
item-key="id"
|
||||||
tag="div"
|
tag="div"
|
||||||
:component-data="{ class: 'grid gap-4 grid-subscribe-card px-2' }"
|
:component-data="{ class: 'grid gap-4 grid-subscribe-card px-2' }"
|
||||||
|
:disabled="props.statusFilter !== 'all'"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<SubscribeCard :key="element.id" :media="element" @remove="fetchData" @save="fetchData" />
|
<SubscribeCard :key="element.id" :media="element" @remove="fetchData" @save="fetchData" />
|
||||||
@@ -179,8 +235,8 @@ useDynamicButton({
|
|||||||
<NoDataFound
|
<NoDataFound
|
||||||
v-if="displayList.length === 0 && isRefreshed"
|
v-if="displayList.length === 0 && isRefreshed"
|
||||||
error-code="404"
|
error-code="404"
|
||||||
:error-title="t('common.noData')"
|
:error-title="errorTitle"
|
||||||
:error-description="keyword ? t('subscribe.noFilterData') : t('subscribe.noSubscribeData')"
|
:error-description="errorDescription"
|
||||||
/>
|
/>
|
||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
<Teleport to="body" v-if="route.path.startsWith(`/subscribe/${props.type === '电影' ? 'movie' : 'tv'}`)">
|
<Teleport to="body" v-if="route.path.startsWith(`/subscribe/${props.type === '电影' ? 'movie' : 'tv'}`)">
|
||||||
|
|||||||
Reference in New Issue
Block a user