feat: 添加MSW模拟服务和数据源集成
refactor: 重构页面组件移除冗余Layout组件 feat: 实现WebSocket和事件总线系统 feat: 添加队列和调度系统 docs: 更新架构文档和服务映射 style: 清理重复接口定义使用数据源 chore: 更新依赖项配置 feat: 添加运行时系统和领域引导 ci: 配置ESLint边界检查规则 build: 添加Redis和WebSocket依赖 test: 添加MSW浏览器环境入口 perf: 优化数据获取逻辑使用统一数据源 fix: 修复类型定义和状态管理问题
This commit is contained in:
209
dashboard/src/services/afterSalesDataSource.ts
Normal file
209
dashboard/src/services/afterSalesDataSource.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* [MOCK-AFTER-001] AfterSales数据源抽象层
|
||||
* AI注意: 这是数据源抽象层,业务组件通过此层获取数据
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用Mock
|
||||
*
|
||||
* @module services/afterSalesDataSource
|
||||
* @created 2026-03-19
|
||||
*/
|
||||
|
||||
import { IDataSource, IMockDataSource } 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, IMockDataSource {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
|
||||
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';
|
||||
Reference in New Issue
Block a user