优化筛选, 增加记住筛选功能
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import MobileBottomNav from '@/components/MobileBottomNav.vue'
|
||||
|
||||
@@ -22,6 +22,15 @@ import {
|
||||
type HomeBannerSlide,
|
||||
} from '@/features/listings/api/homeConfig'
|
||||
import MobileHomeFilterSheet, { type FilterSection } from './MobileHomeFilterSheet.vue'
|
||||
import {
|
||||
decodeHomeQueryJson,
|
||||
encodeHomeQueryJson,
|
||||
isSameQuery,
|
||||
mergeHomeQuery,
|
||||
mobileHomeFilterQueryKeys,
|
||||
readQueryString,
|
||||
type HomeQueryValue,
|
||||
} from '@/features/listings/composables/useHomeFilterQuery'
|
||||
import {
|
||||
getListingChips,
|
||||
getListingDisplayPrice,
|
||||
@@ -38,6 +47,7 @@ import {
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const session = useSessionStore()
|
||||
const loading = ref(false)
|
||||
const loadingMore = ref(false)
|
||||
@@ -255,6 +265,8 @@ const visibleZoneOptions = computed(() =>
|
||||
}))
|
||||
)
|
||||
|
||||
applyRouteQueryToMobileState()
|
||||
|
||||
onMounted(() => {
|
||||
loadListings()
|
||||
loadHomeConfig()
|
||||
@@ -269,11 +281,20 @@ onBeforeUnmount(() => {
|
||||
watch(
|
||||
() => filterQuerySignature(),
|
||||
() => {
|
||||
syncMobileHomeQuery()
|
||||
loadListings(true)
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => route.query,
|
||||
() => {
|
||||
applyRouteQueryToMobileState()
|
||||
}
|
||||
)
|
||||
|
||||
watch(searchValue, () => {
|
||||
syncMobileHomeQuery()
|
||||
if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
|
||||
searchDebounceTimer = setTimeout(() => {
|
||||
loadListings(true)
|
||||
@@ -367,6 +388,7 @@ function clearFilters() {
|
||||
rangeFilters.value = {}
|
||||
searchValue.value = ''
|
||||
activeZone.value = 'all'
|
||||
syncMobileHomeQuery()
|
||||
}
|
||||
|
||||
function buildListingQuery(page: number): PublicListingQuery {
|
||||
@@ -443,6 +465,57 @@ function parseOptionalNumber(value: string) {
|
||||
return Number.isFinite(number) ? number : undefined
|
||||
}
|
||||
|
||||
function applyRouteQueryToMobileState() {
|
||||
const query = route.query
|
||||
searchValue.value = readQueryString(query, 'keyword')
|
||||
activeSort.value = readQueryString(query, 'sort') || 'recommended'
|
||||
activeZone.value = readQueryString(query, 'zone') || 'all'
|
||||
selectedFilters.value = normalizeSelectedFilters(
|
||||
decodeHomeQueryJson<Record<string, unknown>>(query, 'filters', {})
|
||||
)
|
||||
rangeFilters.value = normalizeRangeFilters(
|
||||
decodeHomeQueryJson<Record<string, unknown>>(query, 'ranges', {})
|
||||
)
|
||||
}
|
||||
|
||||
function syncMobileHomeQuery() {
|
||||
const query = mergeHomeQuery(route.query, mobileHomeFilterQueryKeys, buildMobileHomeQueryValues())
|
||||
if (isSameQuery(route.query, query)) return
|
||||
router.replace({ path: route.path, query })
|
||||
}
|
||||
|
||||
function buildMobileHomeQueryValues(): Record<string, HomeQueryValue> {
|
||||
return {
|
||||
keyword: searchValue.value.trim() || undefined,
|
||||
sort: activeSort.value === 'recommended' ? undefined : activeSort.value,
|
||||
zone: activeZone.value === 'all' ? undefined : activeZone.value,
|
||||
filters: encodeHomeQueryJson(normalizeSelectedFilters(selectedFilters.value)),
|
||||
ranges: encodeHomeQueryJson(normalizeRangeFilters(rangeFilters.value)),
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeSelectedFilters(value: Record<string, unknown>) {
|
||||
const normalized: Record<string, string[]> = {}
|
||||
for (const [key, items] of Object.entries(value)) {
|
||||
if (!Array.isArray(items)) continue
|
||||
const filters = items.map(item => String(item).trim()).filter(Boolean)
|
||||
if (filters.length) normalized[key] = filters
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
function normalizeRangeFilters(value: Record<string, unknown>) {
|
||||
const normalized: Record<string, { min: string; max: string }> = {}
|
||||
for (const [key, range] of Object.entries(value)) {
|
||||
if (!range || typeof range !== 'object' || Array.isArray(range)) continue
|
||||
const record = range as Record<string, unknown>
|
||||
const min = record.min === undefined ? '' : String(record.min).trim()
|
||||
const max = record.max === undefined ? '' : String(record.max).trim()
|
||||
if (min || max) normalized[key] = { min, max }
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
function handleWindowScroll() {
|
||||
showBackTop.value = window.scrollY > 520
|
||||
if (window.innerHeight + window.scrollY < document.documentElement.scrollHeight - 360) return
|
||||
|
||||
Reference in New Issue
Block a user