refactor(listings): 统一移动端与PC端筛选逻辑并支持日消耗与绝密KD
- 统一预设体系:在 useFilterOptions.ts 集中导出 defaultRangePresets,两端共享档位定义,消除移动端私有硬编码档位 - 统一参数模型:在 useHomeFilters.ts 增加 mobileFiltersToHomeFilters,将移动端字典结构标准化转换为领域层 HomeFilters 模型 - 统一查询构建:在 useListingQuery.ts 抽象纯函数 buildListingQueryFromFilters,双端共用同一个后端发包构建器 - 功能对齐:移动端首页完整补充「日消耗」区间筛选;PC端高级抽屉对齐补充「绝密KD」筛选 - 验证通过:补充双端测试用例,全站门禁 ./scripts/check.sh(SQL/Go/MySQL/Vitest/Vite构建)全部绿灯
This commit is contained in:
@@ -40,7 +40,9 @@ import {
|
||||
storeHomeQuery,
|
||||
type HomeQueryValue,
|
||||
} from '@/features/listings/composables/useHomeFilterQuery'
|
||||
import { depositRangeOptions } from '@/features/listings/composables/useFilterOptions'
|
||||
import { defaultRangePresets } from '@/features/listings/composables/useFilterOptions'
|
||||
import { mobileFiltersToHomeFilters } from '@/features/listings/composables/useHomeFilters'
|
||||
import { buildListingQueryFromFilters } from '@/features/listings/composables/useListingQuery'
|
||||
import {
|
||||
getListingChips,
|
||||
getListingDisplayPrice,
|
||||
@@ -139,51 +141,8 @@ const zoneOptions = [
|
||||
{ key: 'highCoin', label: '高币', hint: '100M以上' },
|
||||
]
|
||||
|
||||
/** 押金档位直接复用首页高级筛选项,保证移动端与桌面端完全一致 */
|
||||
const depositPresets = depositRangeOptions
|
||||
.filter(option => option.label !== '全部')
|
||||
.map(option => ({
|
||||
label: option.label,
|
||||
min: option.min === undefined ? '' : String(option.min),
|
||||
max: option.max === undefined ? '' : String(option.max),
|
||||
}))
|
||||
|
||||
const rangePresets: Record<string, Array<{ label: string; min: string; max: string }>> = {
|
||||
price: [
|
||||
{ label: '50-100', min: '50', max: '100' },
|
||||
{ label: '100-200', min: '100', max: '200' },
|
||||
{ label: '200以上', min: '200', max: '' },
|
||||
],
|
||||
coin: [
|
||||
{ label: '0-100', min: '0', max: '100' },
|
||||
{ label: '100-300', min: '100', max: '300' },
|
||||
{ label: '300-500', min: '300', max: '500' },
|
||||
{ label: '500以上', min: '500', max: '' },
|
||||
],
|
||||
ratio: [
|
||||
{ label: '30-40', min: '30', max: '40' },
|
||||
{ label: '40以上', min: '40', max: '' },
|
||||
],
|
||||
deposit: depositPresets,
|
||||
total: [
|
||||
{ label: '0-500', min: '0', max: '500' },
|
||||
{ label: '500-1000', min: '500', max: '1000' },
|
||||
{ label: '1000-2000', min: '1000', max: '2000' },
|
||||
{ label: '2000-5000', min: '2000', max: '5000' },
|
||||
],
|
||||
fireLevel: [
|
||||
{ label: '38-50', min: '38', max: '50' },
|
||||
{ label: '50-60', min: '50', max: '60' },
|
||||
{ label: '60-70', min: '60', max: '70' },
|
||||
{ label: '70以上', min: '70', max: '' },
|
||||
],
|
||||
resource_awmAmmo: [
|
||||
{ label: '20-50', min: '20', max: '50' },
|
||||
{ label: '50-100', min: '50', max: '100' },
|
||||
{ label: '100-200', min: '100', max: '200' },
|
||||
{ label: '200以上', min: '200', max: '' },
|
||||
],
|
||||
}
|
||||
/** 统一使用领域层导出的预设区间,保证与桌面端完全一致 */
|
||||
const rangePresets = defaultRangePresets
|
||||
|
||||
const activeSortLabel = computed(
|
||||
() => sortOptions.find(option => option.key === activeSort.value)?.label || '综合排序'
|
||||
@@ -279,6 +238,14 @@ const filterSections = computed<FilterSection[]>(() => [
|
||||
minPlaceholder: '最低',
|
||||
maxPlaceholder: '最高',
|
||||
},
|
||||
{
|
||||
key: 'dailyLoss',
|
||||
title: '日消耗',
|
||||
type: 'range',
|
||||
unit: 'M/天',
|
||||
minPlaceholder: '最低',
|
||||
maxPlaceholder: '最高',
|
||||
},
|
||||
{
|
||||
key: 'fireLevel',
|
||||
title: '等级',
|
||||
@@ -602,65 +569,18 @@ function clearFilters() {
|
||||
}
|
||||
|
||||
function buildListingQuery(page: number): PublicListingQuery {
|
||||
const query: PublicListingQuery = {
|
||||
const homeFilters = mobileFiltersToHomeFilters(
|
||||
selectedFilters.value,
|
||||
rangeFilters.value,
|
||||
searchValue.value,
|
||||
publishOptions.value.skin_groups.map(group => group.key)
|
||||
)
|
||||
return buildListingQueryFromFilters(homeFilters, {
|
||||
page,
|
||||
page_size: mobilePageSize,
|
||||
keyword: searchValue.value.trim(),
|
||||
pageSize: mobilePageSize,
|
||||
sort: activeSort.value,
|
||||
zone: activeZone.value,
|
||||
}
|
||||
const skinGroups: string[] = []
|
||||
const skinNames: string[] = []
|
||||
for (const [key, values] of Object.entries(selectedFilters.value)) {
|
||||
const value = values.filter(Boolean).join(',')
|
||||
if (!value) continue
|
||||
if (key === 'server') query.server = value
|
||||
else if (key === 'region') query.region = value
|
||||
else if (key === 'login') query.login_method = value
|
||||
else if (key === 'insurance') query.insurance = value
|
||||
else if (key === 'stamina') query.stamina = value
|
||||
else if (key === 'load') query.load = value
|
||||
else if (key === 'rank') query.rank = value
|
||||
else if (isSkinGroupKey(key)) {
|
||||
skinGroups.push(key)
|
||||
skinNames.push(...values)
|
||||
}
|
||||
}
|
||||
if (skinGroups.length) query.skin_group = skinGroups.join(',')
|
||||
if (skinNames.length) query.skin_name = skinNames.join(',')
|
||||
|
||||
for (const [key, range] of Object.entries(rangeFilters.value)) {
|
||||
if (!range.min && !range.max) continue
|
||||
const min = parseOptionalNumber(range.min)
|
||||
const max = parseOptionalNumber(range.max)
|
||||
if (key === 'price') {
|
||||
query.min_price = min
|
||||
query.max_price = max
|
||||
} else if (key === 'coin') {
|
||||
query.min_coin = min
|
||||
query.max_coin = max
|
||||
} else if (key === 'ratio') {
|
||||
query.min_ratio = min
|
||||
query.max_ratio = max
|
||||
} else if (key === 'secretKd') {
|
||||
query.min_secret_kd = min
|
||||
query.max_secret_kd = max
|
||||
} else if (key === 'deposit') {
|
||||
query.min_deposit = min
|
||||
query.max_deposit = max
|
||||
} else if (key === 'total') {
|
||||
query.min_total = min
|
||||
query.max_total = max
|
||||
} else if (key === 'fireLevel') {
|
||||
query.min_fire_level = min
|
||||
query.max_fire_level = max
|
||||
} else if (key.startsWith('resource_')) {
|
||||
const resourceKey = key.replace('resource_', '')
|
||||
query[`resource_${resourceKey}_min`] = min
|
||||
query[`resource_${resourceKey}_max`] = max
|
||||
}
|
||||
}
|
||||
return query
|
||||
})
|
||||
}
|
||||
|
||||
function filterQuerySignature() {
|
||||
@@ -672,12 +592,6 @@ function filterQuerySignature() {
|
||||
})
|
||||
}
|
||||
|
||||
function parseOptionalNumber(value: string) {
|
||||
if (value === '') return undefined
|
||||
const number = Number(value)
|
||||
return Number.isFinite(number) ? number : undefined
|
||||
}
|
||||
|
||||
function applyRouteQueryToMobileState() {
|
||||
const storedQuery = readStoredHomeQuery(mobileHomeFilterStorageKey)
|
||||
const query = hasHomeQueryValues(route.query, mobileHomeFilterQueryKeys)
|
||||
@@ -776,10 +690,6 @@ function scrollToTop() {
|
||||
homeCache.saveScrollTop(0)
|
||||
}
|
||||
|
||||
function isSkinGroupKey(key: string) {
|
||||
return publishOptions.value.skin_groups.some(group => group.key === key)
|
||||
}
|
||||
|
||||
function parseQuantityUnit(price: string) {
|
||||
const unit = price.split('/')[1]?.trim()
|
||||
return unit || undefined
|
||||
|
||||
Reference in New Issue
Block a user