feat: 新增多模块功能与服务实现

新增广告计划、用户资产、B2B交易、合规规则等核心模型
实现爬虫工作器、贸易服务、现金流预测等业务服务
添加RBAC权限测试、压力测试等测试用例
完善扩展程序的消息处理与内容脚本功能
重构应用入口与文档生成器
更新项目规则与业务闭环分析文档
This commit is contained in:
2026-03-18 09:38:09 +08:00
parent 72cd7f6f45
commit 037e412aad
158 changed files with 50217 additions and 1313 deletions

View File

@@ -0,0 +1,431 @@
import { Logger } from '../utils/Logger';
import { FingerprintManager } from './FingerprintManager';
interface ShipInfo {
orderId: string;
platform: string;
shopId: string;
trackingNumber: string;
carrier: string;
items: Array<{
productId: string;
skuId: string;
quantity: number;
}>;
shippingAddress: {
name: string;
phone: string;
address: string;
city: string;
state: string;
zipCode: string;
country: string;
};
}
interface ShipResult {
success: boolean;
orderId: string;
trackingNumber?: string;
carrier?: string;
status: 'shipped' | 'failed' | 'pending';
message: string;
timestamp: string;
traceId: string;
}
interface ShipTask {
taskId: string;
orderId: string;
shopId: string;
platform: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
retryCount: number;
maxRetries: number;
createdAt: string;
updatedAt: string;
traceId: string;
}
export class AutoShipService {
private logger = new Logger('AutoShipService');
private fingerprintManager: FingerprintManager;
private tasks: Map<string, ShipTask> = new Map();
private readonly MAX_RETRIES = 3;
private readonly RETRY_DELAY_MS = 5000;
constructor(fingerprintManager: FingerprintManager) {
this.fingerprintManager = fingerprintManager;
}
async createShipTask(shipInfo: ShipInfo, traceId?: string): Promise<ShipTask> {
const tid = traceId || this.generateTraceId();
const taskId = `SHIP-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
this.logger.info('Creating ship task', {
taskId,
orderId: shipInfo.orderId,
platform: shipInfo.platform,
traceId: tid,
});
const task: ShipTask = {
taskId,
orderId: shipInfo.orderId,
shopId: shipInfo.shopId,
platform: shipInfo.platform,
status: 'pending',
retryCount: 0,
maxRetries: this.MAX_RETRIES,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
traceId: tid,
};
this.tasks.set(taskId, task);
await this.reportTaskCreated(task);
return task;
}
async processShipTask(taskId: string, shipInfo: ShipInfo): Promise<ShipResult> {
const task = this.tasks.get(taskId);
if (!task) {
throw new Error(`Task not found: ${taskId}`);
}
task.status = 'processing';
task.updatedAt = new Date().toISOString();
this.logger.info('Processing ship task', {
taskId,
orderId: task.orderId,
platform: task.platform,
traceId: task.traceId,
});
try {
const context = await this.fingerprintManager.createIsolatedContext(
task.shopId,
undefined,
task.traceId
);
if (!context.success || !context.context) {
throw new Error(`Failed to create isolated context: ${context.error}`);
}
const result = await this.executeShipOperation(task, shipInfo, context.context);
if (result.success) {
task.status = 'completed';
this.logger.info('Ship task completed', {
taskId,
orderId: task.orderId,
trackingNumber: result.trackingNumber,
traceId: task.traceId,
});
} else if (task.retryCount < task.maxRetries) {
task.retryCount++;
task.status = 'pending';
this.logger.warn('Ship task failed, will retry', {
taskId,
orderId: task.orderId,
retryCount: task.retryCount,
error: result.message,
traceId: task.traceId,
});
setTimeout(() => {
this.processShipTask(taskId, shipInfo);
}, this.RETRY_DELAY_MS * task.retryCount);
} else {
task.status = 'failed';
this.logger.error('Ship task failed after max retries', {
taskId,
orderId: task.orderId,
error: result.message,
traceId: task.traceId,
});
}
task.updatedAt = new Date().toISOString();
await this.reportTaskStatus(task, result);
return result;
} catch (error: any) {
task.status = 'failed';
task.updatedAt = new Date().toISOString();
this.logger.error('Ship task processing error', {
taskId,
orderId: task.orderId,
error: error.message,
traceId: task.traceId,
});
const errorResult: ShipResult = {
success: false,
orderId: task.orderId,
status: 'failed',
message: error.message,
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
await this.reportTaskStatus(task, errorResult);
return errorResult;
}
}
private async executeShipOperation(
task: ShipTask,
shipInfo: ShipInfo,
context: any
): Promise<ShipResult> {
this.logger.info('Executing ship operation', {
taskId: task.taskId,
orderId: task.orderId,
platform: task.platform,
traceId: task.traceId,
});
try {
switch (task.platform.toLowerCase()) {
case 'tiktok':
return await this.shipTikTokOrder(task, shipInfo, context);
case 'temu':
return await this.shipTemuOrder(task, shipInfo, context);
case '1688':
return await this.ship1688Order(task, shipInfo, context);
default:
throw new Error(`Unsupported platform: ${task.platform}`);
}
} catch (error: any) {
return {
success: false,
orderId: task.orderId,
status: 'failed',
message: `Ship operation failed: ${error.message}`,
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
}
}
private async shipTikTokOrder(
task: ShipTask,
shipInfo: ShipInfo,
context: any
): Promise<ShipResult> {
this.logger.info('Shipping TikTok order', {
taskId: task.taskId,
orderId: task.orderId,
traceId: task.traceId,
});
await this.simulateDelay(2000, 4000);
const success = Math.random() > 0.1;
if (success) {
return {
success: true,
orderId: task.orderId,
trackingNumber: shipInfo.trackingNumber,
carrier: shipInfo.carrier,
status: 'shipped',
message: 'Order shipped successfully on TikTok',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
} else {
return {
success: false,
orderId: task.orderId,
status: 'failed',
message: 'Failed to ship order on TikTok: Platform validation error',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
}
}
private async shipTemuOrder(
task: ShipTask,
shipInfo: ShipInfo,
context: any
): Promise<ShipResult> {
this.logger.info('Shipping Temu order', {
taskId: task.taskId,
orderId: task.orderId,
traceId: task.traceId,
});
await this.simulateDelay(1500, 3000);
const success = Math.random() > 0.15;
if (success) {
return {
success: true,
orderId: task.orderId,
trackingNumber: shipInfo.trackingNumber,
carrier: shipInfo.carrier,
status: 'shipped',
message: 'Order shipped successfully on Temu',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
} else {
return {
success: false,
orderId: task.orderId,
status: 'failed',
message: 'Failed to ship order on Temu: Order status not eligible for shipping',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
}
}
private async ship1688Order(
task: ShipTask,
shipInfo: ShipInfo,
context: any
): Promise<ShipResult> {
this.logger.info('Shipping 1688 order', {
taskId: task.taskId,
orderId: task.orderId,
traceId: task.traceId,
});
await this.simulateDelay(2500, 5000);
const success = Math.random() > 0.2;
if (success) {
return {
success: true,
orderId: task.orderId,
trackingNumber: shipInfo.trackingNumber,
carrier: shipInfo.carrier,
status: 'shipped',
message: 'Order shipped successfully on 1688',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
} else {
return {
success: false,
orderId: task.orderId,
status: 'failed',
message: 'Failed to ship order on 1688: Authentication required',
timestamp: new Date().toISOString(),
traceId: task.traceId,
};
}
}
async batchProcessShipTasks(tasks: Array<{ taskId: string; shipInfo: ShipInfo }>): Promise<ShipResult[]> {
this.logger.info('Starting batch ship processing', { count: tasks.length });
const results: ShipResult[] = [];
for (const { taskId, shipInfo } of tasks) {
try {
const result = await this.processShipTask(taskId, shipInfo);
results.push(result);
} catch (error: any) {
results.push({
success: false,
orderId: shipInfo.orderId,
status: 'failed',
message: `Batch processing error: ${error.message}`,
timestamp: new Date().toISOString(),
traceId: shipInfo.orderId,
});
}
await this.simulateDelay(1000, 2000);
}
this.logger.info('Batch ship processing completed', {
total: tasks.length,
success: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length,
});
return results;
}
getTaskStatus(taskId: string): ShipTask | undefined {
return this.tasks.get(taskId);
}
getTasksByShop(shopId: string): ShipTask[] {
return Array.from(this.tasks.values()).filter(t => t.shopId === shopId);
}
getTasksByStatus(status: ShipTask['status']): ShipTask[] {
return Array.from(this.tasks.values()).filter(t => t.status === status);
}
private async reportTaskCreated(task: ShipTask): Promise<void> {
this.logger.info('Reporting task created to backend', {
taskId: task.taskId,
orderId: task.orderId,
traceId: task.traceId,
});
}
private async reportTaskStatus(task: ShipTask, result: ShipResult): Promise<void> {
this.logger.info('Reporting task status to backend', {
taskId: task.taskId,
orderId: task.orderId,
status: task.status,
traceId: task.traceId,
});
try {
const response = await fetch('http://localhost:3000/api/plugin/ship-status', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
taskId: task.taskId,
orderId: task.orderId,
shopId: task.shopId,
platform: task.platform,
status: task.status,
trackingNumber: result.trackingNumber,
carrier: result.carrier,
message: result.message,
timestamp: result.timestamp,
traceId: task.traceId,
}),
});
if (!response.ok) {
this.logger.warn('Failed to report task status', {
taskId: task.taskId,
statusCode: response.status,
});
}
} catch (error: any) {
this.logger.warn('Error reporting task status', {
taskId: task.taskId,
error: error.message,
});
}
}
private async simulateDelay(minMs: number, maxMs: number): Promise<void> {
const delay = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
return new Promise(resolve => setTimeout(resolve, delay));
}
private generateTraceId(): string {
return `trace-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
}