Files
bl/modules/player/service/pet.go
xinian 376fa5e8af
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
feat: 新增金豆挂单管理模块及优化购买提示
2026-03-17 16:56:55 +08:00

344 lines
8.0 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/common/utils"
"blazing/cool"
basemodel "blazing/modules/base/model"
"blazing/modules/base/service"
"blazing/modules/player/model"
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// 获取精灵信息 0是仓库,1是放生
func (s *PetService) PetInfo(flag int) []model.Pet {
var tt []model.Pet
err := s.dbm(s.Model).Where("free", flag).Scan(&tt)
if err != nil {
return []model.Pet{}
}
for i := 0; i < len(tt); i++ {
tt[i].Data.CatchTime = tt[i].CatchTime
}
return tt
}
func (s *PetService) PetCount(flag int) int {
ret, err := s.dbm(s.Model).Where("free", flag).Count()
if err != nil {
return 0
}
return ret
}
func (s *PetService) UPdateFree(ctime uint32, free uint32) {
s.dbm(s.Model).Where("catch_time", ctime).Data(
"free", free,
).Update()
}
func (s *PetService) UPdatePrice(ctime uint32, Price uint32, is_sale uint32) error {
if is_sale == 1 {
t, _ := s.dbm(s.Model).Where("is_sale", 1).Count()
if t > 3 {
return fmt.Errorf("精灵数量已满")
}
}
var p model.Pet
s.dbm(s.Model).Where("catch_time", ctime).Scan(&p)
if p.SalePrice != 0 && p.SalePrice != Price && utils.IsToday(p.UpdateTime) { //说明要修改价格
return fmt.Errorf("一天只允许改价一次")
}
res0, err := s.dbm(s.Model).
Where("catch_time", ctime). // 限定 ctime避免全表更新
Where("sale_price = ?", 0). // 只筛选 sale_price=0 的记录
Data(g.Map{
"sale_price": Price,
"is_sale": is_sale,
}).Update()
if err != nil {
return fmt.Errorf("修改 sale_price=0 的记录失败:%w", err)
}
affected0, _ := res0.RowsAffected()
if affected0 == 0 {
priceUpper := Price * 110 / 100 // 上限 = Price * 1.1(整数运算避免浮点误差)
priceLower := Price * 90 / 100 // 下限 = Price * 0.9
res, _ := s.dbm(s.Model).Where("catch_time", ctime).WhereBetween("sale_price", priceLower, priceUpper).Data("sale_price", Price, "is_sale", is_sale).Update()
t, _ := res.RowsAffected()
if t < 0 {
return fmt.Errorf("修改失败")
}
}
return nil
}
func (s *PetService) BuyPet(pid uint32) error {
tt := NewPetService(0).PetInfo_One_ID(pid)
if tt == nil {
return fmt.Errorf("没有此精灵")
}
if tt.IsVip != 0 {
return fmt.Errorf("不允许交易")
}
if tt.IsSale == 0 {
return fmt.Errorf("未上架")
}
if tt.Free == 0 {
return fmt.Errorf("没有此精灵")
}
if tt.SalePrice == 0 {
return fmt.Errorf("未设置价格")
}
if !tt.UpdateTime.AddDate(0, 0, 1).Before(gtime.Now()) {
return fmt.Errorf("未到购买时间")
}
return g.DB().Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
useglod := int64(tt.SalePrice)*102 + int64(tt.SaleCount)*5
var res1 basemodel.BaseSysUser
err := tx.Model(basemodel.BaseSysUser{}).Where("id", s.userid).Fields("free_gold").Scan(&res1)
if err != nil {
return err
}
if res1.FreeGold < useglod {
return fmt.Errorf("余额不足")
}
_, err = tx.Model(basemodel.BaseSysUser{}).Where("id", s.userid).Increment("free_gold", -useglod)
if err != nil {
return err
}
res, err := tx.Model(s.Model).Where("id", tt.ID).Delete()
if err != nil {
return err
}
cd, _ := res.RowsAffected()
if cd == 0 {
return fmt.Errorf("重复订单")
}
_, err = tx.Model(basemodel.BaseSysUser{}).Where("id", tt.PlayerID).Increment("free_gold", int64(tt.SalePrice)*98)
if err != nil {
return err
}
sql := fmt.Sprintf(`
UPDATE %s
SET max_ts = CASE
WHEN max_ts < EXTRACT(EPOCH FROM NOW())::INT THEN EXTRACT(EPOCH FROM NOW())::INT
ELSE max_ts + 1
END
WHERE id = ? AND deleted_at IS NULL
RETURNING max_ts;
`, service.NewBaseSysUserService().Model.TableName())
// 执行 Raw SQL 并扫描返回值
ret, err := tx.Model(service.NewBaseSysUserService().Model).Raw(sql, s.userid).All()
if err != nil {
return err
}
//fmt.Println(ret, err)
tt.CatchTime = ret.Array()[0].Uint32()
var player model.Pet
player.PlayerID = s.userid
player.Data = tt.Data
player.Data.OldCatchTime = 0
player.CatchTime = tt.CatchTime
player.Free = 0
player.SalePrice = tt.SalePrice
player.SaleCount = tt.SaleCount + 1
player.IsVip = cool.Config.ServerInfo.IsVip
_, err = tx.Model(s.Model).Insert(player)
if err != nil {
return err
}
return nil
})
}
func (s *PetService) UPdate(t model.PetInfo) {
m := s.dbm(s.Model).Where("catch_time", t.CatchTime)
var tt *model.Pet
m.Scan(&tt)
if tt == nil {
return
}
tt.Data = t
_, err := m.OnConflict("catch_time").Update(tt)
if err != nil {
panic(err)
}
}
func (s *PetService) PetInfo_One(cachetime uint32) *model.Pet {
m := s.dbm(s.Model).Where("catch_time", cachetime)
var tt *model.Pet
m.Scan(&tt)
if tt == nil {
return nil
}
tt.Data.CatchTime = tt.CatchTime
return tt
}
func (s *PetService) PetInfo_One_ID(Pid uint32) *model.Pet {
m := s.dbm(s.Model).Where("id", Pid)
var tt *model.Pet
m.Scan(&tt)
if tt == nil {
return nil
}
tt.Data.CatchTime = tt.CatchTime
return tt
}
func (s *PetService) PetInfo_One_ohter(userid, cachetime uint32) model.Pet {
m := s.dbm(s.Model).Where("catch_time", cachetime)
var tt model.Pet
m.Scan(&tt)
tt.Data.CatchTime = tt.CatchTime
return tt
}
func (s *PetService) PetInfo_One_Unscoped(cachetime uint32) *model.Pet {
m := s.dbm(s.Model).Where("catch_time", cachetime).Unscoped()
var tt *model.Pet
m.Scan(&tt)
if tt == nil {
return nil
}
tt.Data.CatchTime = tt.CatchTime
return tt
}
func (s *PetService) Pet_del(cachetime uint32) {
s.dbm(s.Model).Where("catch_time", cachetime).Delete()
}
func (s *PetService) Pet_LEVEL_all() []model.Pet {
var tt []model.Pet
s.dbm(s.Model).As("pp").Wheref(`(pp.data->>'Level')::INT > 100`).OrderDesc("(pp.data->>'Level')::INT").Scan(&tt)
return tt
}
// 精灵真正添加后的捕捉时间才是真正的时间
func (s *PetService) PetAdd(y *model.PetInfo, salecount uint32) uint32 {
if y == nil {
return 0
}
sql := fmt.Sprintf(`
UPDATE %s
SET max_ts = CASE
WHEN max_ts < EXTRACT(EPOCH FROM NOW())::INT THEN EXTRACT(EPOCH FROM NOW())::INT
ELSE max_ts + 1
END
WHERE id = ? AND deleted_at IS NULL
RETURNING max_ts;
`, service.NewBaseSysUserService().Model.TableName())
// 执行 Raw SQL 并扫描返回值
ret, _ := cool.DBM(service.NewBaseSysUserService().Model).Raw(sql, s.userid).All()
//fmt.Println(ret, err)
y.CatchTime = ret.Array()[0].Uint32()
m1 := cool.DBM(s.Model).Where("player_id", s.userid)
var player model.Pet
player.PlayerID = s.userid
player.Data = *y
player.CatchTime = y.CatchTime
player.Free = 0
player.SaleCount = salecount
player.IsVip = cool.Config.ServerInfo.IsVip
_, err := m1.Insert(player)
if err != nil {
panic(err)
}
return y.CatchTime
}
// func (s *PetService) ModifyBefore(ctx context.Context, method string, param map[string]interface{}) (err error) {
// admin := cool.GetAdmin(ctx)
// userId := admin.UserId
// s.userid = uint32(userId)
// // if method == "Update" {
// // if gconv.Uint(param["free"]) != 0 {
// // err = fmt.Errorf("修改失败")
// // }
// // if userId != gconv.Uint(param["player_id"]) {
// // err = fmt.Errorf("修改失败")
// // }
// // }
// return
// }
type PetService struct {
BaseService
}
func NewPetService(userid uint32) *PetService {
return &PetService{
BaseService: BaseService{
userid: userid,
Service: &cool.Service{
Model: model.NewPet(),
ListQueryOp: &cool.QueryOp{
FieldEQ: []string{"player_id", "free", "is_sale"},
Where: func(ctx context.Context) [][]interface{} {
return [][]interface{}{
// {"player_id", userId, true},
{"free", 1, true},
{"is_vip", 0, true},
}
},
},
PageQueryOp: &cool.QueryOp{
FieldEQ: []string{"player_id", "free", "is_sale"},
Where: func(ctx context.Context) [][]interface{} {
// var (
// admin = cool.GetAdmin(ctx)
// // userId = admin.UserId
// )
return [][]interface{}{
// {"player_id", userId, true},
{"free", 1, true},
{"is_vip", 0, true},
}
},
},
},
},
}
}