本文档验证前端UI重构后与后端API接口的完全兼容性。所有前端改动均基于后端Controller定义的接口契约。
API.md - REST API完整文档backend/src/main/java/com/timecho/tsfile/viewer/controller/ - Controller源码backend/src/main/java/com/timecho/tsfile/viewer/dto/ - DTO定义控制器: MetadataController.java
@GetMapping("/{fileId}") public ResponseEntity<TSFileMetadataDTO> getMetadata(@PathVariable String fileId)
前端实现: frontend/src/api/metadata.ts
export const metadataApi = { getMetadata(fileId: string): Promise<TSFileMetadata> { return client.get(`/meta/${fileId}`) } }
验证结果: ✅ 完全兼容
TSFileMetadataDTO控制器: DataController.java
@PostMapping("/preview") public ResponseEntity<DataPreviewResponse> previewData( @RequestBody @Valid DataPreviewRequest request)
后端DTO: DataPreviewRequest.java
- fileId: String (required) - startTime: Long (optional) - endTime: Long (optional) - devices: List<String> (optional) - measurements: List<String> (optional) - valueRange: ValueRange (optional) // min/max - limit: int (1-1000, default 100) - offset: int (>=0, default 0)
前端实现: frontend/src/api/data.ts
export const dataApi = { previewData(request: DataPreviewRequest): Promise<DataPreviewResponse> { return client.post('/data/preview', request) } }
前端类型: frontend/src/api/types.ts
export interface DataPreviewRequest { fileId: string startTime?: number endTime?: number devices?: string[] measurements?: string[] valueRange?: ValueRange // { min?: number; max?: number } limit?: number offset?: number }
验证结果: ✅ 完全兼容
控制器: DataController.java
@PostMapping("/query") public ResponseEntity<ChartDataResponse> queryChartData( @RequestBody @Valid ChartDataRequest request)
后端DTO: ChartDataRequest.java
- fileId: String (required) - startTime: Long (optional) - endTime: Long (optional) - measurements: List<String> (required, not empty) - devices: List<String> (optional) - aggregation: AggregationType (optional) // MIN, MAX, AVG, COUNT - windowSize: Integer (optional) - maxPoints: Integer (optional)
前端实现: frontend/src/api/data.ts
export const dataApi = { queryChartData(request: ChartDataRequest): Promise<ChartData> { return client.post('/data/query', request) } }
前端类型: frontend/src/api/types.ts
export interface ChartDataRequest { fileId: string startTime?: number endTime?: number measurements: string[] devices?: string[] aggregation?: AggregationType windowSize?: number maxPoints?: number } export type AggregationType = 'MIN' | 'MAX' | 'AVG' | 'COUNT'
验证结果: ✅ 完全兼容
实现位置: frontend/src/components/ChartPanel.vue
接口调用流程:
用户点击刷新按钮
↓
ChartPanel emit('refresh')
↓
ChartVisualizationView.loadChartData()
↓
dataApi.queryChartData(request) → POST /api/data/query
↓
使用现有接口,无需新增端点
验证: ✅ 使用现有接口 /api/data/query,不引入新API
实现位置: frontend/src/components/DataTable.vue
接口影响: ❌ 无
验证: ✅ 无API调用,不影响接口兼容性
实现位置: frontend/src/components/FilterPanel.vue
对应后端字段: DataPreviewRequest.valueRange
数据流:
// 前端 FilterPanel localFilters.value = { minValue: 10, maxValue: 100 } // 转换为API请求 const filters = { fileId: props.fileId, valueRange: { min: localFilters.value.minValue, max: localFilters.value.maxValue } } // 调用后端 dataApi.previewData(filters) → POST /api/data/preview
后端处理: DataPreviewRequest.toFilterConditions()
if (valueRange != null) { builder.valueRange(valueRange); }
验证: ✅ 完全对应后端 ValueRange 定义
实现位置:
frontend/src/components/FilterPanel.vuefrontend/src/views/ChartVisualizationView.vue接口影响:
startTime 和 endTime 毫秒时间戳Long startTime, Long endTime 定义示例:
// 选择"最近1小时" const now = Date.now() const request = { fileId: 'xxx', startTime: now - 3600000, // Long类型 endTime: now // Long类型 }
验证: ✅ 时间戳类型与后端 Long 完全兼容
后端支持:
TSFileMetadataDTO.tables 字段可选(Table Model专用)前端处理:
// frontend/src/api/types.ts export interface TSFileMetadata { // ... 基础字段 tables?: Table[] // 可选,Table Model专用 } // FilterPanel.vue const isTableModel = computed(() => { return metadata.value?.tables && metadata.value.tables.length > 0 })
验证: ✅ 前端正确检测和处理两种模型
后端错误响应格式: GlobalExceptionHandler.java
{ "status": 400, "error": "Bad Request", "message": "Detailed error message", "timestamp": "2024-01-17T10:30:00Z", "path": "/api/files/upload", "validationErrors": [...] }
前端错误处理: frontend/src/api/client.ts
client.interceptors.response.use( response => response.data, error => { const errorMessage = error.response?.data?.message || error.message // 统一错误处理 throw new Error(errorMessage) } )
验证: ✅ 前端正确解析后端错误响应
所有前端改动均为以下类型之一:
UI增强(无API变更)
使用现有API的新功能
/api/data/query)前端内部重构
ChartPanel @refresh - 前端事件,触发已有API调用DataTable @update:sort - 前端事件,不调用APIAPI.md 完整文档✅ 所有前端改动完全符合后端API接口定义
| 前端组件 | 使用的API端点 | 对应DTO | 验证状态 |
|---|---|---|---|
| FilterPanel | GET /api/meta/{fileId} | TSFileMetadataDTO | ✅ |
| DataPreviewView | POST /api/data/preview | DataPreviewRequest/Response | ✅ |
| ChartVisualizationView | POST /api/data/query | ChartDataRequest/Response | ✅ |
| MetadataView | GET /api/meta/{fileId} | TSFileMetadataDTO | ✅ |
| ChartPanel (refresh) | POST /api/data/query | ChartDataRequest/Response | ✅ |
所有接口调用均已验证,与后端定义完全一致。