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();
|
||||
|
||||
Reference in New Issue
Block a user