Files
makemd/dashboard/src/services/afterSalesDataSource.ts
wurenzhi 427becbc8f refactor(types): 重构类型系统,统一共享类型定义
feat(types): 新增共享类型中心,包含用户、产品、订单等核心领域类型
fix(types): 修复类型定义错误,统一各模块类型引用
style(types): 优化类型文件格式和注释
docs(types): 更新类型文档和变更日志
test(types): 添加类型测试用例
build(types): 配置类型共享路径
chore(types): 清理重复类型定义文件
2026-03-20 17:53:46 +08:00

232 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* [MOCK-AFTER-001] AfterSales数据源抽象层
* AI注意: 这是数据源抽象层,业务组件通过此层获取数据
* 仅在REACT_APP_USE_MOCK=true时启用Mock
*
* @module services/afterSalesDataSource
* @created 2026-03-19
*/
import { IDataSource } from '@/types/datasource';
// ============================================
// 类型定义
// ============================================
export interface OrderItem {
id: string;
skuId: string;
productName: string;
quantity: number;
unitPrice: number;
totalPrice: number;
}
export interface ReturnApplication {
id: string;
orderId: string;
returnReason: string;
returnDescription: string;
returnItems: string[];
images: string[];
contactPhone: string;
status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'PROCESSING' | 'COMPLETED' | 'CANCELLED';
createdAt: string;
updatedAt: string;
}
export interface AfterSalesQueryParams {
orderId?: string;
status?: string;
startDate?: string;
endDate?: string;
}
// ============================================
// AfterSales专用接口
// ============================================
export interface IAfterSalesDataSource {
fetchOrderItems(orderId: string): Promise<OrderItem[]>;
submitReturn(data: Partial<ReturnApplication>): Promise<ReturnApplication>;
fetchReturnApplications(params?: AfterSalesQueryParams): Promise<ReturnApplication[]>;
fetchReturnDetail(id: string): Promise<ReturnApplication | null>;
updateReturnStatus(id: string, status: string): Promise<ReturnApplication>;
}
// ============================================
// API实现
// ============================================
class ApiAfterSalesDataSource implements IAfterSalesDataSource {
async fetchOrderItems(orderId: string): Promise<OrderItem[]> {
const response = await fetch(`/api/v1/orders/${orderId}/items`);
const result = await response.json();
return result.data;
}
async submitReturn(data: Partial<ReturnApplication>): Promise<ReturnApplication> {
const response = await fetch('/api/v1/returns', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
const result = await response.json();
return result.data;
}
async fetchReturnApplications(params?: AfterSalesQueryParams): Promise<ReturnApplication[]> {
const query = new URLSearchParams(params as any).toString();
const response = await fetch(`/api/v1/returns?${query}`);
const result = await response.json();
return result.data;
}
async fetchReturnDetail(id: string): Promise<ReturnApplication | null> {
const response = await fetch(`/api/v1/returns/${id}`);
const result = await response.json();
return result.data;
}
async updateReturnStatus(id: string, status: string): Promise<ReturnApplication> {
const response = await fetch(`/api/v1/returns/${id}/status`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status }),
});
const result = await response.json();
return result.data;
}
}
// ============================================
// Mock实现
// ============================================
/**
* [MOCK] AfterSales Mock数据源
* AI注意: 这是Mock实现不是真实业务逻辑
* 仅在REACT_APP_USE_MOCK=true时启用
*/
class MockAfterSalesDataSource implements IAfterSalesDataSource {
readonly __MOCK__ = true as const;
readonly __MOCK_NAME__ = 'MockAfterSalesDataSource';
private mockOrderItems: Record<string, OrderItem[]> = {
'order-001': [
{ id: 'item_001', skuId: 'SKU_001', productName: 'Wireless Bluetooth Headphones', quantity: 2, unitPrice: 29.99, totalPrice: 59.98 },
{ id: 'item_002', skuId: 'SKU_002', productName: 'USB-C Charging Cable', quantity: 5, unitPrice: 4.99, totalPrice: 24.95 },
],
};
private mockReturns: ReturnApplication[] = [
{
id: 'RET-001',
orderId: 'order-001',
returnReason: 'DEFECTIVE',
returnDescription: 'Product arrived damaged',
returnItems: ['item_001'],
images: [],
contactPhone: '+1 555-0123',
status: 'PENDING',
createdAt: '2026-03-18T10:00:00Z',
updatedAt: '2026-03-18T10:00:00Z',
},
];
async fetchOrderItems(orderId: string): Promise<OrderItem[]> {
await this.simulateDelay(500);
return this.mockOrderItems[orderId] || [
{ id: 'item_001', skuId: 'SKU_001', productName: 'Wireless Bluetooth Headphones', quantity: 2, unitPrice: 29.99, totalPrice: 59.98 },
{ id: 'item_002', skuId: 'SKU_002', productName: 'USB-C Charging Cable', quantity: 5, unitPrice: 4.99, totalPrice: 24.95 },
];
}
async submitReturn(data: Partial<ReturnApplication>): Promise<ReturnApplication> {
await this.simulateDelay(1000);
const newReturn: ReturnApplication = {
id: `RET-${Date.now()}`,
orderId: data.orderId || '',
returnReason: data.returnReason || '',
returnDescription: data.returnDescription || '',
returnItems: data.returnItems || [],
images: data.images || [],
contactPhone: data.contactPhone || '',
status: 'PENDING',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
this.mockReturns.push(newReturn);
return newReturn;
}
async fetchReturnApplications(params?: AfterSalesQueryParams): Promise<ReturnApplication[]> {
await this.simulateDelay(300);
let result = [...this.mockReturns];
if (params?.orderId) {
result = result.filter(r => r.orderId === params.orderId);
}
if (params?.status) {
result = result.filter(r => r.status === params.status);
}
return result;
}
async fetchReturnDetail(id: string): Promise<ReturnApplication | null> {
await this.simulateDelay(200);
const ret = this.mockReturns.find(r => r.id === id);
return ret ? { ...ret } : null;
}
async updateReturnStatus(id: string, status: string): Promise<ReturnApplication> {
await this.simulateDelay(300);
const index = this.mockReturns.findIndex(r => r.id === id);
if (index === -1) throw new Error('Return application not found');
this.mockReturns[index] = {
...this.mockReturns[index],
status: status as ReturnApplication['status'],
updatedAt: new Date().toISOString(),
};
return this.mockReturns[index];
}
private simulateDelay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Mock特定方法
reset(): void {
this.mockReturns = [
{
id: 'RET-001',
orderId: 'order-001',
returnReason: 'DEFECTIVE',
returnDescription: 'Product arrived damaged',
returnItems: ['item_001'],
images: [],
contactPhone: '+1 555-0123',
status: 'PENDING',
createdAt: '2026-03-18T10:00:00Z',
updatedAt: '2026-03-18T10:00:00Z',
},
];
}
getMockData(): ReturnApplication[] {
return this.mockReturns;
}
}
// ============================================
// 导出数据源实例
// ============================================
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
export const afterSalesDataSource: IAfterSalesDataSource = useMock
? new MockAfterSalesDataSource()
: new ApiAfterSalesDataSource();
export const __MOCK__ = useMock;
export const __DATA_SOURCE_TYPE__ = useMock ? 'mock' : 'api';