package developer import ( "fmt" "strconv" "time" "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" "verification-platform-backend/pkg/response" "github.com/gin-gonic/gin" ) func SetupOrderRoutes(r *gin.RouterGroup) { r.GET("/orders", handleGetOrders) r.GET("/orders/:id", handleGetOrder) r.POST("/orders/:id/refund", handleRefundOrder) r.GET("/orders/stats", handleGetOrderStats) } func handleGetOrders(c *gin.Context) { userID := c.GetUint("user_id") page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) orderType := c.Query("order_type") status := c.Query("status") applicationID := c.Query("application_id") search := c.Query("search") startDate := c.Query("start_date") endDate := c.Query("end_date") var orders []model.Order var total int64 query := database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID) if orderType != "" { query = query.Where("orders.order_type = ?", orderType) } if status != "" { query = query.Where("orders.status = ?", status) } if applicationID != "" && applicationID != "all" { query = query.Where("orders.application_id = ?", applicationID) } if search != "" { query = query.Where("orders.order_no LIKE ? OR orders.title LIKE ?", "%"+search+"%", "%"+search+"%") } if startDate != "" { query = query.Where("orders.created_at >= ?", startDate+" 00:00:00") } if endDate != "" { query = query.Where("orders.created_at <= ?", endDate+" 23:59:59") } query.Count(&total) offset := (page - 1) * pageSize if err := query.Preload("User").Preload("Application"). Order("orders.created_at DESC"). Offset(offset).Limit(pageSize). Find(&orders).Error; err != nil { response.Error(c, 500, "获取订单列表失败") return } response.Success(c, gin.H{ "orders": orders, "total": total, "page": page, "page_size": pageSize, "total_page": (total + int64(pageSize) - 1) / int64(pageSize), }) } func handleGetOrder(c *gin.Context) { userID := c.GetUint("user_id") orderID := c.Param("id") var order model.Order if err := database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("orders.id = ? AND (applications.user_id = ? OR orders.application_id IS NULL)", orderID, userID). Preload("User").Preload("Application"). First(&order).Error; err != nil { response.Error(c, 404, "订单不存在") return } response.Success(c, order) } func handleRefundOrder(c *gin.Context) { userID := c.GetUint("user_id") orderID := c.Param("id") var req struct { Reason string `json:"reason" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误: "+err.Error()) return } var order model.Order if err := database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("orders.id = ? AND (applications.user_id = ? OR orders.application_id IS NULL)", orderID, userID). First(&order).Error; err != nil { response.Error(c, 404, "订单不存在") return } if order.Status != "paid" { response.Error(c, 400, "只能退款已支付的订单") return } tx := database.DB.Begin() now := time.Now() order.Status = "refunded" order.RefundAt = &now order.RefundReason = req.Reason if err := tx.Save(&order).Error; err != nil { tx.Rollback() response.Error(c, 500, "退款失败") return } switch order.OrderType { case "card_recharge": var rechargeRecord model.RechargeRecord if err := tx.Where("order_no = ?", order.OrderNo).First(&rechargeRecord).Error; err == nil { rechargeRecord.Status = "refunded" tx.Save(&rechargeRecord) } } tx.Commit() response.Success(c, gin.H{ "message": "退款成功", "order": order, }) } func handleGetOrderStats(c *gin.Context) { userID := c.GetUint("user_id") applicationID := c.Query("application_id") startDate := c.Query("start_date") endDate := c.Query("end_date") query := database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID) if applicationID != "" && applicationID != "all" { query = query.Where("orders.application_id = ?", applicationID) } if startDate != "" { query = query.Where("orders.created_at >= ?", startDate+" 00:00:00") } if endDate != "" { query = query.Where("orders.created_at <= ?", endDate+" 23:59:59") } var totalOrders, pendingOrders, paidOrders, refundedOrders int64 var totalAmount, paidAmount, refundedAmount float64 query.Count(&totalOrders) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status = ?", "pending"). Count(&pendingOrders) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status = ?", "paid"). Count(&paidOrders) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status = ?", "refunded"). Count(&refundedOrders) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status IN ?", []string{"paid", "refunded"}). Select("COALESCE(SUM(amount), 0)"). Scan(&totalAmount) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status = ?", "paid"). Select("COALESCE(SUM(amount), 0)"). Scan(&paidAmount) database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Where("orders.status = ?", "refunded"). Select("COALESCE(SUM(amount), 0)"). Scan(&refundedAmount) var typeStats []struct { OrderType string Count int64 TotalAmount float64 } database.DB.Model(&model.Order{}). Joins("LEFT JOIN applications ON orders.application_id = applications.id"). Where("applications.user_id = ? OR orders.application_id IS NULL", userID). Select("order_type, COUNT(*) as count, COALESCE(SUM(amount), 0) as total_amount"). Group("order_type"). Scan(&typeStats) response.Success(c, gin.H{ "total_orders": totalOrders, "pending_orders": pendingOrders, "paid_orders": paidOrders, "refunded_orders": refundedOrders, "total_amount": totalAmount, "paid_amount": paidAmount, "refunded_amount": refundedAmount, "type_stats": typeStats, }) } func CreateOrder(orderType string, userID uint, applicationID *uint, title string, amount float64, paymentType string, description string) (*model.Order, error) { orderNo := fmt.Sprintf("ORD%d%d", time.Now().Unix(), userID) order := model.Order{ OrderNo: orderNo, UserID: userID, ApplicationID: applicationID, OrderType: orderType, Title: title, Amount: amount, PaymentType: paymentType, Status: "pending", Description: description, } if err := database.DB.Create(&order).Error; err != nil { return nil, err } return &order, nil } func PayOrder(orderNo string) error { var order model.Order if err := database.DB.Where("order_no = ?", orderNo).First(&order).Error; err != nil { return err } now := time.Now() order.Status = "paid" order.PaymentAt = &now return database.DB.Save(&order).Error }