feat: 实现多商户管理模块与前端服务
refactor: 优化服务层代码并修复类型问题 docs: 更新开发进度文档 feat(merchant): 新增商户监控与数据统计服务 feat(dashboard): 添加商户管理前端页面与服务 fix: 修复类型转换与可选参数处理 feat: 实现商户订单、店铺与结算管理功能 refactor: 重构审计日志格式与服务调用 feat: 新增商户入驻与身份注册功能 fix(controller): 修复路由参数类型问题 feat: 添加商户排名与统计报告功能 chore: 更新模拟数据与服务配置
This commit is contained in:
135
dashboard/src/services/merchantOrderService.ts
Normal file
135
dashboard/src/services/merchantOrderService.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
// 商户订单管理服务
|
||||
|
||||
interface Order {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
merchantName: string;
|
||||
orderId: string;
|
||||
platform: string;
|
||||
totalAmount: number;
|
||||
status: 'PENDING' | 'PROCESSING' | 'SHIPPED' | 'DELIVERED' | 'CANCELLED' | 'REFUNDED';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface OrderResponse {
|
||||
data: Order[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const mockOrders: Order[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
merchantName: '商户A',
|
||||
orderId: 'AMZ123456',
|
||||
platform: 'Amazon',
|
||||
totalAmount: 100.50,
|
||||
status: 'DELIVERED',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-03T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
merchantId: '1',
|
||||
merchantName: '商户A',
|
||||
orderId: 'EBAY789012',
|
||||
platform: 'eBay',
|
||||
totalAmount: 50.25,
|
||||
status: 'SHIPPED',
|
||||
createdAt: '2026-03-02T10:00:00Z',
|
||||
updatedAt: '2026-03-03T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
merchantId: '2',
|
||||
merchantName: '商户B',
|
||||
orderId: 'SHOPEE345678',
|
||||
platform: 'Shopee',
|
||||
totalAmount: 75.75,
|
||||
status: 'PROCESSING',
|
||||
createdAt: '2026-03-03T10:00:00Z',
|
||||
updatedAt: '2026-03-03T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
merchantId: '3',
|
||||
merchantName: '商户C',
|
||||
orderId: 'TIKTOK901234',
|
||||
platform: 'TikTok',
|
||||
totalAmount: 120.00,
|
||||
status: 'PENDING',
|
||||
createdAt: '2026-03-04T10:00:00Z',
|
||||
updatedAt: '2026-03-04T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
merchantId: '1',
|
||||
merchantName: '商户A',
|
||||
orderId: 'AMZ567890',
|
||||
platform: 'Amazon',
|
||||
totalAmount: 200.00,
|
||||
status: 'CANCELLED',
|
||||
createdAt: '2026-03-05T10:00:00Z',
|
||||
updatedAt: '2026-03-05T10:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
// 获取商户订单列表
|
||||
export const getMerchantOrders = async (): Promise<OrderResponse> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return {
|
||||
data: mockOrders,
|
||||
total: mockOrders.length,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
};
|
||||
|
||||
// 根据商户ID获取订单列表
|
||||
export const getOrdersByMerchantId = async (merchantId: string): Promise<Order[]> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return mockOrders.filter(o => o.merchantId === merchantId);
|
||||
};
|
||||
|
||||
// 更新订单状态
|
||||
export const updateOrderStatus = async (orderId: string, status: Order['status']): Promise<Order> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const index = mockOrders.findIndex(o => o.id === orderId);
|
||||
if (index === -1) {
|
||||
throw new Error('订单不存在');
|
||||
}
|
||||
mockOrders[index] = {
|
||||
...mockOrders[index],
|
||||
status,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
return mockOrders[index];
|
||||
};
|
||||
|
||||
// 获取订单详情
|
||||
export const getOrderById = async (orderId: string): Promise<Order> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const order = mockOrders.find(o => o.id === orderId);
|
||||
if (!order) {
|
||||
throw new Error('订单不存在');
|
||||
}
|
||||
return order;
|
||||
};
|
||||
|
||||
// 搜索订单
|
||||
export const searchOrders = async (keyword: string): Promise<Order[]> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return mockOrders.filter(o =>
|
||||
o.orderId.includes(keyword) ||
|
||||
o.merchantName.toLowerCase().includes(keyword.toLowerCase())
|
||||
);
|
||||
};
|
||||
137
dashboard/src/services/merchantService.ts
Normal file
137
dashboard/src/services/merchantService.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
// 商户管理服务
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
interface MerchantResponse {
|
||||
data: Merchant[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const mockMerchants: Merchant[] = [
|
||||
{
|
||||
id: '1',
|
||||
tenantId: 'tenant1',
|
||||
companyName: '商户A',
|
||||
businessLicense: '1234567890',
|
||||
contactEmail: 'merchantA@example.com',
|
||||
contactPhone: '13800138001',
|
||||
status: 'ACTIVE',
|
||||
tier: 'PRO',
|
||||
traceId: 'trace1',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-01T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
tenantId: 'tenant2',
|
||||
companyName: '商户B',
|
||||
businessLicense: '0987654321',
|
||||
contactEmail: 'merchantB@example.com',
|
||||
contactPhone: '13900139001',
|
||||
status: 'PENDING',
|
||||
tier: 'BASIC',
|
||||
traceId: 'trace2',
|
||||
createdAt: '2026-03-02T10:00:00Z',
|
||||
updatedAt: '2026-03-02T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
tenantId: 'tenant3',
|
||||
companyName: '商户C',
|
||||
businessLicense: '1122334455',
|
||||
contactEmail: 'merchantC@example.com',
|
||||
contactPhone: '13700137001',
|
||||
status: 'SUSPENDED',
|
||||
tier: 'ENTERPRISE',
|
||||
traceId: 'trace3',
|
||||
createdAt: '2026-03-03T10:00:00Z',
|
||||
updatedAt: '2026-03-03T10:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
// 获取商户列表
|
||||
export const getMerchants = async (): Promise<MerchantResponse> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return {
|
||||
data: mockMerchants,
|
||||
total: mockMerchants.length,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
};
|
||||
|
||||
// 创建商户
|
||||
export const createMerchant = async (merchantData: Partial<Merchant>): Promise<Merchant> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const newMerchant: Merchant = {
|
||||
id: `new-${Date.now()}`,
|
||||
tenantId: merchantData.tenantId || 'default-tenant',
|
||||
companyName: merchantData.companyName || '',
|
||||
businessLicense: merchantData.businessLicense || '',
|
||||
contactEmail: merchantData.contactEmail || '',
|
||||
contactPhone: merchantData.contactPhone || '',
|
||||
status: merchantData.status || 'PENDING',
|
||||
tier: merchantData.tier || 'BASIC',
|
||||
traceId: `trace-${Date.now()}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
mockMerchants.push(newMerchant);
|
||||
return newMerchant;
|
||||
};
|
||||
|
||||
// 更新商户
|
||||
export const updateMerchant = async (merchantId: string, merchantData: Partial<Merchant>): Promise<Merchant> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const index = mockMerchants.findIndex(m => m.id === merchantId);
|
||||
if (index === -1) {
|
||||
throw new Error('商户不存在');
|
||||
}
|
||||
mockMerchants[index] = {
|
||||
...mockMerchants[index],
|
||||
...merchantData,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
return mockMerchants[index];
|
||||
};
|
||||
|
||||
// 删除商户
|
||||
export const deleteMerchant = async (merchantId: string): Promise<boolean> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const index = mockMerchants.findIndex(m => m.id === merchantId);
|
||||
if (index === -1) {
|
||||
throw new Error('商户不存在');
|
||||
}
|
||||
mockMerchants.splice(index, 1);
|
||||
return true;
|
||||
};
|
||||
|
||||
// 获取商户详情
|
||||
export const getMerchantById = async (merchantId: string): Promise<Merchant> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const merchant = mockMerchants.find(m => m.id === merchantId);
|
||||
if (!merchant) {
|
||||
throw new Error('商户不存在');
|
||||
}
|
||||
return merchant;
|
||||
};
|
||||
133
dashboard/src/services/merchantSettlementService.ts
Normal file
133
dashboard/src/services/merchantSettlementService.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
// 商户结算管理服务
|
||||
|
||||
interface Settlement {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
merchantName: string;
|
||||
periodStart: string;
|
||||
periodEnd: string;
|
||||
totalAmount: number;
|
||||
status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface SettlementResponse {
|
||||
data: Settlement[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const mockSettlements: Settlement[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
merchantName: '商户A',
|
||||
periodStart: '2026-02-01',
|
||||
periodEnd: '2026-02-29',
|
||||
totalAmount: 15000.00,
|
||||
status: 'COMPLETED',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-02T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
merchantId: '2',
|
||||
merchantName: '商户B',
|
||||
periodStart: '2026-02-01',
|
||||
periodEnd: '2026-02-29',
|
||||
totalAmount: 8000.00,
|
||||
status: 'COMPLETED',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-02T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
merchantId: '3',
|
||||
merchantName: '商户C',
|
||||
periodStart: '2026-02-01',
|
||||
periodEnd: '2026-02-29',
|
||||
totalAmount: 12000.00,
|
||||
status: 'PROCESSING',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-01T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
merchantId: '1',
|
||||
merchantName: '商户A',
|
||||
periodStart: '2026-03-01',
|
||||
periodEnd: '2026-03-31',
|
||||
totalAmount: 0.00,
|
||||
status: 'PENDING',
|
||||
createdAt: '2026-04-01T10:00:00Z',
|
||||
updatedAt: '2026-04-01T10:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
// 获取商户结算列表
|
||||
export const getMerchantSettlements = async (): Promise<SettlementResponse> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return {
|
||||
data: mockSettlements,
|
||||
total: mockSettlements.length,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
};
|
||||
|
||||
// 根据商户ID获取结算列表
|
||||
export const getSettlementsByMerchantId = async (merchantId: string): Promise<Settlement[]> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return mockSettlements.filter(s => s.merchantId === merchantId);
|
||||
};
|
||||
|
||||
// 处理结算
|
||||
export const processSettlement = async (settlementId: string): Promise<Settlement> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
const index = mockSettlements.findIndex(s => s.id === settlementId);
|
||||
if (index === -1) {
|
||||
throw new Error('结算单不存在');
|
||||
}
|
||||
mockSettlements[index] = {
|
||||
...mockSettlements[index],
|
||||
status: 'COMPLETED',
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
return mockSettlements[index];
|
||||
};
|
||||
|
||||
// 获取结算详情
|
||||
export const getSettlementById = async (settlementId: string): Promise<Settlement> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const settlement = mockSettlements.find(s => s.id === settlementId);
|
||||
if (!settlement) {
|
||||
throw new Error('结算单不存在');
|
||||
}
|
||||
return settlement;
|
||||
};
|
||||
|
||||
// 创建结算单
|
||||
export const createSettlement = async (settlementData: Partial<Settlement>): Promise<Settlement> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const newSettlement: Settlement = {
|
||||
id: `new-${Date.now()}`,
|
||||
merchantId: settlementData.merchantId || '',
|
||||
merchantName: settlementData.merchantName || '',
|
||||
periodStart: settlementData.periodStart || '',
|
||||
periodEnd: settlementData.periodEnd || '',
|
||||
totalAmount: settlementData.totalAmount || 0,
|
||||
status: 'PENDING',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
mockSettlements.push(newSettlement);
|
||||
return newSettlement;
|
||||
};
|
||||
139
dashboard/src/services/merchantShopService.ts
Normal file
139
dashboard/src/services/merchantShopService.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
// 商户店铺管理服务
|
||||
|
||||
interface Shop {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
shopName: string;
|
||||
platform: string;
|
||||
shopUrl: string;
|
||||
status: 'ACTIVE' | 'INACTIVE' | 'SUSPENDED';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface ShopResponse {
|
||||
data: Shop[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const mockShops: Shop[] = [
|
||||
{
|
||||
id: '1',
|
||||
merchantId: '1',
|
||||
shopName: '商户A的Amazon店铺',
|
||||
platform: 'Amazon',
|
||||
shopUrl: 'https://www.amazon.com/shop/merchantA',
|
||||
status: 'ACTIVE',
|
||||
createdAt: '2026-03-01T10:00:00Z',
|
||||
updatedAt: '2026-03-01T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
merchantId: '1',
|
||||
shopName: '商户A的eBay店铺',
|
||||
platform: 'eBay',
|
||||
shopUrl: 'https://www.ebay.com/str/merchantA',
|
||||
status: 'ACTIVE',
|
||||
createdAt: '2026-03-02T10:00:00Z',
|
||||
updatedAt: '2026-03-02T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
merchantId: '2',
|
||||
shopName: '商户B的Shopee店铺',
|
||||
platform: 'Shopee',
|
||||
shopUrl: 'https://shopee.com.my/merchantB',
|
||||
status: 'INACTIVE',
|
||||
createdAt: '2026-03-03T10:00:00Z',
|
||||
updatedAt: '2026-03-03T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
merchantId: '3',
|
||||
shopName: '商户C的TikTok店铺',
|
||||
platform: 'TikTok',
|
||||
shopUrl: 'https://www.tiktok.com/@merchantC',
|
||||
status: 'SUSPENDED',
|
||||
createdAt: '2026-03-04T10:00:00Z',
|
||||
updatedAt: '2026-03-04T10:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
// 获取商户店铺列表
|
||||
export const getMerchantShops = async (): Promise<ShopResponse> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return {
|
||||
data: mockShops,
|
||||
total: mockShops.length,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
};
|
||||
|
||||
// 创建商户店铺
|
||||
export const createMerchantShop = async (shopData: Partial<Shop>): Promise<Shop> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const newShop: Shop = {
|
||||
id: `new-${Date.now()}`,
|
||||
merchantId: shopData.merchantId || '',
|
||||
shopName: shopData.shopName || '',
|
||||
platform: shopData.platform || '',
|
||||
shopUrl: shopData.shopUrl || '',
|
||||
status: shopData.status || 'INACTIVE',
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
mockShops.push(newShop);
|
||||
return newShop;
|
||||
};
|
||||
|
||||
// 更新商户店铺
|
||||
export const updateMerchantShop = async (shopId: string, shopData: Partial<Shop>): Promise<Shop> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const index = mockShops.findIndex(s => s.id === shopId);
|
||||
if (index === -1) {
|
||||
throw new Error('店铺不存在');
|
||||
}
|
||||
mockShops[index] = {
|
||||
...mockShops[index],
|
||||
...shopData,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
return mockShops[index];
|
||||
};
|
||||
|
||||
// 删除商户店铺
|
||||
export const deleteMerchantShop = async (shopId: string): Promise<boolean> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const index = mockShops.findIndex(s => s.id === shopId);
|
||||
if (index === -1) {
|
||||
throw new Error('店铺不存在');
|
||||
}
|
||||
mockShops.splice(index, 1);
|
||||
return true;
|
||||
};
|
||||
|
||||
// 获取店铺详情
|
||||
export const getShopById = async (shopId: string): Promise<Shop> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
const shop = mockShops.find(s => s.id === shopId);
|
||||
if (!shop) {
|
||||
throw new Error('店铺不存在');
|
||||
}
|
||||
return shop;
|
||||
};
|
||||
|
||||
// 根据商户ID获取店铺列表
|
||||
export const getShopsByMerchantId = async (merchantId: string): Promise<Shop[]> => {
|
||||
// 模拟API请求延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return mockShops.filter(s => s.merchantId === merchantId);
|
||||
};
|
||||
Reference in New Issue
Block a user