@@ -2266,6 +2266,87 @@ func (s *Service) ListUsageLogs(ctx context.Context, page int, pageSize int, fil
22662266 }, offset , limit )
22672267}
22682268
2269+ // UsageStatisticsFilter 描述管理员仪表盘的用量统计条件。
2270+ type UsageStatisticsFilter struct {
2271+ StartDate time.Time
2272+ EndDate time.Time
2273+ UserID uint
2274+ PlatformModelName string
2275+ BillingScope string
2276+ RankBy string
2277+ }
2278+
2279+ // GetUsageStatistics 查询管理员仪表盘使用的全局用量统计。
2280+ func (s * Service ) GetUsageStatistics (ctx context.Context , filter UsageStatisticsFilter ) (domainbilling.UsageStatistics , error ) {
2281+ statisticsRepo , ok := s .repo .(repository.UsageStatisticsRepository )
2282+ if ! ok {
2283+ return domainbilling.UsageStatistics {}, errors .New ("usage statistics repository unavailable" )
2284+ }
2285+
2286+ startDate := time .Date (filter .StartDate .Year (), filter .StartDate .Month (), filter .StartDate .Day (), 0 , 0 , 0 , 0 , filter .StartDate .Location ())
2287+ endDate := time .Date (filter .EndDate .Year (), filter .EndDate .Month (), filter .EndDate .Day (), 0 , 0 , 0 , 0 , filter .EndDate .Location ())
2288+ if endDate .Before (startDate ) {
2289+ return domainbilling.UsageStatistics {}, errors .New ("invalid usage statistics date range" )
2290+ }
2291+ days := int (endDate .Sub (startDate ).Hours ()/ 24 ) + 1
2292+ if days <= 0 || days > 366 {
2293+ return domainbilling.UsageStatistics {}, errors .New ("invalid usage statistics date range" )
2294+ }
2295+
2296+ granularity := "day"
2297+ if days > 90 {
2298+ granularity = "month"
2299+ }
2300+ result , err := statisticsRepo .GetUsageStatistics (ctx , repository.UsageStatisticsFilter {
2301+ StartDate : startDate ,
2302+ EndDateExclusive : endDate .AddDate (0 , 0 , 1 ),
2303+ UserID : filter .UserID ,
2304+ PlatformModelName : strings .TrimSpace (filter .PlatformModelName ),
2305+ BillingScope : strings .TrimSpace (filter .BillingScope ),
2306+ Granularity : granularity ,
2307+ RankBy : strings .TrimSpace (filter .RankBy ),
2308+ RankLimit : 10 ,
2309+ })
2310+ if err != nil {
2311+ return domainbilling.UsageStatistics {}, err
2312+ }
2313+ result .Granularity = granularity
2314+ result .Trend = fillUsageStatisticsTrend (result .Trend , startDate , endDate , granularity )
2315+ return result , nil
2316+ }
2317+
2318+ func fillUsageStatisticsTrend (
2319+ items []domainbilling.UsageStatisticsTrendPoint ,
2320+ startDate time.Time ,
2321+ endDate time.Time ,
2322+ granularity string ,
2323+ ) []domainbilling.UsageStatisticsTrendPoint {
2324+ byPeriod := make (map [string ]domainbilling.UsageStatisticsTrendPoint , len (items ))
2325+ for _ , item := range items {
2326+ byPeriod [item .PeriodStart .Format ("2006-01-02" )] = item
2327+ }
2328+
2329+ current := startDate
2330+ if granularity == "month" {
2331+ current = time .Date (startDate .Year (), startDate .Month (), 1 , 0 , 0 , 0 , 0 , startDate .Location ())
2332+ }
2333+ results := make ([]domainbilling.UsageStatisticsTrendPoint , 0 , len (items ))
2334+ for ! current .After (endDate ) {
2335+ key := current .Format ("2006-01-02" )
2336+ if item , exists := byPeriod [key ]; exists {
2337+ results = append (results , item )
2338+ } else {
2339+ results = append (results , domainbilling.UsageStatisticsTrendPoint {PeriodStart : current })
2340+ }
2341+ if granularity == "month" {
2342+ current = current .AddDate (0 , 1 , 0 )
2343+ } else {
2344+ current = current .AddDate (0 , 0 , 1 )
2345+ }
2346+ }
2347+ return results
2348+ }
2349+
22692350// ListPaymentOrders 分页查询管理员支付订单记录。
22702351func (s * Service ) ListPaymentOrders (ctx context.Context , page int , pageSize int , filter PaymentOrderListFilter ) ([]domainbilling.PaymentOrder , int64 , error ) {
22712352 offset , limit := normalizePage (page , pageSize )
0 commit comments