package admin import ( "strconv" "time" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "go.uber.org/zap" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" rechargeOrderSvc "github.com/break/junhong_cmp_fiber/internal/service/recharge_order" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" ) // AdminRechargeOrderHandler 后台充值订单 Handler type AdminRechargeOrderHandler struct { service *rechargeOrderSvc.Service validator *validator.Validate logger *zap.Logger } // NewAdminRechargeOrderHandler 创建后台充值订单 Handler func NewAdminRechargeOrderHandler(service *rechargeOrderSvc.Service, validator *validator.Validate, logger *zap.Logger) *AdminRechargeOrderHandler { return &AdminRechargeOrderHandler{service: service, validator: validator, logger: logger} } // List 后台充值订单列表 // GET /api/admin/recharge-orders func (h *AdminRechargeOrderHandler) List(c *fiber.Ctx) error { var req dto.AdminRechargeOrderListRequest if err := c.QueryParser(&req); err != nil { return errors.New(errors.CodeInvalidParam, "请求参数解析失败") } if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 { req.PageSize = constants.DefaultPageSize } if req.PageSize > constants.MaxPageSize { req.PageSize = constants.MaxPageSize } params := &postgres.ListRechargeOrderParams{ Page: req.Page, PageSize: req.PageSize, Status: req.Status, } if req.ResourceType != "" && req.ResourceID != nil { params.ResourceType = &req.ResourceType params.ResourceID = req.ResourceID } if req.StartTime != "" { t, err := time.Parse(time.RFC3339, req.StartTime) if err == nil { params.StartTime = t } } if req.EndTime != "" { t, err := time.Parse(time.RFC3339, req.EndTime) if err == nil { params.EndTime = t } } orders, total, err := h.service.AdminList(c.UserContext(), params) if err != nil { return err } items := make([]dto.AdminRechargeOrderListItem, 0, len(orders)) for _, order := range orders { if order == nil { continue } items = append(items, dto.AdminRechargeOrderListItem{ ID: order.ID, RechargeOrderNo: order.RechargeOrderNo, UserID: order.UserID, ResourceType: order.ResourceType, ResourceID: order.ResourceID, Amount: order.Amount, Status: order.Status, StatusName: getAdminRechargeOrderStatusName(order.Status), AutoPurchaseStatus: order.AutoPurchaseStatus, RejectionReason: order.RejectionReason, CreatedAt: order.CreatedAt.Format(time.RFC3339), }) } return response.SuccessWithPagination(c, items, total, req.Page, req.PageSize) } // Get 后台充值订单详情 // GET /api/admin/recharge-orders/:id func (h *AdminRechargeOrderHandler) Get(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 64) if err != nil { return errors.New(errors.CodeInvalidParam, "无效的订单 ID") } order, payments, err := h.service.AdminGet(c.UserContext(), uint(id)) if err != nil { return err } var paymentDetails []dto.AdminRechargeOrderPaymentDetail for _, p := range payments { if p == nil { continue } paymentDetails = append(paymentDetails, dto.AdminRechargeOrderPaymentDetail{ PaymentID: p.ID, PaymentNo: p.PaymentNo, PaymentMethod: p.PaymentMethod, Amount: p.Amount, Status: p.Status, StatusName: getAdminPaymentStatusName(p.Status), ThirdPartyTradeNo: p.ThirdPartyTradeNo, PaidAt: formatAdminTimePtr(p.PaidAt), CreatedAt: p.CreatedAt.Format(time.RFC3339), }) } detail := &dto.AdminRechargeOrderDetail{ ID: order.ID, RechargeOrderNo: order.RechargeOrderNo, UserID: order.UserID, AssetWalletID: order.AssetWalletID, ResourceType: order.ResourceType, ResourceID: order.ResourceID, Amount: order.Amount, Status: order.Status, StatusName: getAdminRechargeOrderStatusName(order.Status), AutoPurchaseStatus: order.AutoPurchaseStatus, LinkedPackageIDs: order.LinkedPackageIDs, RejectionReason: order.RejectionReason, CreatedAt: order.CreatedAt.Format(time.RFC3339), PaidAt: formatAdminTimePtr(order.PaidAt), Payments: paymentDetails, } return response.Success(c, detail) } // Reject 驳回充值订单 // POST /api/admin/recharge-orders/:id/reject func (h *AdminRechargeOrderHandler) Reject(c *fiber.Ctx) error { id, err := strconv.ParseUint(c.Params("id"), 10, 64) if err != nil { return errors.New(errors.CodeInvalidParam, "无效的订单 ID") } var req dto.AdminRechargeOrderRejectRequest if err := c.BodyParser(&req); err != nil { return errors.New(errors.CodeInvalidParam, "请求参数解析失败") } if err := h.validator.Struct(&req); err != nil { return errors.New(errors.CodeInvalidParam) } if err := h.service.Reject(c.UserContext(), uint(id), req.RejectionReason); err != nil { return err } return response.Success(c, nil) } func getAdminRechargeOrderStatusName(status int) string { switch status { case model.RechargeOrderStatusPending: return "待支付" case model.RechargeOrderStatusPaid: return "已支付" case model.RechargeOrderStatusClosed: return "已关闭" case model.RechargeOrderStatusRefunded: return "已退款" case model.RechargeOrderStatusRejected: return "已驳回" default: return "未知" } } func getAdminPaymentStatusName(status int) string { switch status { case model.PaymentRecordStatusPending: return "待支付" case model.PaymentRecordStatusPaid: return "已支付" case model.PaymentRecordStatusFailed: return "已失败" case model.PaymentRecordStatusRefunded: return "已退款" default: return "未知" } } func formatAdminTimePtr(t *time.Time) string { if t == nil { return "" } return t.Format(time.RFC3339) }