import type { Request, Response } from 'express'; type ProductStatus = | 'draft' | 'pending_review' | 'online' | 'offline' | 'rejected'; type ProductItem = { id: string; name: string; category: string; sku: string; originalPrice: number; salePrice: number; costPrice?: number; stock: number; safetyStock: number; status: ProductStatus; description?: string; imageUrl?: string; createdAt: string; updatedAt: string; }; type ProductBody = Partial; const PRODUCT_STATUS_LIST: ProductStatus[] = [ 'draft', 'pending_review', 'online', 'offline', 'rejected', ]; const now = () => new Date().toISOString(); let productList: ProductItem[] = [ { id: 'prod-1001', name: '智能降噪耳机 Pro', category: 'audio', sku: 'AUDIO-001', originalPrice: 1599, salePrice: 1299, costPrice: 760, stock: 45, safetyStock: 20, status: 'online', description: '旗舰主动降噪,支持空间音频。', imageUrl: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?q=80&w=200&auto=format&fit=crop', createdAt: '2024-02-14T09:00:00.000Z', updatedAt: '2024-02-14T09:00:00.000Z', }, { id: 'prod-1002', name: '机械键盘无线版', category: 'peripheral', sku: 'KEYB-002', originalPrice: 799, salePrice: 599, costPrice: 320, stock: 0, safetyStock: 10, status: 'offline', description: '三模连接,热插拔轴体。', imageUrl: 'https://images.unsplash.com/photo-1511467687858-23d96c32e4ae?q=80&w=200&auto=format&fit=crop', createdAt: '2024-02-14T10:30:00.000Z', updatedAt: '2024-02-14T10:30:00.000Z', }, { id: 'prod-1003', name: '4K 电竞显示器', category: 'digital', sku: 'DISP-003', originalPrice: 3999, salePrice: 3599, costPrice: 2410, stock: 8, safetyStock: 12, status: 'pending_review', description: '144Hz 刷新率,HDR 1000。', imageUrl: 'https://images.unsplash.com/photo-1527443224154-c4a3942d3acf?q=80&w=200&auto=format&fit=crop', createdAt: '2024-02-14T11:15:00.000Z', updatedAt: '2024-02-14T11:15:00.000Z', }, { id: 'prod-1004', name: '便携投影仪 Lite', category: 'digital', sku: 'PROJ-004', originalPrice: 2999, salePrice: 2599, stock: 22, safetyStock: 8, status: 'draft', description: '1080P 分辨率,自动梯形校正。', createdAt: '2024-02-15T08:20:00.000Z', updatedAt: '2024-02-15T08:20:00.000Z', }, { id: 'prod-1005', name: '智能手环 X2', category: 'wearable', sku: 'WEAR-005', originalPrice: 399, salePrice: 299, costPrice: 120, stock: 15, safetyStock: 15, status: 'rejected', description: '支持心率、血氧与睡眠监测。', createdAt: '2024-02-15T10:00:00.000Z', updatedAt: '2024-02-15T10:00:00.000Z', }, ]; const coreFieldChanged = ( product: ProductItem, patch: ProductBody, ): boolean => { return ( (typeof patch.name === 'string' && patch.name !== product.name) || (typeof patch.sku === 'string' && patch.sku !== product.sku) || (typeof patch.originalPrice === 'number' && patch.originalPrice !== product.originalPrice) || (typeof patch.salePrice === 'number' && patch.salePrice !== product.salePrice) ); }; const isProductStatus = (value: unknown): value is ProductStatus => { return ( typeof value === 'string' && PRODUCT_STATUS_LIST.includes(value as ProductStatus) ); }; const isPositiveNumber = (value: unknown): value is number => { return typeof value === 'number' && value > 0; }; const hasCreatePriceError = (payload: ProductBody): boolean => { if (!isPositiveNumber(payload.originalPrice)) { return true; } if (!isPositiveNumber(payload.salePrice)) { return true; } return payload.salePrice > payload.originalPrice; }; const hasPriceError = (payload: ProductBody): boolean => { if (typeof payload.originalPrice === 'number' && payload.originalPrice <= 0) { return true; } if (typeof payload.salePrice === 'number' && payload.salePrice <= 0) { return true; } if ( typeof payload.originalPrice === 'number' && typeof payload.salePrice === 'number' && payload.salePrice > payload.originalPrice ) { return true; } return false; }; const parseString = (value: unknown): string | undefined => { return typeof value === 'string' && value.trim() ? value.trim() : undefined; }; export default { 'GET /api/products': (req: Request, res: Response) => { const current = Number(req.query.current) || 1; const pageSize = Number(req.query.pageSize) || 10; const name = parseString(req.query.name); const category = parseString(req.query.category); const sku = parseString(req.query.sku); const status = parseString(req.query.status) as ProductStatus | undefined; const stockWarning = parseString(req.query.stockWarning); let filtered = [...productList]; if (name) { filtered = filtered.filter((item) => item.name.includes(name)); } if (category) { filtered = filtered.filter((item) => item.category === category); } if (sku) { filtered = filtered.filter((item) => item.sku.includes(sku)); } if (status) { filtered = filtered.filter((item) => item.status === status); } if (stockWarning === 'warning') { filtered = filtered.filter( (item) => item.stock > 0 && item.stock < item.safetyStock, ); } if (stockWarning === 'empty') { filtered = filtered.filter((item) => item.stock === 0); } const start = (current - 1) * pageSize; const data = filtered.slice(start, start + pageSize); res.json({ success: true, data, total: filtered.length, }); }, 'GET /api/products/:id': (req: Request, res: Response) => { const { id } = req.params; const item = productList.find((product) => product.id === id); if (!item) { res.status(404).json({ success: false, message: '商品不存在' }); return; } res.json(item); }, 'POST /api/products': (req: Request, res: Response) => { const payload = req.body as ProductBody; if (hasCreatePriceError(payload)) { res.status(400).json({ success: false, message: '价格校验失败' }); return; } if (payload.status !== undefined && !isProductStatus(payload.status)) { res.status(400).json({ success: false, message: '状态非法' }); return; } const created: ProductItem = { id: `prod-${Date.now()}`, name: String(payload.name || ''), category: String(payload.category || 'digital'), sku: String(payload.sku || ''), originalPrice: Number(payload.originalPrice || 0), salePrice: Number(payload.salePrice || 0), costPrice: typeof payload.costPrice === 'number' ? Number(payload.costPrice) : undefined, stock: Number(payload.stock || 0), safetyStock: Number(payload.safetyStock || 0), status: payload.status ?? 'draft', description: payload.description, imageUrl: payload.imageUrl, createdAt: now(), updatedAt: now(), }; productList = [created, ...productList]; res.json(created); }, 'PUT /api/products/status': (req: Request, res: Response) => { const payload = req.body as { ids?: string[]; status?: ProductStatus }; const ids = Array.isArray(payload.ids) ? payload.ids : []; const status = payload.status; if (!status || !['online', 'offline'].includes(status)) { res.status(400).json({ success: false, message: '状态非法' }); return; } productList = productList.map((item) => ids.includes(item.id) ? { ...item, status, updatedAt: now() } : item, ); res.json({ success: true }); }, 'PUT /api/products/:id': (req: Request, res: Response) => { const { id } = req.params; const payload = req.body as ProductBody; const index = productList.findIndex((product) => product.id === id); if (index === -1) { res.status(404).json({ success: false, message: '商品不存在' }); return; } const current = productList[index]; if (payload.status !== undefined && !isProductStatus(payload.status)) { res.status(400).json({ success: false, message: '状态非法' }); return; } if (current.status === 'online' && coreFieldChanged(current, payload)) { res.status(400).json({ success: false, message: '已上架商品修改核心字段前需先下架', }); return; } const merged = { ...current, ...payload, updatedAt: now(), } as ProductItem; if (hasPriceError(merged)) { res.status(400).json({ success: false, message: '价格校验失败' }); return; } productList[index] = merged; res.json(productList[index]); }, 'DELETE /api/products/:id': (req: Request, res: Response) => { const { id } = req.params; const target = productList.find((item) => item.id === id); if (!target) { res.status(404).json({ success: false, message: '商品不存在' }); return; } if (!['draft', 'offline'].includes(target.status)) { res.status(400).json({ success: false, message: '仅草稿和已下架商品可删除', }); return; } productList = productList.filter((item) => item.id !== id); res.json({ success: true }); }, };