refactor(terminology): 统一术语标准并优化代码类型安全
- 将B2B统一为TOB术语 - 将状态值统一为大写格式 - 优化类型声明,避免使用any - 将float类型替换为decimal以提高精度 - 新增术语标准化文档 - 优化路由结构和菜单分类 - 添加TypeORM实体类 - 增强加密模块安全性 - 重构前端路由结构 - 完善任务模板和验收标准
This commit is contained in:
776
server/src/api/controllers/OmnichannelController.ts
Normal file
776
server/src/api/controllers/OmnichannelController.ts
Normal file
@@ -0,0 +1,776 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { OmnichannelCommunicationService } from '../services/OmnichannelCommunicationService';
|
||||
import { OmnichannelMarketingService } from '../services/OmnichannelMarketingService';
|
||||
import { UnifiedFulfillmentService } from '../services/UnifiedFulfillmentService';
|
||||
import { StoreCreationService } from '../services/StoreCreationService';
|
||||
import { CrossBorderIntegrationService } from '../services/CrossBorderIntegrationService';
|
||||
import { AuditService } from '../services/AuditService';
|
||||
import { logger } from '../utils/logger';
|
||||
|
||||
export class OmnichannelController {
|
||||
static async aggregateMessages(req: Request, res: Response) {
|
||||
const { channels } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const messages = await OmnichannelCommunicationService.aggregateMessages(tenantId, channels);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'COMMUNICATION',
|
||||
action: 'AGGREGATE_MESSAGES',
|
||||
resourceType: 'message',
|
||||
metadata: { channelCount: channels.length, messageCount: messages.length },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: messages });
|
||||
} catch (err: any) {
|
||||
logger.error(`[OmnichannelController] Aggregate messages failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async autoReply(req: Request, res: Response) {
|
||||
const { customerId, question, context } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const reply = await OmnichannelCommunicationService.autoReply(tenantId, customerId, question, context);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'COMMUNICATION',
|
||||
action: 'AUTO_REPLY',
|
||||
resourceType: 'customer',
|
||||
resourceId: customerId,
|
||||
metadata: { question },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: { reply } });
|
||||
} catch (err: any) {
|
||||
logger.error(`[OmnichannelController] Auto reply failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createTeamTask(req: Request, res: Response) {
|
||||
const { assignedTo, customerId, taskType, priority, description, dueDate } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const task = await OmnichannelCommunicationService.createTeamTask(tenantId, {
|
||||
assignedTo,
|
||||
customerId,
|
||||
taskType,
|
||||
priority,
|
||||
status: 'pending',
|
||||
description,
|
||||
dueDate: dueDate ? new Date(dueDate) : undefined,
|
||||
});
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'COMMUNICATION',
|
||||
action: 'CREATE_TEAM_TASK',
|
||||
resourceType: 'task',
|
||||
resourceId: task.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: task });
|
||||
} catch (err: any) {
|
||||
logger.error(`[OmnichannelController] Create team task failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateCustomerProfile(req: Request, res: Response) {
|
||||
const { customerId } = req.params;
|
||||
const { channels, tags, preferences } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const profile = await OmnichannelCommunicationService.updateCustomerProfile(tenantId, customerId, {
|
||||
channels,
|
||||
tags,
|
||||
preferences,
|
||||
});
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'COMMUNICATION',
|
||||
action: 'UPDATE_CUSTOMER_PROFILE',
|
||||
resourceType: 'customer',
|
||||
resourceId: customerId,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: profile });
|
||||
} catch (err: any) {
|
||||
logger.error(`[OmnichannelController] Update customer profile failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async translateMessage(req: Request, res: Response) {
|
||||
const { content, targetLanguage } = req.body;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const translated = await OmnichannelCommunicationService.translateMessage(tenantId, content, targetLanguage);
|
||||
res.json({ success: true, data: { translated } });
|
||||
} catch (err: any) {
|
||||
logger.error(`[OmnichannelController] Translate message failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class MarketingController {
|
||||
static async integrateChannels(req: Request, res: Response) {
|
||||
const { channels } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integrated = await OmnichannelMarketingService.integrateChannels(tenantId, channels);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'MARKETING',
|
||||
action: 'INTEGRATE_CHANNELS',
|
||||
resourceType: 'channel',
|
||||
metadata: { channelCount: integrated.length },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: integrated });
|
||||
} catch (err: any) {
|
||||
logger.error(`[MarketingController] Integrate channels failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createAutomation(req: Request, res: Response) {
|
||||
const { name, trigger, actions, status } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const rule = await OmnichannelMarketingService.createAutomation(tenantId, {
|
||||
name,
|
||||
trigger,
|
||||
actions,
|
||||
status: status || 'active',
|
||||
});
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'MARKETING',
|
||||
action: 'CREATE_AUTOMATION',
|
||||
resourceType: 'automation',
|
||||
resourceId: rule.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: rule });
|
||||
} catch (err: any) {
|
||||
logger.error(`[MarketingController] Create automation failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async analyzeCampaign(req: Request, res: Response) {
|
||||
const { campaignId } = req.params;
|
||||
const { start, end } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const metrics = await OmnichannelMarketingService.analyzeCampaignEffect(
|
||||
tenantId,
|
||||
campaignId,
|
||||
{ start: new Date(start as string), end: new Date(end as string) }
|
||||
);
|
||||
|
||||
res.json({ success: true, data: metrics });
|
||||
} catch (err: any) {
|
||||
logger.error(`[MarketingController] Analyze campaign failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async runABTest(req: Request, res: Response) {
|
||||
const { name, variants, trafficSplit } = req.body;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const result = await OmnichannelMarketingService.runABTest(tenantId, {
|
||||
name,
|
||||
variants,
|
||||
trafficSplit,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[MarketingController] Run A/B test failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class FulfillmentController {
|
||||
static async unifyOrders(req: Request, res: Response) {
|
||||
const { platformOrders } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const unified = await UnifiedFulfillmentService.unifyOrders(tenantId, platformOrders);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'FULFILLMENT',
|
||||
action: 'UNIFY_ORDERS',
|
||||
resourceType: 'order',
|
||||
metadata: { orderCount: unified.length },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: unified });
|
||||
} catch (err: any) {
|
||||
logger.error(`[FulfillmentController] Unify orders failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async routeOrder(req: Request, res: Response) {
|
||||
const { orderId } = req.params;
|
||||
const { inventoryData } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const route = await UnifiedFulfillmentService.routeOrder(tenantId, orderId, inventoryData);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'FULFILLMENT',
|
||||
action: 'ROUTE_ORDER',
|
||||
resourceType: 'order',
|
||||
resourceId: orderId,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: route });
|
||||
} catch (err: any) {
|
||||
logger.error(`[FulfillmentController] Route order failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async manageFulfillment(req: Request, res: Response) {
|
||||
const { orderId } = req.params;
|
||||
const { action, params } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const status = await UnifiedFulfillmentService.manageFulfillment(tenantId, orderId, action, params);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'FULFILLMENT',
|
||||
action: 'MANAGE_FULFILLMENT',
|
||||
resourceType: 'order',
|
||||
resourceId: orderId,
|
||||
metadata: { action },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: status });
|
||||
} catch (err: any) {
|
||||
logger.error(`[FulfillmentController] Manage fulfillment failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async syncStatus(req: Request, res: Response) {
|
||||
const { orderId } = req.params;
|
||||
const { status } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const result = await UnifiedFulfillmentService.syncStatus(tenantId, orderId, status);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'FULFILLMENT',
|
||||
action: 'SYNC_STATUS',
|
||||
resourceType: 'order',
|
||||
resourceId: orderId,
|
||||
metadata: { status },
|
||||
result: result.success ? 'success' : 'failed',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: result.success, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[FulfillmentController] Sync status failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class StoreCreationController {
|
||||
static async createTemplate(req: Request, res: Response) {
|
||||
const { name, category, designParams } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const template = await StoreCreationService.createTemplate(tenantId, { name, category, designParams });
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'STORE_CREATION',
|
||||
action: 'CREATE_TEMPLATE',
|
||||
resourceType: 'template',
|
||||
resourceId: template.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: template });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Create template failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updatePageComponents(req: Request, res: Response) {
|
||||
const { websiteId, pageId } = req.params;
|
||||
const { components } = req.body;
|
||||
|
||||
try {
|
||||
const page = await StoreCreationService.updatePageComponents(websiteId, pageId, components);
|
||||
res.json({ success: true, data: page });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Update page components failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async adaptResponsiveLayout(req: Request, res: Response) {
|
||||
const { websiteId, pageId } = req.params;
|
||||
const { deviceType } = req.query;
|
||||
|
||||
try {
|
||||
const components = await StoreCreationService.adaptResponsiveLayout(
|
||||
websiteId,
|
||||
pageId,
|
||||
deviceType as 'desktop' | 'tablet' | 'mobile'
|
||||
);
|
||||
res.json({ success: true, data: components });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Adapt responsive layout failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async setupMultilingual(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { languages } = req.body;
|
||||
|
||||
try {
|
||||
const config = await StoreCreationService.setupMultilingual(websiteId, languages);
|
||||
res.status(201).json({ success: true, data: config });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Setup multilingual failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createBrand(req: Request, res: Response) {
|
||||
const { name, designAssets } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const brand = await StoreCreationService.createBrand(tenantId, { name, designAssets });
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'STORE_CREATION',
|
||||
action: 'CREATE_BRAND',
|
||||
resourceType: 'brand',
|
||||
resourceId: brand.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: brand });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Create brand failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async manageContent(req: Request, res: Response) {
|
||||
const { brandId } = req.params;
|
||||
const { type, content } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.manageContent(brandId, { type, content });
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Manage content failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateEcommerce(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { features } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.integrateEcommerce(websiteId, features);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Integrate ecommerce failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateMarketing(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { params } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.integrateMarketing(websiteId, params);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Integrate marketing failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async configureShipping(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { params } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.configureShipping(websiteId, params);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Configure shipping failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async generateAnalytics(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { metrics, timeRange } = req.body;
|
||||
|
||||
try {
|
||||
const report = await StoreCreationService.generateAnalytics(websiteId, { metrics, timeRange });
|
||||
res.json({ success: true, data: report });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Generate analytics failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async optimizeSEO(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { params } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.optimizeSEO(websiteId, params);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Optimize SEO failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateSocialMedia(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { accounts } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.integrateSocialMedia(websiteId, accounts);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Integrate social media failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async manageContentMarketing(req: Request, res: Response) {
|
||||
const { websiteId } = req.params;
|
||||
const { contentData } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.manageContentMarketing(websiteId, contentData);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Manage content marketing failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async spreadBrandStory(req: Request, res: Response) {
|
||||
const { brandId } = req.params;
|
||||
const { channels, schedule } = req.body;
|
||||
|
||||
try {
|
||||
const result = await StoreCreationService.spreadBrandStory(brandId, { channels, schedule });
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[StoreCreationController] Spread brand story failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class CrossBorderController {
|
||||
static async integrateSellbrite(req: Request, res: Response) {
|
||||
const { credentials } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integration = await CrossBorderIntegrationService.integrateSellbrite(tenantId, credentials);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'INTEGRATE_SELLBRITE',
|
||||
resourceType: 'integration',
|
||||
resourceId: integration.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: integration });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Integrate Sellbrite failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateShoplazza(req: Request, res: Response) {
|
||||
const { credentials } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integration = await CrossBorderIntegrationService.integrateShoplazza(tenantId, credentials);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'INTEGRATE_SHOPLAZZA',
|
||||
resourceType: 'integration',
|
||||
resourceId: integration.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: integration });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Integrate Shoplazza failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateSaleSmartly(req: Request, res: Response) {
|
||||
const { credentials } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integration = await CrossBorderIntegrationService.integrateSaleSmartly(tenantId, credentials);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'INTEGRATE_SALESMARTLY',
|
||||
resourceType: 'integration',
|
||||
resourceId: integration.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: integration });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Integrate SaleSmartly failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async syncInventory(req: Request, res: Response) {
|
||||
const { inventoryData } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const records = await CrossBorderIntegrationService.syncInventoryToPlatforms(tenantId, inventoryData);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'SYNC_INVENTORY',
|
||||
resourceType: 'inventory',
|
||||
metadata: { recordCount: records.length },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: records });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Sync inventory failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async integrateMarketing(req: Request, res: Response) {
|
||||
const { platform, campaignId, config } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integration = await CrossBorderIntegrationService.integrateMarketing(tenantId, {
|
||||
platform,
|
||||
campaignId,
|
||||
config,
|
||||
});
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'INTEGRATE_MARKETING',
|
||||
resourceType: 'marketing',
|
||||
resourceId: integration.id,
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: integration });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Integrate marketing failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getIntegrationStatus(req: Request, res: Response) {
|
||||
const { platform } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const integrations = await CrossBorderIntegrationService.getIntegrationStatus(
|
||||
tenantId,
|
||||
platform as string
|
||||
);
|
||||
res.json({ success: true, data: integrations });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Get integration status failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async disconnectPlatform(req: Request, res: Response) {
|
||||
const { platform } = req.params;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const result = await CrossBorderIntegrationService.disconnectPlatform(tenantId, platform);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'CROSS_BORDER',
|
||||
action: 'DISCONNECT_PLATFORM',
|
||||
resourceType: 'integration',
|
||||
metadata: { platform },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CrossBorderController] Disconnect platform failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { CompetitorPulseService } from '../../services/CompetitorPulseService';
|
||||
import { ConfigService } from '../../services/ConfigService';
|
||||
import { CrawlerService } from '../../services/CrawlerService';
|
||||
import { DynamicPricingService } from '../../services/DynamicPricingService';
|
||||
import { MultiPlatformProductService } from '../../services/MultiPlatformProductService';
|
||||
import { ProductService } from '../../services/ProductService';
|
||||
import { SupplierInquiryService } from '../../services/SupplierInquiryService';
|
||||
import { SupplyChainService } from '../../services/SupplyChainService';
|
||||
@@ -511,4 +512,148 @@ export class ProductController {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [BE-P006] 多平台商品整合接口
|
||||
*/
|
||||
static async createPlatformMapping(req: Request, res: Response) {
|
||||
const { masterProductId, masterPlatform, platformMappings } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const mappings = await MultiPlatformProductService.createMapping(
|
||||
tenantId,
|
||||
masterProductId,
|
||||
masterPlatform,
|
||||
platformMappings
|
||||
);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'PRODUCT',
|
||||
action: 'CREATE_PLATFORM_MAPPING',
|
||||
resourceType: 'product',
|
||||
resourceId: masterProductId,
|
||||
afterSnapshot: { mappings },
|
||||
result: 'success',
|
||||
source: 'console'
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: mappings });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [BE-P006] 获取商品的平台映射
|
||||
*/
|
||||
static async getPlatformMappings(req: Request, res: Response) {
|
||||
const { productId } = req.params;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const mappings = await MultiPlatformProductService.getMappings(tenantId, productId);
|
||||
res.json({ success: true, data: mappings });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [BE-P007] 批量商品操作接口
|
||||
*/
|
||||
static async batchOperation(req: Request, res: Response) {
|
||||
const { productIds, operation } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const result = await MultiPlatformProductService.batchOperation(
|
||||
tenantId,
|
||||
productIds,
|
||||
operation
|
||||
);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'PRODUCT',
|
||||
action: 'BATCH_OPERATION',
|
||||
resourceType: 'product',
|
||||
metadata: { operation, totalItems: result.totalItems, successItems: result.successItems },
|
||||
result: result.success ? 'success' : 'partial',
|
||||
source: 'console'
|
||||
});
|
||||
|
||||
res.json({ success: result.success, data: result });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [BE-P008] 跨平台库存同步接口
|
||||
*/
|
||||
static async syncInventory(req: Request, res: Response) {
|
||||
const { productId } = req.params;
|
||||
const { quantity, platforms } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const syncResults = await MultiPlatformProductService.syncInventory(
|
||||
tenantId,
|
||||
productId,
|
||||
quantity,
|
||||
platforms
|
||||
);
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'PRODUCT',
|
||||
action: 'SYNC_INVENTORY',
|
||||
resourceType: 'product',
|
||||
resourceId: productId,
|
||||
afterSnapshot: { quantity, syncResults },
|
||||
result: 'success',
|
||||
source: 'console'
|
||||
});
|
||||
|
||||
res.json({ success: true, data: syncResults });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [BE-P008] 获取库存同步状态
|
||||
*/
|
||||
static async getSyncStatus(req: Request, res: Response) {
|
||||
const { productId } = req.params;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const mappings = await MultiPlatformProductService.getMappings(tenantId, productId);
|
||||
const syncStatus = mappings.map((m) => ({
|
||||
platform: m.platform,
|
||||
platformProductId: m.platformProductId,
|
||||
status: m.status,
|
||||
lastSyncAt: m.lastSyncAt,
|
||||
syncError: m.syncError,
|
||||
}));
|
||||
res.json({ success: true, data: syncStatus });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
791
server/src/api/controllers/SettingsController.ts
Normal file
791
server/src/api/controllers/SettingsController.ts
Normal file
@@ -0,0 +1,791 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { WinNodeService } from '../services/WinNodeService';
|
||||
import { TaskCenterService } from '../services/TaskCenterService';
|
||||
import { IndependentSiteService } from '../services/IndependentSiteService';
|
||||
import { CostTemplateService } from '../services/CostTemplateService';
|
||||
import { PlatformAccountService } from '../services/PlatformAccountService';
|
||||
import { ReturnService } from '../services/ReturnService';
|
||||
import { AuditService } from '../services/AuditService';
|
||||
import { logger } from '../utils/logger';
|
||||
|
||||
export class WinNodeController {
|
||||
static async list(req: Request, res: Response) {
|
||||
const { status, shopId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const nodes = await WinNodeService.list(tenantId, { status: status as string, shopId: shopId as string });
|
||||
res.json({ success: true, data: nodes });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] List failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getById(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const node = await WinNodeService.getById(id);
|
||||
if (!node) {
|
||||
res.status(404).json({ success: false, error: 'Node not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data: node });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Get by id failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async create(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const node = await WinNodeService.create(tenantId, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: req.body.shopId,
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'WINNODE',
|
||||
action: 'CREATE',
|
||||
resourceType: 'winnode',
|
||||
metadata: { nodeId: node.id, name: node.name },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: node });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Create failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async update(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const node = await WinNodeService.update(id, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: node.shopId,
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'WINNODE',
|
||||
action: 'UPDATE',
|
||||
resourceType: 'winnode',
|
||||
metadata: { nodeId: id },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: node });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Update failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
await WinNodeService.delete(id);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: '',
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'WINNODE',
|
||||
action: 'DELETE',
|
||||
resourceType: 'winnode',
|
||||
metadata: { nodeId: id },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Delete failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async testConnection(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const result = await WinNodeService.testConnection(id);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Test connection failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async restart(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const result = await WinNodeService.restart(id);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Restart failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async heartbeat(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await WinNodeService.heartbeat(id, req.body);
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Heartbeat failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getStats(req: Request, res: Response) {
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const stats = await WinNodeService.getStats(tenantId);
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (err: any) {
|
||||
logger.error(`[WinNodeController] Get stats failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TaskCenterController {
|
||||
static async list(req: Request, res: Response) {
|
||||
const { status, taskType, shopId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const tasks = await TaskCenterService.list(tenantId, {
|
||||
status: status as string,
|
||||
taskType: taskType as string,
|
||||
shopId: shopId as string,
|
||||
});
|
||||
res.json({ success: true, data: tasks });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] List failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getById(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const task = await TaskCenterService.getById(id);
|
||||
if (!task) {
|
||||
res.status(404).json({ success: false, error: 'Task not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data: task });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Get by id failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async create(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const task = await TaskCenterService.create(tenantId, { ...req.body, traceId });
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: req.body.shopId,
|
||||
taskId: task.id,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'TASKCENTER',
|
||||
action: 'CREATE',
|
||||
resourceType: 'task',
|
||||
metadata: { taskId: task.id, taskType: task.taskType },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: task });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Create failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateStatus(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { status, progress, output, error } = req.body;
|
||||
|
||||
try {
|
||||
const task = await TaskCenterService.updateStatus(id, status, progress, output, error);
|
||||
res.json({ success: true, data: task });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Update status failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async cancel(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await TaskCenterService.cancel(id);
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Cancel failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async retry(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const task = await TaskCenterService.retry(id);
|
||||
res.json({ success: true, data: task });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Retry failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getStats(req: Request, res: Response) {
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const stats = await TaskCenterService.getStats(tenantId);
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (err: any) {
|
||||
logger.error(`[TaskCenterController] Get stats failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class IndependentSiteController {
|
||||
static async listSites(req: Request, res: Response) {
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const sites = await IndependentSiteService.listSites(tenantId);
|
||||
res.json({ success: true, data: sites });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] List sites failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getSiteById(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const site = await IndependentSiteService.getSiteById(id);
|
||||
if (!site) {
|
||||
res.status(404).json({ success: false, error: 'Site not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data: site });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Get site failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createSite(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const site = await IndependentSiteService.createSite(tenantId, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: '',
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'INDEPENDENTSITE',
|
||||
action: 'CREATE',
|
||||
resourceType: 'site',
|
||||
metadata: { siteId: site.id, domain: site.domain },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: site });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Create site failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateSite(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const site = await IndependentSiteService.updateSite(id, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: '',
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'INDEPENDENTSITE',
|
||||
action: 'UPDATE',
|
||||
resourceType: 'site',
|
||||
metadata: { siteId: id },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: site });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Update site failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async deleteSite(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
await IndependentSiteService.deleteSite(id);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: '',
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'INDEPENDENTSITE',
|
||||
action: 'DELETE',
|
||||
resourceType: 'site',
|
||||
metadata: { siteId: id },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Delete site failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async syncProducts(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { productIds } = req.body;
|
||||
|
||||
try {
|
||||
const results = await IndependentSiteService.syncProducts(id, productIds);
|
||||
res.json({ success: true, data: results });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Sync products failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getSiteProducts(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const products = await IndependentSiteService.getSiteProducts(id);
|
||||
res.json({ success: true, data: products });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Get products failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getSiteOrders(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { status } = req.query;
|
||||
|
||||
try {
|
||||
const orders = await IndependentSiteService.getSiteOrders(id, { status: status as string });
|
||||
res.json({ success: true, data: orders });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Get orders failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getSiteAnalytics(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { start, end } = req.query;
|
||||
|
||||
try {
|
||||
const analytics = await IndependentSiteService.getSiteAnalytics(id, {
|
||||
start: start as string,
|
||||
end: end as string,
|
||||
});
|
||||
res.json({ success: true, data: analytics });
|
||||
} catch (err: any) {
|
||||
logger.error(`[IndependentSiteController] Get analytics failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class CostTemplateController {
|
||||
static async list(req: Request, res: Response) {
|
||||
const { platform, category } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const templates = await CostTemplateService.list(tenantId, {
|
||||
platform: platform as string,
|
||||
category: category as string,
|
||||
});
|
||||
res.json({ success: true, data: templates });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] List failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getById(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const template = await CostTemplateService.getById(id);
|
||||
if (!template) {
|
||||
res.status(404).json({ success: false, error: 'Template not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data: template });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Get failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async create(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const template = await CostTemplateService.create(tenantId, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: '',
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'COSTTEMPLATE',
|
||||
action: 'CREATE',
|
||||
resourceType: 'cost_template',
|
||||
metadata: { templateId: template.id, name: template.name },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: template });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Create failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async update(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const template = await CostTemplateService.update(id, req.body);
|
||||
res.json({ success: true, data: template });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Update failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await CostTemplateService.delete(id);
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Delete failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async duplicate(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const template = await CostTemplateService.duplicate(id);
|
||||
res.json({ success: true, data: template });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Duplicate failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async calculateCost(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { basePrice, quantity } = req.body;
|
||||
|
||||
try {
|
||||
const result = await CostTemplateService.calculateCost(id, basePrice, quantity);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[CostTemplateController] Calculate cost failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PlatformAccountController {
|
||||
static async list(req: Request, res: Response) {
|
||||
const { platform, status, shopId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const accounts = await PlatformAccountService.list(tenantId, {
|
||||
platform: platform as string,
|
||||
status: status as string,
|
||||
shopId: shopId as string,
|
||||
});
|
||||
res.json({ success: true, data: accounts });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] List failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getById(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const account = await PlatformAccountService.getById(id);
|
||||
if (!account) {
|
||||
res.status(404).json({ success: false, error: 'Account not found' });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data: account });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Get failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async create(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const account = await PlatformAccountService.create(tenantId, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: req.body.shopId,
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'PLATFORMACCOUNT',
|
||||
action: 'CREATE',
|
||||
resourceType: 'platform_account',
|
||||
metadata: { accountId: account.id, platform: account.platform },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: account });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Create failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async update(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const account = await PlatformAccountService.update(id, req.body);
|
||||
res.json({ success: true, data: account });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Update failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
await PlatformAccountService.delete(id);
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Delete failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async refreshToken(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const result = await PlatformAccountService.refreshToken(id);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Refresh token failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async testConnection(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const result = await PlatformAccountService.testConnection(id);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Test connection failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async sync(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const result = await PlatformAccountService.syncAccount(id);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Sync failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getStats(req: Request, res: Response) {
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const stats = await PlatformAccountService.getStats(tenantId);
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (err: any) {
|
||||
logger.error(`[PlatformAccountController] Get stats failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ReturnController {
|
||||
static async fetchSKUData(req: Request, res: Response) {
|
||||
const { status, shopId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const data = await ReturnService.fetchSKUData(tenantId, {
|
||||
status: status as string,
|
||||
shopId: shopId as string,
|
||||
});
|
||||
res.json({ success: true, data });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Fetch SKU data failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateSKUStatus(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
try {
|
||||
const sku = await ReturnService.updateSKUStatus(id, status);
|
||||
res.json({ success: true, data: sku });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Update SKU status failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async fetchReturns(req: Request, res: Response) {
|
||||
const { status, shopId, skuId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const data = await ReturnService.fetchReturns(tenantId, {
|
||||
status: status as string,
|
||||
shopId: shopId as string,
|
||||
skuId: skuId as string,
|
||||
});
|
||||
res.json({ success: true, data });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Fetch returns failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createReturn(req: Request, res: Response) {
|
||||
const { tenantId, userId, traceId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const returnData = await ReturnService.createReturn(tenantId, req.body);
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId: req.body.shopId,
|
||||
taskId: '',
|
||||
traceId,
|
||||
userId,
|
||||
module: 'RETURN',
|
||||
action: 'CREATE',
|
||||
resourceType: 'return',
|
||||
metadata: { returnId: returnData.id, orderId: returnData.orderId },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: returnData });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Create return failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateReturnStatus(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
try {
|
||||
const returnData = await ReturnService.updateReturnStatus(id, status);
|
||||
res.json({ success: true, data: returnData });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Update return status failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getTrend(req: Request, res: Response) {
|
||||
const { shopId, startDate, endDate } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const trend = await ReturnService.getReturnTrend(tenantId, {
|
||||
shopId: shopId as string,
|
||||
startDate: startDate as string,
|
||||
endDate: endDate as string,
|
||||
});
|
||||
res.json({ success: true, data: trend });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Get trend failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getStats(req: Request, res: Response) {
|
||||
const { shopId } = req.query;
|
||||
const { tenantId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const stats = await ReturnService.getReturnStats(tenantId, { shopId: shopId as string });
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (err: any) {
|
||||
logger.error(`[ReturnController] Get stats failed: ${err.message}`);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,8 @@
|
||||
import { IsString, IsOptional, IsObject } from 'class-validator';
|
||||
|
||||
export class StoreBindingDto {
|
||||
@IsString()
|
||||
merchantId: string;
|
||||
|
||||
@IsString()
|
||||
platform: string;
|
||||
|
||||
@IsString()
|
||||
platformShopId: string;
|
||||
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@IsObject()
|
||||
authInfo: Record<string, any>;
|
||||
}
|
||||
|
||||
284
server/src/api/routes/omnichannel.ts
Normal file
284
server/src/api/routes/omnichannel.ts
Normal file
@@ -0,0 +1,284 @@
|
||||
import { Router } from 'express';
|
||||
import { requireTraceContext } from '../../core/guards/trace-context.guard';
|
||||
import { requirePermission } from '../../core/guards/rbac.guard';
|
||||
import {
|
||||
OmnichannelController,
|
||||
MarketingController,
|
||||
FulfillmentController,
|
||||
StoreCreationController,
|
||||
CrossBorderController,
|
||||
} from '../controllers/OmnichannelController';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// [BE-CS005] Omnichannel message aggregation
|
||||
router.post(
|
||||
'/communication/aggregate',
|
||||
requireTraceContext,
|
||||
requirePermission('communication:read'),
|
||||
OmnichannelController.aggregateMessages
|
||||
);
|
||||
|
||||
// [BE-CS006] Intelligent automated customer service
|
||||
router.post(
|
||||
'/communication/auto-reply',
|
||||
requireTraceContext,
|
||||
requirePermission('communication:write'),
|
||||
OmnichannelController.autoReply
|
||||
);
|
||||
|
||||
// [BE-CS007] Team collaboration management
|
||||
router.post(
|
||||
'/communication/team-task',
|
||||
requireTraceContext,
|
||||
requirePermission('communication:write'),
|
||||
OmnichannelController.createTeamTask
|
||||
);
|
||||
|
||||
// [BE-CS008] Customer fine-grained management
|
||||
router.put(
|
||||
'/communication/customer/:customerId/profile',
|
||||
requireTraceContext,
|
||||
requirePermission('customer:write'),
|
||||
OmnichannelController.updateCustomerProfile
|
||||
);
|
||||
|
||||
// [BE-CS009] Cross-border communication adaptation
|
||||
router.post(
|
||||
'/communication/translate',
|
||||
requireTraceContext,
|
||||
requirePermission('communication:write'),
|
||||
OmnichannelController.translateMessage
|
||||
);
|
||||
|
||||
// [BE-AD004] Multi-channel integration
|
||||
router.post(
|
||||
'/marketing/channels',
|
||||
requireTraceContext,
|
||||
requirePermission('marketing:write'),
|
||||
MarketingController.integrateChannels
|
||||
);
|
||||
|
||||
// [BE-AD005] Intelligent marketing automation
|
||||
router.post(
|
||||
'/marketing/automation',
|
||||
requireTraceContext,
|
||||
requirePermission('marketing:write'),
|
||||
MarketingController.createAutomation
|
||||
);
|
||||
|
||||
// [BE-AD006] Marketing effect analysis
|
||||
router.get(
|
||||
'/marketing/campaign/:campaignId/analyze',
|
||||
requireTraceContext,
|
||||
requirePermission('marketing:read'),
|
||||
MarketingController.analyzeCampaign
|
||||
);
|
||||
|
||||
// [BE-AD007] A/B test automation
|
||||
router.post(
|
||||
'/marketing/ab-test',
|
||||
requireTraceContext,
|
||||
requirePermission('marketing:write'),
|
||||
MarketingController.runABTest
|
||||
);
|
||||
|
||||
// [BE-O005] Multi-platform order unification
|
||||
router.post(
|
||||
'/fulfillment/orders/unify',
|
||||
requireTraceContext,
|
||||
requirePermission('order:write'),
|
||||
FulfillmentController.unifyOrders
|
||||
);
|
||||
|
||||
// [BE-O006] Intelligent order routing
|
||||
router.post(
|
||||
'/fulfillment/order/:orderId/route',
|
||||
requireTraceContext,
|
||||
requirePermission('order:write'),
|
||||
FulfillmentController.routeOrder
|
||||
);
|
||||
|
||||
// [BE-O007] Full-process fulfillment management
|
||||
router.post(
|
||||
'/fulfillment/order/:orderId/manage',
|
||||
requireTraceContext,
|
||||
requirePermission('order:write'),
|
||||
FulfillmentController.manageFulfillment
|
||||
);
|
||||
|
||||
// [BE-O008] Cross-platform status sync
|
||||
router.post(
|
||||
'/fulfillment/order/:orderId/sync-status',
|
||||
requireTraceContext,
|
||||
requirePermission('order:write'),
|
||||
FulfillmentController.syncStatus
|
||||
);
|
||||
|
||||
// [BE-SC001] Template-based website design
|
||||
router.post(
|
||||
'/store/template',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.createTemplate
|
||||
);
|
||||
|
||||
// [BE-SC002] Drag-and-drop page editor
|
||||
router.put(
|
||||
'/store/website/:websiteId/page/:pageId/components',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.updatePageComponents
|
||||
);
|
||||
|
||||
// [BE-SC003] Responsive layout adaptation
|
||||
router.get(
|
||||
'/store/website/:websiteId/page/:pageId/adapt',
|
||||
requireTraceContext,
|
||||
StoreCreationController.adaptResponsiveLayout
|
||||
);
|
||||
|
||||
// [BE-SC004] Multilingual support
|
||||
router.post(
|
||||
'/store/website/:websiteId/multilingual',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.setupMultilingual
|
||||
);
|
||||
|
||||
// [BE-SC005] Brand identity and visual design
|
||||
router.post(
|
||||
'/store/brand',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.createBrand
|
||||
);
|
||||
|
||||
// [BE-SC006] Brand story and content management
|
||||
router.post(
|
||||
'/store/brand/:brandId/content',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.manageContent
|
||||
);
|
||||
|
||||
// [BE-SC007] Ecommerce feature integration
|
||||
router.post(
|
||||
'/store/website/:websiteId/ecommerce',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.integrateEcommerce
|
||||
);
|
||||
|
||||
// [BE-SC008] Marketing tool integration
|
||||
router.post(
|
||||
'/store/website/:websiteId/marketing',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.integrateMarketing
|
||||
);
|
||||
|
||||
// [BE-SC009] Shipping and delivery configuration
|
||||
router.post(
|
||||
'/store/website/:websiteId/shipping',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.configureShipping
|
||||
);
|
||||
|
||||
// [BE-SC010] Data analysis and reporting
|
||||
router.post(
|
||||
'/store/website/:websiteId/analytics',
|
||||
requireTraceContext,
|
||||
requirePermission('store:read'),
|
||||
StoreCreationController.generateAnalytics
|
||||
);
|
||||
|
||||
// [BE-SC011] SEO optimization
|
||||
router.post(
|
||||
'/store/website/:websiteId/seo',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.optimizeSEO
|
||||
);
|
||||
|
||||
// [BE-SC012] Social media integration
|
||||
router.post(
|
||||
'/store/website/:websiteId/social',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.integrateSocialMedia
|
||||
);
|
||||
|
||||
// [BE-SC013] Content marketing support
|
||||
router.post(
|
||||
'/store/website/:websiteId/content-marketing',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.manageContentMarketing
|
||||
);
|
||||
|
||||
// [BE-SC014] Brand story spreading
|
||||
router.post(
|
||||
'/store/brand/:brandId/spread',
|
||||
requireTraceContext,
|
||||
requirePermission('store:write'),
|
||||
StoreCreationController.spreadBrandStory
|
||||
);
|
||||
|
||||
// [BE-CB006] Sellbrite platform integration
|
||||
router.post(
|
||||
'/cross-border/sellbrite',
|
||||
requireTraceContext,
|
||||
requirePermission('integration:write'),
|
||||
CrossBorderController.integrateSellbrite
|
||||
);
|
||||
|
||||
// [BE-CB007] Shoplazza platform integration
|
||||
router.post(
|
||||
'/cross-border/shoplazza',
|
||||
requireTraceContext,
|
||||
requirePermission('integration:write'),
|
||||
CrossBorderController.integrateShoplazza
|
||||
);
|
||||
|
||||
// [BE-CB008] SaleSmartly platform integration
|
||||
router.post(
|
||||
'/cross-border/salesmartly',
|
||||
requireTraceContext,
|
||||
requirePermission('integration:write'),
|
||||
CrossBorderController.integrateSaleSmartly
|
||||
);
|
||||
|
||||
// [BE-CB009] Multi-platform inventory sync
|
||||
router.post(
|
||||
'/cross-border/inventory/sync',
|
||||
requireTraceContext,
|
||||
requirePermission('inventory:write'),
|
||||
CrossBorderController.syncInventory
|
||||
);
|
||||
|
||||
// [BE-CB010] Omnichannel marketing integration
|
||||
router.post(
|
||||
'/cross-border/marketing',
|
||||
requireTraceContext,
|
||||
requirePermission('marketing:write'),
|
||||
CrossBorderController.integrateMarketing
|
||||
);
|
||||
|
||||
// Get integration status
|
||||
router.get(
|
||||
'/cross-border/integration',
|
||||
requireTraceContext,
|
||||
CrossBorderController.getIntegrationStatus
|
||||
);
|
||||
|
||||
// Disconnect platform
|
||||
router.delete(
|
||||
'/cross-border/integration/:platform',
|
||||
requireTraceContext,
|
||||
requirePermission('integration:write'),
|
||||
CrossBorderController.disconnectPlatform
|
||||
);
|
||||
|
||||
export default router;
|
||||
@@ -25,4 +25,15 @@ router.post('/', requireTraceContext, requirePermission('product:write'), Produc
|
||||
router.put('/:id', requireTraceContext, requirePermission('product:write'), ProductController.update);
|
||||
router.delete('/:id', requireTraceContext, requirePermission('product:delete'), ProductController.delete);
|
||||
|
||||
// [BE-P006] Multi-platform product mapping
|
||||
router.post('/platform-mapping', requireTraceContext, requirePermission('product:write'), ProductController.createPlatformMapping);
|
||||
router.get('/:productId/platform-mappings', requireTraceContext, ProductController.getPlatformMappings);
|
||||
|
||||
// [BE-P007] Batch operations
|
||||
router.post('/batch', requireTraceContext, requirePermission('product:write'), ProductController.batchOperation);
|
||||
|
||||
// [BE-P008] Cross-platform inventory sync
|
||||
router.post('/:productId/sync-inventory', requireTraceContext, requirePermission('product:write'), ProductController.syncInventory);
|
||||
router.get('/:productId/sync-status', requireTraceContext, ProductController.getSyncStatus);
|
||||
|
||||
export default router;
|
||||
|
||||
355
server/src/api/routes/settings.ts
Normal file
355
server/src/api/routes/settings.ts
Normal file
@@ -0,0 +1,355 @@
|
||||
import { Router } from 'express';
|
||||
import { requireTraceContext } from '../../core/guards/trace-context.guard';
|
||||
import { requirePermission } from '../../core/guards/rbac.guard';
|
||||
import {
|
||||
WinNodeController,
|
||||
TaskCenterController,
|
||||
IndependentSiteController,
|
||||
CostTemplateController,
|
||||
PlatformAccountController,
|
||||
ReturnController,
|
||||
} from '../controllers/SettingsController';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// WinNode routes
|
||||
router.get(
|
||||
'/winnode',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
WinNodeController.list
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/winnode/stats',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
WinNodeController.getStats
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/winnode/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
WinNodeController.getById
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/winnode',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
WinNodeController.create
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/winnode/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
WinNodeController.update
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/winnode/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
WinNodeController.delete
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/winnode/:id/test',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
WinNodeController.testConnection
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/winnode/:id/restart',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
WinNodeController.restart
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/winnode/:id/heartbeat',
|
||||
WinNodeController.heartbeat
|
||||
);
|
||||
|
||||
// TaskCenter routes
|
||||
router.get(
|
||||
'/taskcenter',
|
||||
requireTraceContext,
|
||||
requirePermission('task:read'),
|
||||
TaskCenterController.list
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/taskcenter/stats',
|
||||
requireTraceContext,
|
||||
requirePermission('task:read'),
|
||||
TaskCenterController.getStats
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/taskcenter/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('task:read'),
|
||||
TaskCenterController.getById
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/taskcenter',
|
||||
requireTraceContext,
|
||||
requirePermission('task:write'),
|
||||
TaskCenterController.create
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/taskcenter/:id/status',
|
||||
requireTraceContext,
|
||||
requirePermission('task:write'),
|
||||
TaskCenterController.updateStatus
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/taskcenter/:id/cancel',
|
||||
requireTraceContext,
|
||||
requirePermission('task:write'),
|
||||
TaskCenterController.cancel
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/taskcenter/:id/retry',
|
||||
requireTraceContext,
|
||||
requirePermission('task:write'),
|
||||
TaskCenterController.retry
|
||||
);
|
||||
|
||||
// IndependentSite routes
|
||||
router.get(
|
||||
'/independent-site',
|
||||
requireTraceContext,
|
||||
requirePermission('site:read'),
|
||||
IndependentSiteController.listSites
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/independent-site/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('site:read'),
|
||||
IndependentSiteController.getSiteById
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/independent-site',
|
||||
requireTraceContext,
|
||||
requirePermission('site:write'),
|
||||
IndependentSiteController.createSite
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/independent-site/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('site:write'),
|
||||
IndependentSiteController.updateSite
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/independent-site/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('site:write'),
|
||||
IndependentSiteController.deleteSite
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/independent-site/:id/sync-products',
|
||||
requireTraceContext,
|
||||
requirePermission('site:write'),
|
||||
IndependentSiteController.syncProducts
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/independent-site/:id/products',
|
||||
requireTraceContext,
|
||||
requirePermission('site:read'),
|
||||
IndependentSiteController.getSiteProducts
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/independent-site/:id/orders',
|
||||
requireTraceContext,
|
||||
requirePermission('site:read'),
|
||||
IndependentSiteController.getSiteOrders
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/independent-site/:id/analytics',
|
||||
requireTraceContext,
|
||||
requirePermission('site:read'),
|
||||
IndependentSiteController.getSiteAnalytics
|
||||
);
|
||||
|
||||
// CostTemplate routes
|
||||
router.get(
|
||||
'/cost-template',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
CostTemplateController.list
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/cost-template/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
CostTemplateController.getById
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/cost-template',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
CostTemplateController.create
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/cost-template/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
CostTemplateController.update
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/cost-template/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
CostTemplateController.delete
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/cost-template/:id/duplicate',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
CostTemplateController.duplicate
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/cost-template/:id/calculate',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
CostTemplateController.calculateCost
|
||||
);
|
||||
|
||||
// PlatformAccount routes
|
||||
router.get(
|
||||
'/platform-account',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
PlatformAccountController.list
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/platform-account/stats',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
PlatformAccountController.getStats
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/platform-account/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:read'),
|
||||
PlatformAccountController.getById
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/platform-account',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.create
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/platform-account/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.update
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/platform-account/:id',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.delete
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/platform-account/:id/refresh-token',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.refreshToken
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/platform-account/:id/test',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.testConnection
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/platform-account/:id/sync',
|
||||
requireTraceContext,
|
||||
requirePermission('settings:write'),
|
||||
PlatformAccountController.sync
|
||||
);
|
||||
|
||||
// Return routes
|
||||
router.get(
|
||||
'/return/sku',
|
||||
requireTraceContext,
|
||||
requirePermission('return:read'),
|
||||
ReturnController.fetchSKUData
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/return/sku/:id/status',
|
||||
requireTraceContext,
|
||||
requirePermission('return:write'),
|
||||
ReturnController.updateSKUStatus
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/return',
|
||||
requireTraceContext,
|
||||
requirePermission('return:read'),
|
||||
ReturnController.fetchReturns
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/return',
|
||||
requireTraceContext,
|
||||
requirePermission('return:write'),
|
||||
ReturnController.createReturn
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/return/:id/status',
|
||||
requireTraceContext,
|
||||
requirePermission('return:write'),
|
||||
ReturnController.updateReturnStatus
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/return/trend',
|
||||
requireTraceContext,
|
||||
requirePermission('return:read'),
|
||||
ReturnController.getTrend
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/return/stats',
|
||||
requireTraceContext,
|
||||
requirePermission('return:read'),
|
||||
ReturnController.getStats
|
||||
);
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user