package handlers import ( "bufio" "fmt" "log/slog" "platform/pkg/env" "platform/pkg/u" "platform/web/auth" "platform/web/core" g "platform/web/globals" m "platform/web/models" q "platform/web/queries" s "platform/web/services" "time" "github.com/gofiber/fiber/v2" "github.com/valyala/fasthttp" ) // PageTradeByAdmin 分页查询所有订单 func PageTradeByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeTradeRead) if err != nil { return err } // 解析请求参数 req := new(PageTradeByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 构建查询语句 do := q.Trade.Where() if req.UserPhone != nil { do = do.Where(q.User.As("User").Phone.Eq(*req.UserPhone)) } if req.InnerNo != nil { do = do.Where(q.Trade.InnerNo.Eq(*req.InnerNo)) } if req.OuterNo != nil { do = do.Where(q.Trade.OuterNo.Eq(*req.OuterNo)) } if req.Method != nil { do = do.Where(q.Trade.Method.Eq(*req.Method)) } if req.Platform != nil { do = do.Where(q.Trade.Platform.Eq(*req.Platform)) } if req.Status != nil { do = do.Where(q.Trade.Status.Eq(*req.Status)) } if req.CreatedAtStart != nil { time := u.DateHead(*req.CreatedAtStart) do = do.Where(q.Trade.CreatedAt.Gte(time)) } if req.CreatedAtEnd != nil { time := u.DateTail(*req.CreatedAtEnd) do = do.Where(q.Trade.CreatedAt.Lte(time)) } // 查询用户列表 list, total, err := q.Trade. Joins(q.Trade.User). Select( q.Trade.ALL, q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), ). Where(do). Order(q.Trade.CreatedAt.Desc()). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err } // 返回结果 return c.JSON(core.PageResp{ List: list, Total: int(total), Page: req.GetPage(), Size: req.GetSize(), }) } type PageTradeByAdminReq struct { core.PageReq UserPhone *string `json:"user_phone,omitempty"` InnerNo *string `json:"inner_no,omitempty"` OuterNo *string `json:"outer_no,omitempty"` Method *int `json:"method,omitempty"` Platform *int `json:"platform,omitempty"` Status *int `json:"status,omitempty"` CreatedAtStart *time.Time `json:"created_at_start,omitempty"` CreatedAtEnd *time.Time `json:"created_at_end,omitempty"` } // PageTradeOfUserByAdmin 分页查询指定用户的订单 func PageTradeOfUserByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeTradeReadOfUser) if err != nil { return err } // 解析请求参数 req := new(PageTradeOfUserByAdminReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 构建查询语句 do := q.Trade.Where(q.Trade.UserID.Eq(req.UserID)) if req.InnerNo != nil { do = do.Where(q.Trade.InnerNo.Eq(*req.InnerNo)) } if req.OuterNo != nil { do = do.Where(q.Trade.OuterNo.Eq(*req.OuterNo)) } if req.Method != nil { do = do.Where(q.Trade.Method.Eq(*req.Method)) } if req.Platform != nil { do = do.Where(q.Trade.Platform.Eq(*req.Platform)) } if req.Status != nil { do = do.Where(q.Trade.Status.Eq(*req.Status)) } if req.CreatedAtStart != nil { time := u.DateHead(*req.CreatedAtStart) do = do.Where(q.Trade.CreatedAt.Gte(time)) } if req.CreatedAtEnd != nil { time := u.DateTail(*req.CreatedAtEnd) do = do.Where(q.Trade.CreatedAt.Lte(time)) } // 查询订单列表 list, total, err := q.Trade. Joins(q.Trade.User). Select( q.Trade.ALL, q.User.As("User").Phone.As("User__phone"), q.User.As("User").Name.As("User__name"), ). Where(do). Order(q.Trade.CreatedAt.Desc()). FindByPage(req.GetOffset(), req.GetLimit()) if err != nil { return err } // 返回结果 return c.JSON(core.PageResp{ List: list, Total: int(total), Page: req.GetPage(), Size: req.GetSize(), }) } type PageTradeOfUserByAdminReq struct { core.PageReq UserID int32 `json:"user_id" validate:"required"` InnerNo *string `json:"inner_no,omitempty"` OuterNo *string `json:"outer_no,omitempty"` Method *int `json:"method,omitempty"` Platform *int `json:"platform,omitempty"` Status *int `json:"status,omitempty"` CreatedAtStart *time.Time `json:"created_at_start,omitempty"` CreatedAtEnd *time.Time `json:"created_at_end,omitempty"` } // ============================================================ // 创建订单 func TradeCreate(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } if authCtx.User.IDType == m.UserIDTypeUnverified { return core.NewBizErr("请先实名认证后再购买") } // 解析请求参数 req := new(TradeCreateReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } switch req.Type { case m.TradeTypePurchase: if req.Resource == nil { return core.NewBizErr("购买信息不能为空") } case m.TradeTypeRecharge: if req.Recharge == nil { return core.NewBizErr("充值信息不能为空") } } // 处理订单 var result *s.CreateTradeResult switch req.Type { case m.TradeTypePurchase: result, err = s.Trade.Create(authCtx.User, req.CreateTradeData, req.Resource) case m.TradeTypeRecharge: result, err = s.Trade.Create(authCtx.User, req.CreateTradeData, req.Recharge) } if err != nil { return core.NewServErr("处理购买产品信息失败", err) } return c.JSON(result) } type TradeCreateReq struct { *s.CreateTradeData Type m.TradeType `json:"type" validate:"required"` Resource *s.CreateResourceData `json:"resource,omitempty"` Recharge *s.UpdateBalanceData `json:"recharge,omitempty"` } // ============================================================ // 完成订单 func TradeComplete(c *fiber.Ctx) error { // 检查权限 authCtx, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } // 解析请求参数 var req s.TradeRef if err := g.Validator.ParseBody(c, &req); err != nil { return err } // 检查订单状态 err = s.Trade.CompleteTrade(authCtx.User, &req) if err != nil { return err } return c.SendStatus(fiber.StatusNoContent) } // 管理员完成订单 func TradeCompleteByAdmin(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitAdmin(core.ScopeTradeWriteComplete) if err != nil { return err } // 解析请求参数 var req struct { s.TradeRef UserID int32 `json:"user_id" validate:"required"` } if err := g.Validator.ParseBody(c, &req); err != nil { return err } // 获取用户信息 user, err := s.User.Get(q.Q, req.UserID) if err != nil { return err } // 完成订单 err = s.Trade.CompleteTrade(user, &req.TradeRef) if err != nil { return err } return c.SendStatus(fiber.StatusNoContent) } // ============================================================ // 取消订单 func TradeCancel(c *fiber.Ctx) error { // 检查权限 _, err := auth.GetAuthCtx(c).PermitUser() if err != nil { return err } // 解析请求参数 req := new(TradeCancelReq) if err := g.Validator.ParseBody(c, req); err != nil { return err } // 取消交易 err = s.Trade.CancelTrade(&req.TradeRef) if err != nil { slog.Error("取消交易失败", "trade_no", req.TradeNo, "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "取消交易失败"}) } return c.SendStatus(fiber.StatusNoContent) } type TradeCancelReq struct { s.TradeRef } // ============================================================ // 检查订单 func TradeCheck(c *fiber.Ctx) error { // 检查权限:sse 接口暂时不检查权限 // 解析请求参数 req := new(TradeCheckReq) if err := g.Validator.ParseQuery(c, req); err != nil { return err } c.Set(fiber.HeaderContentType, "text/event-stream") c.Set(fiber.HeaderCacheControl, "no-cache") c.Set(fiber.HeaderConnection, "keep-alive") c.Set(fiber.HeaderTransferEncoding, "chunked") c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) { expire := env.TradeExpire interval := 5 for range expire / interval { // 检查订单状态 result, err := s.Trade.CheckTrade(&req.TradeRef) if err != nil { slog.Error("检查订单状态失败", "trade_no", req.TradeNo, "error", err) return } // 写入订单状态 _, err = fmt.Fprintf(w, "data: %d\n\n", result.Status) if err != nil { slog.Error("写入订单状态失败", "trade_no", req.TradeNo, "error", err) return } err = w.Flush() if err != nil { return } // 当订单离开支付状态后结束查询 if result.Status != m.TradeStatusPending { return } time.Sleep(time.Duration(interval) * time.Second) } })) return nil } type TradeCheckReq struct { s.TradeRef }