diff --git a/frontend/src/composables/home/__tests__/useFilterOptions.spec.ts b/frontend/src/composables/home/__tests__/useFilterOptions.spec.ts new file mode 100644 index 0000000..0d77d62 --- /dev/null +++ b/frontend/src/composables/home/__tests__/useFilterOptions.spec.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from 'vitest' +import { rangeLabel, isRangeSelected } from '@/composables/home/useFilterOptions' + +describe('useFilterOptions', () => { + describe('rangeLabel', () => { + it('应该返回双向范围标签', () => { + expect(rangeLabel(100, 500, '哈夫币')).toBe('100-500') + }) + + it('应该返回最小值+标签', () => { + expect(rangeLabel(500, undefined, '哈夫币')).toBe('500+') + }) + + it('应该返回最大值标签', () => { + expect(rangeLabel(undefined, 500, '哈夫币')).toBe('≤500') + }) + + it('应该返回默认标签', () => { + expect(rangeLabel(undefined, undefined, '哈夫币')).toBe('哈夫币') + }) + }) + + describe('isRangeSelected', () => { + it('应该正确判断范围是否选中', () => { + expect(isRangeSelected(100, 500, 100, 500)).toBe(true) + expect(isRangeSelected(100, 500, 200, 500)).toBe(false) + expect(isRangeSelected(undefined, undefined, undefined, undefined)).toBe(true) + }) + }) +}) diff --git a/frontend/src/composables/home/__tests__/useHomeFilters.spec.ts b/frontend/src/composables/home/__tests__/useHomeFilters.spec.ts new file mode 100644 index 0000000..d784cc8 --- /dev/null +++ b/frontend/src/composables/home/__tests__/useHomeFilters.spec.ts @@ -0,0 +1,57 @@ +import { describe, it, expect } from 'vitest' +import { useHomeFilters } from '@/composables/home/useHomeFilters' +import { ref } from 'vue' +import { emptyListingPublishOptions } from '@/api/listingOptions' + +describe('useHomeFilters', () => { + it('应该初始化空的筛选器', () => { + const publishOptions = ref(emptyListingPublishOptions) + const listings = ref([]) + + const { filters } = useHomeFilters(publishOptions, listings) + + expect(filters.keyword).toBe('') + expect(filters.minCoin).toBeUndefined() + expect(filters.maxCoin).toBeUndefined() + }) + + it('应该正确重置筛选器', () => { + const publishOptions = ref(emptyListingPublishOptions) + const listings = ref([]) + + const { filters, resetFilters } = useHomeFilters(publishOptions, listings) + + filters.keyword = '测试' + filters.minCoin = 100 + filters.region = '北京' + + resetFilters() + + expect(filters.keyword).toBe('') + expect(filters.minCoin).toBeUndefined() + expect(filters.region).toBe('') + }) + + it('应该正确设置字符串筛选器', () => { + const publishOptions = ref(emptyListingPublishOptions) + const listings = ref([]) + + const { filters, setStringFilter, closeFilterPopover } = useHomeFilters(publishOptions, listings) + + setStringFilter('region', '上海') + + expect(filters.region).toBe('上海') + }) + + it('应该正确设置范围筛选器', () => { + const publishOptions = ref(emptyListingPublishOptions) + const listings = ref([]) + + const { filters, setCoinRange } = useHomeFilters(publishOptions, listings) + + setCoinRange(100, 500) + + expect(filters.minCoin).toBe(100) + expect(filters.maxCoin).toBe(500) + }) +}) diff --git a/frontend/src/composables/home/useListingQuery.ts b/frontend/src/composables/home/useListingQuery.ts index 07184ca..483b048 100644 --- a/frontend/src/composables/home/useListingQuery.ts +++ b/frontend/src/composables/home/useListingQuery.ts @@ -100,8 +100,13 @@ export function useListingQuery( window.removeEventListener('scroll', handleWindowScroll) }) + // 使用防抖优化搜索 + let debounceTimer: ReturnType | null = null watch(() => listingQuerySignature(), () => { - loadListingsPage(true) + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => { + loadListingsPage(true) + }, 300) }) return { diff --git a/frontend/src/views/public/components/ListingCard.vue b/frontend/src/views/public/components/ListingCard.vue index 4c77ff5..cbfff16 100644 --- a/frontend/src/views/public/components/ListingCard.vue +++ b/frontend/src/views/public/components/ListingCard.vue @@ -31,10 +31,11 @@ const props = defineProps()
HFB