fix: distinguish track mileage evidence

This commit is contained in:
lingniu
2026-07-19 12:32:01 +08:00
parent f825c9f417
commit 4e4f383988
10 changed files with 63 additions and 32 deletions

View File

@@ -1036,7 +1036,7 @@ func (m *MockStore) HistoryLocationsFromTDengine(ctx context.Context, query url.
VIN: row.VIN, Plate: row.Plate, Protocol: row.Protocol,
Longitude: row.Longitude - float64(remaining)*0.0062,
Latitude: row.Latitude - float64(remaining)*0.0021 + float64(index%3)*0.0008,
SpeedKmh: speed, TotalMileageKm: row.TotalMileageKm - float64(remaining)*1.35,
SpeedKmh: speed, TotalMileageKm: row.TotalMileageKm - float64(remaining)*1.35, MileageAvailable: true,
DeviceTime: observedAt, ServerTime: observedAt,
})
}

View File

@@ -101,6 +101,7 @@ type TrackPlaybackSummary struct {
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
DistanceKm float64 `json:"distanceKm"`
DistanceMethod string `json:"distanceMethod"`
DurationSeconds int64 `json:"durationSeconds"`
AverageSpeedKmh float64 `json:"averageSpeedKmh"`
MaximumSpeedKmh float64 `json:"maximumSpeedKmh"`
@@ -1304,19 +1305,20 @@ type VehicleRealtimeRow struct {
}
type HistoryLocationRow struct {
VIN string `json:"vin"`
Plate string `json:"plate"`
Protocol string `json:"protocol"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
SpeedKmh float64 `json:"speedKmh"`
SOCPercent float64 `json:"socPercent"`
SOCAvailable bool `json:"socAvailable"`
DirectionDeg *int64 `json:"directionDeg,omitempty"`
AlarmFlag *int64 `json:"alarmFlag,omitempty"`
TotalMileageKm float64 `json:"totalMileageKm"`
DeviceTime string `json:"deviceTime"`
ServerTime string `json:"serverTime"`
VIN string `json:"vin"`
Plate string `json:"plate"`
Protocol string `json:"protocol"`
Longitude float64 `json:"longitude"`
Latitude float64 `json:"latitude"`
SpeedKmh float64 `json:"speedKmh"`
SOCPercent float64 `json:"socPercent"`
SOCAvailable bool `json:"socAvailable"`
DirectionDeg *int64 `json:"directionDeg,omitempty"`
AlarmFlag *int64 `json:"alarmFlag,omitempty"`
TotalMileageKm float64 `json:"totalMileageKm"`
MileageAvailable bool `json:"mileageAvailable"`
DeviceTime string `json:"deviceTime"`
ServerTime string `json:"serverTime"`
}
type RawFrameRow struct {

View File

@@ -616,7 +616,7 @@ func (s *ProductionStore) HistoryLocations(ctx context.Context, query url.Values
for _, row := range realtime.Items {
items = append(items, HistoryLocationRow{
VIN: row.VIN, Plate: row.Plate, Protocol: row.Protocol, Longitude: row.Longitude, Latitude: row.Latitude,
SpeedKmh: row.SpeedKmh, SOCPercent: row.SOCPercent, SOCAvailable: row.SOCPercent > 0, TotalMileageKm: row.TotalMileageKm, DeviceTime: row.LastSeen, ServerTime: row.LastSeen,
SpeedKmh: row.SpeedKmh, SOCPercent: row.SOCPercent, SOCAvailable: row.SOCPercent > 0, TotalMileageKm: row.TotalMileageKm, MileageAvailable: row.TotalMileageKm > 0, DeviceTime: row.LastSeen, ServerTime: row.LastSeen,
})
}
return Page[HistoryLocationRow]{Items: items, Total: realtime.Total, Limit: realtime.Limit, Offset: realtime.Offset}, nil
@@ -675,6 +675,7 @@ func (s *ProductionStore) HistoryLocationsFromTDengine(ctx context.Context, quer
row.DirectionDeg = nullInt64Pointer(direction)
row.AlarmFlag = nullInt64Pointer(alarm)
row.TotalMileageKm = nullFloat64(mileage)
row.MileageAvailable = mileage.Valid
row.DeviceTime = time.UnixMilli(ts).UTC().Format(time.RFC3339Nano)
row.ServerTime = row.DeviceTime
if receivedAt.Valid {

View File

@@ -3474,10 +3474,14 @@ func summarizeTrack(points []HistoryLocationRow) TrackPlaybackSummary {
summary.AverageSpeedKmh = speedTotal / float64(speedCount)
}
mileageDistance := points[len(points)-1].TotalMileageKm - points[0].TotalMileageKm
if points[0].Protocol == points[len(points)-1].Protocol && mileageDistance >= 0 && mileageDistance < 10000 {
if points[0].Protocol == points[len(points)-1].Protocol &&
points[0].MileageAvailable && points[len(points)-1].MileageAvailable &&
mileageDistance >= 0 && mileageDistance < 10000 {
summary.DistanceKm = mileageDistance
summary.DistanceMethod = "odometer"
} else {
summary.DistanceKm = coordinateDistance
summary.DistanceMethod = "coordinates"
}
start, startOK := parseVehicleServiceTime(summary.StartTime)
end, endOK := parseVehicleServiceTime(summary.EndTime)

View File

@@ -377,15 +377,26 @@ func TestCompleteProtocolStatsIncludesCanonicalSlots(t *testing.T) {
func TestSummarizeTrackUsesMileageAndChronology(t *testing.T) {
points := []HistoryLocationRow{
{DeviceTime: "2026-07-03 10:00:00", TotalMileageKm: 100, SpeedKmh: 0, Longitude: 113.1, Latitude: 23.1},
{DeviceTime: "2026-07-03 10:30:00", TotalMileageKm: 112.5, SpeedKmh: 50, Longitude: 113.2, Latitude: 23.2},
{DeviceTime: "2026-07-03 10:00:00", TotalMileageKm: 100, MileageAvailable: true, SpeedKmh: 0, Longitude: 113.1, Latitude: 23.1},
{DeviceTime: "2026-07-03 10:30:00", TotalMileageKm: 112.5, MileageAvailable: true, SpeedKmh: 50, Longitude: 113.2, Latitude: 23.2},
}
summary := summarizeTrack(points)
if summary.DistanceKm != 12.5 || summary.DurationSeconds != 1800 || summary.MaximumSpeedKmh != 50 {
if summary.DistanceKm != 12.5 || summary.DistanceMethod != "odometer" || summary.DurationSeconds != 1800 || summary.MaximumSpeedKmh != 50 {
t.Fatalf("unexpected track summary: %+v", summary)
}
}
func TestSummarizeTrackUsesCoordinatesWhenProtocolMileageIsMissing(t *testing.T) {
points := []HistoryLocationRow{
{Protocol: "JT808", DeviceTime: "2026-07-03 10:00:00", Longitude: 113.1, Latitude: 23.1},
{Protocol: "JT808", DeviceTime: "2026-07-03 10:01:00", Longitude: 113.101, Latitude: 23.101},
}
summary := summarizeTrack(points)
if summary.DistanceMethod != "coordinates" || summary.DistanceKm <= 0 {
t.Fatalf("missing protocol mileage must use an explicitly labelled coordinate distance: %+v", summary)
}
}
func TestTrackEventKeepsSynchronizedTelemetryEvidence(t *testing.T) {
direction := int64(88)
alarm := int64(2)