Files
bl/modules/player/service/gold_list.go
昔念 77909a5940
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
1
2026-04-21 02:27:11 +08:00

267 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"blazing/cool"
basemodel "blazing/modules/base/model"
"blazing/modules/base/service"
"blazing/modules/player/model"
"context"
"fmt"
"math"
"time"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
)
type GoldListService struct {
BaseService
}
func (s *GoldListService) validateOrderInput(exchangeNum uint32, rate float64) error {
if exchangeNum == 0 {
return gerror.New("出售数量必须大于0")
}
if rate <= 0 {
return gerror.New("汇率必须大于0")
}
return nil
}
func (s *GoldListService) validateOrderRecord(order *model.GoldBeanOrder) error {
if order == nil || order.ID == 0 {
return gerror.New("重复订单")
}
return s.validateOrderInput(order.ExchangeNum, order.Rate)
}
func (s *GoldListService) getPrevDayAvgRate() float64 {
var (
now = gtime.Now()
yesterday = now.AddDate(0, 0, -1)
dayStart = gtime.NewFromStr(yesterday.Format("Y-m-d") + " 00:00:00")
nextDay = dayStart.AddDate(0, 0, 1)
result struct {
AvgRate float64 `json:"avg_rate"`
}
)
err := s.dbm_fix(s.Model).
Fields("COALESCE(AVG(rate), 0) AS avg_rate").
Where("status", 1).
WhereGTE("createTime", dayStart).
WhereLT("createTime", nextDay).
Scan(&result)
if err != nil || result.AvgRate <= 0 {
return 1
}
return result.AvgRate
}
func (s *GoldListService) ModifyBefore(ctx context.Context, method string, param map[string]interface{}) (err error) {
admin := cool.GetAdmin(ctx)
userId := admin.UserId
if method == "Add" {
var (
exchangeNum = gconv.Uint32(param["exchange_num"])
rate = gconv.Float64(param["rate"])
)
if err = s.validateOrderInput(exchangeNum, rate); err != nil {
return err
}
if service.NewBaseSysUserService().GetGold(userId) < int64(exchangeNum)*100 {
return fmt.Errorf("金额不足")
}
t, _ := s.dbm_fix(s.Model).Where("player_id", userId).Where("status", 0).Count()
if t > 0 {
return fmt.Errorf("不允许多挂单")
}
var (
prevAvg = s.getPrevDayAvgRate()
minRate = math.Round(prevAvg*0.9*10000) / 10000
maxRate = math.Round(prevAvg*1.1*10000) / 10000
)
if rate < minRate || rate > maxRate {
return fmt.Errorf("不允许超过10%%的单子,当前需在昨日均价 %.4f 的上下10%%范围内(%.4f - %.4f", prevAvg, minRate, maxRate)
}
} else {
var items []model.GoldBeanOrder
if err = s.dbm_fix(s.Model).WhereIn("id", param["ids"]).Scan(&items); err != nil {
return err
}
for _, v := range items {
if _, err = s.dbm_fix(s.Model).
Where("rate", v.Rate).
Where("exchange_num", v.ExchangeNum).
Where("player_id", 10001).
Delete(); err != nil {
return err
}
}
}
return
}
func (s *GoldListService) Done(listid uint32) (*model.GoldBeanOrder, error) {
var rr model.GoldBeanOrder
s.dbm_fix(s.Model).Where("id", listid).Scan(&rr)
if err := s.validateOrderRecord(&rr); err != nil {
return nil, err
}
r, err := s.dbm_fix(s.Model).Data("status", 1).Where("status", 0).Where("id", listid).Update()
if err != nil {
return nil, err
}
is, _ := r.RowsAffected()
if is == 0 {
return nil, fmt.Errorf("重复订单")
}
return &rr, nil
}
func (s *GoldListService) Trade(ctx context.Context, listid uint32, buyerID uint32) (*model.GoldBeanOrder, error) {
var result *model.GoldBeanOrder
err := g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
var (
order model.GoldBeanOrder
buyer basemodel.BaseSysUser
seller basemodel.BaseSysUser
)
if err := tx.Model(s.Model).Where("id", listid).Where("status", 0).Scan(&order); err != nil {
return err
}
if err := s.validateOrderRecord(&order); err != nil {
return err
}
if !order.UpdateTime.Add(1 * time.Hour).Before(gtime.Now()) {
return fmt.Errorf("未到购买时间")
}
costFree := int64(math.Round(order.Rate * float64(order.ExchangeNum) * 100))
sellerGold := int64(order.ExchangeNum) * 100
sellerIncome := int64(math.Round(order.Rate * float64(order.ExchangeNum) * 95))
buyerGold := int64(order.ExchangeNum * 95)
if err := tx.Model(basemodel.BaseSysUser{}).Where("id", buyerID).Fields("free_gold").Scan(&buyer); err != nil {
return err
}
if buyer.FreeGold < costFree {
return fmt.Errorf("余额不足")
}
if err := tx.Model(basemodel.BaseSysUser{}).Where("id", order.PlayerID).Fields("goldbean").Scan(&seller); err != nil {
return err
}
if seller.GoldBean < sellerGold {
return fmt.Errorf("卖家余额不足")
}
res, err := tx.Model(basemodel.BaseSysUser{}).
Where("id", buyerID).
WhereGTE("free_gold", costFree).
Increment("free_gold", -costFree)
if err != nil {
return err
}
rows, _ := res.RowsAffected()
if rows == 0 {
return fmt.Errorf("余额不足")
}
res, err = tx.Model(basemodel.BaseSysUser{}).
Where("id", order.PlayerID).
WhereGTE("goldbean", sellerGold).
Increment("goldbean", -sellerGold)
if err != nil {
return err
}
rows, _ = res.RowsAffected()
if rows == 0 {
return fmt.Errorf("卖家余额不足")
}
if _, err = tx.Model(basemodel.BaseSysUser{}).Where("id", order.PlayerID).Increment("free_gold", sellerIncome); err != nil {
return err
}
if _, err = tx.Model(basemodel.BaseSysUser{}).Where("id", buyerID).Increment("goldbean", buyerGold); err != nil {
return err
}
res, err = tx.Model(s.Model).
Data("status", 1).
Where("id", listid).
Where("status", 0).
Update()
if err != nil {
return err
}
rows, _ = res.RowsAffected()
if rows == 0 {
return fmt.Errorf("重复订单")
}
result = &order
return nil
})
if err != nil {
return nil, err
}
return result, nil
}
func (s *GoldListService) Get() []model.GoldBeanOrder {
var rr []model.GoldBeanOrder
s.dbm_fix(s.Model).
Where("status", 0).
WhereGT("exchange_num", 0).
WhereGT("rate", 0).
Order("rate", "asc").
Scan(&rr)
return rr
}
func NewGoldListService(id uint32) *GoldListService {
return &GoldListService{
BaseService: BaseService{userid: id,
Service: &cool.Service{Model: model.NewGoldBeanOrder(),
Where: func(ctx context.Context) []g.Array {
admin := cool.GetAdmin(ctx)
return [][]interface{}{
{"player_id", admin.UserId, true},
}
},
ListQueryOp: &cool.QueryOp{
Extend: func(ctx g.Ctx, m *gdb.Model) *gdb.Model {
return m.WhereGT("exchange_num", 0).WhereGT("rate", 0)
},
AddOrderby: g.MapStrStr{"updateTime": "asc"},
},
InsertParam: func(ctx context.Context) g.MapStrAny {
admin := cool.GetAdmin(ctx)
return g.MapStrAny{
"player_id": admin.UserId,
}
},
},
},
}
}