package handler import ( "encoding/json" "net/http" "time" "soul-api/internal/database" "github.com/gin-gonic/gin" ) // AdminTrackStats GET /api/admin/track/stats 管理端-按钮/标签点击统计(按模块+action聚合) func AdminTrackStats(c *gin.Context) { period := c.DefaultQuery("period", "today") db := database.DB() now := time.Now() var since time.Time switch period { case "today": since = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) case "week": since = now.AddDate(0, 0, -7) case "month": since = now.AddDate(0, -1, 0) default: since = time.Time{} } type rawRow struct { Action string `gorm:"column:action"` Target string `gorm:"column:target"` ExtraData []byte `gorm:"column:extra_data"` } query := db.Table("user_tracks").Select("action, COALESCE(target, '') as target, extra_data") if !since.IsZero() { query = query.Where("created_at >= ?", since) } query = query.Where("action NOT LIKE '%union%' AND action NOT LIKE '%jndi%' AND action NOT LIKE '%SLEEP%'") var rawRows []rawRow query.Find(&rawRows) type statKey struct { Module string Action string Target string } type statItem struct { Action string `json:"action"` Target string `json:"target"` Module string `json:"module"` Page string `json:"page"` Count int64 `json:"count"` } aggregated := make(map[statKey]*statItem) total := int64(0) for _, r := range rawRows { module := "other" page := "" if len(r.ExtraData) > 0 { var extra map[string]interface{} if json.Unmarshal(r.ExtraData, &extra) == nil { if m, ok := extra["module"].(string); ok && m != "" { module = m } if p, ok := extra["page"].(string); ok && p != "" { page = p } } } key := statKey{Module: module, Action: r.Action, Target: r.Target} if existing, ok := aggregated[key]; ok { existing.Count++ } else { aggregated[key] = &statItem{ Action: r.Action, Target: r.Target, Module: module, Page: page, Count: 1, } } total++ } byModule := make(map[string][]statItem) for _, item := range aggregated { byModule[item.Module] = append(byModule[item.Module], *item) } c.JSON(http.StatusOK, gin.H{ "success": true, "period": period, "total": total, "byModule": byModule, }) }