package realtime import ( "encoding/json" "net/http" "strings" ) func NewOpenAPIHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } if strings.Trim(r.URL.Path, "/") != "openapi.json" { writeError(w, http.StatusNotFound, "route not found") return } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(realtimeOpenAPISpec()) }) } func NewSwaggerUIHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeError(w, http.StatusMethodNotAllowed, "method not allowed") return } w.Header().Set("Content-Type", "text/html; charset=utf-8") _, _ = w.Write([]byte(swaggerHTML)) }) } func realtimeOpenAPISpec() map[string]any { return map[string]any{ "openapi": "3.0.3", "info": map[string]any{ "title": "Lingniu Vehicle Realtime API", "version": "1.0.0", "description": "MySQL realtime query APIs for vehicle_realtime_snapshot, vehicle_realtime_location, and vehicle_realtime_kv.", }, "paths": map[string]any{ "/api/realtime/snapshots": map[string]any{ "get": map[string]any{ "summary": "查询车辆实时快照", "description": "从 vehicle_realtime_snapshot 查询各协议最新在线快照,支持协议、VIN、车牌过滤和分页。默认不执行 COUNT(*),total 默认表示本页返回条数;需要精确总数时传 includeTotal=true。", "tags": []string{"Realtime Snapshot API"}, "x-table": "vehicle_realtime_snapshot", "parameters": commonRealtimeParameters(), "responses": map[string]any{ "200": map[string]any{ "description": "Snapshot page", "content": map[string]any{ "application/json": map[string]any{ "schema": map[string]any{"$ref": "#/components/schemas/SnapshotPage"}, }, }, }, }, }, }, "/api/realtime/locations": map[string]any{ "get": map[string]any{ "summary": "查询车辆实时位置", "description": "从 vehicle_realtime_location 查询各协议最新位置,支持协议、VIN、车牌过滤和分页。默认不执行 COUNT(*),total 默认表示本页返回条数;需要精确总数时传 includeTotal=true。", "tags": []string{"Realtime Location API"}, "x-table": "vehicle_realtime_location", "parameters": commonRealtimeParameters(), "responses": map[string]any{ "200": map[string]any{ "description": "Location page", "content": map[string]any{ "application/json": map[string]any{ "schema": map[string]any{"$ref": "#/components/schemas/LocationPage"}, }, }, }, }, }, }, "/api/realtime/kv": map[string]any{ "get": map[string]any{ "summary": "查询车辆实时 KV 字段", "description": "从 vehicle_realtime_kv 查询实时字段投影,支持协议、VIN、domain、field 过滤和分页。适合 UI 局部刷新、快速字段查询和统计输入。", "tags": []string{"Realtime KV API"}, "x-table": "vehicle_realtime_kv", "parameters": kvRealtimeParameters(), "responses": map[string]any{ "200": map[string]any{ "description": "KV page", "content": map[string]any{ "application/json": map[string]any{ "schema": map[string]any{"$ref": "#/components/schemas/KVPage"}, }, }, }, }, }, }, }, "components": map[string]any{ "schemas": map[string]any{ "SnapshotPage": pageSchema("#/components/schemas/SnapshotRow"), "LocationPage": pageSchema("#/components/schemas/LocationRow"), "KVPage": pageSchema("#/components/schemas/KVRow"), "SnapshotRow": map[string]any{ "type": "object", "properties": map[string]any{ "protocol": stringSchema("GB32960"), "vin": stringSchema("LB9A32A21R0LS1707"), "plate": stringSchema("浙A12345"), "event_time": stringSchema("2026-07-02 16:01:02.123"), "received_at": stringSchema("2026-07-02 16:01:03.456"), "event_id": stringSchema("event id"), "updated_at": stringSchema("2026-07-02 16:01:04"), }, }, "LocationRow": map[string]any{ "type": "object", "properties": map[string]any{ "protocol": stringSchema("JT808"), "vin": stringSchema("LKLG7C4E3NA774736"), "plate": stringSchema("粤B98765"), "event_time": stringSchema("2026-07-02 16:11:02.000"), "latitude": numberSchema(30.123456), "longitude": numberSchema(120.654321), "speed_kmh": numberSchema(54.3), "total_mileage_km": numberSchema(48798.9), "soc_percent": numberSchema(81.5), "altitude_m": numberSchema(19.0), "direction_deg": numberSchema(88.0), "alarm_flag": integerSchema(0), "status_flag": integerSchema(3), "received_at": stringSchema("2026-07-02 16:11:03.000"), "event_id": stringSchema("event id"), "updated_at": stringSchema("2026-07-02 16:11:04"), }, }, "KVRow": map[string]any{ "type": "object", "properties": map[string]any{ "protocol": stringSchema("GB32960"), "vin": stringSchema("LNXNEGRR0SR321372"), "domain": stringSchema("gd_fc_stack"), "field": stringSchema("stack_water_outlet_temp_c"), "value": stringSchema("63"), "value_type": stringSchema("number"), "event_time": stringSchema("2026-07-03 11:18:45.000"), "received_at": stringSchema("2026-07-03 11:18:45.123"), "event_id": stringSchema("event id"), "updated_at": stringSchema("2026-07-03 11:18:46"), }, }, }, }, } } func kvRealtimeParameters() []map[string]any { params := commonRealtimeParameters() params = append(params, map[string]any{"name": "domain", "in": "query", "schema": map[string]any{"type": "string", "example": "gd_fc_stack"}, "required": false}, map[string]any{"name": "field", "in": "query", "schema": map[string]any{"type": "string", "example": "stack_water_outlet_temp_c"}, "required": false}, ) return params } func commonRealtimeParameters() []map[string]any { return []map[string]any{ {"name": "protocol", "in": "query", "schema": map[string]any{"type": "string", "enum": []string{"GB32960", "JT808", "YUTONG_MQTT"}}, "required": false}, {"name": "vin", "in": "query", "schema": map[string]any{"type": "string"}, "required": false}, {"name": "plate", "in": "query", "schema": map[string]any{"type": "string"}, "required": false}, {"name": "includeTotal", "in": "query", "schema": map[string]any{"type": "boolean", "default": false}, "required": false, "description": "默认 false,不执行 COUNT(*);true 时返回精确总数。"}, {"name": "limit", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 1, "maximum": 1000, "default": 50}, "required": false}, {"name": "offset", "in": "query", "schema": map[string]any{"type": "integer", "minimum": 0, "maximum": 1000000, "default": 0}, "required": false}, } } func pageSchema(itemRef string) map[string]any { return map[string]any{ "type": "object", "properties": map[string]any{ "items": map[string]any{"type": "array", "items": map[string]any{"$ref": itemRef}}, "total": map[string]any{"type": "integer", "example": 1, "description": "默认表示本页返回条数;includeTotal=true 时表示精确总数。"}, "limit": integerSchema(50), "offset": integerSchema(0), }, } } func stringSchema(example string) map[string]any { return map[string]any{"type": "string", "example": example} } func numberSchema(example float64) map[string]any { return map[string]any{"type": "number", "example": example} } func integerSchema(example int64) map[string]any { return map[string]any{"type": "integer", "example": example} } const swaggerHTML = ` Lingniu Vehicle Realtime API
`