- Add CSV upload service with upsert logic for meters - Add CSV upload routes (POST /csv-upload/meters, POST /csv-upload/readings) - Add template download endpoints for CSV format - Create standalone upload-panel React app on port 5174 - Support concentrator_serial lookup for meter creation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
66 lines
1.4 KiB
TypeScript
66 lines
1.4 KiB
TypeScript
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api';
|
|
|
|
export interface UploadError {
|
|
row: number;
|
|
field?: string;
|
|
message: string;
|
|
data?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface UploadResult {
|
|
total: number;
|
|
inserted: number;
|
|
updated: number;
|
|
errors: UploadError[];
|
|
}
|
|
|
|
export interface ApiResponse {
|
|
success: boolean;
|
|
message: string;
|
|
data?: UploadResult;
|
|
}
|
|
|
|
/**
|
|
* Upload meters CSV file
|
|
*/
|
|
export async function uploadMetersCSV(file: File): Promise<ApiResponse> {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
const response = await fetch(`${API_BASE_URL}/csv-upload/meters`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
return response.json();
|
|
}
|
|
|
|
/**
|
|
* Upload readings CSV file
|
|
*/
|
|
export async function uploadReadingsCSV(file: File): Promise<ApiResponse> {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
const response = await fetch(`${API_BASE_URL}/csv-upload/readings`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
return response.json();
|
|
}
|
|
|
|
/**
|
|
* Download meters CSV template
|
|
*/
|
|
export function downloadMetersTemplate(): void {
|
|
window.open(`${API_BASE_URL}/csv-upload/meters/template`, '_blank');
|
|
}
|
|
|
|
/**
|
|
* Download readings CSV template
|
|
*/
|
|
export function downloadReadingsTemplate(): void {
|
|
window.open(`${API_BASE_URL}/csv-upload/readings/template`, '_blank');
|
|
}
|