diff --git a/backend/internal/modules/listing/public_filter.go b/backend/internal/modules/listing/public_filter.go index 2a0647a..6e54758 100644 --- a/backend/internal/modules/listing/public_filter.go +++ b/backend/internal/modules/listing/public_filter.go @@ -103,6 +103,20 @@ func sortPublicListings(items []ListingDTO, sortKey string) { return a.PriceCent > b.PriceCent case "coinDesc": return a.HafCoinAmount > b.HafCoinAmount + case "ratioDesc", "ratio": + aRatio := ratioFromListing(a) + bRatio := ratioFromListing(b) + if aRatio != bRatio { + return aRatio > bRatio + } + return a.HafCoinAmount > b.HafCoinAmount + case "ratioAsc": + aRatio := ratioFromListing(a) + bRatio := ratioFromListing(b) + if aRatio != bRatio { + return aRatio < bRatio + } + return a.HafCoinAmount > b.HafCoinAmount case "awmDesc": aAmmo := resourceQuantity(a.AssetSummary, "awmAmmo") bAmmo := resourceQuantity(b.AssetSummary, "awmAmmo") diff --git a/backend/internal/modules/listing/public_filter_test.go b/backend/internal/modules/listing/public_filter_test.go index bf8e9bb..10ee653 100644 --- a/backend/internal/modules/listing/public_filter_test.go +++ b/backend/internal/modules/listing/public_filter_test.go @@ -178,6 +178,45 @@ func TestSortPublicListingsDefaultUsesShuffleKey(t *testing.T) { } } +func TestSortPublicListingsByRatio(t *testing.T) { + items := []ListingDTO{ + { + ID: 1, + HafCoinAmount: 50_000_000, + PriceCent: 5_000, + AssetSummary: map[string]any{"publish_ratio": 20.0}, + }, + { + ID: 2, + HafCoinAmount: 50_000_000, + PriceCent: 2_500, + AssetSummary: map[string]any{"publish_ratio": 45.0}, + }, + { + ID: 3, + HafCoinAmount: 80_000_000, + PriceCent: 3_000, + AssetSummary: map[string]any{"publish_ratio": 35.0}, + }, + { + ID: 4, + HafCoinAmount: 100_000_000, + PriceCent: 4_000, + AssetSummary: map[string]any{"publish_ratio": 35.0}, + }, + } + + sortPublicListings(items, "ratioDesc") + + // 预期顺序:ID=2 (45.0) > ID=4 (35.0, 100M 币更多) > ID=3 (35.0, 80M) > ID=1 (20.0) + expectedIDs := []uint64{2, 4, 3, 1} + for i, expected := range expectedIDs { + if items[i].ID != expected { + t.Fatalf("at index %d, expected listing %d, got %d (ratio=%.1f)", i, expected, items[i].ID, ratioFromListing(items[i])) + } + } +} + func TestIsNightAvailableSummaryUsesEarlyMorningResponse(t *testing.T) { tests := []struct { name string diff --git a/frontend/src/features/listings/views/HomeView.vue b/frontend/src/features/listings/views/HomeView.vue index ac83f3c..511a065 100644 --- a/frontend/src/features/listings/views/HomeView.vue +++ b/frontend/src/features/listings/views/HomeView.vue @@ -72,6 +72,7 @@ const publishOptions = ref(emptyListingPublishOptions) const sortBy = ref('recommended') const sortOptions = [ { value: 'recommended', label: '综合推荐' }, + { value: 'ratioDesc', label: '比例排序' }, { value: 'coinDesc', label: '哈夫币' }, { value: 'awmDesc', label: 'AWM数量' }, { value: 'priceAsc', label: '价格最低' }, diff --git a/frontend/src/features/listings/views/MobileHomeView.vue b/frontend/src/features/listings/views/MobileHomeView.vue index bf50d99..87cc50d 100644 --- a/frontend/src/features/listings/views/MobileHomeView.vue +++ b/frontend/src/features/listings/views/MobileHomeView.vue @@ -125,6 +125,7 @@ let searchDebounceTimer: ReturnType | null = null const sortOptions = [ { key: 'recommended', label: '综合推荐' }, + { key: 'ratioDesc', label: '比例排序' }, { key: 'coinDesc', label: '哈夫币' }, { key: 'awmDesc', label: 'AWM数量' }, { key: 'priceAsc', label: '价格最低' },