2026-03-20 09:53:25 +08:00
|
|
|
import { Router, Request, Response, NextFunction } from 'express';
|
2026-03-17 22:07:19 +08:00
|
|
|
import { TurboGateway } from '../../core/gateway/TurboGateway';
|
|
|
|
|
import { requireTraceContext } from '../../core/guards/trace-context.guard';
|
|
|
|
|
import { requirePermission } from '../../core/guards/rbac.guard';
|
|
|
|
|
import { ProductController } from '../controllers/ProductController';
|
2026-03-20 09:53:25 +08:00
|
|
|
import { z } from 'zod';
|
|
|
|
|
|
|
|
|
|
// 验证模式
|
|
|
|
|
const productIdSchema = z.string().min(1, 'Product ID is required');
|
|
|
|
|
const batchOperationSchema = z.object({
|
|
|
|
|
operation: z.string().min(1, 'Operation is required'),
|
|
|
|
|
productIds: z.array(z.string().min(1, 'Product ID is required')),
|
|
|
|
|
data: z.record(z.string(), z.any()).optional()
|
|
|
|
|
});
|
|
|
|
|
const platformMappingSchema = z.object({
|
|
|
|
|
productId: z.string().min(1, 'Product ID is required'),
|
|
|
|
|
platform: z.string().min(1, 'Platform is required'),
|
|
|
|
|
platformProductId: z.string().min(1, 'Platform product ID is required'),
|
|
|
|
|
mappingData: z.record(z.string(), z.any()).optional()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 验证中间件
|
|
|
|
|
const validateBody = (schema: z.ZodObject<any>) => {
|
|
|
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
|
|
|
try {
|
|
|
|
|
schema.parse(req.body);
|
|
|
|
|
next();
|
2026-03-20 17:53:46 +08:00
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
|
|
|
res.status(400).json({ error: errorMessage });
|
2026-03-20 09:53:25 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validateParam = (paramName: string, schema: z.ZodString) => {
|
|
|
|
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
|
|
|
try {
|
|
|
|
|
schema.parse(req.params[paramName]);
|
|
|
|
|
next();
|
2026-03-20 17:53:46 +08:00
|
|
|
} catch (error: unknown) {
|
|
|
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
|
|
|
res.status(400).json({ error: errorMessage });
|
2026-03-20 09:53:25 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
2026-03-17 22:07:19 +08:00
|
|
|
|
|
|
|
|
const router = Router();
|
|
|
|
|
|
|
|
|
|
// Standard CRUD
|
|
|
|
|
router.get('/', TurboGateway.cache(300), ProductController.getAll);
|
|
|
|
|
|
|
|
|
|
// Enhanced Crawlful AI functions
|
|
|
|
|
router.post('/autonomous-listing', requireTraceContext, ProductController.startAutonomousListing);
|
|
|
|
|
router.post('/collect-async', requireTraceContext, ProductController.collectAsync);
|
|
|
|
|
router.get('/collect-and-optimize', TurboGateway.throttle(10, 60000), ProductController.collectAndOptimize);
|
|
|
|
|
router.get('/:id/arbitrage-analyze', requireTraceContext, ProductController.analyzeArbitrage);
|
|
|
|
|
router.get('/visual-match', TurboGateway.cache(600), ProductController.findSimilar);
|
|
|
|
|
router.post('/:id/review', requireTraceContext, requirePermission('product:write'), ProductController.approve);
|
|
|
|
|
router.post('/:id/pulse', requireTraceContext, ProductController.checkPulse);
|
|
|
|
|
router.post('/:id/wash', requireTraceContext, requirePermission('product:write'), ProductController.washAndLocalize);
|
|
|
|
|
router.post('/:id/inquiry', requireTraceContext, requirePermission('product:write'), ProductController.generateInquiry);
|
|
|
|
|
router.get('/:id/price-advice', ProductController.getPriceAdvice);
|
|
|
|
|
router.get('/:id', TurboGateway.cache(300), ProductController.getById);
|
|
|
|
|
router.post('/', requireTraceContext, requirePermission('product:write'), ProductController.create);
|
|
|
|
|
router.put('/:id', requireTraceContext, requirePermission('product:write'), ProductController.update);
|
|
|
|
|
router.delete('/:id', requireTraceContext, requirePermission('product:delete'), ProductController.delete);
|
|
|
|
|
|
2026-03-20 09:43:50 +08:00
|
|
|
// [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);
|
|
|
|
|
|
2026-03-23 15:41:50 +08:00
|
|
|
// [BE-P101] Product Collection APIs
|
|
|
|
|
router.post('/collection-tasks', requireTraceContext, requirePermission('product:write'), ProductController.createCollectionTask);
|
|
|
|
|
router.get('/collection-tasks', requireTraceContext, ProductController.getCollectionTasks);
|
|
|
|
|
router.post('/collection-tasks/batch', requireTraceContext, requirePermission('product:write'), ProductController.batchCreateCollectionTasks);
|
|
|
|
|
router.post('/collection-tasks/:taskId/execute', requireTraceContext, requirePermission('product:write'), ProductController.executeCollectionTask);
|
|
|
|
|
router.post('/collection-tasks/:taskId/retry', requireTraceContext, requirePermission('product:write'), ProductController.retryCollectionTask);
|
|
|
|
|
|
2026-03-17 22:07:19 +08:00
|
|
|
export default router;
|