feat: Add subscribe filtering and localization

Co-authored-by: jxxghp <jxxghp@qq.com>
This commit is contained in:
Cursor Agent
2025-09-16 00:17:40 +00:00
parent 1c019cd5c8
commit dbcc213562
3 changed files with 157 additions and 2 deletions

View File

@@ -872,6 +872,7 @@ export default {
batchEnableError: 'Batch enable operation failed',
batchPauseError: 'Batch pause operation failed',
batchDeleteError: 'Batch delete operation failed',
minSubscribers: 'Min Subscribers',
},
recommend: {
all: 'All',

View File

@@ -869,6 +869,7 @@ export default {
batchEnableError: '批量启用操作失败',
batchPauseError: '批量暂停操作失败',
batchDeleteError: '批量删除操作失败',
minSubscribers: '最小订阅人数',
},
recommend: {
all: '全部',

View File

@@ -34,13 +34,96 @@ const isRefreshed = ref(false)
const dataList = ref<MediaInfo[]>([])
const currData = ref<MediaInfo[]>([])
// 筛选参数
const filterParams = reactive({
genre_id: '',
min_rating: 0,
max_rating: 10,
min_sub: 1,
})
// 当前Key用于重新加载数据
const currentKey = ref(0)
// TMDB电影风格字典
const tmdbMovieGenreDict: Record<string, string> = {
'28': t('tmdb.genreType.action'),
'12': t('tmdb.genreType.adventure'),
'16': t('tmdb.genreType.animation'),
'35': t('tmdb.genreType.comedy'),
'80': t('tmdb.genreType.crime'),
'99': t('tmdb.genreType.documentary'),
'18': t('tmdb.genreType.drama'),
'10751': t('tmdb.genreType.family'),
'14': t('tmdb.genreType.fantasy'),
'36': t('tmdb.genreType.history'),
'27': t('tmdb.genreType.horror'),
'10402': t('tmdb.genreType.music'),
'9648': t('tmdb.genreType.mystery'),
'10749': t('tmdb.genreType.romance'),
'878': t('tmdb.genreType.scienceFiction'),
'10770': t('tmdb.genreType.tvMovie'),
'53': t('tmdb.genreType.thriller'),
'10752': t('tmdb.genreType.war'),
'37': t('tmdb.genreType.western'),
}
// TMDB电视剧风格字典
const tmdbTvGenreDict: Record<string, string> = {
'10759': t('tmdb.genreType.actionAdventure'),
'16': t('tmdb.genreType.animation'),
'35': t('tmdb.genreType.comedy'),
'80': t('tmdb.genreType.crime'),
'99': t('tmdb.genreType.documentary'),
'18': t('tmdb.genreType.drama'),
'10751': t('tmdb.genreType.family'),
'10762': t('tmdb.genreType.kids'),
'9648': t('tmdb.genreType.mystery'),
'10763': t('tmdb.genreType.news'),
'10764': t('tmdb.genreType.reality'),
'10765': t('tmdb.genreType.sciFiFantasy'),
'10766': t('tmdb.genreType.soap'),
'10767': t('tmdb.genreType.talk'),
'10768': t('tmdb.genreType.warPolitics'),
'37': t('tmdb.genreType.western'),
}
// 获取当前类型对应的风格字典
const currentGenreDict = computed(() => {
return props.type === '电影' ? tmdbMovieGenreDict : tmdbTvGenreDict
})
// 监听筛选参数变化
watch(filterParams, () => {
// 重置数据
dataList.value = []
page.value = 1
isRefreshed.value = false
currentKey.value++
}, { deep: true })
// 拼装参数
function getParams() {
let params = {
let params: { [key: string]: any } = {
stype: props.type,
page: page.value,
count: 30,
}
// 添加筛选参数
if (filterParams.genre_id) {
params.genre_id = parseInt(filterParams.genre_id)
}
if (filterParams.min_rating > 0) {
params.min_rating = filterParams.min_rating
}
if (filterParams.max_rating < 10) {
params.max_rating = filterParams.max_rating
}
if (filterParams.min_sub > 1) {
params.min_sub = filterParams.min_sub
}
return params
}
@@ -110,8 +193,78 @@ async function fetchData({ done }: { done: any }) {
</script>
<template>
<!-- 筛选器 -->
<div class="px-3 mb-4">
<div class="flex justify-start align-center mb-3">
<div class="mr-5">
<VLabel>{{ t('tmdb.genre') }}</VLabel>
</div>
<VChipGroup v-model="filterParams.genre_id">
<VChip
:color="filterParams.genre_id == key ? 'primary' : ''"
filter
tile
:value="key"
v-for="(value, key) in currentGenreDict"
:key="key"
>
{{ value }}
</VChip>
</VChipGroup>
</div>
<div class="flex justify-start align-center mb-3">
<div class="mr-5">
<VLabel>{{ t('tmdb.rating') }}</VLabel>
</div>
<div class="flex align-center" style="width: 300px;">
<VTextField
v-model="filterParams.min_rating"
variant="outlined"
density="compact"
type="number"
hide-details
single-line
min="0"
max="10"
step="0.1"
style="width: 80px;"
/>
<span class="mx-2">-</span>
<VTextField
v-model="filterParams.max_rating"
variant="outlined"
density="compact"
type="number"
hide-details
single-line
min="0"
max="10"
step="0.1"
style="width: 80px;"
/>
</div>
</div>
<div class="flex justify-start align-center">
<div class="mr-5">
<VLabel>{{ t('subscribe.minSubscribers') }}</VLabel>
</div>
<VTextField
v-model="filterParams.min_sub"
variant="outlined"
density="compact"
type="number"
hide-details
single-line
min="1"
style="width: 120px;"
/>
</div>
</div>
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
<VInfiniteScroll mode="intersect" side="end" :items="dataList" class="overflow-visible px-2" @load="fetchData">
<VInfiniteScroll mode="intersect" side="end" :items="dataList" class="overflow-visible px-2" @load="fetchData" :key="currentKey">
<template #loading />
<template #empty />
<div v-if="dataList.length > 0" class="grid gap-4 grid-media-card" tabindex="0">