feat: 用户管理显示资格和消费金额,订单管理添加详情功能

- 用户管理: 显示资格数和消费金额,支持编辑资格
- 订单管理: 添加订单详情查看功能
- 后端: AdminGetUsers返回消费金额, AdminGetByID获取订单详情

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 18:36:19 +08:00
parent ec0a30c43d
commit ded24ddccc
6 changed files with 303 additions and 10 deletions
+44 -5
View File
@@ -376,7 +376,42 @@ func (h *AuthHandler) Install(c *gin.Context) {
func (h *AuthHandler) AdminGetUsers(c *gin.Context) {
var users []models.User
utils.DB.Select("id, username, email, role, purchase_credits, is_active, email_verified, created_at").Find(&users)
c.JSON(http.StatusOK, gin.H{"data": users})
// 计算每个用户的消费金额
type UserWithSpent struct {
ID uint `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Role string `json:"role"`
PurchaseCredits int `json:"purchase_credits"`
IsActive bool `json:"is_active"`
EmailVerified bool `json:"email_verified"`
CreatedAt time.Time `json:"created_at"`
TotalSpent float64 `json:"total_spent"`
}
result := make([]UserWithSpent, len(users))
for i, user := range users {
var totalSpent float64
utils.DB.Model(&models.Order{}).
Where("user_id = ? AND status IN ?", user.ID, []string{"completed", "shipped"}).
Select("COALESCE(SUM(total_amount), 0)").
Scan(&totalSpent)
result[i] = UserWithSpent{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Role: user.Role,
PurchaseCredits: user.PurchaseCredits,
IsActive: user.IsActive,
EmailVerified: user.EmailVerified,
CreatedAt: user.CreatedAt,
TotalSpent: totalSpent,
}
}
c.JSON(http.StatusOK, gin.H{"data": result})
}
func (h *AuthHandler) AdminUpdateUser(c *gin.Context) {
@@ -388,10 +423,11 @@ func (h *AuthHandler) AdminUpdateUser(c *gin.Context) {
}
var req struct {
Username *string `json:"username"`
Email *string `json:"email"`
Role *string `json:"role"`
IsActive *bool `json:"is_active"`
Username *string `json:"username"`
Email *string `json:"email"`
Role *string `json:"role"`
IsActive *bool `json:"is_active"`
PurchaseCredits *int `json:"purchase_credits"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
@@ -411,6 +447,9 @@ func (h *AuthHandler) AdminUpdateUser(c *gin.Context) {
if req.IsActive != nil {
updates["is_active"] = *req.IsActive
}
if req.PurchaseCredits != nil {
updates["purchase_credits"] = *req.PurchaseCredits
}
utils.DB.Model(&user).Updates(updates)
utils.DB.First(&user, id)
+14
View File
@@ -503,6 +503,20 @@ func (h *OrderHandler) AdminList(c *gin.Context) {
})
}
func (h *OrderHandler) AdminGetByID(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
var order models.Order
if err := utils.DB.Preload("OrderItems.Product").Preload("ShippingAddress").Preload("User").First(&order, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
return
}
checkOrderExpired(&order)
c.JSON(http.StatusOK, gin.H{"data": order})
}
func (h *OrderHandler) ProcessRefund(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
+1
View File
@@ -174,6 +174,7 @@ func SetupRoutes(r *gin.Engine) {
adminOrders := admin.Group("/orders")
{
adminOrders.GET("", orderHandler.AdminList)
adminOrders.GET("/:id", orderHandler.AdminGetByID)
adminOrders.GET("/export", orderHandler.Export)
adminOrders.PUT("/:id/refund", orderHandler.ProcessRefund)
}