package logic import ( "context" "fmt" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service" "time" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) type sHome struct{} func NewHome() *sHome { return &sHome{} } func init() { service.RegisterHome(NewHome()) } func (s *sHome) GetCardStatistics(ctx context.Context) (stats *model.CardStatistics, err error) { stats = new(model.CardStatistics) deptId := contexts.GetDeptId(ctx) table := dao.TSimCardInfo.Table() // 1. TotalCount - 卡总数 totalCount, err := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Count() if err != nil { return nil, err } stats.TotalCount = int64(totalCount) // 正确的日期处理:先转为本月1号,再加1个月,彻底规避月底溢出 Bug now := gtime.Now() monthStartStr := now.Format("Y-m-01 00:00:00") monthEndStr := now.AddDate(0, 1, 0).Format("Y-m-01 00:00:00") // 2. MonthlyNewCount - 本月新增 monthlyNewCount, err := g.DB().Model(table).Ctx(ctx). Where("dept_id", deptId). Where("boss_activate_at >= ?", monthStartStr). Where("boss_activate_at < ?", monthEndStr). Count() if err != nil { return nil, err } stats.MonthlyNewCount = int64(monthlyNewCount) // 3. MonthlyFlowUsage - 本月流量使用 var flowResult struct { Total float64 } err = g.DB().Model(table).Ctx(ctx). Fields("IFNULL(SUM(used_flow_mb), 0) as total"). Where("dept_id", deptId). Scan(&flowResult) if err != nil { return nil, err } stats.MonthlyFlowUsage = int64(flowResult.Total) // 4. MonthlyActiveCount - 本月活跃卡数 monthlyActiveCount, err := g.DB().Model(table).Ctx(ctx). Where("dept_id", deptId). Where("used_flow_mb > 0"). Count() if err != nil { return nil, err } stats.MonthlyActiveCount = int64(monthlyActiveCount) return stats, nil } // GetCardStatusStatistics 获取卡状态统计 func (s *sHome) GetCardStatusStatistics(ctx context.Context) (stats *model.CardStatusStatistics, err error) { stats = new(model.CardStatusStatistics) deptId := contexts.GetDeptId(ctx) table := dao.TSimCardInfo.Table() // 卡状态统计 // 待激活(1) pendingActivationCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 1).Count() stats.PendingActivationCount = int64(pendingActivationCount) // 已激活(2) activatedCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 2).Count() stats.ActivatedCount = int64(activatedCount) // 停机(4) stoppedCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 4).Count() stats.StoppedCount = int64(stoppedCount) // 可测试(6) testableCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 6).Count() stats.TestableCount = int64(testableCount) // 库存(7) inventoryCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 7).Count() stats.InventoryCount = int64(inventoryCount) // 预销户(8) preCancelCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 8).Count() stats.PreCancelCount = int64(preCancelCount) // 已销户(9) canceledCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 9).Count() stats.CanceledCount = int64(canceledCount) // 未知(0) unknownCount, _ := g.DB().Model(table).Ctx(ctx).Where("dept_id", deptId).Where("boss_card_status", 0).Count() stats.UnknownCount = int64(unknownCount) return stats, nil } // GetDeptFlowUsageChart 获取部门流量使用图表数据,用于折线图展示 // period: 7d 前7天, 1m 前6个月 func (s *sHome) GetDeptFlowUsageChart(ctx context.Context, period string) (*model.FlowUsageChartData, error) { deptId := contexts.GetDeptId(ctx) table := dao.TDeptFlowDaily.Table() // 使用标准库 time 获取当前时间 now := time.Now() var ( startDateStr string endDateStr string groupBy string // SQL 分组字段 labels = make([]string, 0) values = make([]int64, 0) ) switch period { case "7d": // 前7天:包含今天在内的过去7天 startDateStr = now.AddDate(0, 0, -6).Format("2006-01-02") endDateStr = now.Format("2006-01-02") groupBy = "stat_date" // 按天分组 case "1m": // 前6个月:从6个月前的1号开始,方便按月对齐 startDateStr = now.AddDate(0, -5, 0).Format("2006-01-01") endDateStr = now.Format("2006-01-02") // 使用 MySQL 的 DATE_FORMAT 函数按月聚合 groupBy = "DATE_FORMAT(stat_date, '%Y-%m')" default: // 默认当月(按天) startDateStr = now.Format("2006-01-01") endDateStr = now.Format("2006-01-02") groupBy = "stat_date" } // 1. 从数据库查询聚合数据 var list []struct { TimeKey string `json:"time_key"` UsedFlowMb int64 `json:"used_flow_mb"` } fields := fmt.Sprintf("%s as time_key, IFNULL(SUM(total_used_flow_mb), 0) as used_flow_mb", groupBy) err := g.DB().Model(table).Ctx(ctx). Fields(fields). Where("dept_id", deptId). Where("stat_date >= ? AND stat_date <= ?", startDateStr, endDateStr). Group(groupBy). Order("time_key ASC"). Scan(&list) if err != nil { return nil, err } // 2. 将查询结果转换为 Map,方便 O(1) 复杂度查找 dataMap := make(map[string]int64) for _, item := range list { dataMap[item.TimeKey] = item.UsedFlowMb } // 3. 核心:将字符串转回标准 time.Time 对象,用来做连续日期循环 startTime, _ := time.Parse("2006-01-02", startDateStr) endTime, _ := time.Parse("2006-01-02", endDateStr) if period == "1m" { // 【6个月模式】:按月循环 for t := startTime; !t.After(endTime); t = t.AddDate(0, 1, 0) { // 匹配数据库返回的 key 格式 "2026-06" mapKey := t.Format("2006-01") // 放入返回的 Labels 数组 (格式要求:2026-06) labels = append(labels, mapKey) // 提取数据或补 0 if val, exists := dataMap[mapKey]; exists { values = append(values, val) } else { values = append(values, 0) } } } else { // 【7天/默认模式】:按天循环 for t := startTime; !t.After(endTime); t = t.AddDate(0, 0, 1) { // 匹配数据库返回的 key 格式 "2026-06-25" mapKey := t.Format("2006-01-02") // 放入返回的 Labels 数组 (格式要求:06-25) labels = append(labels, t.Format("01-02")) // 提取数据或补 0 if val, exists := dataMap[mapKey]; exists { values = append(values, val) } else { values = append(values, 0) } } } return &model.FlowUsageChartData{ Labels: labels, Values: values, }, nil } // GetTopUsageCardsYesterday 获取前一天流量使用前五名的卡片 func (s *sHome) GetTopUsageCardsYesterday(ctx context.Context) ([]model.TopUsageCard, error) { return service.TrafficUsage().GetTopUsageCardsYesterday(ctx) } // GetFlowPoolUsageList 获取该用户下所有流量池的流量使用情况 func (s *sHome) GetFlowPoolUsageList(ctx context.Context) ([]model.FlowPoolUsageItem, error) { deptId := contexts.GetDeptId(ctx) var pools []model.FlowPoolUsageItem err := g.DB().Model("t_sim_flow_pool"). Fields("flow_pool_code, total_flow_mb, used_flow_mb"). Where("dept_id", deptId). Where("pool_status", 0). Scan(&pools) if err != nil { return nil, err } return pools, nil }