From a3a91ef1f8d3fcf4a41bc33dc6d37afc67fe6709 Mon Sep 17 00:00:00 2001 From: lingniu Date: Fri, 3 Jul 2026 21:40:40 +0800 Subject: [PATCH] feat(platform): resolve vehicle detail keyword --- .../api/internal/platform/handler_test.go | 13 ++++ .../apps/api/internal/platform/service.go | 59 ++++++++++++------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/vehicle-data-platform/apps/api/internal/platform/handler_test.go b/vehicle-data-platform/apps/api/internal/platform/handler_test.go index 8b0f2339..c00135d1 100644 --- a/vehicle-data-platform/apps/api/internal/platform/handler_test.go +++ b/vehicle-data-platform/apps/api/internal/platform/handler_test.go @@ -48,6 +48,19 @@ func TestHandlerVehicleDetail(t *testing.T) { } } +func TestHandlerVehicleDetailResolvesPlateToVIN(t *testing.T) { + handler := NewHandler(NewService(NewMockStore())) + rec := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, "/api/vehicles/detail?vin=粤AG18312", 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(), `"vin":"LB9A32A24R0LS1426"`) { + t.Fatalf("response should resolve plate to VIN: %s", rec.Body.String()) + } +} + func TestHandlerRealtimeLocations(t *testing.T) { handler := NewHandler(NewService(NewMockStore())) rec := httptest.NewRecorder() diff --git a/vehicle-data-platform/apps/api/internal/platform/service.go b/vehicle-data-platform/apps/api/internal/platform/service.go index 2a5e53ca..0bc2f48a 100644 --- a/vehicle-data-platform/apps/api/internal/platform/service.go +++ b/vehicle-data-platform/apps/api/internal/platform/service.go @@ -47,22 +47,28 @@ func (s *Service) Vehicles(ctx context.Context, query url.Values) (Page[VehicleR } func (s *Service) VehicleDetail(ctx context.Context, vin string, protocol string) (VehicleDetail, error) { - vin = strings.TrimSpace(vin) + keyword := strings.TrimSpace(vin) protocol = strings.TrimSpace(protocol) - vehicleQuery := url.Values{"keyword": {vin}, "limit": {"10"}} - realtimeQuery := url.Values{"vin": {vin}, "limit": {"20"}} - historyQuery := url.Values{"vin": {vin}, "limit": {"20"}} - rawQuery := RawFrameQuery{VIN: vin, IncludeFields: true, Limit: 10} - mileageQuery := url.Values{"vin": {vin}, "limit": {"20"}} + vehicleQuery := url.Values{"keyword": {keyword}, "limit": {"10"}} + vehicles, err := s.store.Vehicles(ctx, vehicleQuery) + if err != nil { + return VehicleDetail{}, err + } + identity := resolveVehicleIdentity(keyword, vehicles.Items) + resolvedVIN := keyword + if identity != nil && strings.TrimSpace(identity.VIN) != "" { + resolvedVIN = identity.VIN + } + + realtimeQuery := url.Values{"vin": {resolvedVIN}, "limit": {"20"}} + historyQuery := url.Values{"vin": {resolvedVIN}, "limit": {"20"}} + rawQuery := RawFrameQuery{VIN: resolvedVIN, IncludeFields: true, Limit: 10} + mileageQuery := url.Values{"vin": {resolvedVIN}, "limit": {"20"}} if protocol != "" { realtimeQuery.Set("protocol", protocol) historyQuery.Set("protocol", protocol) rawQuery.Protocol = protocol } - vehicles, err := s.store.Vehicles(ctx, vehicleQuery) - if err != nil { - return VehicleDetail{}, err - } realtime, err := s.store.RealtimeLocations(ctx, realtimeQuery) if err != nil { return VehicleDetail{}, err @@ -79,18 +85,8 @@ func (s *Service) VehicleDetail(ctx context.Context, vin string, protocol string if err != nil { return VehicleDetail{}, err } - var identity *VehicleRow - for index := range vehicles.Items { - if strings.EqualFold(vehicles.Items[index].VIN, vin) { - identity = &vehicles.Items[index] - break - } - } - if identity == nil && len(vehicles.Items) > 0 { - identity = &vehicles.Items[0] - } return VehicleDetail{ - VIN: vin, + VIN: resolvedVIN, Identity: identity, Sources: vehicleSources(vehicles.Items, realtime.Items, raw.Items, mileage.Items), Realtime: realtime.Items, @@ -100,6 +96,27 @@ func (s *Service) VehicleDetail(ctx context.Context, vin string, protocol string }, nil } +func resolveVehicleIdentity(keyword string, vehicles []VehicleRow) *VehicleRow { + keyword = strings.TrimSpace(keyword) + if keyword == "" { + return nil + } + for index := range vehicles { + if strings.EqualFold(vehicles[index].VIN, keyword) { + return &vehicles[index] + } + } + for index := range vehicles { + if strings.EqualFold(vehicles[index].Plate, keyword) || strings.EqualFold(vehicles[index].Phone, keyword) { + return &vehicles[index] + } + } + if len(vehicles) > 0 { + return &vehicles[0] + } + return nil +} + func (s *Service) RealtimeLocations(ctx context.Context, query url.Values) (Page[RealtimeLocationRow], error) { return s.store.RealtimeLocations(ctx, query) }