/** * [MOCK] 物流管理数据源 * AI注意: 这是Mock实现,不是真实业务逻辑 * 仅在USE_MOCK=true时启用 */ export interface LogisticsProvider { id: string; name: string; code: string; status: 'ACTIVE' | 'INACTIVE'; apiEndpoint?: string; createdAt: string; updatedAt: string; } export interface Shipment { id: string; orderId: string; trackingNumber: string; provider: string; status: 'PENDING' | 'PICKED_UP' | 'IN_TRANSIT' | 'OUT_FOR_DELIVERY' | 'DELIVERED' | 'FAILED'; origin: string; destination: string; estimatedDelivery: string; actualDelivery?: string; createdAt: string; updatedAt: string; } export interface TrackingEvent { id: string; shipmentId: string; status: string; location: string; description: string; timestamp: string; } export interface FreightQuote { id: string; channel: string; carrier: string; name: string; basePrice: number; pricePerKg: number; pricePerVol: number; estimatedDays: number; totalPrice: number; fuelSurcharge: number; remoteAreaSurcharge: number; customsDuty: number; insurance: number; totalWithDuty: number; } export interface ILogisticsDataSource { fetchProviders(): Promise; createProvider(data: Partial): Promise; updateProvider(id: string, data: Partial): Promise; deleteProvider(id: string): Promise; fetchShipments(params?: { status?: string; provider?: string }): Promise; createShipment(data: Partial): Promise; updateShipment(id: string, data: Partial): Promise; fetchTrackingEvents(shipmentId: string): Promise; calculateFreight(params: { origin: string; destination: string; weight: number; dimensions: { length: number; width: number; height: number } }): Promise<{ provider: string; cost: number; estimatedDays: number }[]>; } class MockLogisticsDataSource implements ILogisticsDataSource { private providers: LogisticsProvider[] = [ { id: '1', name: 'FedEx', code: 'FEDEX', status: 'ACTIVE', createdAt: '2026-03-01', updatedAt: '2026-03-01' }, { id: '2', name: 'UPS', code: 'UPS', status: 'ACTIVE', createdAt: '2026-03-01', updatedAt: '2026-03-01' }, { id: '3', name: 'DHL', code: 'DHL', status: 'ACTIVE', createdAt: '2026-03-01', updatedAt: '2026-03-01' }, ]; private shipments: Shipment[] = [ { id: '1', orderId: 'ORD-2026-001', trackingNumber: 'FX123456789', provider: 'FEDEX', status: 'IN_TRANSIT', origin: 'Los Angeles, CA', destination: 'New York, NY', estimatedDelivery: '2026-03-20', createdAt: '2026-03-15', updatedAt: '2026-03-16', }, ]; private trackingEvents: TrackingEvent[] = [ { id: '1', shipmentId: '1', status: 'PICKED_UP', location: 'Los Angeles, CA', description: 'Package picked up', timestamp: '2026-03-15T10:00:00Z' }, { id: '2', shipmentId: '1', status: 'IN_TRANSIT', location: 'Phoenix, AZ', description: 'In transit', timestamp: '2026-03-16T08:00:00Z' }, ]; async fetchProviders(): Promise { await new Promise(resolve => setTimeout(resolve, 300)); return [...this.providers]; } async createProvider(data: Partial): Promise { await new Promise(resolve => setTimeout(resolve, 300)); const newProvider: LogisticsProvider = { id: `${Date.now()}`, name: data.name || '', code: data.code || '', status: 'ACTIVE', createdAt: new Date().toISOString().split('T')[0], updatedAt: new Date().toISOString().split('T')[0], ...data, }; this.providers.push(newProvider); return newProvider; } async updateProvider(id: string, data: Partial): Promise { await new Promise(resolve => setTimeout(resolve, 300)); const index = this.providers.findIndex(p => p.id === id); if (index === -1) throw new Error('Provider not found'); this.providers[index] = { ...this.providers[index], ...data, updatedAt: new Date().toISOString().split('T')[0] }; return this.providers[index]; } async deleteProvider(id: string): Promise { await new Promise(resolve => setTimeout(resolve, 300)); const index = this.providers.findIndex(p => p.id === id); if (index !== -1) { this.providers.splice(index, 1); } } async fetchShipments(params?: { status?: string; provider?: string }): Promise { await new Promise(resolve => setTimeout(resolve, 300)); let result = [...this.shipments]; if (params?.status) { result = result.filter(s => s.status === params.status); } if (params?.provider) { result = result.filter(s => s.provider === params.provider); } return result; } async createShipment(data: Partial): Promise { await new Promise(resolve => setTimeout(resolve, 300)); const newShipment: Shipment = { id: `${Date.now()}`, orderId: data.orderId || '', trackingNumber: `FX${Date.now()}`, provider: data.provider || 'FEDEX', status: 'PENDING', origin: data.origin || '', destination: data.destination || '', estimatedDelivery: data.estimatedDelivery || '', createdAt: new Date().toISOString().split('T')[0], updatedAt: new Date().toISOString().split('T')[0], ...data, }; this.shipments.push(newShipment); return newShipment; } async updateShipment(id: string, data: Partial): Promise { await new Promise(resolve => setTimeout(resolve, 300)); const index = this.shipments.findIndex(s => s.id === id); if (index === -1) throw new Error('Shipment not found'); this.shipments[index] = { ...this.shipments[index], ...data, updatedAt: new Date().toISOString().split('T')[0] }; return this.shipments[index]; } async fetchTrackingEvents(shipmentId: string): Promise { await new Promise(resolve => setTimeout(resolve, 300)); return this.trackingEvents.filter(e => e.shipmentId === shipmentId); } async calculateFreight(params: { origin: string; destination: string; weight: number; dimensions: { length: number; width: number; height: number } }): Promise<{ provider: string; cost: number; estimatedDays: number }[]> { await new Promise(resolve => setTimeout(resolve, 500)); return [ { provider: 'FEDEX', cost: 15.99, estimatedDays: 3 }, { provider: 'UPS', cost: 18.50, estimatedDays: 2 }, { provider: 'DHL', cost: 22.00, estimatedDays: 1 }, ]; } } class ApiLogisticsDataSource implements ILogisticsDataSource { private baseUrl = '/api/logistics'; async fetchProviders(): Promise { const response = await fetch(`${this.baseUrl}/providers`); if (!response.ok) throw new Error('Failed to fetch providers'); return response.json(); } async createProvider(data: Partial): Promise { const response = await fetch(`${this.baseUrl}/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Failed to create provider'); return response.json(); } async updateProvider(id: string, data: Partial): Promise { const response = await fetch(`${this.baseUrl}/providers/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Failed to update provider'); return response.json(); } async deleteProvider(id: string): Promise { const response = await fetch(`${this.baseUrl}/providers/${id}`, { method: 'DELETE' }); if (!response.ok) throw new Error('Failed to delete provider'); } async fetchShipments(params?: { status?: string; provider?: string }): Promise { const response = await fetch(`${this.baseUrl}/shipments?${new URLSearchParams(params as any)}`); if (!response.ok) throw new Error('Failed to fetch shipments'); return response.json(); } async createShipment(data: Partial): Promise { const response = await fetch(`${this.baseUrl}/shipments`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Failed to create shipment'); return response.json(); } async updateShipment(id: string, data: Partial): Promise { const response = await fetch(`${this.baseUrl}/shipments/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!response.ok) throw new Error('Failed to update shipment'); return response.json(); } async fetchTrackingEvents(shipmentId: string): Promise { const response = await fetch(`${this.baseUrl}/shipments/${shipmentId}/tracking`); if (!response.ok) throw new Error('Failed to fetch tracking events'); return response.json(); } async calculateFreight(params: { origin: string; destination: string; weight: number; dimensions: { length: number; width: number; height: number } }): Promise<{ provider: string; cost: number; estimatedDays: number }[]> { const response = await fetch(`${this.baseUrl}/freight/calculate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params), }); if (!response.ok) throw new Error('Failed to calculate freight'); return response.json(); } } const useMock = process.env.REACT_APP_USE_MOCK === 'true'; export const logisticsDataSource: ILogisticsDataSource = useMock ? new MockLogisticsDataSource() : new ApiLogisticsDataSource();