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