smart_ims/src/shared/api/assetApi.ts

208 lines
6.8 KiB
TypeScript

import { apiClient } from './client';
// Frontend Interface (CamelCase)
export interface Asset {
id: string;
parentId?: string; // DB: parent_id
parentName?: string; // Joined
name: string;
category: string;
model: string; // DB: model_name
serialNumber: string; // DB: serial_number
manufacturer: string;
location: string;
purchaseDate: string; // DB: purchase_date
manager: string;
status: 'active' | 'maintain' | 'broken' | 'disposed';
purchasePrice?: number; // DB: purchase_price
image?: string; // DB: image_url
calibrationCycle?: string; // DB: calibration_cycle
specs?: string;
quantity?: number;
children?: Partial<Asset>[]; // List of sub-assets
}
// DB Interface (SnakeCase) - for internal mapping
interface DBAsset {
id: string;
parent_id?: string;
parent_name?: string; // Joined or added in response
name: string;
category: string;
model_name: string;
serial_number: string;
manufacturer: string;
location: string;
purchase_date: string;
manager: string;
status: 'active' | 'maintain' | 'broken' | 'disposed';
purchase_price?: number;
image_url?: string;
calibration_cycle: string;
specs: string;
quantity?: number;
created_at: string;
updated_at: string;
children?: any[];
}
export interface MaintenanceRecord {
id: number;
asset_id: string;
maintenance_date: string;
type: string;
content: string;
image_url?: string; // Legacy
images?: string[]; // New: Multiple images
created_at?: string;
parts?: PartUsage[];
}
export interface PartUsage {
id?: number; // maintenance_parts id
part_id: string; // asset id
part_name?: string; // joined
model_name?: string; // joined
quantity: number;
}
// Manual Interface
export interface Manual {
id: number;
asset_id: string;
file_name: string;
file_url: string;
created_at?: string;
}
export const assetApi = {
getAll: async (): Promise<Asset[]> => {
try {
const response = await apiClient.get<DBAsset[]>('/assets');
if (!response.data || !Array.isArray(response.data)) return [];
return response.data.map(mapDBToAsset);
} catch (err) {
console.error('API Error in getAll:', err);
throw err;
}
},
getById: async (id: string): Promise<Asset> => {
const response = await apiClient.get<DBAsset>(`/assets/${id}`);
const asset = mapDBToAsset(response.data);
if (response.data.children) {
asset.children = response.data.children.map(c => ({
id: c.id,
name: c.name,
category: c.category,
status: c.status,
location: c.location
}));
}
if (response.data.parent_name) {
asset.parentName = response.data.parent_name;
}
return asset;
},
create: (data: Partial<Asset>) => {
const dbData = mapAssetToDB(data);
return apiClient.post<{ message: string, id: string }>('/assets', dbData);
},
update: (id: string, data: Partial<Asset>) => {
const dbData = mapAssetToDB(data);
return apiClient.put(`/assets/${id}`, dbData);
},
uploadImage: (file: File) => {
const formData = new FormData();
formData.append('image', file);
return apiClient.post<{ url: string }>('/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});
},
// Maintenance History
getMaintenanceHistory: async (assetId: string): Promise<MaintenanceRecord[]> => {
const response = await apiClient.get<any[]>(`/assets/${assetId}/maintenance`);
return response.data.map(record => ({
...record,
// Ensure images is parsed as array if it comes as string from DB
images: typeof record.images === 'string' ? JSON.parse(record.images) : (record.images || [])
}));
},
addMaintenance: async (assetId: string, data: Partial<MaintenanceRecord>) => {
return apiClient.post(`/assets/${assetId}/maintenance`, data);
},
deleteMaintenance: async (id: number) => {
return apiClient.delete(`/maintenance/${id}`);
},
updateMaintenance: async (id: number, data: Partial<MaintenanceRecord>) => {
return apiClient.put(`/maintenance/${id}`, data);
},
// Manuals / Instructions
getManuals: async (assetId: string): Promise<Manual[]> => {
const response = await apiClient.get<Manual[]>(`/assets/${assetId}/manuals`);
return response.data;
},
addManual: async (assetId: string, data: { file_name: string; file_url: string }) => {
return apiClient.post(`/assets/${assetId}/manuals`, data);
},
deleteManual: async (id: number) => {
return apiClient.delete(`/manuals/${id}`);
},
// Accessories
getAccessories: async (assetId: string): Promise<any[]> => {
const response = await apiClient.get<any[]>(`/assets/${assetId}/accessories`);
return response.data;
},
addAccessory: async (assetId: string, data: { name: string, spec: string, quantity: number }) => {
return apiClient.post(`/assets/${assetId}/accessories`, data);
},
deleteAccessory: async (id: number) => {
return apiClient.delete(`/accessories/${id}`);
}
};
// Helper Mappers
const mapDBToAsset = (db: DBAsset): Asset => ({
id: db.id,
parentId: db.parent_id,
name: db.name,
category: db.category,
model: db.model_name || '',
serialNumber: db.serial_number || '',
manufacturer: db.manufacturer || '',
location: db.location || '',
purchaseDate: db.purchase_date ? new Date(db.purchase_date).toISOString().split('T')[0] : '', // Format YYYY-MM-DD
manager: db.manager || '',
status: db.status,
purchasePrice: db.purchase_price,
image: db.image_url,
calibrationCycle: db.calibration_cycle || '',
specs: db.specs || '',
quantity: db.quantity
});
const mapAssetToDB = (asset: Partial<Asset>): Partial<DBAsset> => {
const db: any = { ...asset };
if (asset.parentId !== undefined) { db.parent_id = asset.parentId; delete db.parentId; }
if (asset.model !== undefined) { db.model_name = asset.model; delete db.model; }
if (asset.serialNumber !== undefined) { db.serial_number = asset.serialNumber; delete db.serialNumber; }
if (asset.purchaseDate !== undefined) { db.purchase_date = asset.purchaseDate; delete db.purchaseDate; }
if (asset.purchasePrice !== undefined) { db.purchase_price = asset.purchasePrice; delete db.purchasePrice; }
if (asset.image !== undefined) { db.image_url = asset.image; delete db.image; }
if (asset.calibrationCycle !== undefined) { db.calibration_cycle = asset.calibrationCycle; delete db.calibrationCycle; }
return db;
};