feat(platform): filter vehicle rows by service status

This commit is contained in:
lingniu
2026-07-04 02:26:39 +08:00
parent cbd02956ff
commit e7de41894b
4 changed files with 50 additions and 3 deletions

View File

@@ -49,6 +49,22 @@ func TestHandlerVehicles(t *testing.T) {
}
}
func TestHandlerVehiclesFiltersServiceStatus(t *testing.T) {
handler := NewHandler(NewService(NewMockStore()))
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/vehicles?limit=10&serviceStatus=degraded", nil)
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d body=%s", rec.Code, rec.Body.String())
}
if !strings.Contains(rec.Body.String(), "LB9A32A24R0LS1426") {
t.Fatalf("degraded vehicles should include partially online vehicle: %s", rec.Body.String())
}
if strings.Contains(rec.Body.String(), "LMRKH9AC2R1004087") {
t.Fatalf("degraded vehicles should exclude healthy vehicle: %s", rec.Body.String())
}
}
func TestHandlerVehicleCoverage(t *testing.T) {
handler := NewHandler(NewService(NewMockStore()))
rec := httptest.NewRecorder()

View File

@@ -61,10 +61,14 @@ func (m *MockStore) DashboardSummary(context.Context) (DashboardSummary, error)
func (m *MockStore) Vehicles(_ context.Context, query url.Values) (Page[VehicleRow], error) {
items := filterVehicles(m.vehicles, query)
for index := range items {
items[index].ServiceStatus = m.vehicleRowServiceStatus(items[index])
enriched := make([]VehicleRow, 0, len(items))
for _, item := range items {
item.ServiceStatus = m.vehicleRowServiceStatus(item)
if keepServiceStatus(item.ServiceStatus, query.Get("serviceStatus")) {
enriched = append(enriched, item)
}
}
return page(items, query), nil
return page(enriched, query), nil
}
func (m *MockStore) vehicleRowServiceStatus(row VehicleRow) *VehicleServiceStatus {

View File

@@ -27,6 +27,16 @@ func buildVehicleListSQL(query url.Values) SQLQuery {
where = append(where, "s.protocol = ?")
args = append(args, protocol)
}
switch strings.TrimSpace(query.Get("serviceStatus")) {
case "identity_required":
where = append(where, "(b.vin IS NULL OR b.vin = '')")
case "offline":
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "COALESCE(vs.source_count, 0) > 0", "COALESCE(vs.online_source_count, 0) = 0")
case "degraded":
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "vs.source_count > 0", "vs.online_source_count > 0", "vs.online_source_count < vs.source_count")
case "healthy":
where = append(where, "b.vin IS NOT NULL", "b.vin <> ''", "vs.source_count > 0", "vs.online_source_count = vs.source_count")
}
countArgs := append([]any(nil), args...)
args = append(args, limit, offset)
fromSQL := `FROM vehicle_realtime_snapshot s ` +

View File

@@ -26,6 +26,23 @@ func TestBuildVehicleListSQL(t *testing.T) {
}
}
func TestBuildVehicleListSQLFiltersServiceStatus(t *testing.T) {
query := url.Values{"serviceStatus": {"degraded"}, "limit": {"8"}}
built := buildVehicleListSQL(query)
for _, want := range []string{
"vs.source_count > 0",
"vs.online_source_count > 0",
"vs.online_source_count < vs.source_count",
} {
if !strings.Contains(built.Text, want) {
t.Fatalf("SQL missing vehicle list service status predicate %q: %s", want, built.Text)
}
}
if !strings.Contains(built.CountText, "vs.source_count > 0") || !strings.Contains(built.CountText, "vs.online_source_count < vs.source_count") {
t.Fatalf("count SQL should include vehicle list service status predicate: %s", built.CountText)
}
}
func TestBuildVehicleCoverageSQL(t *testing.T) {
query := url.Values{"keyword": {"粤A"}, "protocol": {"GB32960"}, "coverage": {"multi"}, "online": {"online"}, "bindingStatus": {"bound"}, "limit": {"8"}, "offset": {"16"}}
built := buildVehicleCoverageSQL(query)