From 51c3f2767fcd170e673afe52d933e482cc2faab0 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sat, 15 Aug 2026 13:32:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(listing):=20=E5=85=AC=E5=85=B1=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E6=96=B0=E5=A2=9E=E6=97=A5=E6=B6=88=E8=80=97=E5=8C=BA?= =?UTF-8?q?=E9=97=B4=EF=BC=88=E9=AB=98=E7=BA=A7=E7=AD=9B=E9=80=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/modules/listing/dto.go | 2 ++ .../internal/modules/listing/handler_parse.go | 2 ++ .../internal/modules/listing/public_filter.go | 3 +++ .../internal/modules/listing/public_query.go | 3 +++ .../src/features/listings/api/listings.ts | 2 ++ .../listings/components/HomeFilters.vue | 21 +++++++++++++++++++ .../listings/composables/useFilterOptions.ts | 10 +++++++++ .../composables/useHomeFilterQuery.ts | 2 ++ .../listings/composables/useHomeFilters.ts | 14 +++++++++++++ .../listings/composables/useListingQuery.ts | 2 ++ .../src/features/listings/views/HomeView.vue | 4 ++++ 11 files changed, 65 insertions(+) diff --git a/backend/internal/modules/listing/dto.go b/backend/internal/modules/listing/dto.go index 39d2047..6358e57 100644 --- a/backend/internal/modules/listing/dto.go +++ b/backend/internal/modules/listing/dto.go @@ -146,6 +146,8 @@ type PublicListQuery struct { MaxTotal *float64 MinFireLevel *float64 MaxFireLevel *float64 + MinDailyLoss *float64 + MaxDailyLoss *float64 MinSecretKD *float64 MaxSecretKD *float64 ResourceRanges map[string]NumberRange diff --git a/backend/internal/modules/listing/handler_parse.go b/backend/internal/modules/listing/handler_parse.go index be7105f..579dfb7 100644 --- a/backend/internal/modules/listing/handler_parse.go +++ b/backend/internal/modules/listing/handler_parse.go @@ -114,6 +114,8 @@ func parsePublicListQuery(c *gin.Context) PublicListQuery { MaxTotal: parseOptionalFloat(c.Query("max_total")), MinFireLevel: parseOptionalFloat(c.Query("min_fire_level")), MaxFireLevel: parseOptionalFloat(c.Query("max_fire_level")), + MinDailyLoss: parseOptionalFloat(c.Query("min_daily_loss")), + MaxDailyLoss: parseOptionalFloat(c.Query("max_daily_loss")), MinSecretKD: parseOptionalFloat(c.Query("min_secret_kd")), MaxSecretKD: parseOptionalFloat(c.Query("max_secret_kd")), ResourceRanges: parseResourceRanges(c), diff --git a/backend/internal/modules/listing/public_filter.go b/backend/internal/modules/listing/public_filter.go index 26a714e..701de0e 100644 --- a/backend/internal/modules/listing/public_filter.go +++ b/backend/internal/modules/listing/public_filter.go @@ -78,6 +78,9 @@ func matchesPublicQuery(item ListingDTO, query PublicListQuery) bool { if !numberInRange(readSummaryNumber(item.AssetSummary["fire_level"]), NumberRange{Min: query.MinFireLevel, Max: query.MaxFireLevel}) { return false } + if !numberInRange(readSummaryNumber(item.AssetSummary["daily_loss_m"]), NumberRange{Min: query.MinDailyLoss, Max: query.MaxDailyLoss}) { + return false + } if !numberInRange(readSummaryNumber(item.AssetSummary["secret_kd"]), NumberRange{Min: query.MinSecretKD, Max: query.MaxSecretKD}) { return false } diff --git a/backend/internal/modules/listing/public_query.go b/backend/internal/modules/listing/public_query.go index 9741786..69501cf 100644 --- a/backend/internal/modules/listing/public_query.go +++ b/backend/internal/modules/listing/public_query.go @@ -130,6 +130,9 @@ func canListPublicWithSQL(query PublicListQuery) bool { if query.MinFireLevel != nil || query.MaxFireLevel != nil || query.MinSecretKD != nil || query.MaxSecretKD != nil { return false } + if query.MinDailyLoss != nil || query.MaxDailyLoss != nil { + return false + } switch query.Sort { case "", "published", "recommended", "comprehensive", "priceAsc", "priceDesc", "coinDesc": return true diff --git a/frontend/src/features/listings/api/listings.ts b/frontend/src/features/listings/api/listings.ts index dd8b935..19ed28a 100644 --- a/frontend/src/features/listings/api/listings.ts +++ b/frontend/src/features/listings/api/listings.ts @@ -76,6 +76,8 @@ export interface PublicListingQuery { max_total?: number min_fire_level?: number max_fire_level?: number + min_daily_loss?: number + max_daily_loss?: number min_secret_kd?: number max_secret_kd?: number [key: `resource_${string}_min`]: number | undefined diff --git a/frontend/src/features/listings/components/HomeFilters.vue b/frontend/src/features/listings/components/HomeFilters.vue index 0e3fa13..8d407b5 100644 --- a/frontend/src/features/listings/components/HomeFilters.vue +++ b/frontend/src/features/listings/components/HomeFilters.vue @@ -10,6 +10,7 @@ import { depositRangeOptions, totalRangeOptions, fireLevelRangeOptions, + dailyLossRangeOptions, isRangeSelected, } from '@/features/listings/composables/useFilterOptions' import type { ListingPublishOptions } from '@/features/listings/api/listingOptions' @@ -69,6 +70,7 @@ function toggleRange( | 'minDeposit' | 'minTotal' | 'minFireLevel' + | 'minDailyLoss' | 'minAwmAmmo', maxKey: | 'maxCoin' @@ -77,6 +79,7 @@ function toggleRange( | 'maxDeposit' | 'maxTotal' | 'maxFireLevel' + | 'maxDailyLoss' | 'maxAwmAmmo', option: RangeOption ) { @@ -97,6 +100,7 @@ function isRangeActive( | 'minDeposit' | 'minTotal' | 'minFireLevel' + | 'minDailyLoss' | 'minAwmAmmo', maxKey: | 'maxCoin' @@ -105,6 +109,7 @@ function isRangeActive( | 'maxDeposit' | 'maxTotal' | 'maxFireLevel' + | 'maxDailyLoss' | 'maxAwmAmmo', option: RangeOption ) { @@ -355,6 +360,22 @@ const redSkinGroup = computed(() => +
+ +
+ +
+
+
diff --git a/frontend/src/features/listings/composables/useFilterOptions.ts b/frontend/src/features/listings/composables/useFilterOptions.ts index 8f93b8e..b9e0478 100644 --- a/frontend/src/features/listings/composables/useFilterOptions.ts +++ b/frontend/src/features/listings/composables/useFilterOptions.ts @@ -62,6 +62,16 @@ export const fireLevelRangeOptions = [ { label: '50-60', min: 50, max: 60 }, ] +/** 日消耗(M/天):发布档位为 10/20/30/40/50 */ +export const dailyLossRangeOptions = [ + { label: '全部', min: undefined, max: undefined }, + { label: '≤10', min: undefined, max: 10 }, + { label: '10-20', min: 10, max: 20 }, + { label: '20-30', min: 20, max: 30 }, + { label: '30-40', min: 30, max: 40 }, + { label: '40以上', min: 40, max: undefined }, +] + export function rangeLabel(min: number | undefined, max: number | undefined, fallback: string) { if (min !== undefined && max !== undefined) return `${min}-${max}` if (min !== undefined) return `${min}+` diff --git a/frontend/src/features/listings/composables/useHomeFilterQuery.ts b/frontend/src/features/listings/composables/useHomeFilterQuery.ts index 0b38d95..00b51fd 100644 --- a/frontend/src/features/listings/composables/useHomeFilterQuery.ts +++ b/frontend/src/features/listings/composables/useHomeFilterQuery.ts @@ -26,6 +26,8 @@ export const desktopHomeFilterQueryKeys = [ 'max_total', 'min_fire_level', 'max_fire_level', + 'min_daily_loss', + 'max_daily_loss', 'resource_awmAmmo_min', 'resource_awmAmmo_max', ] as const diff --git a/frontend/src/features/listings/composables/useHomeFilters.ts b/frontend/src/features/listings/composables/useHomeFilters.ts index 78aa949..ff400f2 100644 --- a/frontend/src/features/listings/composables/useHomeFilters.ts +++ b/frontend/src/features/listings/composables/useHomeFilters.ts @@ -52,6 +52,9 @@ export interface HomeFilters { maxTotal: number | undefined minFireLevel: number | undefined maxFireLevel: number | undefined + /** 日消耗(M/天)区间 */ + minDailyLoss: number | undefined + maxDailyLoss: number | undefined /** AWM 子弹数量区间 */ minAwmAmmo: number | undefined maxAwmAmmo: number | undefined @@ -89,6 +92,8 @@ export function useHomeFilters( maxTotal: undefined, minFireLevel: undefined, maxFireLevel: undefined, + minDailyLoss: undefined, + maxDailyLoss: undefined, minAwmAmmo: undefined, maxAwmAmmo: undefined, }) @@ -153,6 +158,7 @@ export function useHomeFilters( if (filters.minDeposit !== undefined || filters.maxDeposit !== undefined) count += 1 if (filters.minTotal !== undefined || filters.maxTotal !== undefined) count += 1 if (filters.minFireLevel !== undefined || filters.maxFireLevel !== undefined) count += 1 + if (filters.minDailyLoss !== undefined || filters.maxDailyLoss !== undefined) count += 1 return count }) @@ -182,6 +188,8 @@ export function useHomeFilters( filters.maxTotal = undefined filters.minFireLevel = undefined filters.maxFireLevel = undefined + filters.minDailyLoss = undefined + filters.maxDailyLoss = undefined filters.minAwmAmmo = undefined filters.maxAwmAmmo = undefined } @@ -236,6 +244,11 @@ export function useHomeFilters( filters.maxFireLevel = max } + function setDailyLossRange(min: number | undefined, max: number | undefined) { + filters.minDailyLoss = min + filters.maxDailyLoss = max + } + function setAwmAmmoRange(min: number | undefined, max: number | undefined) { filters.minAwmAmmo = min filters.maxAwmAmmo = max @@ -288,6 +301,7 @@ export function useHomeFilters( setDepositRange, setTotalRange, setFireLevelRange, + setDailyLossRange, setAwmAmmoRange, toggleRange, setFilterPopover, diff --git a/frontend/src/features/listings/composables/useListingQuery.ts b/frontend/src/features/listings/composables/useListingQuery.ts index 6c22ffe..c42e6e1 100644 --- a/frontend/src/features/listings/composables/useListingQuery.ts +++ b/frontend/src/features/listings/composables/useListingQuery.ts @@ -50,6 +50,8 @@ export function useListingQuery( max_total: filters.maxTotal, min_fire_level: filters.minFireLevel, max_fire_level: filters.maxFireLevel, + min_daily_loss: filters.minDailyLoss, + max_daily_loss: filters.maxDailyLoss, resource_awmAmmo_min: filters.minAwmAmmo, resource_awmAmmo_max: filters.maxAwmAmmo, } diff --git a/frontend/src/features/listings/views/HomeView.vue b/frontend/src/features/listings/views/HomeView.vue index 6806ec8..6f6dd39 100644 --- a/frontend/src/features/listings/views/HomeView.vue +++ b/frontend/src/features/listings/views/HomeView.vue @@ -216,6 +216,8 @@ function applyRouteQueryToHomeState() { filters.maxTotal = readQueryNumber(query, 'max_total') filters.minFireLevel = readQueryNumber(query, 'min_fire_level') filters.maxFireLevel = readQueryNumber(query, 'max_fire_level') + filters.minDailyLoss = readQueryNumber(query, 'min_daily_loss') + filters.maxDailyLoss = readQueryNumber(query, 'max_daily_loss') filters.minAwmAmmo = readQueryNumber(query, 'resource_awmAmmo_min') filters.maxAwmAmmo = readQueryNumber(query, 'resource_awmAmmo_max') // 无 sort 参数即综合推荐(默认) @@ -268,6 +270,8 @@ function buildDesktopHomeQueryValues(): Record { max_total: filters.maxTotal, min_fire_level: filters.minFireLevel, max_fire_level: filters.maxFireLevel, + min_daily_loss: filters.minDailyLoss, + max_daily_loss: filters.maxDailyLoss, resource_awmAmmo_min: filters.minAwmAmmo, resource_awmAmmo_max: filters.maxAwmAmmo, }