package dashboard import ( "time" "git.apinb.com/heqiapp/platforms/backend/api/internal/impl" "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common" "git.apinb.com/heqiapp/platforms/backend/api/internal/models" ) // MetricSlice 是仪表盘图表使用的名称/数值序列。 type MetricSlice struct { Name string `json:"name"` Value int64 `json:"value"` } // DailyMetric 是按自然日聚合的运营指标。 type DailyMetric struct { Date string `json:"date"` OrderCount int64 `json:"order_count"` OrderAmount int64 `json:"order_amount"` } // DashboardStatistics 是平台运营总览。该接口专用结构只属于 dashboard 逻辑层。 type DashboardStatistics struct { GasBasicCount int64 `json:"gas_basic_count"` DeliveryBasicCount int64 `json:"delivery_basic_count"` StaffCount int64 `json:"staff_count"` UserCount int64 `json:"user_count"` ProductCount int64 `json:"product_count"` ActiveContractCount int64 `json:"active_contract_count"` TodayOrderCount int64 `json:"today_order_count"` TodayOrderAmount int64 `json:"today_order_amount"` PendingTicketCount int64 `json:"pending_ticket_count"` PaidAmount int64 `json:"paid_amount"` OrderStatuses []MetricSlice `json:"order_statuses"` ProductStatuses []MetricSlice `json:"product_statuses"` PaymentChannels []MetricSlice `json:"payment_channels"` RecentOrders []DailyMetric `json:"recent_orders"` } type statusAggregate struct { Status int Count int64 } type channelAggregate struct { Name string Value int64 } type dailyAggregate struct { Date time.Time OrderCount int64 OrderAmount int64 } var orderStatusNames = map[int]string{ common.StatusCreated: "已创建", common.StatusOrdered: "已下单", common.StatusAssigned: "已分配", common.StatusFilling: "充装中", common.StatusReady: "已就绪", common.StatusDelivering: "配送中", common.StatusAwaitingConfirmation: "待确认", common.StatusCompleted: "已完成", common.StatusCancelled: "已取消", common.StatusException: "异常", } var productStatusNames = map[int]string{ common.StatusPending: "待处理", common.StatusInStock: "在库", common.StatusInTransit: "运输中", common.StatusInUse: "使用中", common.StatusRepairing: "维修中", common.StatusScrapped: "已报废", } // GetDashboardOverview 汇总组织、人员、资产、订单、支付及客服维度的数据。 func GetDashboardOverview() (DashboardStatistics, error) { result := DashboardStatistics{ OrderStatuses: make([]MetricSlice, 0), ProductStatuses: make([]MetricSlice, 0), PaymentChannels: make([]MetricSlice, 0), RecentOrders: make([]DailyMetric, 0), } counts := []struct { model any where string args []any out *int64 }{ {&models.GasBasic{}, "status = ?", []any{common.StatusEnable}, &result.GasBasicCount}, {&models.DeliveryBasic{}, "status = ?", []any{common.StatusEnable}, &result.DeliveryBasicCount}, {&models.StaffAccount{}, "status = ? AND work_status = ?", []any{common.StatusEnable, "on_duty"}, &result.StaffCount}, {&models.UserAccount{}, "status = ?", []any{common.StatusEnable}, &result.UserCount}, {&models.ProductInfo{}, "status = ?", []any{common.StatusEnable}, &result.ProductCount}, {&models.GasorderContract{}, "status = ? AND contract_status = ?", []any{common.StatusEnable, common.StatusActive}, &result.ActiveContractCount}, {&models.GasorderBasic{}, "status = ? AND created_at >= CURRENT_DATE", []any{common.StatusEnable}, &result.TodayOrderCount}, {&models.CsTicket{}, "status = ? AND ticket_status = ?", []any{common.StatusEnable, common.StatusOpen}, &result.PendingTicketCount}, } for _, item := range counts { if err := impl.DBService.Model(item.model).Where(item.where, item.args...).Count(item.out).Error; err != nil { return DashboardStatistics{}, err } } if err := impl.DBService.Model(&models.GasorderBasic{}). Select("COALESCE(SUM(payable_amount), 0)"). Where("status = ? AND created_at >= CURRENT_DATE", common.StatusEnable). Scan(&result.TodayOrderAmount).Error; err != nil { return DashboardStatistics{}, err } if err := impl.DBService.Model(&models.PaymentOrder{}). Select("COALESCE(SUM(amount), 0)"). Where("status = ? AND payment_status = ?", common.StatusEnable, 23). Scan(&result.PaidAmount).Error; err != nil { return DashboardStatistics{}, err } var orderStatuses []statusAggregate if err := impl.DBService.Model(&models.GasorderBasic{}). Select("order_status AS status, COUNT(*) AS count"). Where("status = ?", common.StatusEnable).Group("order_status").Scan(&orderStatuses).Error; err != nil { return DashboardStatistics{}, err } result.OrderStatuses = namedStatuses(orderStatuses, orderStatusNames) var productStatuses []statusAggregate if err := impl.DBService.Model(&models.ProductInfo{}). Select("product_status AS status, COUNT(*) AS count"). Where("status = ?", common.StatusEnable).Group("product_status").Scan(&productStatuses).Error; err != nil { return DashboardStatistics{}, err } result.ProductStatuses = namedStatuses(productStatuses, productStatusNames) if err := impl.DBService.Model(&models.PaymentOrder{}). Select("pay_channel AS name, COALESCE(SUM(amount), 0) AS value"). Where("status = ? AND payment_status = ?", common.StatusEnable, 23). Group("pay_channel").Order("value DESC").Scan(&result.PaymentChannels).Error; err != nil { return DashboardStatistics{}, err } var daily []dailyAggregate if err := impl.DBService.Model(&models.GasorderBasic{}). Select("DATE_TRUNC('day', created_at) AS date, COUNT(*) AS order_count, COALESCE(SUM(payable_amount), 0) AS order_amount"). Where("status = ? AND created_at >= CURRENT_DATE - INTERVAL '6 days'", common.StatusEnable). Group("DATE_TRUNC('day', created_at)").Order("date").Scan(&daily).Error; err != nil { return DashboardStatistics{}, err } result.RecentOrders = fillRecentDays(daily, time.Now()) return result, nil } func namedStatuses(rows []statusAggregate, names map[int]string) []MetricSlice { result := make([]MetricSlice, 0, len(rows)) for _, row := range rows { name, ok := names[row.Status] if !ok { name = "其他" } result = append(result, MetricSlice{Name: name, Value: row.Count}) } return result } func fillRecentDays(rows []dailyAggregate, now time.Time) []DailyMetric { values := make(map[string]dailyAggregate, len(rows)) for _, row := range rows { values[row.Date.Format("2006-01-02")] = row } result := make([]DailyMetric, 0, 7) for offset := -6; offset <= 0; offset++ { date := now.AddDate(0, 0, offset).Format("2006-01-02") row := values[date] result = append(result, DailyMetric{Date: date, OrderCount: row.OrderCount, OrderAmount: row.OrderAmount}) } return result }