From 000e6a23cf0a43f7c2e68ac885604577a9d17fe4 Mon Sep 17 00:00:00 2001 From: dai0v0 <dai.0v0@qq.com> Date: Tue, 28 Jan 2025 02:02:59 +0800 Subject: [PATCH] feat: enhance student list sorting and filtering - Implement advanced birthday sorting - Refactor data processing logic in App.vue for more efficient filtering and sorting --- src/App.vue | 73 +++++++++++++-------------- src/assets/requestUtils/dateFormat.ts | 57 ++++++++++++++++++++- src/assets/utils/search.ts | 3 +- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/App.vue b/src/App.vue index ddb7103..64f5325 100644 --- a/src/App.vue +++ b/src/App.vue @@ -119,10 +119,11 @@ import { RouterLink, RouterView } from 'vue-router' import i18n from '@/locales/i18n' import { baseStudent, studentInfo } from '@/assets/requestUtils/interface' import { getStudents, getSchoolIcon } from '@/assets/requestUtils/request' +import { birthday_sort, SupportedLanguage } from '@/assets/requestUtils/dateFormat' import { download } from '@/assets/imgUtils/download' import { store } from '@/assets/storeUtils/store' import { talkHistory } from '@/assets/storeUtils/talkHistory' -import { search, debounce } from '@/assets/utils/search' +import { debounce, search } from '@/assets/utils/search' import Popper from 'vue3-popper' store.getData() @@ -139,10 +140,10 @@ const dataDisplay = ref<studentInfo[]>(database.value) const showPopper = ref<boolean>(false) const filter_condition = ref( { - sort_type: '', // 排序类型 名字 生日 学校 社团 - sort_asc: true, // 排序顺序 true 升序 false 降序 - filter_star: 0, // 稀有度 0 1 2 3 - filter_released: true, // 已实装 true false + sort_type: '', // 排序类型 名字 生日 学校 社团 + sort_asc: true, // 排序顺序 true 升序 false 降序 + filter_star: 0, // 稀有度 0 1 2 3 + filter_released: true, // 已实装 true false } ) const filter_condition_copy = ref(filter_condition.value) @@ -161,40 +162,36 @@ const popperConfirm = () => { const searchText = ref<string>('') const searchSchool = ref<string>('') -const dataFilter = () => { - dataDisplay.value = database.value.filter((item) => { - if (filter_condition.value.filter_star > 0 && item.Star !== filter_condition.value.filter_star) return false - if (item.Released !== filter_condition.value.filter_released) return false - return true - }) -} -const dataSort = () => { - if (filter_condition.value.sort_type === '') { - if (!filter_condition.value.sort_asc) dataDisplay.value = dataDisplay.value.reverse() - return - } - dataDisplay.value = dataDisplay.value.sort((a, b) => { - // TODO: if sort_type == "Birthday" - // student who has birthday today(or in 3 days) will be at the top, and her school will be show as a birthday cake icon - const aValue = a[filter_condition.value.sort_type as keyof studentInfo] as string - const bValue = b[filter_condition.value.sort_type as keyof studentInfo] as string - return filter_condition.value.sort_asc ? - aValue.localeCompare(bValue) : - bValue.localeCompare(aValue) - }) -} -const dataSearch = debounce(() => { - dataDisplay.value = search( - dataDisplay.value, - searchText.value, - searchSchool.value - ) +const processData = debounce(() => { + dataDisplay.value = database.value + // filter + .filter(item => { + if (filter_condition.value.filter_star > 0 && item.Star !== filter_condition.value.filter_star) return false + if (item.Released !== filter_condition.value.filter_released) return false + return true + }) + // search + .filter(item => search([item], searchText.value, searchSchool.value).length > 0) + // sort + .sort((a, b) => { + if (filter_condition.value.sort_type === '') { + return filter_condition.value.sort_asc ? 0 : -1 + } + + if (filter_condition.value.sort_type === 'Birthday') { + return filter_condition.value.sort_asc ? + birthday_sort(a, b, store.language as SupportedLanguage) : + birthday_sort(b, a, store.language as SupportedLanguage) + } + + const aValue = a[filter_condition.value.sort_type as keyof studentInfo] as string + const bValue = b[filter_condition.value.sort_type as keyof studentInfo] as string + return filter_condition.value.sort_asc ? + aValue.localeCompare(bValue) : + bValue.localeCompare(aValue) + }) }, 300) // 防抖 -const processData = () => { - dataFilter() - dataSearch() - dataSort() -} + processData() watch(filter_condition, () => { processData() diff --git a/src/assets/requestUtils/dateFormat.ts b/src/assets/requestUtils/dateFormat.ts index 0d6e55a..483ee2b 100644 --- a/src/assets/requestUtils/dateFormat.ts +++ b/src/assets/requestUtils/dateFormat.ts @@ -17,7 +17,7 @@ const getOrdinalSuffix = (day: number): string => { } export const dateFormat = (birthday: string, lng: SupportedLanguage) => { - if (!birthday) return '???' + if (!birthday || !/^\d+\/\d+$/.test(birthday)) return '???' const TOOL = { zh: (month: number, day: number) => `${month}月${day}日`, tw: (month: number, day: number) => `${month}月${day}日`, @@ -29,3 +29,58 @@ export const dateFormat = (birthday: string, lng: SupportedLanguage) => { const [month, day] = birthday.split('/').map(Number) return TOOL[lng](month, day) } + +export const dateFormatReverse = (date: string, lng: SupportedLanguage): string => { + if (!date) return '' + + const parseDate = { + zh: (str: string) => { + const nums = str.match(/\d+/g)?.map(Number) + return nums?.length === 2 ? nums : null + }, + tw: (str: string) => parseDate.zh(str), + jp: (str: string) => parseDate.zh(str), + kr: (str: string) => parseDate.zh(str), + en: (str: string) => { + const monthName = MONTHS_EN.find(m => str.toLowerCase().includes(m.toLowerCase())) + if (!monthName) return null + const month = MONTHS_EN.indexOf(monthName) + 1 + const day = parseInt(str.match(/\d+/)?.[0] || '') + return [month, day] + } + } + + const [month, day] = parseDate[lng](date) || [] + + if (!month || !day || month < 1 || month > 12 || day < 1 || day > 31) { + return '' + } + + return `${month}/${day}` +} + +export const birthday_sort = (a: any, b: any, lng: SupportedLanguage) => { + // 将 MM/DD 格式转换为今年的日期以进行比较 + const today = new Date() + const currentYear = today.getFullYear() + + const getDateFromBirthday = (birthday: string) => { + birthday = dateFormatReverse(birthday, lng) + if (!birthday) { + const yesterday = new Date() + yesterday.setDate(yesterday.getDate() - 1) + return yesterday + } + const [month, day] = birthday.split('/').map(Number) + return new Date(currentYear, month - 1, day - 1) + } + + const aDate = getDateFromBirthday(a.Birthday) + const bDate = getDateFromBirthday(b.Birthday) + + // 如果日期已经过了,使用明年的日期 + if (aDate < today) aDate.setFullYear(currentYear + 1) + if (bDate < today) bDate.setFullYear(currentYear + 1) + + return aDate.getTime() - bDate.getTime() +} \ No newline at end of file diff --git a/src/assets/utils/search.ts b/src/assets/utils/search.ts index 5ff97a3..3574fd0 100644 --- a/src/assets/utils/search.ts +++ b/src/assets/utils/search.ts @@ -19,7 +19,8 @@ const search = (data: studentInfo[], key: string, filter: string) => { if (!processedKey && !processedFilter) return data return data.filter(item => { - if (!processedKey) return processString(item.School).includes(processedFilter) + if (processedFilter && !processString(item.School).includes(processedFilter)) return false + if (!processedKey) return true // 检查名字(简体、繁体、拼音) const name = processString(item.Name)