feat: 初始化项目结构并添加核心功能模块
- 新增文档模板和导航结构 - 实现服务器基础API路由和控制器 - 添加扩展插件配置和前端框架 - 引入多租户和权限管理模块 - 集成日志和数据库配置 - 添加核心业务模型和类型定义
This commit is contained in:
160
server/src/api/controllers/SyncController.ts
Normal file
160
server/src/api/controllers/SyncController.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { Request, Response } from 'express';
|
||||
import db from '../../config/database';
|
||||
import { isValidSyncStatusTransition } from '../../core/guards/state-transition.guard';
|
||||
import { AuditService } from '../../services/AuditService';
|
||||
|
||||
export class SyncController {
|
||||
/**
|
||||
* [UX_DEV_03] 接收插件端上报的 E2E 异常
|
||||
*/
|
||||
static async reportAudit(req: Request, res: Response) {
|
||||
try {
|
||||
const { action, targetType, targetId, metadata } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId, roleCode } = (req as any).traceContext;
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
roleCode,
|
||||
module: 'SYNC',
|
||||
action: action || 'AUDIT_REPORT',
|
||||
resourceType: targetType || 'sync',
|
||||
resourceId: targetId ? String(targetId) : undefined,
|
||||
result: 'success',
|
||||
source: 'extension',
|
||||
metadata,
|
||||
});
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分发产品数据至全平台 (Mock 实现,实际应触发各平台发布 Worker)
|
||||
*/
|
||||
static async distribute(req: Request, res: Response) {
|
||||
try {
|
||||
const { originalUrl, productData } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId, roleCode } = (req as any).traceContext;
|
||||
|
||||
const platforms = ['Temu', 'TikTok', 'Shopee'];
|
||||
|
||||
for (const platform of platforms) {
|
||||
const existing = await db('cf_sync_status')
|
||||
.where({ originalUrl, platform })
|
||||
.first();
|
||||
|
||||
if (existing) {
|
||||
await db('cf_sync_status')
|
||||
.where({ id: existing.id })
|
||||
.update({
|
||||
status: 'pending',
|
||||
productData: JSON.stringify(productData || {}),
|
||||
updated_at: new Date()
|
||||
});
|
||||
} else {
|
||||
await db('cf_sync_status').insert({
|
||||
originalUrl,
|
||||
platform,
|
||||
status: 'pending',
|
||||
productData: JSON.stringify(productData || {}),
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
roleCode,
|
||||
module: 'SYNC',
|
||||
action: 'DISTRIBUTE',
|
||||
resourceType: 'sync',
|
||||
resourceId: String(originalUrl || ''),
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
res.json({ success: true, data: { triggered: true } });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async recordAction(req: Request, res: Response) {
|
||||
try {
|
||||
const { platform, action, status } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId, roleCode } = (req as any).traceContext;
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
roleCode,
|
||||
module: 'SYNC',
|
||||
action: 'RECORD_ACTION',
|
||||
resourceType: 'sync_log',
|
||||
resourceId: platform,
|
||||
afterSnapshot: { action, status },
|
||||
result: 'success',
|
||||
source: 'console',
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [FSM] 状态流转控制
|
||||
*/
|
||||
static async updateStatus(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { status } = req.body;
|
||||
const { tenantId, shopId, taskId, traceId, userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const record = await db('cf_sync_status').where({ id }).first();
|
||||
if (!record) return res.status(404).json({ success: false, error: 'Sync record not found' });
|
||||
|
||||
const previousStatus = record.status;
|
||||
const nextStatus = status;
|
||||
|
||||
if (!isValidSyncStatusTransition(previousStatus, nextStatus)) {
|
||||
return res.status(400).json({ success: false, error: `Invalid sync status transition: ${previousStatus} -> ${nextStatus}` });
|
||||
}
|
||||
|
||||
await db('cf_sync_status').where({ id }).update({ status: nextStatus, updated_at: new Date() });
|
||||
|
||||
await AuditService.log({
|
||||
tenantId,
|
||||
shopId,
|
||||
taskId,
|
||||
traceId,
|
||||
userId,
|
||||
module: 'SYNC',
|
||||
action: 'UPDATE_SYNC_STATUS',
|
||||
resourceType: 'sync',
|
||||
resourceId: String(record.id),
|
||||
beforeSnapshot: { status: previousStatus },
|
||||
afterSnapshot: { status: nextStatus },
|
||||
result: 'success',
|
||||
source: 'node',
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user