mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-11 18:10:49 +08:00
refactor(search): optimize sorting logic for season filter options
This commit is contained in:
@@ -71,37 +71,120 @@ function initOptions(data: Context) {
|
||||
|
||||
// 对季过滤选项进行排序
|
||||
const sortSeasonFilterOptions = computed(() => {
|
||||
return seasonFilterOptions.value.sort((a, b) => {
|
||||
// 按季,集降序排序
|
||||
// 预解析所有选项
|
||||
const parsedOptions = seasonFilterOptions.value.map((option, index) => {
|
||||
const parseSeasonEpisode = (str: string) => {
|
||||
const seasonRangeMatch = str.match(/S(\d+)(?:-S(\d+))?/)
|
||||
const episodeRangeMatch = str.match(/E(\d+)(?:-E(\d+))?/)
|
||||
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 {
|
||||
seasonStart: seasonRangeMatch?.[1] ? parseInt(seasonRangeMatch[1]) : 0,
|
||||
seasonEnd: seasonRangeMatch?.[2] ? parseInt(seasonRangeMatch[2]) : 0,
|
||||
episodeStart: episodeRangeMatch?.[1] ? parseInt(episodeRangeMatch[1]) : 0,
|
||||
episodeEnd: episodeRangeMatch?.[2] ? parseInt(episodeRangeMatch[2]) : 0,
|
||||
original: str,
|
||||
seasonStart,
|
||||
seasonEnd,
|
||||
episodeStart,
|
||||
episodeEnd,
|
||||
maxSeason,
|
||||
maxEpisode,
|
||||
index,
|
||||
}
|
||||
}
|
||||
const parsedA = parseSeasonEpisode(a)
|
||||
const parsedB = parseSeasonEpisode(b)
|
||||
// 先按季降序排序
|
||||
if (parsedB.seasonStart !== parsedA.seasonStart) {
|
||||
return parsedB.seasonStart - parsedA.seasonStart
|
||||
}
|
||||
if (parsedB.seasonEnd !== parsedA.seasonEnd) {
|
||||
return parsedB.seasonEnd - parsedA.seasonEnd
|
||||
}
|
||||
// 按集降序排序
|
||||
if (parsedB.episodeStart !== parsedA.episodeStart) {
|
||||
return parsedB.episodeStart - parsedA.episodeStart
|
||||
}
|
||||
if (parsedB.episodeEnd !== parsedA.episodeEnd) {
|
||||
return parsedB.episodeEnd - parsedA.episodeEnd
|
||||
}
|
||||
// 兜底
|
||||
return b.localeCompare(a)
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
// 计算分组后的列表
|
||||
|
||||
@@ -81,37 +81,120 @@ function initOptions(data: Context) {
|
||||
|
||||
// 对季过滤选项进行排序
|
||||
const sortSeasonFilterOptions = computed(() => {
|
||||
return seasonFilterOptions.value.sort((a, b) => {
|
||||
// 按季,集降序排序
|
||||
// 预解析所有选项
|
||||
const parsedOptions = seasonFilterOptions.value.map((option, index) => {
|
||||
const parseSeasonEpisode = (str: string) => {
|
||||
const seasonRangeMatch = str.match(/S(\d+)(?:-S(\d+))?/)
|
||||
const episodeRangeMatch = str.match(/E(\d+)(?:-E(\d+))?/)
|
||||
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 {
|
||||
seasonStart: seasonRangeMatch?.[1] ? parseInt(seasonRangeMatch[1]) : 0,
|
||||
seasonEnd: seasonRangeMatch?.[2] ? parseInt(seasonRangeMatch[2]) : 0,
|
||||
episodeStart: episodeRangeMatch?.[1] ? parseInt(episodeRangeMatch[1]) : 0,
|
||||
episodeEnd: episodeRangeMatch?.[2] ? parseInt(episodeRangeMatch[2]) : 0,
|
||||
original: str,
|
||||
seasonStart,
|
||||
seasonEnd,
|
||||
episodeStart,
|
||||
episodeEnd,
|
||||
maxSeason,
|
||||
maxEpisode,
|
||||
index,
|
||||
}
|
||||
}
|
||||
const parsedA = parseSeasonEpisode(a)
|
||||
const parsedB = parseSeasonEpisode(b)
|
||||
// 先按季降序排序
|
||||
if (parsedB.seasonStart !== parsedA.seasonStart) {
|
||||
return parsedB.seasonStart - parsedA.seasonStart
|
||||
}
|
||||
if (parsedB.seasonEnd !== parsedA.seasonEnd) {
|
||||
return parsedB.seasonEnd - parsedA.seasonEnd
|
||||
}
|
||||
// 按集降序排序
|
||||
if (parsedB.episodeStart !== parsedA.episodeStart) {
|
||||
return parsedB.episodeStart - parsedA.episodeStart
|
||||
}
|
||||
if (parsedB.episodeEnd !== parsedA.episodeEnd) {
|
||||
return parsedB.episodeEnd - parsedA.episodeEnd
|
||||
}
|
||||
// 兜底
|
||||
return b.localeCompare(a)
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
// 排序
|
||||
|
||||
Reference in New Issue
Block a user