go-platform/controllers/platform_home.go
2026-05-05 18:31:29 +08:00

256 lines
6.2 KiB
Go
Raw Permalink 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 controllers
import (
"fmt"
"strconv"
"strings"
"time"
"server/models"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// PlatformHomeController 平台首页统计(需登录)
type PlatformHomeController struct {
beego.Controller
}
func cellToDateKey(v interface{}) string {
if v == nil {
return ""
}
switch x := v.(type) {
case []byte:
s := strings.TrimSpace(string(x))
if len(s) >= 10 {
return s[:10]
}
return s
case string:
s := strings.TrimSpace(x)
if len(s) >= 10 {
return s[:10]
}
return s
case time.Time:
if x.IsZero() {
return ""
}
return x.In(time.Local).Format("2006-01-02")
default:
s := strings.TrimSpace(fmt.Sprint(x))
if len(s) >= 10 {
return s[:10]
}
return s
}
}
func cellToInt64(v interface{}) int64 {
if v == nil {
return 0
}
switch x := v.(type) {
case []byte:
n, _ := strconv.ParseInt(strings.TrimSpace(string(x)), 10, 64)
return n
case int64:
return x
case int32:
return int64(x)
case int:
return int64(x)
default:
n, _ := strconv.ParseInt(strings.TrimSpace(fmt.Sprint(x)), 10, 64)
return n
}
}
func queryExtractedCountByDay(table string, start, endExclusive time.Time) (map[string]int64, error) {
// 不按 delete_time 过滤:部分库未删除行存 0000-00-00 或非 NULL会导致统计全空。
// Raw + QueryRows 对别名映射不稳定,改用 Values 解析 d/c。
sql := fmt.Sprintf(`
SELECT DATE(extracted_time) AS d, COUNT(*) AS c
FROM %s
WHERE is_extracted IN (1, 2)
AND extracted_time IS NOT NULL
AND extracted_time >= ?
AND extracted_time < ?
GROUP BY DATE(extracted_time)
ORDER BY d
`, table)
var maps []orm.Params
_, err := models.Orm.Raw(sql, start, endExclusive).Values(&maps)
if err != nil {
return nil, err
}
out := make(map[string]int64, len(maps))
for _, m := range maps {
var dk, ck interface{}
for _, k := range []string{"d", "D"} {
if v, ok := m[k]; ok {
dk = v
break
}
}
for _, k := range []string{"c", "C"} {
if v, ok := m[k]; ok {
ck = v
break
}
}
key := cellToDateKey(dk)
if key == "" {
continue
}
out[key] = cellToInt64(ck)
}
return out, nil
}
// AccountPoolDailyExtract GET /platform/home/accountPoolDailyExtract?days=14
// 按天统计各号池「已提取」数量,依据 extracted_time 落在当天的记录。
func (c *PlatformHomeController) AccountPoolDailyExtract() {
if _, err := requirePlatformAuth(&c.Controller); err != nil {
poolJSONErr(&c.Controller, 401, 401, err.Error())
return
}
n, _ := c.GetInt("days", 14)
if n < 1 {
n = 1
}
if n > 90 {
n = 90
}
now := time.Now().In(time.Local)
today0 := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
firstDay := today0.AddDate(0, 0, -(n - 1))
endExclusive := today0.AddDate(0, 0, 1)
cursorTable := (&models.PlatformAccountPoolCursor{}).TableName()
windsurfTable := (&models.PlatformAccountPoolWindsurf{}).TableName()
kiroTable := (&models.PlatformAccountPoolKiro{}).TableName()
mCursor, err := queryExtractedCountByDay(cursorTable, firstDay, endExclusive)
if err != nil {
poolJSONErr(&c.Controller, 500, 500, "统计 Cursor 失败: "+err.Error())
return
}
mWindsurf, err := queryExtractedCountByDay(windsurfTable, firstDay, endExclusive)
if err != nil {
poolJSONErr(&c.Controller, 500, 500, "统计 Windsurf 失败: "+err.Error())
return
}
mKiro, err := queryExtractedCountByDay(kiroTable, firstDay, endExclusive)
if err != nil {
poolJSONErr(&c.Controller, 500, 500, "统计 Kiro 失败: "+err.Error())
return
}
dayKeys := make([]string, 0, n)
dayLabels := make([]string, 0, n)
cursorVals := make([]int64, 0, n)
windsurfVals := make([]int64, 0, n)
kiroVals := make([]int64, 0, n)
for i := 0; i < n; i++ {
d := firstDay.AddDate(0, 0, i)
key := d.Format("2006-01-02")
dayKeys = append(dayKeys, key)
dayLabels = append(dayLabels, d.Format("01/02"))
cursorVals = append(cursorVals, mCursor[key])
windsurfVals = append(windsurfVals, mWindsurf[key])
kiroVals = append(kiroVals, mKiro[key])
}
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{
"days": dayLabels,
"dayKeys": dayKeys,
"cursor": int64SliceToInt(cursorVals),
"windsurf": int64SliceToInt(windsurfVals),
"kiro": int64SliceToInt(kiroVals),
"daysLength": n,
},
}
_ = c.ServeJSON()
}
func int64SliceToInt(in []int64) []int {
out := make([]int, len(in))
for i, v := range in {
out[i] = int(v)
}
return out
}
func countPoolInventory(mi interface{}, soldOnly bool) (int64, error) {
qs := models.Orm.QueryTable(mi).Filter("delete_time__isnull", true)
if soldOnly {
qs = qs.Filter("is_extracted__in", 1, 2)
}
n, err := qs.Count()
return n, err
}
// AccountPoolInventoryTotals GET /platform/home/accountPoolInventoryTotals
// 各号池账号总数未删、已售卖is_extracted 为 1 或 2
func (c *PlatformHomeController) AccountPoolInventoryTotals() {
if _, err := requirePlatformAuth(&c.Controller); err != nil {
poolJSONErr(&c.Controller, 401, 401, err.Error())
return
}
type invModule struct {
Key string `json:"key"`
Label string `json:"label"`
Total int64 `json:"total"`
Sold int64 `json:"sold"`
}
modules := []invModule{
{Key: "cursor", Label: "Cursor"},
{Key: "krio", Label: "Kiro"},
{Key: "windsurf", Label: "Windsurf"},
}
modelsList := []interface{}{
new(models.PlatformAccountPoolCursor),
new(models.PlatformAccountPoolKiro),
new(models.PlatformAccountPoolWindsurf),
}
var grandTotal, grandSold int64
for i := range modules {
tot, err := countPoolInventory(modelsList[i], false)
if err != nil {
poolJSONErr(&c.Controller, 500, 500, "统计失败: "+err.Error())
return
}
sd, err := countPoolInventory(modelsList[i], true)
if err != nil {
poolJSONErr(&c.Controller, 500, 500, "统计失败: "+err.Error())
return
}
modules[i].Total = tot
modules[i].Sold = sd
grandTotal += tot
grandSold += sd
}
c.Data["json"] = map[string]interface{}{
"code": 200,
"msg": "success",
"data": map[string]interface{}{
"modules": modules,
"grandTotal": grandTotal,
"grandSold": grandSold,
},
}
_ = c.ServeJSON()
}