基本功能复刻完成
All checks were successful
build / build (api, amd64, linux) (push) Successful in -47s
build / build (api, arm64, linux) (push) Successful in -47s
build / build (api.exe, amd64, windows) (push) Successful in -48s

This commit is contained in:
CN-JS-HuiBai
2026-04-17 12:24:00 +08:00
parent 06da23fbbc
commit 981ee4f406
37 changed files with 11737 additions and 770 deletions

View File

@@ -0,0 +1,169 @@
package handler
import (
"fmt"
"strconv"
"time"
"xboard-go/internal/database"
"xboard-go/internal/model"
"github.com/gin-gonic/gin"
)
// AdminGetTrafficRank returns traffic ranking for nodes or users.
func AdminGetTrafficRank(c *gin.Context) {
rankType := c.Query("type") // node or user
startTimeStr := c.Query("start_time")
endTimeStr := c.Query("end_time")
startTime, _ := strconv.ParseInt(startTimeStr, 10, 64)
endTime, _ := strconv.ParseInt(endTimeStr, 10, 64)
if startTime == 0 {
startTime = time.Now().AddDate(0, 0, -7).Unix()
}
if endTime == 0 {
endTime = time.Now().Unix()
}
var result []gin.H
if rankType == "user" {
type userRank struct {
ID int `json:"id"`
Value int64 `json:"value"`
Email string `json:"name"`
}
var ranks []userRank
database.DB.Model(&model.StatUser{}).
Select("user_id as id, SUM(u + d) as value").
Where("record_at >= ? AND record_at <= ?", startTime, endTime).
Group("user_id").
Order("value DESC").
Limit(10).
Scan(&ranks)
var userIDs []int
for _, r := range ranks {
userIDs = append(userIDs, r.ID)
}
userEmails := loadUserEmailMap(userIDs)
for _, r := range ranks {
result = append(result, gin.H{
"id": fmt.Sprintf("%d", r.ID),
"name": userEmails[r.ID],
"value": r.Value,
})
}
} else {
// Default to node
type nodeRank struct {
ID int `json:"id"`
Value int64 `json:"value"`
Name string `json:"name"`
}
var ranks []nodeRank
database.DB.Model(&model.StatServer{}).
Select("server_id as id, SUM(u + d) as value").
Where("record_at >= ? AND record_at <= ?", startTime, endTime).
Group("server_id").
Order("value DESC").
Limit(10).
Scan(&ranks)
var nodeIDs []int
for _, r := range ranks {
nodeIDs = append(nodeIDs, r.ID)
}
nodeNames := loadNodeNameMap(nodeIDs)
for _, r := range ranks {
result = append(result, gin.H{
"id": fmt.Sprintf("%d", r.ID),
"name": nodeNames[r.ID],
"value": r.Value,
})
}
}
Success(c, result)
}
// AdminGetOrderStats returns order-related statistics for charts.
func AdminGetOrderStats(c *gin.Context) {
startDateStr := c.Query("start_date")
endDateStr := c.Query("end_date")
statType := c.Query("type") // paid_total, paid_count, etc.
var startDate int64
var endDate int64
if startDateStr != "" {
t, _ := time.Parse("2006-01-02", startDateStr)
startDate = t.Unix()
} else {
startDate = time.Now().AddDate(0, 0, -30).Truncate(24 * time.Hour).Unix()
}
if endDateStr != "" {
t, _ := time.Parse("2006-01-02", endDateStr)
endDate = t.Unix() + 86399
} else {
endDate = time.Now().Unix()
}
var stats []model.Stat
database.DB.Where("record_at >= ? AND record_at <= ? AND record_type = ?", startDate, endDate, "d").
Order("record_at ASC").
Find(&stats)
var list []gin.H
for _, s := range stats {
dateStr := time.Unix(s.RecordAt, 0).Format("2006-01-02")
item := gin.H{
"date": dateStr,
}
if statType != "" {
item["value"] = getStatFieldValue(s, statType)
} else {
item["paid_total"] = s.PaidTotal
item["paid_count"] = s.PaidCount
item["commission_total"] = s.CommissionTotal
}
list = append(list, item)
}
Success(c, gin.H{
"list": list,
})
}
func loadNodeNameMap(ids []int) map[int]string {
result := make(map[int]string)
if len(ids) == 0 {
return result
}
var servers []model.Server
database.DB.Select("id", "name").Where("id IN ?", ids).Find(&servers)
for _, s := range servers {
result[s.ID] = s.Name
}
return result
}
func getStatFieldValue(s model.Stat, field string) any {
switch field {
case "paid_total":
return s.PaidTotal
case "paid_count":
return s.PaidCount
case "commission_total":
return s.CommissionTotal
case "commission_count":
return s.CommissionCount
case "register_count":
return s.RegisterCount
default:
return 0
}
}