优化发布等各种状态

This commit is contained in:
yml2213
2026-05-23 15:52:44 +08:00
parent f2492d5e40
commit b101415e9d
25 changed files with 368 additions and 70 deletions
+2 -2
View File
@@ -39,10 +39,10 @@ type CreateRequest struct {
HafCoinAmount int64 `json:"haf_coin_amount"`
AssetSummary map[string]any `json:"asset_summary"`
ScreenshotURLS []string `json:"screenshot_urls"`
PriceHourly float64 `json:"price_hourly" binding:"required"`
PriceHourly float64 `json:"price_hourly"`
PriceDaily float64 `json:"price_daily"`
PriceWeekly float64 `json:"price_weekly"`
DepositAmount float64 `json:"deposit_amount" binding:"required"`
DepositAmount float64 `json:"deposit_amount"`
}
type UpdateRequest = CreateRequest
@@ -301,6 +301,18 @@ func writeListingError(c *gin.Context, err error) {
switch {
case errors.Is(err, ErrDependencyUnavailable):
response.ServiceUnavailable(c, "数据库未连接")
case errors.Is(err, ErrMissingTitle):
response.BadRequest(c, "发布标题不能为空")
case errors.Is(err, ErrMissingServerRegion):
response.BadRequest(c, "请选择区服")
case errors.Is(err, ErrInvalidPrice):
response.BadRequest(c, "发布价格不正确")
case errors.Is(err, ErrInvalidDeposit):
response.BadRequest(c, "押金不能小于 0")
case errors.Is(err, ErrInvalidHafCoin):
response.BadRequest(c, "哈夫币数量不正确")
case errors.Is(err, ErrMissingScreenshot):
response.BadRequest(c, "请至少上传一张账号截图")
case errors.Is(err, ErrInvalidInput):
response.BadRequest(c, "发布信息不符合规则")
case errors.Is(err, ErrListingLocked):
+29 -16
View File
@@ -22,7 +22,15 @@ func NewRepository(db *gorm.DB) *Repository {
return &Repository{db: db}
}
func (r *Repository) Create(ownerID uint64, req CreateRequest) (*ListingDTO, error) {
func initialPublishState(reviewRequired bool) (string, string, *time.Time) {
if reviewRequired {
return "draft", "pending", nil
}
now := time.Now()
return "published", "approved", &now
}
func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bool) (*ListingDTO, error) {
var dto *ListingDTO
err := r.db.Transaction(func(tx *gorm.DB) error {
screenshots, err := marshalScreenshots(req.ScreenshotURLS)
@@ -33,6 +41,7 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest) (*ListingDTO, err
if err != nil {
return err
}
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
account := model.GameAccount{
OwnerID: ownerID,
GameName: "delta_force",
@@ -44,7 +53,7 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest) (*ListingDTO, err
HafCoinAmount: req.HafCoinAmount,
AssetSummary: assetSummary,
ScreenshotURLS: screenshots,
Status: "draft",
Status: listingStatus,
}
if err := tx.Create(&account).Error; err != nil {
return err
@@ -56,8 +65,9 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest) (*ListingDTO, err
PriceDaily: req.PriceDaily,
PriceWeekly: req.PriceWeekly,
DepositAmount: req.DepositAmount,
Status: "draft",
ReviewStatus: "none",
Status: listingStatus,
ReviewStatus: reviewStatus,
PublishedAt: publishedAt,
}
if err := tx.Create(&listing).Error; err != nil {
return err
@@ -68,7 +78,7 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest) (*ListingDTO, err
return dto, err
}
func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest) (*ListingDTO, error) {
func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest, reviewRequired bool) (*ListingDTO, error) {
var dto *ListingDTO
err := r.db.Transaction(func(tx *gorm.DB) error {
listing, account, err := r.findOwnedForUpdate(tx, ownerID, listingID)
@@ -95,18 +105,20 @@ func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest)
return err
}
account.ScreenshotURLS = screenshots
if err := tx.Save(account).Error; err != nil {
return err
}
listing.PriceHourly = req.PriceHourly
listing.PriceDaily = req.PriceDaily
listing.PriceWeekly = req.PriceWeekly
listing.DepositAmount = req.DepositAmount
listing.Status = "draft"
listing.ReviewStatus = "none"
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
listing.Status = listingStatus
listing.ReviewStatus = reviewStatus
listing.ReviewReason = ""
listing.PublishedAt = nil
listing.PublishedAt = publishedAt
account.Status = listingStatus
if err := tx.Save(account).Error; err != nil {
return err
}
if err := tx.Save(listing).Error; err != nil {
return err
}
@@ -116,7 +128,7 @@ func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest)
return dto, err
}
func (r *Repository) SubmitReview(ownerID uint64, listingID uint64) (*ListingDTO, error) {
func (r *Repository) SubmitReview(ownerID uint64, listingID uint64, reviewRequired bool) (*ListingDTO, error) {
var dto *ListingDTO
err := r.db.Transaction(func(tx *gorm.DB) error {
listing, account, err := r.findOwnedForUpdate(tx, ownerID, listingID)
@@ -126,11 +138,12 @@ func (r *Repository) SubmitReview(ownerID uint64, listingID uint64) (*ListingDTO
if listing.Status == "rented" {
return ErrListingLocked
}
listing.Status = "draft"
listing.ReviewStatus = "pending"
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
listing.Status = listingStatus
listing.ReviewStatus = reviewStatus
listing.ReviewReason = ""
listing.PublishedAt = nil
account.Status = "draft"
listing.PublishedAt = publishedAt
account.Status = listingStatus
if err := tx.Save(account).Error; err != nil {
return err
}
+59 -12
View File
@@ -2,6 +2,7 @@ package listing
import (
"errors"
"strconv"
"strings"
)
@@ -9,14 +10,27 @@ var (
ErrDependencyUnavailable = errors.New("dependency unavailable")
ErrInvalidInput = errors.New("invalid listing input")
ErrListingLocked = errors.New("listing locked")
ErrMissingTitle = errors.New("missing listing title")
ErrMissingServerRegion = errors.New("missing server region")
ErrInvalidPrice = errors.New("invalid listing price")
ErrInvalidDeposit = errors.New("invalid listing deposit")
ErrInvalidHafCoin = errors.New("invalid haf coin amount")
ErrMissingScreenshot = errors.New("missing screenshot")
)
type Service struct {
repo *Repository
repo *Repository
config ConfigReader
}
func NewService(repo *Repository) *Service {
return &Service{repo: repo}
type ConfigReader interface {
FindValue(key string) (string, error)
}
const reviewRequiredConfigKey = "listing.review_required"
func NewService(repo *Repository, config ConfigReader) *Service {
return &Service{repo: repo, config: config}
}
func (s *Service) Create(ownerID uint64, req CreateRequest) (*ListingDTO, error) {
@@ -26,7 +40,11 @@ func (s *Service) Create(ownerID uint64, req CreateRequest) (*ListingDTO, error)
if err := validateRequest(req); err != nil {
return nil, err
}
return s.repo.Create(ownerID, req)
reviewRequired, err := s.reviewRequired()
if err != nil {
return nil, err
}
return s.repo.Create(ownerID, req, reviewRequired)
}
func (s *Service) Update(ownerID uint64, id uint64, req UpdateRequest) (*ListingDTO, error) {
@@ -36,14 +54,22 @@ func (s *Service) Update(ownerID uint64, id uint64, req UpdateRequest) (*Listing
if err := validateRequest(req); err != nil {
return nil, err
}
return s.repo.Update(ownerID, id, req)
reviewRequired, err := s.reviewRequired()
if err != nil {
return nil, err
}
return s.repo.Update(ownerID, id, req, reviewRequired)
}
func (s *Service) SubmitReview(ownerID uint64, id uint64) (*ListingDTO, error) {
if s.repo == nil {
return nil, ErrDependencyUnavailable
}
return s.repo.SubmitReview(ownerID, id)
reviewRequired, err := s.reviewRequired()
if err != nil {
return nil, err
}
return s.repo.SubmitReview(ownerID, id, reviewRequired)
}
func (s *Service) ListPendingReview() ([]ListingDTO, error) {
@@ -140,17 +166,23 @@ func (s *Service) FindMine(ownerID uint64, id uint64) (*ListingDTO, error) {
}
func validateRequest(req CreateRequest) error {
if req.Title == "" || req.ServerRegion == "" {
return ErrInvalidInput
if strings.TrimSpace(req.Title) == "" {
return ErrMissingTitle
}
if req.PriceHourly <= 0 || req.DepositAmount < 0 {
return ErrInvalidInput
if strings.TrimSpace(req.ServerRegion) == "" {
return ErrMissingServerRegion
}
if req.PriceHourly <= 0 {
return ErrInvalidPrice
}
if req.DepositAmount < 0 {
return ErrInvalidDeposit
}
if req.HafCoinAmount < 0 {
return ErrInvalidInput
return ErrInvalidHafCoin
}
if !hasScreenshotURL(req.ScreenshotURLS) {
return ErrInvalidInput
return ErrMissingScreenshot
}
return nil
}
@@ -163,3 +195,18 @@ func hasScreenshotURL(urls []string) bool {
}
return false
}
func (s *Service) reviewRequired() (bool, error) {
if s.config == nil {
return false, nil
}
value, err := s.config.FindValue(reviewRequiredConfigKey)
if err != nil {
return false, err
}
required, err := strconv.ParseBool(strings.TrimSpace(value))
if err != nil {
return false, nil
}
return required, nil
}
@@ -33,6 +33,7 @@ var defaultConfigs = []defaultConfig{
{Key: "handoff.owner_return_confirm_timeout_minutes", Value: "120", Description: "号主待确认归还超时分钟数"},
{Key: "order.return_overdue_grace_minutes", Value: "10", Description: "预计截止后归还宽限分钟数"},
{Key: "deposit.min_amount", Value: "50", Description: "发布租号最低押金"},
{Key: "listing.review_required", Value: "false", Description: "发布账号是否需要后台人工审核"},
{Key: "risk.sms_limit_per_phone_hour", Value: "5", Description: "单手机号每小时短信验证码次数"},
{Key: "risk.sms_limit_per_ip_hour", Value: "20", Description: "单 IP 每小时短信验证码次数"},
{Key: "realname.required_for_order", Value: "false", Description: "下单是否必须完成实名认证"},