perf: 性能优化与错误修复
- 修复 N+1 查询: users/devices/agents 批量 GROUP BY 替代循环查询 - 添加分页: cards/finance/agents/devices API - Redis 初始化根据安装配置 redis.enabled 决定是否连接 - 修复 DefaultVal 解析错误: 使用 sql.NullString 处理 NULL 值 - Dashboard 优化: 替换 ECharts 世界地图为 Chart.js 环形饼图 - 适配前端 cards 页面新 API 响应格式 - 添加数据库索引优化查询性能 - 实现可配置的数据清理定时任务
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"verification-platform-backend/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserWithStatus struct {
|
||||
@@ -192,6 +193,28 @@ func handleGetUsers(c *gin.Context) {
|
||||
offlineCount := 0
|
||||
bannedCount := 0
|
||||
|
||||
userIDs := make([]uint, len(users))
|
||||
for i, u := range users {
|
||||
userIDs[i] = u.ID
|
||||
}
|
||||
|
||||
deviceCountMap := make(map[uint]int)
|
||||
if len(userIDs) > 0 {
|
||||
type DeviceCountResult struct {
|
||||
UserID uint
|
||||
Count int
|
||||
}
|
||||
var deviceCounts []DeviceCountResult
|
||||
database.DB.Model(&model.UserDevice{}).
|
||||
Select("user_id, COUNT(*) as count").
|
||||
Where("user_id IN ?", userIDs).
|
||||
Group("user_id").
|
||||
Find(&deviceCounts)
|
||||
for _, dc := range deviceCounts {
|
||||
deviceCountMap[dc.UserID] = dc.Count
|
||||
}
|
||||
}
|
||||
|
||||
usersWithStatus := make([]UserWithStatus, 0, len(users))
|
||||
for _, user := range users {
|
||||
log.Printf("[DEBUG] User ID=%d, Username=%s, LastLoginAt=%v, LastHeartbeatAt=%v", user.ID, user.Username, user.LastLoginAt, user.LastHeartbeatAt)
|
||||
@@ -214,15 +237,12 @@ func handleGetUsers(c *gin.Context) {
|
||||
bannedCount++
|
||||
}
|
||||
|
||||
var deviceCount int64
|
||||
database.DB.Model(&model.UserDevice{}).Where("user_id = ?", user.ID).Count(&deviceCount)
|
||||
|
||||
log.Printf("[DEBUG] 用户 %s (ID=%d) 余额: %f", user.Username, user.ID, user.Balance)
|
||||
|
||||
usersWithStatus = append(usersWithStatus, UserWithStatus{
|
||||
AppUser: user,
|
||||
OnlineStatus: onlineStatus,
|
||||
DeviceCount: int(deviceCount),
|
||||
DeviceCount: deviceCountMap[user.ID],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -705,22 +725,35 @@ func handleUpdateExpiry(c *gin.Context) {
|
||||
}
|
||||
} else {
|
||||
if req.Type == "recharge" {
|
||||
appUser.Balance += req.Amount
|
||||
if err := database.DB.Model(&model.AppUser{}).Where("id = ?", appUser.ID).
|
||||
Update("balance", gorm.Expr("balance + ?", req.Amount)).Error; err != nil {
|
||||
response.Error(c, 500, "充值失败")
|
||||
return
|
||||
}
|
||||
} else if req.Type == "deduct" {
|
||||
if appUser.Balance < req.Amount {
|
||||
result := database.DB.Model(&model.AppUser{}).Where("id = ? AND balance >= ?", appUser.ID, req.Amount).
|
||||
Update("balance", gorm.Expr("balance - ?", req.Amount))
|
||||
if result.Error != nil {
|
||||
response.Error(c, 500, "扣费失败")
|
||||
return
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
response.Error(c, 400, "余额不足")
|
||||
return
|
||||
}
|
||||
appUser.Balance -= req.Amount
|
||||
} else {
|
||||
response.Error(c, 400, "操作类型错误")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := database.DB.Save(&appUser).Error; err != nil {
|
||||
response.Error(c, 500, "更新失败")
|
||||
return
|
||||
if app.BillingType == "balance" {
|
||||
database.DB.Where("id = ?", appUser.ID).First(&appUser)
|
||||
} else {
|
||||
if err := database.DB.Save(&appUser).Error; err != nil {
|
||||
response.Error(c, 500, "更新失败")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
response.Success(c, appUser)
|
||||
|
||||
Reference in New Issue
Block a user