feat: 添加货币和汇率管理功能
refactor: 重构前端路由和登录逻辑 docs: 更新业务闭环、任务和架构文档 style: 调整代码格式和文件结构 chore: 更新依赖项和配置文件
This commit is contained in:
@@ -1,131 +1,472 @@
|
||||
/**
|
||||
* [MOCK-INVENTORY] Inventory模块DataSource
|
||||
* [MOCK-010] 库存模块DataSource
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
|
||||
export interface InventoryItem {
|
||||
id: string;
|
||||
sku: string;
|
||||
productName: string;
|
||||
quantity: number;
|
||||
availableQty: number;
|
||||
reservedQty: number;
|
||||
warehouseId: string;
|
||||
warehouseName: string;
|
||||
status: 'in_stock' | 'low_stock' | 'out_of_stock';
|
||||
reorderPoint: number;
|
||||
lastRestocked: string;
|
||||
}
|
||||
import { Inventory } from '../types/inventory';
|
||||
|
||||
export interface Warehouse {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
capacity: number;
|
||||
usedCapacity: number;
|
||||
status: 'active' | 'inactive' | 'maintenance';
|
||||
contact: string;
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export interface InventoryForecast {
|
||||
sku: string;
|
||||
productName: string;
|
||||
currentStock: number;
|
||||
avgDailySales: number;
|
||||
daysOfStock: number;
|
||||
suggestedReorderQty: number;
|
||||
estimatedStockoutDate: string;
|
||||
confidence: number;
|
||||
}
|
||||
|
||||
export interface IInventoryDataSource {
|
||||
fetchInventory(params?: { warehouseId?: string; status?: string }): Promise<InventoryItem[]>;
|
||||
updateInventory(id: string, data: Partial<InventoryItem>): Promise<InventoryItem>;
|
||||
// 库存数据接口
|
||||
export interface InventoryDataSource {
|
||||
list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
productId?: string;
|
||||
status?: string;
|
||||
warehouseId?: string;
|
||||
}): Promise<{ data: Inventory[]; total: number }>;
|
||||
|
||||
fetchWarehouses(): Promise<Warehouse[]>;
|
||||
saveWarehouse(data: Partial<Warehouse>): Promise<Warehouse>;
|
||||
deleteWarehouse(id: string): Promise<void>;
|
||||
get(id: string): Promise<Inventory | null>;
|
||||
|
||||
fetchForecast(): Promise<InventoryForecast[]>;
|
||||
adjustStock(id: string, quantity: number, reason: string): Promise<void>;
|
||||
create(inventory: Omit<Inventory, 'id' | 'createdAt' | 'updatedAt'>): Promise<Inventory>;
|
||||
|
||||
update(id: string, inventory: Partial<Inventory>): Promise<Inventory | null>;
|
||||
|
||||
updateStock(id: string, quantity: number): Promise<Inventory | null>;
|
||||
|
||||
getByProductId(productId: string): Promise<Inventory[]>;
|
||||
|
||||
getByWarehouseId(warehouseId: string): Promise<Inventory[]>;
|
||||
|
||||
getLowStockAlerts(threshold: number): Promise<Inventory[]>;
|
||||
|
||||
getInventoryStatistics(): Promise<{
|
||||
totalItems: number;
|
||||
totalStock: number;
|
||||
lowStockItems: number;
|
||||
outOfStockItems: number;
|
||||
warehouseDistribution: Record<string, number>;
|
||||
}>;
|
||||
}
|
||||
|
||||
class MockInventoryDataSource implements IInventoryDataSource {
|
||||
async fetchInventory(params?: { warehouseId?: string; status?: string }): Promise<InventoryItem[]> {
|
||||
return [
|
||||
{ id: 'inv_001', sku: 'SKU-001', productName: 'Wireless Headphones', quantity: 500, availableQty: 450, reservedQty: 50, warehouseId: 'wh_001', warehouseName: 'US East', status: 'in_stock', reorderPoint: 100, lastRestocked: '2026-03-15' },
|
||||
{ id: 'inv_002', sku: 'SKU-002', productName: 'USB-C Cable', quantity: 80, availableQty: 75, reservedQty: 5, warehouseId: 'wh_001', warehouseName: 'US East', status: 'low_stock', reorderPoint: 100, lastRestocked: '2026-03-10' },
|
||||
{ id: 'inv_003', sku: 'SKU-003', productName: 'Phone Case', quantity: 0, availableQty: 0, reservedQty: 0, warehouseId: 'wh_002', warehouseName: 'US West', status: 'out_of_stock', reorderPoint: 50, lastRestocked: '2026-03-01' },
|
||||
{ id: 'inv_004', sku: 'SKU-004', productName: 'Smart Watch', quantity: 200, availableQty: 180, reservedQty: 20, warehouseId: 'wh_002', warehouseName: 'US West', status: 'in_stock', reorderPoint: 50, lastRestocked: '2026-03-12' },
|
||||
// 库存DataSource实现
|
||||
export class InventoryDataSourceImpl implements InventoryDataSource {
|
||||
async list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
productId?: string;
|
||||
status?: string;
|
||||
warehouseId?: string;
|
||||
}): Promise<{ data: Inventory[]; total: number }> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_2',
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 200,
|
||||
threshold: 30,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-11'),
|
||||
createdAt: new Date('2026-02-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'inv_3',
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 150,
|
||||
threshold: 25,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-12'),
|
||||
createdAt: new Date('2026-02-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
{
|
||||
id: 'inv_4',
|
||||
productId: '4',
|
||||
productName: '智能手机',
|
||||
quantity: 5,
|
||||
threshold: 10,
|
||||
status: 'low_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-09'),
|
||||
createdAt: new Date('2026-02-04'),
|
||||
updatedAt: new Date('2026-03-09'),
|
||||
},
|
||||
{
|
||||
id: 'inv_5',
|
||||
productId: '5',
|
||||
productName: '平板电脑',
|
||||
quantity: 0,
|
||||
threshold: 15,
|
||||
status: 'out_of_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-08'),
|
||||
createdAt: new Date('2026-02-05'),
|
||||
updatedAt: new Date('2026-03-08'),
|
||||
},
|
||||
];
|
||||
|
||||
let filteredInventory = mockInventory;
|
||||
|
||||
if (params?.productId) {
|
||||
filteredInventory = filteredInventory.filter(i => i.productId === params.productId);
|
||||
}
|
||||
|
||||
if (params?.status) {
|
||||
filteredInventory = filteredInventory.filter(i => i.status === params.status);
|
||||
}
|
||||
|
||||
if (params?.warehouseId) {
|
||||
filteredInventory = filteredInventory.filter(i => i.warehouseId === params.warehouseId);
|
||||
}
|
||||
|
||||
const page = params?.page || 1;
|
||||
const pageSize = params?.pageSize || 10;
|
||||
const start = (page - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const paginatedInventory = filteredInventory.slice(start, end);
|
||||
|
||||
return {
|
||||
data: paginatedInventory,
|
||||
total: filteredInventory.length,
|
||||
};
|
||||
}
|
||||
|
||||
async updateInventory(id: string, data: Partial<InventoryItem>): Promise<InventoryItem> {
|
||||
return { id, ...data } as InventoryItem;
|
||||
}
|
||||
|
||||
async fetchWarehouses(): Promise<Warehouse[]> {
|
||||
return [
|
||||
{ id: 'wh_001', name: 'US East Warehouse', location: 'New Jersey, USA', capacity: 10000, usedCapacity: 6500, status: 'active', contact: 'John Smith', phone: '+1-555-0100' },
|
||||
{ id: 'wh_002', name: 'US West Warehouse', location: 'California, USA', capacity: 8000, usedCapacity: 4200, status: 'active', contact: 'Jane Doe', phone: '+1-555-0200' },
|
||||
{ id: 'wh_003', name: 'EU Warehouse', location: 'Frankfurt, Germany', capacity: 5000, usedCapacity: 2800, status: 'active', contact: 'Hans Mueller', phone: '+49-555-0300' },
|
||||
async get(id: string): Promise<Inventory | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_2',
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 200,
|
||||
threshold: 30,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-11'),
|
||||
createdAt: new Date('2026-02-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
];
|
||||
|
||||
const inventory = mockInventory.find(i => i.id === id);
|
||||
return inventory || null;
|
||||
}
|
||||
|
||||
async saveWarehouse(data: Partial<Warehouse>): Promise<Warehouse> {
|
||||
return { ...data, id: data.id || `wh_${Date.now()}` } as Warehouse;
|
||||
async create(inventory: Omit<Inventory, 'id' | 'createdAt' | 'updatedAt'>): Promise<Inventory> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const newInventory: Inventory = {
|
||||
...inventory,
|
||||
id: `inv_${Date.now()}`,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return newInventory;
|
||||
}
|
||||
|
||||
async deleteWarehouse(id: string): Promise<void> {}
|
||||
async update(id: string, inventory: Partial<Inventory>): Promise<Inventory | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingInventory = await this.get(id);
|
||||
if (!existingInventory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async fetchForecast(): Promise<InventoryForecast[]> {
|
||||
return [
|
||||
{ sku: 'SKU-001', productName: 'Wireless Headphones', currentStock: 500, avgDailySales: 25, daysOfStock: 20, suggestedReorderQty: 750, estimatedStockoutDate: '2026-04-07', confidence: 0.92 },
|
||||
{ sku: 'SKU-002', productName: 'USB-C Cable', currentStock: 80, avgDailySales: 15, daysOfStock: 5.3, suggestedReorderQty: 450, estimatedStockoutDate: '2026-03-23', confidence: 0.88 },
|
||||
{ sku: 'SKU-004', productName: 'Smart Watch', currentStock: 200, avgDailySales: 8, daysOfStock: 25, suggestedReorderQty: 240, estimatedStockoutDate: '2026-04-12', confidence: 0.95 },
|
||||
const updatedInventory: Inventory = {
|
||||
...existingInventory,
|
||||
...inventory,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return updatedInventory;
|
||||
}
|
||||
|
||||
async updateStock(id: string, quantity: number): Promise<Inventory | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingInventory = await this.get(id);
|
||||
if (!existingInventory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newQuantity = existingInventory.quantity + quantity;
|
||||
let status: 'in_stock' | 'low_stock' | 'out_of_stock';
|
||||
|
||||
if (newQuantity <= 0) {
|
||||
status = 'out_of_stock';
|
||||
} else if (newQuantity < existingInventory.threshold) {
|
||||
status = 'low_stock';
|
||||
} else {
|
||||
status = 'in_stock';
|
||||
}
|
||||
|
||||
const updatedInventory: Inventory = {
|
||||
...existingInventory,
|
||||
quantity: newQuantity,
|
||||
status,
|
||||
lastStockUpdate: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return updatedInventory;
|
||||
}
|
||||
|
||||
async getByProductId(productId: string): Promise<Inventory[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_2',
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 200,
|
||||
threshold: 30,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-11'),
|
||||
createdAt: new Date('2026-02-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockInventory.filter(i => i.productId === productId);
|
||||
}
|
||||
|
||||
async adjustStock(id: string, quantity: number, reason: string): Promise<void> {}
|
||||
}
|
||||
async getByWarehouseId(warehouseId: string): Promise<Inventory[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_2',
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 200,
|
||||
threshold: 30,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-11'),
|
||||
createdAt: new Date('2026-02-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'inv_3',
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 150,
|
||||
threshold: 25,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-12'),
|
||||
createdAt: new Date('2026-02-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
];
|
||||
|
||||
class ApiInventoryDataSource implements IInventoryDataSource {
|
||||
private baseUrl = '/api/inventory';
|
||||
|
||||
async fetchInventory(params?: { warehouseId?: string; status?: string }): Promise<InventoryItem[]> {
|
||||
const query = new URLSearchParams(params as any).toString();
|
||||
const res = await fetch(`${this.baseUrl}?${query}`);
|
||||
return res.json();
|
||||
return mockInventory.filter(i => i.warehouseId === warehouseId);
|
||||
}
|
||||
|
||||
async updateInventory(id: string, data: Partial<InventoryItem>): Promise<InventoryItem> {
|
||||
const res = await fetch(`${this.baseUrl}/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
|
||||
return res.json();
|
||||
async getLowStockAlerts(threshold: number): Promise<Inventory[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_4',
|
||||
productId: '4',
|
||||
productName: '智能手机',
|
||||
quantity: 5,
|
||||
threshold: 10,
|
||||
status: 'low_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-09'),
|
||||
createdAt: new Date('2026-02-04'),
|
||||
updatedAt: new Date('2026-03-09'),
|
||||
},
|
||||
{
|
||||
id: 'inv_5',
|
||||
productId: '5',
|
||||
productName: '平板电脑',
|
||||
quantity: 0,
|
||||
threshold: 15,
|
||||
status: 'out_of_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-08'),
|
||||
createdAt: new Date('2026-02-05'),
|
||||
updatedAt: new Date('2026-03-08'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockInventory.filter(i => i.quantity <= threshold);
|
||||
}
|
||||
|
||||
async fetchWarehouses(): Promise<Warehouse[]> {
|
||||
const res = await fetch(`${this.baseUrl}/warehouses`);
|
||||
return res.json();
|
||||
}
|
||||
async getInventoryStatistics(): Promise<{
|
||||
totalItems: number;
|
||||
totalStock: number;
|
||||
lowStockItems: number;
|
||||
outOfStockItems: number;
|
||||
warehouseDistribution: Record<string, number>;
|
||||
}> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockInventory: Inventory[] = [
|
||||
{
|
||||
id: 'inv_1',
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 100,
|
||||
threshold: 20,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-10'),
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'inv_2',
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 200,
|
||||
threshold: 30,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-11'),
|
||||
createdAt: new Date('2026-02-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'inv_3',
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 150,
|
||||
threshold: 25,
|
||||
status: 'in_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-12'),
|
||||
createdAt: new Date('2026-02-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
{
|
||||
id: 'inv_4',
|
||||
productId: '4',
|
||||
productName: '智能手机',
|
||||
quantity: 5,
|
||||
threshold: 10,
|
||||
status: 'low_stock',
|
||||
warehouseId: 'warehouse_1',
|
||||
warehouseName: '北京仓库',
|
||||
lastStockUpdate: new Date('2026-03-09'),
|
||||
createdAt: new Date('2026-02-04'),
|
||||
updatedAt: new Date('2026-03-09'),
|
||||
},
|
||||
{
|
||||
id: 'inv_5',
|
||||
productId: '5',
|
||||
productName: '平板电脑',
|
||||
quantity: 0,
|
||||
threshold: 15,
|
||||
status: 'out_of_stock',
|
||||
warehouseId: 'warehouse_2',
|
||||
warehouseName: '上海仓库',
|
||||
lastStockUpdate: new Date('2026-03-08'),
|
||||
createdAt: new Date('2026-02-05'),
|
||||
updatedAt: new Date('2026-03-08'),
|
||||
},
|
||||
];
|
||||
|
||||
async saveWarehouse(data: Partial<Warehouse>): Promise<Warehouse> {
|
||||
const res = await fetch(`${this.baseUrl}/warehouses`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
|
||||
return res.json();
|
||||
}
|
||||
const totalItems = mockInventory.length;
|
||||
const totalStock = mockInventory.reduce((sum, item) => sum + item.quantity, 0);
|
||||
const lowStockItems = mockInventory.filter(i => i.status === 'low_stock').length;
|
||||
const outOfStockItems = mockInventory.filter(i => i.status === 'out_of_stock').length;
|
||||
|
||||
async deleteWarehouse(id: string): Promise<void> {
|
||||
await fetch(`${this.baseUrl}/warehouses/${id}`, { method: 'DELETE' });
|
||||
}
|
||||
const warehouseDistribution: Record<string, number> = {};
|
||||
mockInventory.forEach(item => {
|
||||
warehouseDistribution[item.warehouseName] = (warehouseDistribution[item.warehouseName] || 0) + item.quantity;
|
||||
});
|
||||
|
||||
async fetchForecast(): Promise<InventoryForecast[]> {
|
||||
const res = await fetch(`${this.baseUrl}/forecast`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async adjustStock(id: string, quantity: number, reason: string): Promise<void> {
|
||||
await fetch(`${this.baseUrl}/${id}/adjust`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ quantity, reason }) });
|
||||
return {
|
||||
totalItems,
|
||||
totalStock,
|
||||
lowStockItems,
|
||||
outOfStockItems,
|
||||
warehouseDistribution,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const inventoryDataSource: IInventoryDataSource = useMock ? new MockInventoryDataSource() : new ApiInventoryDataSource();
|
||||
// 导出DataSource实例
|
||||
export const inventoryDataSource = new InventoryDataSourceImpl();
|
||||
|
||||
@@ -1,312 +1,425 @@
|
||||
/**
|
||||
* [MOCK-ORDER-001] Order数据源抽象层
|
||||
* AI注意: 这是数据源抽象层,业务组件通过此层获取数据
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用Mock
|
||||
*
|
||||
* @module services/orderDataSource
|
||||
* @created 2026-03-19
|
||||
*/
|
||||
|
||||
import { IDataSource, IMockDataSource, OrderQueryParams } from '@/types/datasource';
|
||||
|
||||
// ============================================
|
||||
// 类型定义
|
||||
// ============================================
|
||||
|
||||
export interface OrderItem {
|
||||
id: string;
|
||||
sku: string;
|
||||
productName: string;
|
||||
quantity: number;
|
||||
unitPrice: number;
|
||||
totalPrice: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface ShippingInfo {
|
||||
carrier: string;
|
||||
trackingNumber: string;
|
||||
estimatedDelivery: string;
|
||||
shippedAt?: string;
|
||||
}
|
||||
|
||||
export interface OrderDetailData {
|
||||
orderId: string;
|
||||
platform: string;
|
||||
status: string;
|
||||
paymentStatus: string;
|
||||
customer: {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
};
|
||||
shippingAddress: {
|
||||
name: string;
|
||||
address: string;
|
||||
city: string;
|
||||
state: string;
|
||||
country: string;
|
||||
postalCode: string;
|
||||
};
|
||||
items: OrderItem[];
|
||||
subtotal: number;
|
||||
shippingFee: number;
|
||||
tax: number;
|
||||
totalAmount: number;
|
||||
currency: string;
|
||||
shippingInfo?: ShippingInfo;
|
||||
timeline: Array<{
|
||||
status: string;
|
||||
time: string;
|
||||
description: string;
|
||||
}>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface OrderListItem {
|
||||
id: string;
|
||||
orderId: string;
|
||||
platform: string;
|
||||
status: string;
|
||||
customerName: string;
|
||||
totalAmount: number;
|
||||
currency: string;
|
||||
itemCount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Order专用接口
|
||||
// ============================================
|
||||
|
||||
export interface IOrderDataSource extends IDataSource<OrderDetailData, OrderQueryParams> {
|
||||
fetchOrderDetail(orderId: string): Promise<OrderDetailData | null>;
|
||||
updateStatus(orderId: string, status: string): Promise<OrderDetailData>;
|
||||
updateAddress(orderId: string, address: Partial<OrderDetailData['shippingAddress']>): Promise<OrderDetailData>;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// API实现
|
||||
// ============================================
|
||||
|
||||
class ApiOrderDataSource implements IOrderDataSource {
|
||||
async list(params?: OrderQueryParams): Promise<OrderDetailData[]> {
|
||||
const query = new URLSearchParams(params as any).toString();
|
||||
const response = await fetch(`/api/v1/orders?${query}`);
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async detail(id: string): Promise<OrderDetailData | null> {
|
||||
return this.fetchOrderDetail(id);
|
||||
}
|
||||
|
||||
async fetchOrderDetail(orderId: string): Promise<OrderDetailData | null> {
|
||||
const response = await fetch(`/api/v1/orders/${orderId}`);
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async create(data: Partial<OrderDetailData>): Promise<OrderDetailData> {
|
||||
const response = await fetch('/api/v1/orders', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<OrderDetailData>): Promise<OrderDetailData> {
|
||||
const response = await fetch(`/api/v1/orders/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await fetch(`/api/v1/orders/${id}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
async updateStatus(orderId: string, status: string): Promise<OrderDetailData> {
|
||||
const response = await fetch(`/api/v1/orders/${orderId}/status`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ status }),
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
|
||||
async updateAddress(orderId: string, address: Partial<OrderDetailData['shippingAddress']>): Promise<OrderDetailData> {
|
||||
const response = await fetch(`/api/v1/orders/${orderId}/address`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(address),
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.data;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Mock实现
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* [MOCK] Order Mock数据源
|
||||
* [MOCK-008] 订单模块DataSource
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在REACT_APP_USE_MOCK=true时启用
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
class MockOrderDataSource implements IOrderDataSource, IMockDataSource {
|
||||
readonly __MOCK__ = true as const;
|
||||
readonly __MOCK_NAME__ = 'MockOrderDataSource';
|
||||
|
||||
private mockOrders: OrderDetailData[] = [
|
||||
{
|
||||
orderId: 'ORD-2026-001',
|
||||
platform: 'AMAZON',
|
||||
status: 'SHIPPED',
|
||||
paymentStatus: 'PAID',
|
||||
customer: {
|
||||
name: 'John Smith',
|
||||
email: 'john.smith@email.com',
|
||||
phone: '+1 (555) 123-4567',
|
||||
import { Order } from '../types/order';
|
||||
|
||||
// 订单数据接口
|
||||
export interface OrderDataSource {
|
||||
list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
status?: string;
|
||||
customerId?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}): Promise<{ data: Order[]; total: number }>;
|
||||
|
||||
get(id: string): Promise<Order | null>;
|
||||
|
||||
create(order: Omit<Order, 'id' | 'createdAt' | 'updatedAt'>): Promise<Order>;
|
||||
|
||||
update(id: string, order: Partial<Order>): Promise<Order | null>;
|
||||
|
||||
updateStatus(id: string, status: string): Promise<Order | null>;
|
||||
|
||||
cancel(id: string): Promise<Order | null>;
|
||||
|
||||
getByCustomerId(customerId: string): Promise<Order[]>;
|
||||
|
||||
getStatistics(params?: {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}): Promise<{
|
||||
totalOrders: number;
|
||||
totalAmount: number;
|
||||
averageOrderValue: number;
|
||||
statusDistribution: Record<string, number>;
|
||||
}>;
|
||||
}
|
||||
|
||||
// 订单DataSource实现
|
||||
export class OrderDataSourceImpl implements OrderDataSource {
|
||||
async list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
status?: string;
|
||||
customerId?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}): Promise<{ data: Order[]; total: number }> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockOrders: Order[] = [
|
||||
{
|
||||
id: '1',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 1,
|
||||
price: 199.99
|
||||
}
|
||||
],
|
||||
totalAmount: 199.99,
|
||||
status: 'completed',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-10'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
shippingAddress: {
|
||||
name: 'John Smith',
|
||||
address: '123 Main Street, Apt 4B',
|
||||
city: 'New York',
|
||||
state: 'NY',
|
||||
country: 'United States',
|
||||
postalCode: '10001',
|
||||
{
|
||||
id: '2',
|
||||
customerId: 'cust_2',
|
||||
customerName: '李四',
|
||||
items: [
|
||||
{
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 2,
|
||||
price: 129.99
|
||||
}
|
||||
],
|
||||
totalAmount: 259.98,
|
||||
status: 'processing',
|
||||
paymentMethod: 'paypal',
|
||||
shippingAddress: {
|
||||
street: '上海市浦东新区',
|
||||
city: '上海',
|
||||
country: '中国',
|
||||
zipCode: '200000'
|
||||
},
|
||||
createdAt: new Date('2026-03-11'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
items: [
|
||||
{ id: '1', sku: 'SKU-001', productName: 'Wireless Bluetooth Headphones', quantity: 2, unitPrice: 49.99, totalPrice: 99.98, status: 'SHIPPED' },
|
||||
{ id: '2', sku: 'SKU-002', productName: 'USB-C Charging Cable', quantity: 3, unitPrice: 9.99, totalPrice: 29.97, status: 'SHIPPED' },
|
||||
{ id: '3', sku: 'SKU-003', productName: 'Phone Case', quantity: 1, unitPrice: 19.99, totalPrice: 19.99, status: 'SHIPPED' },
|
||||
],
|
||||
subtotal: 149.94,
|
||||
shippingFee: 5.99,
|
||||
tax: 12.06,
|
||||
totalAmount: 167.99,
|
||||
currency: 'USD',
|
||||
shippingInfo: {
|
||||
carrier: 'FedEx',
|
||||
trackingNumber: 'FX123456789US',
|
||||
estimatedDelivery: '2026-03-22',
|
||||
shippedAt: '2026-03-18 14:00:00',
|
||||
{
|
||||
id: '3',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 1,
|
||||
price: 89.99
|
||||
}
|
||||
],
|
||||
totalAmount: 89.99,
|
||||
status: 'pending',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-12'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
timeline: [
|
||||
{ status: 'PULLED', time: '2026-03-18 10:30:00', description: 'Order pulled from Amazon' },
|
||||
{ status: 'PENDING_REVIEW', time: '2026-03-18 10:35:00', description: 'Order submitted for review' },
|
||||
{ status: 'CONFIRMED', time: '2026-03-18 11:00:00', description: 'Order confirmed by operator' },
|
||||
{ status: 'ALLOCATED', time: '2026-03-18 12:00:00', description: 'Stock allocated from warehouse' },
|
||||
{ status: 'READY_TO_SHIP', time: '2026-03-18 13:00:00', description: 'Order packed and ready' },
|
||||
{ status: 'SHIPPED', time: '2026-03-18 14:00:00', description: 'Shipped via FedEx' },
|
||||
],
|
||||
createdAt: '2026-03-18 10:30:00',
|
||||
updatedAt: '2026-03-18 14:00:00',
|
||||
},
|
||||
];
|
||||
];
|
||||
|
||||
async list(params?: OrderQueryParams): Promise<OrderDetailData[]> {
|
||||
await this.simulateDelay(300);
|
||||
return [...this.mockOrders];
|
||||
}
|
||||
|
||||
async detail(id: string): Promise<OrderDetailData | null> {
|
||||
return this.fetchOrderDetail(id);
|
||||
}
|
||||
|
||||
async fetchOrderDetail(orderId: string): Promise<OrderDetailData | null> {
|
||||
await this.simulateDelay(500);
|
||||
const order = this.mockOrders.find(o => o.orderId === orderId);
|
||||
if (!order) {
|
||||
return this.mockOrders[0];
|
||||
let filteredOrders = mockOrders;
|
||||
|
||||
if (params?.status) {
|
||||
filteredOrders = filteredOrders.filter(o => o.status === params.status);
|
||||
}
|
||||
return { ...order };
|
||||
|
||||
if (params?.customerId) {
|
||||
filteredOrders = filteredOrders.filter(o => o.customerId === params.customerId);
|
||||
}
|
||||
|
||||
const page = params?.page || 1;
|
||||
const pageSize = params?.pageSize || 10;
|
||||
const start = (page - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const paginatedOrders = filteredOrders.slice(start, end);
|
||||
|
||||
return {
|
||||
data: paginatedOrders,
|
||||
total: filteredOrders.length,
|
||||
};
|
||||
}
|
||||
|
||||
async create(data: Partial<OrderDetailData>): Promise<OrderDetailData> {
|
||||
await this.simulateDelay(500);
|
||||
const newOrder: OrderDetailData = {
|
||||
orderId: `ORD-${Date.now()}`,
|
||||
platform: data.platform || 'AMAZON',
|
||||
status: 'PULLED',
|
||||
paymentStatus: 'PENDING',
|
||||
customer: data.customer || { name: '', email: '', phone: '' },
|
||||
shippingAddress: data.shippingAddress || { name: '', address: '', city: '', state: '', country: '', postalCode: '' },
|
||||
items: data.items || [],
|
||||
subtotal: data.subtotal || 0,
|
||||
shippingFee: data.shippingFee || 0,
|
||||
tax: data.tax || 0,
|
||||
totalAmount: data.totalAmount || 0,
|
||||
currency: data.currency || 'USD',
|
||||
timeline: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
async get(id: string): Promise<Order | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockOrders: Order[] = [
|
||||
{
|
||||
id: '1',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 1,
|
||||
price: 199.99
|
||||
}
|
||||
],
|
||||
totalAmount: 199.99,
|
||||
status: 'completed',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-10'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
customerId: 'cust_2',
|
||||
customerName: '李四',
|
||||
items: [
|
||||
{
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 2,
|
||||
price: 129.99
|
||||
}
|
||||
],
|
||||
totalAmount: 259.98,
|
||||
status: 'processing',
|
||||
paymentMethod: 'paypal',
|
||||
shippingAddress: {
|
||||
street: '上海市浦东新区',
|
||||
city: '上海',
|
||||
country: '中国',
|
||||
zipCode: '200000'
|
||||
},
|
||||
createdAt: new Date('2026-03-11'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
];
|
||||
|
||||
const order = mockOrders.find(o => o.id === id);
|
||||
return order || null;
|
||||
}
|
||||
|
||||
async create(order: Omit<Order, 'id' | 'createdAt' | 'updatedAt'>): Promise<Order> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const newOrder: Order = {
|
||||
...order,
|
||||
id: `order_${Date.now()}`,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
this.mockOrders.unshift(newOrder);
|
||||
|
||||
return newOrder;
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<OrderDetailData>): Promise<OrderDetailData> {
|
||||
await this.simulateDelay(300);
|
||||
const index = this.mockOrders.findIndex(o => o.orderId === id);
|
||||
if (index === -1) throw new Error('Order not found');
|
||||
this.mockOrders[index] = { ...this.mockOrders[index], ...data, updatedAt: new Date().toISOString() };
|
||||
return this.mockOrders[index];
|
||||
}
|
||||
async update(id: string, order: Partial<Order>): Promise<Order | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingOrder = await this.get(id);
|
||||
if (!existingOrder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<void> {
|
||||
await this.simulateDelay(200);
|
||||
this.mockOrders = this.mockOrders.filter(o => o.orderId !== id);
|
||||
}
|
||||
|
||||
async updateStatus(orderId: string, status: string): Promise<OrderDetailData> {
|
||||
await this.simulateDelay(300);
|
||||
const index = this.mockOrders.findIndex(o => o.orderId === orderId);
|
||||
if (index === -1) throw new Error('Order not found');
|
||||
this.mockOrders[index] = {
|
||||
...this.mockOrders[index],
|
||||
status,
|
||||
updatedAt: new Date().toISOString(),
|
||||
const updatedOrder: Order = {
|
||||
...existingOrder,
|
||||
...order,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
return this.mockOrders[index];
|
||||
|
||||
return updatedOrder;
|
||||
}
|
||||
|
||||
async updateAddress(orderId: string, address: Partial<OrderDetailData['shippingAddress']>): Promise<OrderDetailData> {
|
||||
await this.simulateDelay(300);
|
||||
const index = this.mockOrders.findIndex(o => o.orderId === orderId);
|
||||
if (index === -1) throw new Error('Order not found');
|
||||
this.mockOrders[index] = {
|
||||
...this.mockOrders[index],
|
||||
shippingAddress: { ...this.mockOrders[index].shippingAddress, ...address },
|
||||
updatedAt: new Date().toISOString(),
|
||||
async updateStatus(id: string, status: string): Promise<Order | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingOrder = await this.get(id);
|
||||
if (!existingOrder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedOrder: Order = {
|
||||
...existingOrder,
|
||||
status: status as any,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
return this.mockOrders[index];
|
||||
|
||||
return updatedOrder;
|
||||
}
|
||||
|
||||
private simulateDelay(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
async cancel(id: string): Promise<Order | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
return this.updateStatus(id, 'cancelled');
|
||||
}
|
||||
|
||||
async getByCustomerId(customerId: string): Promise<Order[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockOrders: Order[] = [
|
||||
{
|
||||
id: '1',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 1,
|
||||
price: 199.99
|
||||
}
|
||||
],
|
||||
totalAmount: 199.99,
|
||||
status: 'completed',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-10'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 1,
|
||||
price: 89.99
|
||||
}
|
||||
],
|
||||
totalAmount: 89.99,
|
||||
status: 'pending',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-12'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockOrders.filter(o => o.customerId === customerId);
|
||||
}
|
||||
|
||||
async getStatistics(params?: {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}): Promise<{
|
||||
totalOrders: number;
|
||||
totalAmount: number;
|
||||
averageOrderValue: number;
|
||||
statusDistribution: Record<string, number>;
|
||||
}> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockOrders: Order[] = [
|
||||
{
|
||||
id: '1',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '1',
|
||||
productName: '智能手表',
|
||||
quantity: 1,
|
||||
price: 199.99
|
||||
}
|
||||
],
|
||||
totalAmount: 199.99,
|
||||
status: 'completed',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-10'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
customerId: 'cust_2',
|
||||
customerName: '李四',
|
||||
items: [
|
||||
{
|
||||
productId: '2',
|
||||
productName: '无线耳机',
|
||||
quantity: 2,
|
||||
price: 129.99
|
||||
}
|
||||
],
|
||||
totalAmount: 259.98,
|
||||
status: 'processing',
|
||||
paymentMethod: 'paypal',
|
||||
shippingAddress: {
|
||||
street: '上海市浦东新区',
|
||||
city: '上海',
|
||||
country: '中国',
|
||||
zipCode: '200000'
|
||||
},
|
||||
createdAt: new Date('2026-03-11'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
customerId: 'cust_1',
|
||||
customerName: '张三',
|
||||
items: [
|
||||
{
|
||||
productId: '3',
|
||||
productName: '运动鞋',
|
||||
quantity: 1,
|
||||
price: 89.99
|
||||
}
|
||||
],
|
||||
totalAmount: 89.99,
|
||||
status: 'pending',
|
||||
paymentMethod: 'credit_card',
|
||||
shippingAddress: {
|
||||
street: '北京市朝阳区',
|
||||
city: '北京',
|
||||
country: '中国',
|
||||
zipCode: '100000'
|
||||
},
|
||||
createdAt: new Date('2026-03-12'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
];
|
||||
|
||||
const totalOrders = mockOrders.length;
|
||||
const totalAmount = mockOrders.reduce((sum, order) => sum + order.totalAmount, 0);
|
||||
const averageOrderValue = totalOrders > 0 ? totalAmount / totalOrders : 0;
|
||||
|
||||
const statusDistribution: Record<string, number> = {};
|
||||
mockOrders.forEach(order => {
|
||||
statusDistribution[order.status] = (statusDistribution[order.status] || 0) + 1;
|
||||
});
|
||||
|
||||
return {
|
||||
totalOrders,
|
||||
totalAmount,
|
||||
averageOrderValue,
|
||||
statusDistribution,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 导出数据源实例
|
||||
// ============================================
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
|
||||
export const orderDataSource: IOrderDataSource = useMock
|
||||
? new MockOrderDataSource()
|
||||
: new ApiOrderDataSource();
|
||||
|
||||
export const __MOCK__ = useMock;
|
||||
export const __DATA_SOURCE_TYPE__ = useMock ? 'mock' : 'api';
|
||||
// 导出DataSource实例
|
||||
export const orderDataSource = new OrderDataSourceImpl();
|
||||
|
||||
@@ -1,123 +1,274 @@
|
||||
/**
|
||||
* [MOCK-PRODUCT] Product模块DataSource
|
||||
* [MOCK-007] 产品模块DataSource
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
|
||||
export interface Product {
|
||||
id: string;
|
||||
sku: string;
|
||||
name: string;
|
||||
category: string;
|
||||
platform: string;
|
||||
costPrice: number;
|
||||
sellPrice: number;
|
||||
profit: number;
|
||||
profitMargin: number;
|
||||
status: 'active' | 'inactive' | 'draft';
|
||||
inventory: number;
|
||||
createdAt: string;
|
||||
import { Product } from '../types/product';
|
||||
|
||||
// 产品数据接口
|
||||
export interface ProductDataSource {
|
||||
list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
category?: string;
|
||||
status?: string;
|
||||
}): Promise<{ data: Product[]; total: number }>;
|
||||
|
||||
get(id: string): Promise<Product | null>;
|
||||
|
||||
create(product: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Promise<Product>;
|
||||
|
||||
update(id: string, product: Partial<Product>): Promise<Product | null>;
|
||||
|
||||
delete(id: string): Promise<boolean>;
|
||||
|
||||
search(keyword: string): Promise<Product[]>;
|
||||
|
||||
getByCategory(category: string): Promise<Product[]>;
|
||||
|
||||
updateStatus(id: string, status: string): Promise<Product | null>;
|
||||
}
|
||||
|
||||
export interface ROIAnalysis {
|
||||
sku: string;
|
||||
productName: string;
|
||||
revenue: number;
|
||||
cost: number;
|
||||
profit: number;
|
||||
roi: number;
|
||||
trend: 'up' | 'down' | 'stable';
|
||||
}
|
||||
|
||||
export interface ProfitMonitor {
|
||||
sku: string;
|
||||
productName: string;
|
||||
currentMargin: number;
|
||||
threshold: number;
|
||||
status: 'healthy' | 'warning' | 'critical';
|
||||
lastChecked: string;
|
||||
}
|
||||
|
||||
export interface AIPricingSuggestion {
|
||||
sku: string;
|
||||
productName: string;
|
||||
currentPrice: number;
|
||||
suggestedPrice: number;
|
||||
expectedMargin: number;
|
||||
confidence: number;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface IProductDataSource {
|
||||
fetchProducts(params?: { category?: string; status?: string }): Promise<Product[]>;
|
||||
fetchROIAnalysis(): Promise<ROIAnalysis[]>;
|
||||
fetchProfitMonitor(): Promise<ProfitMonitor[]>;
|
||||
fetchAIPricingSuggestions(): Promise<AIPricingSuggestion[]>;
|
||||
applyPricingSuggestion(sku: string, price: number): Promise<void>;
|
||||
}
|
||||
|
||||
class MockProductDataSource implements IProductDataSource {
|
||||
async fetchProducts(params?: { category?: string; status?: string }): Promise<Product[]> {
|
||||
return [
|
||||
{ id: 'prod_001', sku: 'SKU-001', name: 'Wireless Bluetooth Headphones', category: 'Electronics', platform: 'AMAZON', costPrice: 12.50, sellPrice: 29.99, profit: 17.49, profitMargin: 58.3, status: 'active', inventory: 500, createdAt: '2026-01-15' },
|
||||
{ id: 'prod_002', sku: 'SKU-002', name: 'USB-C Charging Cable', category: 'Accessories', platform: 'AMAZON', costPrice: 1.80, sellPrice: 4.99, profit: 3.19, profitMargin: 63.9, status: 'active', inventory: 1200, createdAt: '2026-01-20' },
|
||||
{ id: 'prod_003', sku: 'SKU-003', name: 'Smart Watch Pro', category: 'Electronics', platform: 'AMAZON', costPrice: 45.00, sellPrice: 89.99, profit: 44.99, profitMargin: 50.0, status: 'active', inventory: 200, createdAt: '2026-02-01' },
|
||||
// 产品DataSource实现
|
||||
export class ProductDataSourceImpl implements ProductDataSource {
|
||||
async list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
category?: string;
|
||||
status?: string;
|
||||
}): Promise<{ data: Product[]; total: number }> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockProducts: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手表',
|
||||
description: '多功能智能手表,支持心率监测、运动追踪等功能',
|
||||
price: 199.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/watch1.jpg', 'https://example.com/watch2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '无线耳机',
|
||||
description: '高音质无线耳机,降噪功能',
|
||||
price: 129.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 200,
|
||||
images: ['https://example.com/earphone1.jpg', 'https://example.com/earphone2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '运动鞋',
|
||||
description: '轻便透气运动鞋',
|
||||
price: 89.99,
|
||||
category: '服装',
|
||||
status: 'active',
|
||||
stock: 150,
|
||||
images: ['https://example.com/shoe1.jpg', 'https://example.com/shoe2.jpg'],
|
||||
createdAt: new Date('2026-03-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
];
|
||||
|
||||
let filteredProducts = mockProducts;
|
||||
|
||||
if (params?.category) {
|
||||
filteredProducts = filteredProducts.filter(p => p.category === params.category);
|
||||
}
|
||||
|
||||
if (params?.status) {
|
||||
filteredProducts = filteredProducts.filter(p => p.status === params.status);
|
||||
}
|
||||
|
||||
const page = params?.page || 1;
|
||||
const pageSize = params?.pageSize || 10;
|
||||
const start = (page - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const paginatedProducts = filteredProducts.slice(start, end);
|
||||
|
||||
return {
|
||||
data: paginatedProducts,
|
||||
total: filteredProducts.length,
|
||||
};
|
||||
}
|
||||
|
||||
async fetchROIAnalysis(): Promise<ROIAnalysis[]> {
|
||||
return [
|
||||
{ sku: 'SKU-001', productName: 'Wireless Bluetooth Headphones', revenue: 14995, cost: 6250, profit: 8745, roi: 139.9, trend: 'up' },
|
||||
{ sku: 'SKU-002', productName: 'USB-C Charging Cable', revenue: 5988, cost: 2160, profit: 3828, roi: 177.2, trend: 'stable' },
|
||||
{ sku: 'SKU-003', productName: 'Smart Watch Pro', revenue: 17998, cost: 9000, profit: 8998, roi: 100.0, trend: 'up' },
|
||||
async get(id: string): Promise<Product | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockProducts: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手表',
|
||||
description: '多功能智能手表,支持心率监测、运动追踪等功能',
|
||||
price: 199.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/watch1.jpg', 'https://example.com/watch2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '无线耳机',
|
||||
description: '高音质无线耳机,降噪功能',
|
||||
price: 129.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 200,
|
||||
images: ['https://example.com/earphone1.jpg', 'https://example.com/earphone2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
];
|
||||
|
||||
const product = mockProducts.find(p => p.id === id);
|
||||
return product || null;
|
||||
}
|
||||
|
||||
async fetchProfitMonitor(): Promise<ProfitMonitor[]> {
|
||||
return [
|
||||
{ sku: 'SKU-001', productName: 'Wireless Bluetooth Headphones', currentMargin: 58.3, threshold: 20, status: 'healthy', lastChecked: '2026-03-18 15:00:00' },
|
||||
{ sku: 'SKU-002', productName: 'USB-C Charging Cable', currentMargin: 63.9, threshold: 20, status: 'healthy', lastChecked: '2026-03-18 15:00:00' },
|
||||
{ sku: 'SKU-003', productName: 'Smart Watch Pro', currentMargin: 18.5, threshold: 20, status: 'warning', lastChecked: '2026-03-18 15:00:00' },
|
||||
async create(product: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Promise<Product> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const newProduct: Product = {
|
||||
...product,
|
||||
id: `product_${Date.now()}`,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return newProduct;
|
||||
}
|
||||
|
||||
async update(id: string, product: Partial<Product>): Promise<Product | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingProduct = await this.get(id);
|
||||
if (!existingProduct) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedProduct: Product = {
|
||||
...existingProduct,
|
||||
...product,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return updatedProduct;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<boolean> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
return true;
|
||||
}
|
||||
|
||||
async search(keyword: string): Promise<Product[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockProducts: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手表',
|
||||
description: '多功能智能手表,支持心率监测、运动追踪等功能',
|
||||
price: 199.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/watch1.jpg', 'https://example.com/watch2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '无线耳机',
|
||||
description: '高音质无线耳机,降噪功能',
|
||||
price: 129.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 200,
|
||||
images: ['https://example.com/earphone1.jpg', 'https://example.com/earphone2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockProducts.filter(p =>
|
||||
p.name.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
p.description.toLowerCase().includes(keyword.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
async fetchAIPricingSuggestions(): Promise<AIPricingSuggestion[]> {
|
||||
return [
|
||||
{ sku: 'SKU-001', productName: 'Wireless Bluetooth Headphones', currentPrice: 29.99, suggestedPrice: 32.99, expectedMargin: 62.5, confidence: 0.85, reason: 'Competitor prices increased, market demand stable' },
|
||||
{ sku: 'SKU-002', productName: 'USB-C Charging Cable', currentPrice: 4.99, suggestedPrice: 5.49, expectedMargin: 67.2, confidence: 0.78, reason: 'Seasonal demand increase expected' },
|
||||
{ sku: 'SKU-003', productName: 'Smart Watch Pro', currentPrice: 89.99, suggestedPrice: 94.99, expectedMargin: 52.8, confidence: 0.72, reason: 'New features added, value proposition improved' },
|
||||
async getByCategory(category: string): Promise<Product[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockProducts: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '智能手表',
|
||||
description: '多功能智能手表,支持心率监测、运动追踪等功能',
|
||||
price: 199.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 100,
|
||||
images: ['https://example.com/watch1.jpg', 'https://example.com/watch2.jpg'],
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '无线耳机',
|
||||
description: '高音质无线耳机,降噪功能',
|
||||
price: 129.99,
|
||||
category: '电子产品',
|
||||
status: 'active',
|
||||
stock: 200,
|
||||
images: ['https://example.com/earphone1.jpg', 'https://example.com/earphone2.jpg'],
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: '运动鞋',
|
||||
description: '轻便透气运动鞋',
|
||||
price: 89.99,
|
||||
category: '服装',
|
||||
status: 'active',
|
||||
stock: 150,
|
||||
images: ['https://example.com/shoe1.jpg', 'https://example.com/shoe2.jpg'],
|
||||
createdAt: new Date('2026-03-03'),
|
||||
updatedAt: new Date('2026-03-12'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockProducts.filter(p => p.category === category);
|
||||
}
|
||||
|
||||
async applyPricingSuggestion(sku: string, price: number): Promise<void> {}
|
||||
}
|
||||
async updateStatus(id: string, status: string): Promise<Product | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingProduct = await this.get(id);
|
||||
if (!existingProduct) {
|
||||
return null;
|
||||
}
|
||||
|
||||
class ApiProductDataSource implements IProductDataSource {
|
||||
private baseUrl = '/api/products';
|
||||
const updatedProduct: Product = {
|
||||
...existingProduct,
|
||||
status,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
async fetchProducts(params?: { category?: string; status?: string }): Promise<Product[]> {
|
||||
const query = new URLSearchParams(params as any).toString();
|
||||
const res = await fetch(`${this.baseUrl}?${query}`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async fetchROIAnalysis(): Promise<ROIAnalysis[]> {
|
||||
const res = await fetch(`${this.baseUrl}/roi-analysis`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async fetchProfitMonitor(): Promise<ProfitMonitor[]> {
|
||||
const res = await fetch(`${this.baseUrl}/profit-monitor`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async fetchAIPricingSuggestions(): Promise<AIPricingSuggestion[]> {
|
||||
const res = await fetch(`${this.baseUrl}/ai-pricing`);
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async applyPricingSuggestion(sku: string, price: number): Promise<void> {
|
||||
await fetch(`${this.baseUrl}/${sku}/price`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ price }) });
|
||||
return updatedProduct;
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const productDataSource: IProductDataSource = useMock ? new MockProductDataSource() : new ApiProductDataSource();
|
||||
// 导出DataSource实例
|
||||
export const productDataSource = new ProductDataSourceImpl();
|
||||
|
||||
311
dashboard/src/services/userDataSource.ts
Normal file
311
dashboard/src/services/userDataSource.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* [MOCK-009] 用户模块DataSource
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
|
||||
import { User } from '../types/user';
|
||||
|
||||
// 用户数据接口
|
||||
export interface UserDataSource {
|
||||
list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
role?: string;
|
||||
status?: string;
|
||||
}): Promise<{ data: User[]; total: number }>;
|
||||
|
||||
get(id: string): Promise<User | null>;
|
||||
|
||||
create(user: Omit<User, 'id' | 'createdAt' | 'updatedAt'>): Promise<User>;
|
||||
|
||||
update(id: string, user: Partial<User>): Promise<User | null>;
|
||||
|
||||
delete(id: string): Promise<boolean>;
|
||||
|
||||
updateStatus(id: string, status: string): Promise<User | null>;
|
||||
|
||||
search(keyword: string): Promise<User[]>;
|
||||
|
||||
getByRole(role: string): Promise<User[]>;
|
||||
|
||||
getProfile(userId: string): Promise<{
|
||||
user: User;
|
||||
statistics: {
|
||||
totalOrders: number;
|
||||
totalSpent: number;
|
||||
lastLogin: Date;
|
||||
};
|
||||
} | null>;
|
||||
}
|
||||
|
||||
// 用户DataSource实现
|
||||
export class UserDataSourceImpl implements UserDataSource {
|
||||
async list(params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
role?: string;
|
||||
status?: string;
|
||||
}): Promise<{ data: User[]; total: number }> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
phone: '13800138001',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'cust_2',
|
||||
name: '李四',
|
||||
email: 'lisi@example.com',
|
||||
phone: '13900139002',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'admin_1',
|
||||
name: '管理员',
|
||||
email: 'admin@example.com',
|
||||
phone: '13700137003',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-01'),
|
||||
},
|
||||
];
|
||||
|
||||
let filteredUsers = mockUsers;
|
||||
|
||||
if (params?.role) {
|
||||
filteredUsers = filteredUsers.filter(u => u.role === params.role);
|
||||
}
|
||||
|
||||
if (params?.status) {
|
||||
filteredUsers = filteredUsers.filter(u => u.status === params.status);
|
||||
}
|
||||
|
||||
const page = params?.page || 1;
|
||||
const pageSize = params?.pageSize || 10;
|
||||
const start = (page - 1) * pageSize;
|
||||
const end = start + pageSize;
|
||||
const paginatedUsers = filteredUsers.slice(start, end);
|
||||
|
||||
return {
|
||||
data: paginatedUsers,
|
||||
total: filteredUsers.length,
|
||||
};
|
||||
}
|
||||
|
||||
async get(id: string): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
phone: '13800138001',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'cust_2',
|
||||
name: '李四',
|
||||
email: 'lisi@example.com',
|
||||
phone: '13900139002',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'admin_1',
|
||||
name: '管理员',
|
||||
email: 'admin@example.com',
|
||||
phone: '13700137003',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-01'),
|
||||
},
|
||||
];
|
||||
|
||||
const user = mockUsers.find(u => u.id === id);
|
||||
return user || null;
|
||||
}
|
||||
|
||||
async create(user: Omit<User, 'id' | 'createdAt' | 'updatedAt'>): Promise<User> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const newUser: User = {
|
||||
...user,
|
||||
id: `user_${Date.now()}`,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return newUser;
|
||||
}
|
||||
|
||||
async update(id: string, user: Partial<User>): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingUser = await this.get(id);
|
||||
if (!existingUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedUser: User = {
|
||||
...existingUser,
|
||||
...user,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
async delete(id: string): Promise<boolean> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
return true;
|
||||
}
|
||||
|
||||
async updateStatus(id: string, status: string): Promise<User | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const existingUser = await this.get(id);
|
||||
if (!existingUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updatedUser: User = {
|
||||
...existingUser,
|
||||
status: status as any,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
async search(keyword: string): Promise<User[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
phone: '13800138001',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'cust_2',
|
||||
name: '李四',
|
||||
email: 'lisi@example.com',
|
||||
phone: '13900139002',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'admin_1',
|
||||
name: '管理员',
|
||||
email: 'admin@example.com',
|
||||
phone: '13700137003',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-01'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockUsers.filter(u =>
|
||||
u.name.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
u.email.toLowerCase().includes(keyword.toLowerCase()) ||
|
||||
u.phone.includes(keyword)
|
||||
);
|
||||
}
|
||||
|
||||
async getByRole(role: string): Promise<User[]> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: 'cust_1',
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
phone: '13800138001',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-01'),
|
||||
updatedAt: new Date('2026-03-10'),
|
||||
},
|
||||
{
|
||||
id: 'cust_2',
|
||||
name: '李四',
|
||||
email: 'lisi@example.com',
|
||||
phone: '13900139002',
|
||||
role: 'customer',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-03-02'),
|
||||
updatedAt: new Date('2026-03-11'),
|
||||
},
|
||||
{
|
||||
id: 'admin_1',
|
||||
name: '管理员',
|
||||
email: 'admin@example.com',
|
||||
phone: '13700137003',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date('2026-02-01'),
|
||||
updatedAt: new Date('2026-03-01'),
|
||||
},
|
||||
];
|
||||
|
||||
return mockUsers.filter(u => u.role === role);
|
||||
}
|
||||
|
||||
async getProfile(userId: string): Promise<{
|
||||
user: User;
|
||||
statistics: {
|
||||
totalOrders: number;
|
||||
totalSpent: number;
|
||||
lastLogin: Date;
|
||||
};
|
||||
} | null> {
|
||||
// 这里应该调用实际的API
|
||||
// 暂时返回Mock数据
|
||||
const user = await this.get(userId);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const statistics = {
|
||||
totalOrders: Math.floor(Math.random() * 100) + 1,
|
||||
totalSpent: Math.random() * 10000 + 1000,
|
||||
lastLogin: new Date(),
|
||||
};
|
||||
|
||||
return {
|
||||
user,
|
||||
statistics,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 导出DataSource实例
|
||||
export const userDataSource = new UserDataSourceImpl();
|
||||
Reference in New Issue
Block a user