首页增加比例筛选并优化排序
This commit is contained in:
@@ -104,6 +104,8 @@ type PublicListQuery struct {
|
||||
SkinName []string
|
||||
MinCoin *float64
|
||||
MaxCoin *float64
|
||||
MinRatio *float64
|
||||
MaxRatio *float64
|
||||
MinPrice *float64
|
||||
MaxPrice *float64
|
||||
MinDeposit *float64
|
||||
|
||||
@@ -94,6 +94,8 @@ func parsePublicListQuery(c *gin.Context) PublicListQuery {
|
||||
SkinName: parseCSVQuery(firstNonEmpty(c.Query("skin_name"), c.Query("skin"))),
|
||||
MinCoin: parseOptionalFloat(c.Query("min_coin")),
|
||||
MaxCoin: parseOptionalFloat(c.Query("max_coin")),
|
||||
MinRatio: parseOptionalFloat(c.Query("min_ratio")),
|
||||
MaxRatio: parseOptionalFloat(c.Query("max_ratio")),
|
||||
MinPrice: parseOptionalFloat(c.Query("min_price")),
|
||||
MaxPrice: parseOptionalFloat(c.Query("max_price")),
|
||||
MinDeposit: parseOptionalFloat(c.Query("min_deposit")),
|
||||
|
||||
@@ -65,6 +65,9 @@ func matchesPublicQuery(item ListingDTO, query PublicListQuery) bool {
|
||||
if !numberInRange(coinM, NumberRange{Min: query.MinCoin, Max: query.MaxCoin}) {
|
||||
return false
|
||||
}
|
||||
if !numberInRange(ratioFromListing(item), NumberRange{Min: query.MinRatio, Max: query.MaxRatio}) {
|
||||
return false
|
||||
}
|
||||
if !numberInRange(price, NumberRange{Min: query.MinPrice, Max: query.MaxPrice}) {
|
||||
return false
|
||||
}
|
||||
@@ -106,10 +109,12 @@ func sortPublicListings(items []ListingDTO, sortKey string) {
|
||||
return aAmmo > bAmmo
|
||||
}
|
||||
return a.HafCoinAmount > b.HafCoinAmount
|
||||
case "published", "recommended", "comprehensive", "":
|
||||
case "published":
|
||||
return publicRecentLess(a, b)
|
||||
case "recommended", "comprehensive", "":
|
||||
return publicShuffleLess(a, b)
|
||||
default:
|
||||
return publicRecentLess(a, b)
|
||||
return publicShuffleLess(a, b)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -129,6 +134,19 @@ func publicRecentLess(a ListingDTO, b ListingDTO) bool {
|
||||
return a.ID > b.ID
|
||||
}
|
||||
|
||||
func publicShuffleLess(a ListingDTO, b ListingDTO) bool {
|
||||
aKey := publicShuffleKey(a.ID)
|
||||
bKey := publicShuffleKey(b.ID)
|
||||
if aKey != bKey {
|
||||
return aKey < bKey
|
||||
}
|
||||
return a.ID < b.ID
|
||||
}
|
||||
|
||||
func publicShuffleKey(id uint64) uint64 {
|
||||
return (id*1103515245 + uint64(publicShuffleSeed())) % 2147483647
|
||||
}
|
||||
|
||||
func matchesPublicZone(item ListingDTO, zone string) bool {
|
||||
switch zone {
|
||||
case "", "all":
|
||||
@@ -225,6 +243,22 @@ func coinMFromListing(item ListingDTO) float64 {
|
||||
return float64(item.HafCoinAmount) / 1000000
|
||||
}
|
||||
|
||||
func coinWanFromListing(item ListingDTO) float64 {
|
||||
return float64(item.HafCoinAmount) / 10000
|
||||
}
|
||||
|
||||
func ratioFromListing(item ListingDTO) float64 {
|
||||
ratio := readSummaryNumber(item.AssetSummary["publish_ratio"])
|
||||
if ratio > 0 {
|
||||
return ratio
|
||||
}
|
||||
price := float64(item.PriceCent) / 100
|
||||
if price <= 0 {
|
||||
return 0
|
||||
}
|
||||
return coinWanFromListing(item) / price
|
||||
}
|
||||
|
||||
func readAssetString(summary map[string]any, key string) string {
|
||||
if summary == nil {
|
||||
return ""
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package listing
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFilterPublicListingsByRatio(t *testing.T) {
|
||||
minRatio := 20.0
|
||||
maxRatio := 30.0
|
||||
items := []ListingDTO{
|
||||
{ID: 1, HafCoinAmount: 100_000_000, PriceCent: 10_000, AssetSummary: map[string]any{"publish_ratio": 10.0}},
|
||||
{ID: 2, HafCoinAmount: 100_000_000, PriceCent: 4_000, AssetSummary: map[string]any{"publish_ratio": 25.0}},
|
||||
{ID: 3, HafCoinAmount: 100_000_000, PriceCent: 2_500, AssetSummary: map[string]any{"publish_ratio": 40.0}},
|
||||
}
|
||||
|
||||
filtered := filterPublicListings(items, PublicListQuery{
|
||||
MinRatio: &minRatio,
|
||||
MaxRatio: &maxRatio,
|
||||
})
|
||||
|
||||
if len(filtered) != 1 || filtered[0].ID != 2 {
|
||||
t.Fatalf("expected only listing 2 in ratio range, got %#v", filtered)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortPublicListingsDefaultUsesShuffleKey(t *testing.T) {
|
||||
items := []ListingDTO{
|
||||
{ID: 101},
|
||||
{ID: 102},
|
||||
{ID: 103},
|
||||
{ID: 104},
|
||||
}
|
||||
|
||||
sortPublicListings(items, "recommended")
|
||||
|
||||
for index := 1; index < len(items); index++ {
|
||||
previous := publicShuffleKey(items[index-1].ID)
|
||||
current := publicShuffleKey(items[index].ID)
|
||||
if previous > current {
|
||||
t.Fatalf("expected shuffled order by key, got ids=%v", []uint64{
|
||||
items[0].ID,
|
||||
items[1].ID,
|
||||
items[2].ID,
|
||||
items[3].ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package listing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -117,7 +118,10 @@ func canListPublicWithSQL(query PublicListQuery) bool {
|
||||
if len(query.SkinGroup) > 0 || len(query.SkinName) > 0 || len(query.ResourceRanges) > 0 {
|
||||
return false
|
||||
}
|
||||
if query.MinCoin != nil || query.MaxCoin != nil || query.MinPrice != nil || query.MaxPrice != nil {
|
||||
if query.MinCoin != nil || query.MaxCoin != nil || query.MinRatio != nil || query.MaxRatio != nil {
|
||||
return false
|
||||
}
|
||||
if query.MinPrice != nil || query.MaxPrice != nil {
|
||||
return false
|
||||
}
|
||||
if query.MinDeposit != nil || query.MaxDeposit != nil || query.MinTotal != nil || query.MaxTotal != nil {
|
||||
@@ -142,11 +146,18 @@ func applyPublicSQLSort(db *gorm.DB, sortKey string) *gorm.DB {
|
||||
return db.Order("l.price_cent DESC, l.published_at DESC, l.id DESC")
|
||||
case "coinDesc":
|
||||
return db.Order("a.haf_coin_amount DESC, l.published_at DESC, l.id DESC")
|
||||
default:
|
||||
case "published":
|
||||
return db.Order("l.published_at DESC, l.id DESC")
|
||||
default:
|
||||
return db.Order(fmt.Sprintf("((l.id * 1103515245 + %d) %% 2147483647) ASC, l.id ASC", publicShuffleSeed()))
|
||||
}
|
||||
}
|
||||
|
||||
func publicShuffleSeed() int64 {
|
||||
now := time.Now().UTC()
|
||||
return int64(now.Year()*366 + now.YearDay())
|
||||
}
|
||||
|
||||
func (r *Repository) publicZoneCountsCached(ctx context.Context) (map[string]int64, error) {
|
||||
now := time.Now()
|
||||
r.publicZoneCountsMu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user