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:
2026-05-06 19:19:02 +08:00
parent 98986b0eb7
commit 086c5c6573
27 changed files with 843 additions and 467 deletions
+87 -2
View File
@@ -16,6 +16,7 @@ import (
"verification-platform-backend/pkg/response"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func SetupRoutes(r *gin.RouterGroup) {
@@ -265,7 +266,45 @@ func handleRechargeUser(c *gin.Context) {
newExpiry := baseTime.Add(duration)
user.ExpiryAt = &newExpiry
case "balance":
user.Balance += float64(req.Amount)
tx := database.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Model(&model.AppUser{}).Where("id = ?", user.ID).
Update("balance", gorm.Expr("balance + ?", float64(req.Amount))).Error; err != nil {
tx.Rollback()
service.LogVerification(c, &app.ID, &user.ID, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 保存失败 - %s", user.Username), "", err)
response.Error(c, 500, "充值失败")
return
}
record := model.RechargeRecord{
UserID: user.ID,
OrderNo: fmt.Sprintf("EXT%d%d", time.Now().Unix(), user.ID),
Amount: float64(req.Amount),
Status: "success",
PaymentType: "extension_api",
Remark: req.Description,
}
if err := tx.Create(&record).Error; err != nil {
tx.Rollback()
response.Error(c, 500, "充值失败")
return
}
tx.Commit()
database.DB.Where("id = ?", user.ID).First(&user)
service.LogVerification(c, &app.ID, &user.ID, "extension_recharge", fmt.Sprintf("扩展API充值: 用户%s, 类型:%s, 数量:%d", user.Username, req.Type, req.Amount), "", nil)
response.Success(c, gin.H{
"message": "充值成功",
"user": user,
})
return
default:
service.LogVerification(c, &app.ID, &user.ID, "extension_recharge_failed", fmt.Sprintf("扩展API充值失败: 类型无效 - %s", req.Type), "", fmt.Errorf("充值类型无效"))
response.Error(c, 400, "充值类型无效,仅支持days或balance类型")
@@ -362,7 +401,53 @@ func handleDeductUser(c *gin.Context) {
response.Error(c, 400, "余额不足")
return
}
user.Balance -= float64(req.Amount)
tx := database.DB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
result := tx.Model(&model.AppUser{}).Where("id = ? AND balance >= ?", user.ID, float64(req.Amount)).
Update("balance", gorm.Expr("balance - ?", float64(req.Amount)))
if result.Error != nil {
tx.Rollback()
service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 保存失败 - %s", user.Username), "", result.Error)
response.Error(c, 500, "扣除失败")
return
}
if result.RowsAffected == 0 {
tx.Rollback()
response.Error(c, 400, "余额不足")
return
}
record := model.ConsumptionRecord{
UserID: user.ID,
OrderNo: fmt.Sprintf("EXT%d%d", time.Now().Unix(), user.ID),
Type: req.Type,
Amount: float64(req.Amount),
Status: "success",
PaymentType: "extension_api",
Remark: req.Description,
}
if err := tx.Create(&record).Error; err != nil {
tx.Rollback()
response.Error(c, 500, "扣除失败")
return
}
tx.Commit()
database.DB.Where("id = ?", user.ID).First(&user)
service.LogVerification(c, &app.ID, &user.ID, "extension_deduct", fmt.Sprintf("扩展API扣费: 用户%s, 类型:%s, 数量:%d", user.Username, req.Type, req.Amount), "", nil)
response.Success(c, gin.H{
"message": "扣除成功",
"user": user,
})
return
default:
service.LogVerification(c, &app.ID, &user.ID, "extension_deduct_failed", fmt.Sprintf("扩展API扣费失败: 类型无效 - %s", req.Type), "", fmt.Errorf("扣除类型无效"))
response.Error(c, 400, "扣除类型无效,仅支持days或balance类型")