feat(listings): PC与移动端首页新增比例排序

- 前端选项:在 PC 首页(HomeView)与移动端首页(MobileHomeView)的排序项中,在「综合推荐」后新增「比例排序」(ratioDesc)
- 后端排序:在 sortPublicListings 中实现 ratioDesc/ratio,按折算比例从高到低排序,同比例按哈夫币数量降序次级平局决胜
- 自动化验证:新增 TestSortPublicListingsByRatio 单元测试,全量运行 ./scripts/check.sh 门禁(Go测试、MySQL测试、前端lint/typecheck/build)全部通过
This commit is contained in:
yml2213
2026-10-10 17:26:28 +08:00
parent 9d5d35c7d4
commit 180a21c048
4 changed files with 55 additions and 0 deletions
@@ -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")
@@ -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
@@ -72,6 +72,7 @@ const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
const sortBy = ref('recommended')
const sortOptions = [
{ value: 'recommended', label: '综合推荐' },
{ value: 'ratioDesc', label: '比例排序' },
{ value: 'coinDesc', label: '哈夫币' },
{ value: 'awmDesc', label: 'AWM数量' },
{ value: 'priceAsc', label: '价格最低' },
@@ -125,6 +125,7 @@ let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null
const sortOptions = [
{ key: 'recommended', label: '综合推荐' },
{ key: 'ratioDesc', label: '比例排序' },
{ key: 'coinDesc', label: '哈夫币' },
{ key: 'awmDesc', label: 'AWM数量' },
{ key: 'priceAsc', label: '价格最低' },