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:
371
dashboard/src/services/merchantDataSource.ts
Normal file
371
dashboard/src/services/merchantDataSource.ts
Normal file
@@ -0,0 +1,371 @@
|
||||
/**
|
||||
* [MOCK] 商户管理数据源
|
||||
* AI注意: 这是Mock实现,不是真实业务逻辑
|
||||
* 仅在USE_MOCK=true时启用
|
||||
*/
|
||||
|
||||
export interface Merchant {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
companyName: string;
|
||||
businessLicense: string;
|
||||
contactEmail: string;
|
||||
contactPhone: string;
|
||||
status: 'PENDING' | 'ACTIVE' | 'SUSPENDED' | 'TERMINATED';
|
||||
tier: 'BASIC' | 'PRO' | 'ENTERPRISE';
|
||||
traceId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface MerchantShop {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
shopName: string;
|
||||
platform: string;
|
||||
shopUrl: string;
|
||||
status: 'ACTIVE' | 'INACTIVE' | 'SUSPENDED';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface MerchantOrder {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
orderId: string;
|
||||
totalAmount: number;
|
||||
status: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface MerchantSettlement {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
merchantName: string;
|
||||
periodStart: string;
|
||||
periodEnd: string;
|
||||
totalAmount: number;
|
||||
status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface IMerchantDataSource {
|
||||
fetchMerchants(params?: { status?: string; tier?: string; search?: string }): Promise<Merchant[]>;
|
||||
createMerchant(data: Partial<Merchant>): Promise<Merchant>;
|
||||
updateMerchant(id: string, data: Partial<Merchant>): Promise<Merchant>;
|
||||
deleteMerchant(id: string): Promise<void>;
|
||||
|
||||
fetchShops(params?: { merchantId?: string; platform?: string; status?: string }): Promise<MerchantShop[]>;
|
||||
createShop(data: Partial<MerchantShop>): Promise<MerchantShop>;
|
||||
updateShop(id: string, data: Partial<MerchantShop>): Promise<MerchantShop>;
|
||||
deleteShop(id: string): Promise<void>;
|
||||
|
||||
fetchMerchantOrders(merchantId: string, params?: { status?: string }): Promise<MerchantOrder[]>;
|
||||
fetchSettlements(params?: { merchantId?: string; status?: string }): Promise<MerchantSettlement[]>;
|
||||
processSettlement(id: string, action: 'APPROVE' | 'REJECT'): Promise<MerchantSettlement>;
|
||||
}
|
||||
|
||||
class MockMerchantDataSource implements IMerchantDataSource {
|
||||
private merchants: Merchant[] = [
|
||||
{
|
||||
id: '1',
|
||||
tenantId: 'tenant_001',
|
||||
companyName: 'Test Company A',
|
||||
businessLicense: 'BL-001',
|
||||
contactEmail: 'contact@company-a.com',
|
||||
contactPhone: '+1 (123) 456-7890',
|
||||
status: 'ACTIVE',
|
||||
tier: 'ENTERPRISE',
|
||||
traceId: 'trace_001',
|
||||
createdAt: '2026-03-01',
|
||||
updatedAt: '2026-03-01',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
tenantId: 'tenant_002',
|
||||
companyName: 'Test Company B',
|
||||
businessLicense: 'BL-002',
|
||||
contactEmail: 'contact@company-b.com',
|
||||
contactPhone: '+1 (234) 567-8901',
|
||||
status: 'ACTIVE',
|
||||
tier: 'PRO',
|
||||
traceId: 'trace_002',
|
||||
createdAt: '2026-03-05',
|
||||
updatedAt: '2026-03-05',
|
||||
},
|
||||
];
|
||||
|
||||
private shops: MerchantShop[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
shopName: 'Shop A - Amazon',
|
||||
platform: 'Amazon',
|
||||
shopUrl: 'https://amazon.com/shop-a',
|
||||
status: 'ACTIVE',
|
||||
createdAt: '2026-03-01',
|
||||
updatedAt: '2026-03-01',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
merchantId: '1',
|
||||
shopName: 'Shop A - Shopify',
|
||||
platform: 'Shopify',
|
||||
shopUrl: 'https://shop-a.myshopify.com',
|
||||
status: 'ACTIVE',
|
||||
createdAt: '2026-03-02',
|
||||
updatedAt: '2026-03-02',
|
||||
},
|
||||
];
|
||||
|
||||
private orders: MerchantOrder[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
orderId: 'ORD-2026-001',
|
||||
totalAmount: 1500.00,
|
||||
status: 'COMPLETED',
|
||||
createdAt: '2026-03-15',
|
||||
},
|
||||
];
|
||||
|
||||
async fetchMerchants(params?: { status?: string; tier?: string; search?: string }): Promise<Merchant[]> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
let result = [...this.merchants];
|
||||
if (params?.status) {
|
||||
result = result.filter(m => m.status === params.status);
|
||||
}
|
||||
if (params?.tier) {
|
||||
result = result.filter(m => m.tier === params.tier);
|
||||
}
|
||||
if (params?.search) {
|
||||
result = result.filter(m => m.companyName.toLowerCase().includes(params.search!.toLowerCase()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async createMerchant(data: Partial<Merchant>): Promise<Merchant> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const newMerchant: Merchant = {
|
||||
id: `${Date.now()}`,
|
||||
tenantId: `tenant_${Date.now()}`,
|
||||
companyName: data.companyName || '',
|
||||
businessLicense: data.businessLicense || '',
|
||||
contactEmail: data.contactEmail || '',
|
||||
contactPhone: data.contactPhone || '',
|
||||
status: 'PENDING',
|
||||
tier: 'BASIC',
|
||||
traceId: `trace_${Date.now()}`,
|
||||
createdAt: new Date().toISOString().split('T')[0],
|
||||
updatedAt: new Date().toISOString().split('T')[0],
|
||||
...data,
|
||||
};
|
||||
this.merchants.push(newMerchant);
|
||||
return newMerchant;
|
||||
}
|
||||
|
||||
async updateMerchant(id: string, data: Partial<Merchant>): Promise<Merchant> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const index = this.merchants.findIndex(m => m.id === id);
|
||||
if (index === -1) throw new Error('Merchant not found');
|
||||
this.merchants[index] = { ...this.merchants[index], ...data, updatedAt: new Date().toISOString().split('T')[0] };
|
||||
return this.merchants[index];
|
||||
}
|
||||
|
||||
async deleteMerchant(id: string): Promise<void> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const index = this.merchants.findIndex(m => m.id === id);
|
||||
if (index !== -1) {
|
||||
this.merchants.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchShops(params?: { merchantId?: string; platform?: string; status?: string }): Promise<MerchantShop[]> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
let result = [...this.shops];
|
||||
if (params?.merchantId) {
|
||||
result = result.filter(s => s.merchantId === params.merchantId);
|
||||
}
|
||||
if (params?.platform) {
|
||||
result = result.filter(s => s.platform === params.platform);
|
||||
}
|
||||
if (params?.status) {
|
||||
result = result.filter(s => s.status === params.status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async createShop(data: Partial<MerchantShop>): Promise<MerchantShop> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const newShop: MerchantShop = {
|
||||
id: `${Date.now()}`,
|
||||
merchantId: data.merchantId || '',
|
||||
shopName: data.shopName || '',
|
||||
platform: data.platform || '',
|
||||
shopUrl: data.shopUrl || '',
|
||||
status: 'ACTIVE',
|
||||
createdAt: new Date().toISOString().split('T')[0],
|
||||
updatedAt: new Date().toISOString().split('T')[0],
|
||||
...data,
|
||||
};
|
||||
this.shops.push(newShop);
|
||||
return newShop;
|
||||
}
|
||||
|
||||
async updateShop(id: string, data: Partial<MerchantShop>): Promise<MerchantShop> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const index = this.shops.findIndex(s => s.id === id);
|
||||
if (index === -1) throw new Error('Shop not found');
|
||||
this.shops[index] = { ...this.shops[index], ...data, updatedAt: new Date().toISOString().split('T')[0] };
|
||||
return this.shops[index];
|
||||
}
|
||||
|
||||
async deleteShop(id: string): Promise<void> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const index = this.shops.findIndex(s => s.id === id);
|
||||
if (index !== -1) {
|
||||
this.shops.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchMerchantOrders(merchantId: string, params?: { status?: string }): Promise<MerchantOrder[]> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
let result = this.orders.filter(o => o.merchantId === merchantId);
|
||||
if (params?.status) {
|
||||
result = result.filter(o => o.status === params.status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private settlements: MerchantSettlement[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
merchantName: 'Test Company A',
|
||||
periodStart: '2026-03-01',
|
||||
periodEnd: '2026-03-15',
|
||||
totalAmount: 25000.00,
|
||||
status: 'PENDING',
|
||||
createdAt: '2026-03-16',
|
||||
updatedAt: '2026-03-16',
|
||||
},
|
||||
];
|
||||
|
||||
async fetchSettlements(params?: { merchantId?: string; status?: string }): Promise<MerchantSettlement[]> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
let result = [...this.settlements];
|
||||
if (params?.merchantId) {
|
||||
result = result.filter(s => s.merchantId === params.merchantId);
|
||||
}
|
||||
if (params?.status) {
|
||||
result = result.filter(s => s.status === params.status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async processSettlement(id: string, action: 'APPROVE' | 'REJECT'): Promise<MerchantSettlement> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const index = this.settlements.findIndex(s => s.id === id);
|
||||
if (index === -1) throw new Error('Settlement not found');
|
||||
this.settlements[index] = {
|
||||
...this.settlements[index],
|
||||
status: action === 'APPROVE' ? 'COMPLETED' : 'FAILED',
|
||||
updatedAt: new Date().toISOString().split('T')[0],
|
||||
};
|
||||
return this.settlements[index];
|
||||
}
|
||||
}
|
||||
|
||||
class ApiMerchantDataSource implements IMerchantDataSource {
|
||||
private baseUrl = '/api/merchants';
|
||||
|
||||
async fetchMerchants(params?: { status?: string; tier?: string; search?: string }): Promise<Merchant[]> {
|
||||
const response = await fetch(`${this.baseUrl}?${new URLSearchParams(params as any)}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch merchants');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async createMerchant(data: Partial<Merchant>): Promise<Merchant> {
|
||||
const response = await fetch(this.baseUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to create merchant');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async updateMerchant(id: string, data: Partial<Merchant>): Promise<Merchant> {
|
||||
const response = await fetch(`${this.baseUrl}/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to update merchant');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async deleteMerchant(id: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/${id}`, { method: 'DELETE' });
|
||||
if (!response.ok) throw new Error('Failed to delete merchant');
|
||||
}
|
||||
|
||||
async fetchShops(params?: { merchantId?: string; platform?: string; status?: string }): Promise<MerchantShop[]> {
|
||||
const response = await fetch(`${this.baseUrl}/shops?${new URLSearchParams(params as any)}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch shops');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async createShop(data: Partial<MerchantShop>): Promise<MerchantShop> {
|
||||
const response = await fetch(`${this.baseUrl}/shops`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to create shop');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async updateShop(id: string, data: Partial<MerchantShop>): Promise<MerchantShop> {
|
||||
const response = await fetch(`${this.baseUrl}/shops/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to update shop');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async deleteShop(id: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/shops/${id}`, { method: 'DELETE' });
|
||||
if (!response.ok) throw new Error('Failed to delete shop');
|
||||
}
|
||||
|
||||
async fetchMerchantOrders(merchantId: string, params?: { status?: string }): Promise<MerchantOrder[]> {
|
||||
const response = await fetch(`${this.baseUrl}/${merchantId}/orders?${new URLSearchParams(params as any)}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch merchant orders');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async fetchSettlements(params?: { merchantId?: string; status?: string }): Promise<MerchantSettlement[]> {
|
||||
const response = await fetch(`${this.baseUrl}/settlements?${new URLSearchParams(params as any)}`);
|
||||
if (!response.ok) throw new Error('Failed to fetch settlements');
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async processSettlement(id: string, action: 'APPROVE' | 'REJECT'): Promise<MerchantSettlement> {
|
||||
const response = await fetch(`${this.baseUrl}/settlements/${id}/process`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action }),
|
||||
});
|
||||
if (!response.ok) throw new Error('Failed to process settlement');
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const merchantDataSource: IMerchantDataSource = useMock
|
||||
? new MockMerchantDataSource()
|
||||
: new ApiMerchantDataSource();
|
||||
Reference in New Issue
Block a user