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:
2026-03-19 01:39:34 +08:00
parent cd55097dbf
commit 0dac26d781
176 changed files with 47075 additions and 8404 deletions

View File

@@ -36,46 +36,11 @@ import {
EyeOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { b2bTradeDataSource, BatchOrder, BatchOrderItem, Customer } from '@/services/b2bTradeDataSource';
const { Option } = Select;
const { TextArea } = Input;
interface BatchOrderItem {
key: string;
lineNumber: number;
productId: string;
sku: string;
productName: string;
quantity: number;
unitPrice: number;
totalPrice: number;
customerId: string;
customerName: string;
status: 'VALID' | 'INVALID' | 'PENDING';
error?: string;
}
interface BatchOrder {
id: string;
batchId: string;
customerId: string;
customerName: string;
totalItems: number;
totalAmount: number;
currency: string;
status: 'DRAFT' | 'PENDING_REVIEW' | 'CONFIRMED' | 'PROCESSING' | 'COMPLETED' | 'CANCELLED';
createdAt: string;
validItems: number;
invalidItems: number;
}
interface Customer {
id: string;
name: string;
company: string;
tier: 'BASIC' | 'PRO' | 'ENTERPRISE';
}
const BATCH_STATUS_MAP: Record<string, { color: string; text: string; icon: React.ReactNode }> = {
DRAFT: { color: 'default', text: 'Draft', icon: <FileExcelOutlined /> },
PENDING_REVIEW: { color: 'processing', text: 'Pending Review', icon: <SyncOutlined spin /> },
@@ -119,49 +84,9 @@ export const BatchOrder: React.FC = () => {
const fetchBatchOrders = async () => {
setLoading(true);
try {
const mockOrders: BatchOrder[] = [
{
id: '1',
batchId: 'BO-2026-001',
customerId: 'CUST_001',
customerName: 'ABC Trading Co.',
totalItems: 50,
totalAmount: 25000.00,
currency: 'USD',
status: 'CONFIRMED',
createdAt: '2026-03-18 10:00:00',
validItems: 48,
invalidItems: 2,
},
{
id: '2',
batchId: 'BO-2026-002',
customerId: 'CUST_002',
customerName: 'XYZ Electronics Ltd.',
totalItems: 100,
totalAmount: 45000.00,
currency: 'USD',
status: 'PENDING_REVIEW',
createdAt: '2026-03-17 14:30:00',
validItems: 95,
invalidItems: 5,
},
{
id: '3',
batchId: 'BO-2026-003',
customerId: 'CUST_003',
customerName: 'Global Import Inc.',
totalItems: 200,
totalAmount: 85000.00,
currency: 'USD',
status: 'COMPLETED',
createdAt: '2026-03-15 09:00:00',
validItems: 200,
invalidItems: 0,
},
];
setBatchOrders(mockOrders);
calculateStats(mockOrders);
const orders = await b2bTradeDataSource.fetchBatchOrders();
setBatchOrders(orders);
calculateStats(orders);
} catch (error) {
message.error('Failed to load batch orders');
} finally {
@@ -170,12 +95,12 @@ export const BatchOrder: React.FC = () => {
};
const fetchCustomers = async () => {
const mockCustomers: Customer[] = [
{ id: 'CUST_001', name: 'ABC Trading Co.', company: 'ABC Trading', tier: 'ENTERPRISE' },
{ id: 'CUST_002', name: 'XYZ Electronics Ltd.', company: 'XYZ Electronics', tier: 'PRO' },
{ id: 'CUST_003', name: 'Global Import Inc.', company: 'Global Import', tier: 'ENTERPRISE' },
];
setCustomers(mockCustomers);
try {
const data = await b2bTradeDataSource.fetchCustomers();
setCustomers(data);
} catch (error) {
message.error('Failed to load customers');
}
};
const calculateStats = (orders: BatchOrder[]) => {
@@ -200,30 +125,32 @@ export const BatchOrder: React.FC = () => {
}
};
const parseUploadedFile = (file: any) => {
const mockItems: BatchOrderItem[] = [
{ key: '1', lineNumber: 1, productId: 'PROD_001', sku: 'SKU-001', productName: 'Wireless Headphones', quantity: 100, unitPrice: 22.00, totalPrice: 2200.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' },
{ key: '2', lineNumber: 2, productId: 'PROD_002', sku: 'SKU-002', productName: 'USB-C Cable', quantity: 500, unitPrice: 4.50, totalPrice: 2250.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' },
{ key: '3', lineNumber: 3, productId: 'PROD_003', sku: 'SKU-003', productName: 'Phone Case', quantity: 200, unitPrice: 7.00, totalPrice: 1400.00, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'VALID' },
{ key: '4', lineNumber: 4, productId: 'PROD_004', sku: 'SKU-004', productName: 'Invalid Product', quantity: 50, unitPrice: 0, totalPrice: 0, customerId: selectedCustomer?.id || '', customerName: selectedCustomer?.name || '', status: 'INVALID', error: 'Product not found' },
];
setOrderItems(mockItems);
setCurrentStep(1);
message.success('File parsed successfully');
const parseUploadedFile = async (file: any) => {
try {
const items = await b2bTradeDataSource.parseOrderFile(file, selectedCustomer);
setOrderItems(items);
setCurrentStep(1);
message.success('File parsed successfully');
} catch (error) {
message.error('Failed to parse file');
}
};
const handleRemoveItem = (key: string) => {
setOrderItems(orderItems.filter((item) => item.key !== key));
};
const handleValidateItems = () => {
const handleValidateItems = async () => {
setLoading(true);
setTimeout(() => {
const validCount = orderItems.filter((i) => i.status === 'VALID').length;
const invalidCount = orderItems.filter((i) => i.status === 'INVALID').length;
message.success(`Validation complete: ${validCount} valid, ${invalidCount} invalid`);
try {
const result = await b2bTradeDataSource.validateOrderItems(orderItems);
setOrderItems(result.items);
message.success(`Validation complete: ${result.validCount} valid, ${result.invalidCount} invalid`);
} catch (error) {
message.error('Validation failed');
} finally {
setLoading(false);
}, 1000);
}
};
const handleSubmitBatch = async () => {
@@ -236,18 +163,11 @@ export const BatchOrder: React.FC = () => {
}
setLoading(true);
const totalAmount = validItems.reduce((sum, item) => sum + item.totalPrice, 0);
const batchData = {
await b2bTradeDataSource.submitBatchOrder({
customerId: values.customerId,
items: validItems,
totalAmount,
note: values.note,
};
console.log('Submitting batch order:', batchData);
await new Promise((resolve) => setTimeout(resolve, 1000));
});
message.success('Batch order submitted successfully');
setCurrentStep(2);
@@ -266,8 +186,7 @@ export const BatchOrder: React.FC = () => {
const handleApproveBatch = async (batchId: string) => {
setLoading(true);
try {
console.log('Approving batch order:', batchId);
await new Promise((resolve) => setTimeout(resolve, 500));
await b2bTradeDataSource.approveBatchOrder(batchId);
message.success('Batch order approved');
fetchBatchOrders();
} catch (error) {

View File

@@ -38,16 +38,12 @@ import {
ClockCircleOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { b2bTradeDataSource, Contract } from '@/services/b2bTradeDataSource';
const { Option } = Select;
const { TabPane } = Tabs;
const { RangePicker } = DatePicker;
const { TextArea } = Input;
interface Contract {
id: string;
contractId: string;
contractNumber: string;
customerId: string;
customerName: string;
title: string;

View File

@@ -30,24 +30,11 @@ import {
ShoppingOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { b2bTradeDataSource, Customer, Product } from '@/services/b2bTradeDataSource';
const { Option } = Select;
const { TextArea } = Input;
const { RangePicker } = DatePicker;
interface Customer {
id: string;
name: string;
email: string;
company: string;
tier: 'BASIC' | 'PRO' | 'ENTERPRISE';
}
interface Product {
id: string;
sku: string;
name: string;
costPrice: number;
suggestedPrice: number;
moq: number;
stock: number;