彻底优化数据库字段

This commit is contained in:
yml
2026-05-24 20:49:37 +08:00
parent 80e01dc6d9
commit 5f6a4afcbb
28 changed files with 295 additions and 302 deletions
-6
View File
@@ -19,9 +19,6 @@ type ListingDTO struct {
ScreenshotURLS []string `json:"screenshot_urls"`
CoverURL string `json:"cover_url"`
Price float64 `json:"price"`
PriceHourly float64 `json:"price_hourly"`
PriceDaily float64 `json:"price_daily"`
PriceWeekly float64 `json:"price_weekly"`
DepositAmount float64 `json:"deposit_amount"`
IsAccelerated bool `json:"is_accelerated_sale"`
InTransaction bool `json:"in_transaction"`
@@ -43,9 +40,6 @@ type CreateRequest struct {
AssetSummary map[string]any `json:"asset_summary"`
ScreenshotURLS []string `json:"screenshot_urls"`
Price float64 `json:"price"`
PriceHourly float64 `json:"price_hourly"`
PriceDaily float64 `json:"price_daily"`
PriceWeekly float64 `json:"price_weekly"`
DepositAmount float64 `json:"deposit_amount"`
}
@@ -364,6 +364,8 @@ func writeListingError(c *gin.Context, err error) {
response.BadRequest(c, "发布价格不正确")
case errors.Is(err, ErrInvalidDeposit):
response.BadRequest(c, "押金不能小于 0")
case errors.Is(err, ErrDepositTooLow):
response.BadRequest(c, "押金必须大于额外消耗品总价值")
case errors.Is(err, ErrInvalidHafCoin):
response.BadRequest(c, "哈夫币数量不正确")
case errors.Is(err, ErrMissingScreenshot):
+3 -73
View File
@@ -65,9 +65,6 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bo
AccountID: account.ID,
OwnerID: ownerID,
Price: price,
PriceHourly: listingHourlyPrice(req, price),
PriceDaily: listingDailyPrice(req, price),
PriceWeekly: listingWeeklyPrice(req, price),
DepositAmount: req.DepositAmount,
Status: listingStatus,
ReviewStatus: reviewStatus,
@@ -112,9 +109,6 @@ func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest,
price := normalizedListingPrice(req)
listing.Price = price
listing.PriceHourly = listingHourlyPrice(req, price)
listing.PriceDaily = listingDailyPrice(req, price)
listing.PriceWeekly = listingWeeklyPrice(req, price)
listing.DepositAmount = req.DepositAmount
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
listing.Status = listingStatus
@@ -489,63 +483,7 @@ func rowsToDTO(rows []listingRow) []ListingDTO {
}
func normalizedListingPrice(req CreateRequest) float64 {
if req.Price > 0 {
return req.Price
}
if req.PriceDaily > 0 {
return req.PriceDaily
}
if req.PriceHourly > 0 {
return req.PriceHourly * 24
}
if req.PriceWeekly > 0 {
return req.PriceWeekly / 7
}
return 0
}
func listingHourlyPrice(req CreateRequest, price float64) float64 {
if req.PriceHourly > 0 {
return req.PriceHourly
}
return price / 24
}
func listingDailyPrice(req CreateRequest, price float64) float64 {
if req.PriceDaily > 0 {
return req.PriceDaily
}
return price
}
func listingWeeklyPrice(req CreateRequest, price float64) float64 {
if req.PriceWeekly > 0 {
return req.PriceWeekly
}
return price * 7
}
func listingDisplayPrices(price float64, hourly float64, daily float64, weekly float64) (float64, float64, float64, float64) {
if price <= 0 {
switch {
case daily > 0:
price = daily
case hourly > 0:
price = hourly * 24
case weekly > 0:
price = weekly / 7
}
}
if daily <= 0 {
daily = price
}
if hourly <= 0 && price > 0 {
hourly = price / 24
}
if weekly <= 0 && price > 0 {
weekly = price * 7
}
return price, hourly, daily, weekly
return req.Price
}
func publicListings(items []ListingDTO) []ListingDTO {
@@ -565,7 +503,6 @@ func applyPublicListingURLs(item *ListingDTO) {
func (row listingRow) toDTO() ListingDTO {
assetSummary := decodeAssetSummary(row.AssetSummary)
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(row.ScreenshotURLS))
price, priceHourly, priceDaily, priceWeekly := listingDisplayPrices(row.Price, row.PriceHourly, row.PriceDaily, row.PriceWeekly)
return ListingDTO{
ID: row.ID,
AccountID: row.AccountID,
@@ -582,10 +519,7 @@ func (row listingRow) toDTO() ListingDTO {
AssetSummary: assetSummary,
ScreenshotURLS: screenshotURLS,
CoverURL: publicCoverURL(row.ID, screenshotURLS, row.Status, row.ReviewStatus),
Price: price,
PriceHourly: priceHourly,
PriceDaily: priceDaily,
PriceWeekly: priceWeekly,
Price: row.Price,
DepositAmount: row.DepositAmount,
IsAccelerated: isAcceleratedSale(assetSummary),
InTransaction: row.InTransaction,
@@ -601,7 +535,6 @@ func (row listingRow) toDTO() ListingDTO {
func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
assetSummary := decodeAssetSummary(account.AssetSummary)
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(account.ScreenshotURLS))
price, priceHourly, priceDaily, priceWeekly := listingDisplayPrices(listing.Price, listing.PriceHourly, listing.PriceDaily, listing.PriceWeekly)
return &ListingDTO{
ID: listing.ID,
AccountID: account.ID,
@@ -616,10 +549,7 @@ func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
AssetSummary: assetSummary,
ScreenshotURLS: screenshotURLS,
CoverURL: publicCoverURL(listing.ID, screenshotURLS, listing.Status, listing.ReviewStatus),
Price: price,
PriceHourly: priceHourly,
PriceDaily: priceDaily,
PriceWeekly: priceWeekly,
Price: listing.Price,
DepositAmount: listing.DepositAmount,
IsAccelerated: isAcceleratedSale(assetSummary),
InTransaction: listing.InTransaction,
@@ -3,6 +3,8 @@ package listing
import (
"encoding/json"
"errors"
"math"
"regexp"
"strconv"
"strings"
)
@@ -15,6 +17,7 @@ var (
ErrMissingServerRegion = errors.New("missing server region")
ErrInvalidPrice = errors.New("invalid listing price")
ErrInvalidDeposit = errors.New("invalid listing deposit")
ErrDepositTooLow = errors.New("listing deposit too low")
ErrInvalidHafCoin = errors.New("invalid haf coin amount")
ErrMissingScreenshot = errors.New("missing screenshot")
)
@@ -34,6 +37,8 @@ const (
defaultFireLevelMin = 38
)
var priceNumberPattern = regexp.MustCompile(`(\d+(?:\.\d+)?)`)
type FireLevelTooLowError struct {
Min int
}
@@ -217,6 +222,9 @@ func validateRequest(req CreateRequest, rules publishRules) error {
if req.DepositAmount < 0 {
return ErrInvalidDeposit
}
if consumables := consumableValue(req.AssetSummary); consumables > 0 && req.DepositAmount <= consumables {
return ErrDepositTooLow
}
if req.HafCoinAmount < 0 {
return ErrInvalidHafCoin
}
@@ -229,6 +237,85 @@ func validateRequest(req CreateRequest, rules publishRules) error {
return nil
}
func consumableValue(summary map[string]any) float64 {
if summary == nil {
return 0
}
rawResources, ok := summary["resources"]
if !ok {
return 0
}
resources, ok := rawResources.([]any)
if !ok {
return 0
}
total := 0.0
for _, raw := range resources {
resource, ok := raw.(map[string]any)
if !ok {
continue
}
mode, _ := resource["mode"].(string)
if strings.TrimSpace(mode) != "收费" {
continue
}
quantity := readSummaryFloat(resource["quantity"])
if quantity <= 0 {
continue
}
priceText, _ := resource["price"].(string)
total += quantity * readUnitPrice(priceText)
}
return roundMoney(total)
}
func readSummaryFloat(value any) float64 {
switch current := value.(type) {
case float64:
return current
case int:
return float64(current)
case int64:
return float64(current)
case json.Number:
parsed, err := current.Float64()
if err != nil {
return 0
}
return parsed
case string:
parsed, err := strconv.ParseFloat(strings.TrimSpace(current), 64)
if err != nil {
return 0
}
return parsed
default:
return 0
}
}
func readUnitPrice(priceText string) float64 {
numbers := priceNumberPattern.FindAllString(priceText, -1)
if len(numbers) == 0 {
return 0
}
amount, err := strconv.ParseFloat(numbers[0], 64)
if err != nil {
return 0
}
if len(numbers) >= 2 {
count, err := strconv.ParseFloat(numbers[1], 64)
if err == nil && count > 0 {
return amount / count
}
}
return amount
}
func roundMoney(value float64) float64 {
return math.Round(value*100) / 100
}
func readFireLevel(summary map[string]any) (int, bool) {
if summary == nil {
return 0, false
@@ -0,0 +1,42 @@
package listing
import "testing"
func TestConsumableValueOnlyCountsChargedResources(t *testing.T) {
value := consumableValue(map[string]any{
"resources": []any{
map[string]any{"mode": "收费", "quantity": float64(5), "price": "0.1元/个"},
map[string]any{"mode": "赠送", "quantity": float64(3), "price": "0.6元/个"},
map[string]any{"mode": "收费", "quantity": float64(2), "price": "1元/2个"},
},
})
if value != 1.5 {
t.Fatalf("expected 1.5, got %.2f", value)
}
}
func TestValidateRequestRequiresDepositAboveConsumables(t *testing.T) {
req := CreateRequest{
Title: "测试账号",
ServerRegion: "烽火地带",
Price: 100,
DepositAmount: 1.5,
HafCoinAmount: 1000000,
ScreenshotURLS: []string{"https://example.com/a.png"},
AssetSummary: map[string]any{
"resources": []any{
map[string]any{"mode": "收费", "quantity": float64(2), "price": "1元/个"},
},
},
}
if err := validateRequest(req, publishRules{}); err != ErrDepositTooLow {
t.Fatalf("expected ErrDepositTooLow, got %v", err)
}
req.DepositAmount = 2.01
if err := validateRequest(req, publishRules{}); err != nil {
t.Fatalf("expected valid request, got %v", err)
}
}