feat(platform): add online statistics summary
This commit is contained in:
@@ -42,6 +42,7 @@ func (h *Handler) routes() {
|
||||
h.mux.HandleFunc("POST /api/history/raw-frames/query", h.handleRawFramesPost)
|
||||
h.mux.HandleFunc("GET /api/mileage/summary", h.handleMileageSummary)
|
||||
h.mux.HandleFunc("GET /api/mileage/daily", h.handleDailyMileage)
|
||||
h.mux.HandleFunc("GET /api/statistics/online-summary", h.handleOnlineStatisticsSummary)
|
||||
h.mux.HandleFunc("GET /api/quality/summary", h.handleQualitySummary)
|
||||
h.mux.HandleFunc("GET /api/quality/issues", h.handleQualityIssues)
|
||||
h.mux.HandleFunc("GET /api/quality/notification-plan", h.handleQualityNotificationPlan)
|
||||
@@ -170,6 +171,11 @@ func (h *Handler) handleMileageSummary(w http.ResponseWriter, r *http.Request) {
|
||||
h.write(w, r, data, err)
|
||||
}
|
||||
|
||||
func (h *Handler) handleOnlineStatisticsSummary(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := h.service.OnlineStatisticsSummary(r.Context(), r.URL.Query())
|
||||
h.write(w, r, data, err)
|
||||
}
|
||||
|
||||
func (h *Handler) handleQualityIssues(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := h.service.QualityIssues(r.Context(), r.URL.Query())
|
||||
h.write(w, r, data, err)
|
||||
|
||||
@@ -745,6 +745,7 @@ func TestHandlerHistoryMileageQualityOps(t *testing.T) {
|
||||
{"/api/history/raw-frames?protocol=GB32960&vin=LB9A32A24R0LS1426&limit=1&includeFields=true", "plate"},
|
||||
{"/api/mileage/summary?limit=10", "totalMileageKm"},
|
||||
{"/api/mileage/daily?limit=10", "dailyMileageKm"},
|
||||
{"/api/statistics/online-summary?limit=10", "onlineRatePercent"},
|
||||
{"/api/quality/summary?limit=10", "issueVehicleCount"},
|
||||
{"/api/quality/issues?limit=10", "sourceEndpoint"},
|
||||
{"/api/ops/health", "linkHealth"},
|
||||
@@ -894,12 +895,12 @@ func TestHandlerQualityNotificationPlan(t *testing.T) {
|
||||
|
||||
func TestHandlerOpsHealthIncludesVehicleServiceRuntime(t *testing.T) {
|
||||
handler := NewHandler(NewServiceWithRuntime(NewMockStore(), RuntimeInfo{
|
||||
RequestTimeoutMs: 1500,
|
||||
AMapWebJSConfigured: true,
|
||||
AMapSecurityProxyEnabled: true,
|
||||
AMapSecurityCodeExposed: false,
|
||||
AMapSecurityServiceHost: "/_AMapService",
|
||||
PlatformRelease: "platform-20260704153005",
|
||||
RequestTimeoutMs: 1500,
|
||||
AMapWebJSConfigured: true,
|
||||
AMapSecurityProxyEnabled: true,
|
||||
AMapSecurityCodeExposed: false,
|
||||
AMapSecurityServiceHost: "/_AMapService",
|
||||
PlatformRelease: "platform-20260704153005",
|
||||
}))
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/ops/health", nil)
|
||||
|
||||
@@ -265,6 +265,16 @@ type MileageSummary struct {
|
||||
AverageMileagePerVIN float64 `json:"averageMileagePerVin"`
|
||||
}
|
||||
|
||||
type OnlineStatisticsSummary struct {
|
||||
VehicleCount int `json:"vehicleCount"`
|
||||
OnlineVehicleCount int `json:"onlineVehicleCount"`
|
||||
OfflineVehicleCount int `json:"offlineVehicleCount"`
|
||||
OnlineRatePercent float64 `json:"onlineRatePercent"`
|
||||
RedisOnlineKeys *int `json:"redisOnlineKeys"`
|
||||
ProtocolStats []ProtocolStat `json:"protocolStats"`
|
||||
Evidence string `json:"evidence"`
|
||||
}
|
||||
|
||||
type QualityIssueRow struct {
|
||||
VIN string `json:"vin"`
|
||||
Plate string `json:"plate"`
|
||||
|
||||
@@ -871,6 +871,44 @@ func (s *Service) DailyMileage(ctx context.Context, query url.Values) (Page[Dail
|
||||
return s.store.DailyMileage(ctx, resolvedQuery)
|
||||
}
|
||||
|
||||
func (s *Service) OnlineStatisticsSummary(ctx context.Context, query url.Values) (OnlineStatisticsSummary, error) {
|
||||
resolvedQuery, err := s.resolveVehicleQuery(ctx, query)
|
||||
if err != nil {
|
||||
return OnlineStatisticsSummary{}, err
|
||||
}
|
||||
coverage, err := s.store.VehicleCoverageSummary(ctx, resolvedQuery)
|
||||
if err != nil {
|
||||
return OnlineStatisticsSummary{}, err
|
||||
}
|
||||
serviceSummary, err := s.store.VehicleServiceSummary(ctx)
|
||||
if err != nil {
|
||||
return OnlineStatisticsSummary{}, err
|
||||
}
|
||||
opsHealth, err := s.store.OpsHealth(ctx)
|
||||
if err != nil {
|
||||
return OnlineStatisticsSummary{}, err
|
||||
}
|
||||
total := coverage.TotalVehicles
|
||||
online := coverage.OnlineVehicles
|
||||
offline := total - online
|
||||
if offline < 0 {
|
||||
offline = 0
|
||||
}
|
||||
rate := 0.0
|
||||
if total > 0 {
|
||||
rate = float64(online) / float64(total) * 100
|
||||
}
|
||||
return OnlineStatisticsSummary{
|
||||
VehicleCount: total,
|
||||
OnlineVehicleCount: online,
|
||||
OfflineVehicleCount: offline,
|
||||
OnlineRatePercent: rate,
|
||||
RedisOnlineKeys: opsHealth.RedisOnlineKeys,
|
||||
ProtocolStats: serviceSummary.Protocols,
|
||||
Evidence: "由车辆服务覆盖汇总、实时来源状态和 Redis 在线 key 计算",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) QualitySummary(ctx context.Context, query url.Values) (QualitySummary, error) {
|
||||
return s.store.QualitySummary(ctx, query)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user