package services import ( "context" "encoding/json" "fmt" "platform/pkg/rds" "platform/web/common" m "platform/web/models" q "platform/web/queries" "strings" "time" "github.com/gofiber/fiber/v2" ) var Resource = &resourceService{} type resourceService struct{} func (s *resourceService) PrepareResource(ctx context.Context, data *CreateResourceData, uid int32, tradeNo string, method int32) error { amount := data.GetPrice() // 保存到数据库 err := q.Q.Transaction(func(q *q.Query) error { // 创建交易订单 var trade = m.Trade{ UserID: uid, InnerNo: tradeNo, Subject: "购买套餐 - " + data.GetName(), Method: method, Type: 1, Status: 0, Amount: amount, } err := q.Trade.Create(&trade) if err != nil { return err } // 保存用户帐单 bill := m.Bill{ UserID: uid, TradeID: trade.ID, BillNo: ID.GenReadable("bil"), Info: "购买套餐 - " + data.GetName(), Type: 1, Amount: -amount, } err = q.Bill. Omit(q.Bill.ResourceID, q.Bill.RefundID). Create(&bill) if err != nil { return err } // 保存请求缓存 cache := &CreateResourceCache{ CreateResourceData: *data, Uid: uid, TradeId: trade.ID, BillId: bill.ID, } reqStr, err := json.Marshal(cache) if err != nil { return err } err = rds.Client.Set(ctx, tradeNo, reqStr, 30*time.Minute).Err() if err != nil { return err } return nil }) if err != nil { return err } return nil } func (s *resourceService) CreateResourcePrepared(ctx context.Context, tradeNo string, outerTradeNo string, payment float64, at time.Time) error { // 获取请求缓存 reqStr, err := rds.Client.Get(ctx, tradeNo).Result() if err != nil { return err } cache := new(CreateResourceCache) if err := json.Unmarshal([]byte(reqStr), cache); err != nil { return err } // 保存交易信息 err = q.Q.Transaction(func(q *q.Query) error { // 保存套餐 resource, err := createResource(&cache.CreateResourceData, cache.Uid) if err != nil { return err } // 更新订单状态 _, err = q.Trade.Debug(). Select(q.Trade.OuterNo, q.Trade.Payment, q.Trade.Status, q.Trade.PaidAt). Updates(&m.Trade{ ID: cache.TradeId, OuterNo: outerTradeNo, Payment: payment, Status: 1, PaidAt: common.LocalDateTime(at), }) if err != nil { return err } // 更新账单状态 _, err = q.Bill.Debug(). Select(q.Bill.ResourceID). Updates(&m.Bill{ ID: cache.BillId, ResourceID: resource.ID, }) if err != nil { return err } // 删除缓存 err = rds.Client.Del(ctx, tradeNo).Err() if err != nil { return err } return nil }) if err != nil { return err } return nil } func (s *resourceService) CreateResourceImmediately(data *CreateResourceData, uid int32) error { // 保存交易信息 err := q.Q.Transaction(func(q *q.Query) error { // 保存套餐 resource, err := createResource(data, uid) if err != nil { return err } // 生成账单 bill := m.Bill{ UserID: uid, ResourceID: resource.ID, BillNo: ID.GenReadable("bil"), Info: "购买套餐 - " + data.GetName(), Type: 1, Amount: data.GetPrice(), } err = q.Bill. Omit(q.Bill.TradeID, q.Bill.RefundID). Create(&bill) if err != nil { return err } return nil }) if err != nil { return err } return nil } type CreateResourceData struct { Type int32 `json:"type" validate:"required"` Live int32 `json:"live" validate:"required"` Expire int32 `json:"expire" validate:"required"` Quota int32 `json:"quota" validate:"required"` DailyLimit int32 `json:"daily_limit" validate:"required"` name string price float64 } func (data *CreateResourceData) GetName() string { if data.name == "" { sb := strings.Builder{} sb.WriteString("短效动态") switch data.Type { case 1: sb.WriteString("包时 ") case 2: sb.WriteString("包量 ") } sb.WriteString(fmt.Sprintf("%d 分钟", data.Live/60)) data.name = sb.String() } return data.name } func (data *CreateResourceData) GetPrice() float64 { if data.price == 0 { data.price = 0.01 } return data.price } type CreateResourceCache struct { CreateResourceData `json:"data"` Uid int32 `json:"uid"` TradeId int32 `json:"trade_id"` BillId int32 `json:"bill_id"` } func createResource(data *CreateResourceData, uid int32) (*m.Resource, error) { amount := data.GetPrice() // 检查用户 user, err := q.User. Where( q.User.ID.Eq(uid), q.User.Status.Eq(1), ). Take() if err != nil { return nil, err } // 检查余额 if user.Balance < amount { return nil, fiber.NewError(fiber.StatusBadRequest, "余额不足") } // 创建套餐 resource := &m.Resource{ UserID: user.ID, ResourceNo: ID.GenReadable("res"), Active: true, Type: 1, Pss: &m.ResourcePss{ Type: data.Type, Live: data.Live, Quota: data.Quota, Expire: common.LocalDateTime(time.Now().Add(time.Duration(data.Expire) * time.Second)), DailyLimit: data.DailyLimit, }, } err = q.Resource.Create(resource) if err != nil { return nil, err } // 更新用户余额 user.Balance -= amount _, err = q.User. Where(q.User.ID.Eq(uid)). Update(q.User.Balance, user.Balance) if err != nil { return nil, err } return resource, nil } func (s *resourceService) CancelResource(ctx context.Context, tradeNo string, at time.Time) error { // 获取请求缓存 _, err := rds.Client.Del(ctx, tradeNo).Result() if err != nil { return err } // 更新订单状态 _, err = q.Trade. Where(q.Trade.InnerNo.Eq(tradeNo)). Select(q.Trade.Status, q.Trade.CancelAt). Updates(m.Trade{ Status: 2, CancelAt: common.LocalDateTime(at), }) if err != nil { return err } return nil }