Files
soul-yongping/soul-api/internal/handler/admin_track.go
卡若 76965adb23 chore: 清理敏感与开发文档,仅同步代码
- 永久忽略并从仓库移除 开发文档/
- 移除并忽略 .env 与小程序私有配置
- 同步小程序/管理端/API与脚本改动

Made-with: Cursor
2026-03-17 17:50:12 +08:00

103 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
})
}