重构季集选项排序逻辑:将季集排序功能从计算属性移至组件方法,优化正则表达式以支持新格式,确保在选项更新时自动排序,简化相关代码。

This commit is contained in:
jxxghp
2025-04-21 12:58:55 +08:00
parent c2381deb9f
commit ef32172359
2 changed files with 174 additions and 234 deletions

View File

@@ -76,9 +76,6 @@ const filterMenuOpen = ref(false)
const currentFilter = ref('site')
const currentFilterTitle = computed(() => filterTitles[currentFilter.value])
const currentFilterOptions = computed(() => {
if (currentFilter.value === 'season') {
return sortSeasonFilterOptions.value
}
return filterOptions[currentFilter.value]
})
@@ -86,7 +83,13 @@ const currentFilterOptions = computed(() => {
function initOptions(data: Context) {
const { torrent_info, meta_info } = data
const optionValue = (options: Array<string>, value: string | undefined) => {
value && !options.includes(value) && options.push(value)
if (value && !options.includes(value)) {
options.push(value)
// 如果是season选项立即进行排序
if (options === filterOptions.season) {
sortSeasonOptions()
}
}
}
optionValue(filterOptions.site, torrent_info?.site_name)
optionValue(filterOptions.season, meta_info?.season_episode)
@@ -97,123 +100,80 @@ function initOptions(data: Context) {
optionValue(filterOptions.resolution, meta_info?.resource_pix)
}
// 对季过滤选项进行排序
const sortSeasonFilterOptions = computed(() => {
// 直接对季集选项进行排序的函数
function sortSeasonOptions() {
if (filterOptions.season.length <= 1) {
return // 不需要排序
}
// 预解析所有选项
const parsedOptions = filterOptions.season.map((option, index) => {
const parseSeasonEpisode = (str: string) => {
const match = str.match(/^S(\d+)(?:-S(\d+))?(?:\s*E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 如果字符串格式不正确,返回默认值
return {
original: str,
seasonStart: 0,
seasonEnd: 0,
episodeStart: 0,
episodeEnd: 0,
maxSeason: 0,
maxEpisode: 0,
index,
}
}
const seasonStart = match[1] ? parseInt(match[1], 10) : 0
const seasonEnd = match[2] ? parseInt(match[2], 10) : 0
const episodeStart = match[3] ? parseInt(match[3], 10) : 0
const episodeEnd = match[4] ? parseInt(match[4], 10) : 0
const maxSeason = seasonEnd > 0 ? seasonEnd : seasonStart
const maxEpisode = episodeEnd > 0 ? episodeEnd : episodeStart
// 修改正则表达式以适配 "S01 E07" 格式(注意季号和集号之间的空格)
const match = option.match(/^S(\d+)(?:-S(\d+))?\s*(?:E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 格式不符合规范的放到最后
return {
original: str,
seasonStart,
seasonEnd,
episodeStart,
episodeEnd,
maxSeason,
maxEpisode,
original: option,
seasonNum: 0,
episodeNum: 0,
maxEpisodeNum: 0,
isWholeSeason: false,
index,
}
}
return parseSeasonEpisode(option)
const seasonNum = parseInt(match[1], 10)
const episodeNum = match[3] ? parseInt(match[3], 10) : 0
const maxEpisodeNum = match[4] ? parseInt(match[4], 10) : episodeNum
const isWholeSeason = !match[3] // 没有E部分表示整季
return {
original: option,
seasonNum,
episodeNum,
maxEpisodeNum,
isWholeSeason,
index,
}
})
// 定义判断是否为整季或季范围的函数
const isWholeSeason = (parsed: (typeof parsedOptions)[0]) =>
parsed.seasonStart > 0 &&
(parsed.seasonEnd === 0 || parsed.seasonEnd > parsed.seasonStart) &&
parsed.episodeStart === 0 &&
parsed.episodeEnd === 0
// 先对所有项进行分类
const wholeSeasons = parsedOptions.filter(item => item.isWholeSeason)
const episodes = parsedOptions.filter(item => !item.isWholeSeason)
// 定义判断是否包含集数的函数
const hasEpisodes = (parsed: (typeof parsedOptions)[0]) => parsed.episodeStart > 0 || parsed.episodeEnd > 0
// 排序逻辑
parsedOptions.sort((a, b) => {
const aIsWhole = isWholeSeason(a)
const bIsWhole = isWholeSeason(b)
const aHasEpisodes = hasEpisodes(a)
const bHasEpisodes = hasEpisodes(b)
// 优先级1整季和季范围选项优先于带有集数的选项
if (aIsWhole && !bIsWhole) return -1
if (!aIsWhole && bIsWhole) return 1
// 优先级2如果都是整季或季范围选项按 maxSeason 降序排列
if (aIsWhole && bIsWhole) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
// 如果 maxSeason 相同,则按原始索引
return a.index - b.index
// 对整季按季号降序排序
wholeSeasons.sort((a, b) => {
if (a.seasonNum !== b.seasonNum) {
return b.seasonNum - a.seasonNum // 季号降序
}
// 优先级3如果都是带有集数的选项先按 maxSeason 降序,再按 maxEpisode 降序
if (aHasEpisodes && bHasEpisodes) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
if (b.maxEpisode !== a.maxEpisode) {
return b.maxEpisode - a.maxEpisode
}
// 如果 maxSeason 和 maxEpisode 相同,则按原始索引
return a.index - b.index
}
// 优先级4如果一个有集数一个没有优先有集数的选项
if (aHasEpisodes && !bHasEpisodes) return -1
if (!aHasEpisodes && bHasEpisodes) return 1
// 优先级5对于没有集数且不是整季的选项按 seasonStart 和 seasonEnd 降序排序
if (b.seasonStart !== a.seasonStart) {
return b.seasonStart - a.seasonStart
}
if (b.seasonEnd !== a.seasonEnd) {
return b.seasonEnd - a.seasonEnd
}
// 优先级6按 episodeStart 和 episodeEnd 降序排序
if (b.episodeStart !== a.episodeStart) {
return b.episodeStart - a.episodeStart
}
if (b.episodeEnd !== a.episodeEnd) {
return b.episodeEnd - a.episodeEnd
}
// 优先级7兜底按字母降序排列
if (a.original !== b.original) {
return b.original.localeCompare(a.original)
}
// 优先级8如果所有条件都相同则按原始索引
return a.index - b.index
return a.index - b.index // 相同季号按原始索引
})
// 返回排序后的原始字符串数组
return parsedOptions.map(option => option.original)
})
// 对单集先按季号降序排序,季号相同时按集号降序排序
episodes.sort((a, b) => {
if (a.seasonNum !== b.seasonNum) {
return b.seasonNum - a.seasonNum // 季号降序
}
// 使用最大集号进行排序 (对于范围如 E01-E06)
const aMaxEp = a.maxEpisodeNum || a.episodeNum
const bMaxEp = b.maxEpisodeNum || b.episodeNum
if (aMaxEp !== bMaxEp) {
return bMaxEp - aMaxEp // 集号降序
}
// 如果最大集号相同,再比较起始集号
if (a.episodeNum !== b.episodeNum) {
return b.episodeNum - a.episodeNum
}
return a.index - b.index // 都相同时按原始索引
})
// 合并结果:整季在前,单集在后
const sortedOptions = [...wholeSeasons, ...episodes].map(item => item.original)
// 直接更新 filterOptions.season
filterOptions.season = sortedOptions
}
// 计算分组后的列表
onMounted(() => {
@@ -236,6 +196,11 @@ onMounted(() => {
}
})
groupedDataList.value = groupMap
// 确保季集选项排序
if (filterOptions.season.length > 0) {
sortSeasonOptions()
}
})
// 修改watch监听同时监听排序字段的变化
@@ -326,6 +291,11 @@ function toggleFilterMenu(key: string) {
} else {
currentFilter.value = key
filterMenuOpen.value = true
// 如果是季集选项,确保已排序
if (key === 'season' && filterOptions.season.length > 0) {
sortSeasonOptions()
}
}
}
@@ -343,11 +313,8 @@ function clearFilter(key: string) {
// 全选某个过滤项
function selectAll(key: string) {
if (key === 'season') {
filterForm[key] = [...sortSeasonFilterOptions.value]
} else {
filterForm[key] = [...filterOptions[key]]
}
// 不再需要特殊处理季集选项
filterForm[key] = [...filterOptions[key]]
}
// 计算已选择的过滤条件数量

View File

@@ -55,124 +55,6 @@ const filterOptions: Record<string, string[]> = reactive({
releaseGroup: [] as string[],
})
// 对季过滤选项进行排序
const sortSeasonFilterOptions = computed(() => {
// 预解析所有选项
const parsedOptions = filterOptions.season.map((option, index) => {
const parseSeasonEpisode = (str: string) => {
const match = str.match(/^S(\d+)(?:-S(\d+))?(?:\s*E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 如果字符串格式不正确,返回默认值
return {
original: str,
seasonStart: 0,
seasonEnd: 0,
episodeStart: 0,
episodeEnd: 0,
maxSeason: 0,
maxEpisode: 0,
index,
}
}
const seasonStart = match[1] ? parseInt(match[1], 10) : 0
const seasonEnd = match[2] ? parseInt(match[2], 10) : 0
const episodeStart = match[3] ? parseInt(match[3], 10) : 0
const episodeEnd = match[4] ? parseInt(match[4], 10) : 0
const maxSeason = seasonEnd > 0 ? seasonEnd : seasonStart
const maxEpisode = episodeEnd > 0 ? episodeEnd : episodeStart
return {
original: str,
seasonStart,
seasonEnd,
episodeStart,
episodeEnd,
maxSeason,
maxEpisode,
index,
}
}
return parseSeasonEpisode(option)
})
// 定义判断是否为整季或季范围的函数
const isWholeSeason = (parsed: (typeof parsedOptions)[0]) =>
parsed.seasonStart > 0 &&
(parsed.seasonEnd === 0 || parsed.seasonEnd > parsed.seasonStart) &&
parsed.episodeStart === 0 &&
parsed.episodeEnd === 0
// 定义判断是否包含集数的函数
const hasEpisodes = (parsed: (typeof parsedOptions)[0]) => parsed.episodeStart > 0 || parsed.episodeEnd > 0
// 排序逻辑
parsedOptions.sort((a, b) => {
const aIsWhole = isWholeSeason(a)
const bIsWhole = isWholeSeason(b)
const aHasEpisodes = hasEpisodes(a)
const bHasEpisodes = hasEpisodes(b)
// 优先级1整季和季范围选项优先于带有集数的选项
if (aIsWhole && !bIsWhole) return -1
if (!aIsWhole && bIsWhole) return 1
// 优先级2如果都是整季或季范围选项按 maxSeason 降序排列
if (aIsWhole && bIsWhole) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
// 如果 maxSeason 相同,则按原始索引
return a.index - b.index
}
// 优先级3如果都是带有集数的选项先按 maxSeason 降序,再按 maxEpisode 降序
if (aHasEpisodes && bHasEpisodes) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
if (b.maxEpisode !== a.maxEpisode) {
return b.maxEpisode - a.maxEpisode
}
// 如果 maxSeason 和 maxEpisode 相同,则按原始索引
return a.index - b.index
}
// 优先级4如果一个有集数一个没有优先有集数的选项
if (aHasEpisodes && !bHasEpisodes) return -1
if (!aHasEpisodes && bHasEpisodes) return 1
// 优先级5对于没有集数且不是整季的选项按 seasonStart 和 seasonEnd 降序排序
if (b.seasonStart !== a.seasonStart) {
return b.seasonStart - a.seasonStart
}
if (b.seasonEnd !== a.seasonEnd) {
return b.seasonEnd - a.seasonEnd
}
// 优先级6按 episodeStart 和 episodeEnd 降序排序
if (b.episodeStart !== a.episodeStart) {
return b.episodeStart - a.episodeStart
}
if (b.episodeEnd !== a.episodeEnd) {
return b.episodeEnd - a.episodeEnd
}
// 优先级7兜底按字母降序排列
if (a.original !== b.original) {
return b.original.localeCompare(a.original)
}
// 优先级8如果所有条件都相同则按原始索引
return a.index - b.index
})
// 返回排序后的原始字符串数组
return parsedOptions.map(option => option.original)
})
// 排序字段
const sortField = ref('default')
@@ -221,7 +103,14 @@ function clearAllFilters() {
function initOptions(data: Context) {
const { torrent_info, meta_info } = data
const optionValue = (options: Array<string>, value: string | undefined) => {
value && !options.includes(value) && options.push(value)
if (value && !options.includes(value)) {
options.push(value)
// 如果是season选项立即触发重新计算
if (options === filterOptions.season) {
// 季集选项排序
sortSeasonOptions()
}
}
}
optionValue(filterOptions.site, torrent_info?.site_name)
@@ -233,6 +122,81 @@ function initOptions(data: Context) {
optionValue(filterOptions.resolution, meta_info?.resource_pix)
}
// 直接在组件中添加季集排序函数,而不是用计算属性
function sortSeasonOptions() {
if (filterOptions.season.length <= 1) {
return // 不需要排序
}
// 预解析所有选项
const parsedOptions = filterOptions.season.map((option, index) => {
// 修改正则表达式以适配 "S01 E07" 格式(注意季号和集号之间的空格)
const match = option.match(/^S(\d+)(?:-S(\d+))?\s*(?:E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 格式不符合规范的放到最后
return {
original: option,
seasonNum: 0,
episodeNum: 0,
maxEpisodeNum: 0,
isWholeSeason: false,
index,
}
}
const seasonNum = parseInt(match[1], 10)
const episodeNum = match[3] ? parseInt(match[3], 10) : 0
const maxEpisodeNum = match[4] ? parseInt(match[4], 10) : episodeNum
const isWholeSeason = !match[3] // 没有E部分表示整季
return {
original: option,
seasonNum,
episodeNum,
maxEpisodeNum,
isWholeSeason,
index,
}
})
// 先对所有项进行分类
const wholeSeasons = parsedOptions.filter(item => item.isWholeSeason)
const episodes = parsedOptions.filter(item => !item.isWholeSeason)
// 对整季按季号降序排序
wholeSeasons.sort((a, b) => {
if (a.seasonNum !== b.seasonNum) {
return b.seasonNum - a.seasonNum // 季号降序
}
return a.index - b.index // 相同季号按原始索引
})
// 对单集先按季号降序排序,季号相同时按集号降序排序
episodes.sort((a, b) => {
if (a.seasonNum !== b.seasonNum) {
return b.seasonNum - a.seasonNum // 季号降序
}
// 使用最大集号进行排序 (对于范围如 E01-E06)
const aMaxEp = a.maxEpisodeNum || a.episodeNum
const bMaxEp = b.maxEpisodeNum || b.episodeNum
if (aMaxEp !== bMaxEp) {
return bMaxEp - aMaxEp // 集号降序
}
// 如果最大集号相同,再比较起始集号
if (a.episodeNum !== b.episodeNum) {
return b.episodeNum - a.episodeNum
}
return a.index - b.index // 都相同时按原始索引
})
// 合并结果:整季在前,单集在后
const sortedOptions = [...wholeSeasons, ...episodes].map(item => item.original)
// 直接更新 filterOptions.season
filterOptions.season = sortedOptions
}
// 修改watch监听同时监听排序字段的变化
watch([filterForm, sortField], filterData)
@@ -296,6 +260,12 @@ function filterData() {
// 保存剩余数据
dataList.value = filteredData.slice(20)
}
// 确保在数据筛选完成后重新排序季集选项
if (filterOptions.season.length > 0) {
// 直接排序,不再使用延时
sortSeasonOptions()
}
}
// 过滤菜单相关
@@ -303,9 +273,7 @@ const filterMenuOpen = ref(false)
const currentFilter = ref('site')
const currentFilterTitle = computed(() => filterTitles[currentFilter.value])
const currentFilterOptions = computed(() => {
if (currentFilter.value === 'season') {
return sortSeasonFilterOptions.value
}
// 季集选项不再需要特殊处理,直接从 filterOptions 获取
return filterOptions[currentFilter.value]
})
@@ -344,6 +312,11 @@ function toggleFilterMenu(key: string) {
} else {
currentFilter.value = key
filterMenuOpen.value = true
// 如果是季集选项,确保已排序
if (key === 'season' && filterOptions.season.length > 0) {
sortSeasonOptions()
}
}
}