feat(platform): resolve vehicle detail keyword

This commit is contained in:
lingniu
2026-07-03 21:40:40 +08:00
parent 92d7020b36
commit a3a91ef1f8
2 changed files with 51 additions and 21 deletions

View File

@@ -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()

View File

@@ -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)
}