require('dotenv').config(); const express = require('express'); const cors = require('cors'); const fs = require('fs'); const path = require('path'); const app = express(); const PORT = process.env.PORT || 3003; app.use(cors()); app.use(express.json()); // 数据文件路径 const dbPath = path.join(__dirname, '..', '..', 'data', 'inventory-data.json'); function loadDB() { try { if (fs.existsSync(dbPath)) { return JSON.parse(fs.readFileSync(dbPath, 'utf-8')); } } catch (e) { console.error('加载数据库失败:', e.message); } return { products: [], stockRecords: [], platforms: [] }; } function saveDB(data) { try { const dir = path.dirname(dbPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(dbPath, JSON.stringify(data, null, 2), 'utf-8'); console.log('💾 数据已保存:', dbPath); } catch (e) { console.error('保存数据库失败:', e.message); } } // 初始化 let db = loadDB(); console.log('📊 数据文件:', dbPath); console.log('📦 商品数:', db.products.length); // 健康检查 app.get('/api/health', (req, res) => { res.json({ status: 'ok', service: 'Inventory API', products: db.products.length }); }); // ============ 商品管理 ============ // 获取商品列表 app.get('/api/products', (req, res) => { try { const { status, keyword } = req.query; let products = db.products; if (status) { products = products.filter(p => p.status === status); } if (keyword) { const k = keyword.toLowerCase(); products = products.filter(p => p.name.toLowerCase().includes(k) || p.sku.toLowerCase().includes(k) ); } products.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); res.json({ success: true, data: products }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 获取商品详情 app.get('/api/products/:id', (req, res) => { try { const product = db.products.find(p => p.id == req.params.id); if (!product) { return res.status(404).json({ success: false, error: '商品不存在' }); } res.json({ success: true, data: product }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 创建商品 app.post('/api/products', (req, res) => { try { const { name, sku, category, price, cost, minStock, description } = req.body; if (!name || !sku) { return res.status(400).json({ success: false, error: '商品名称和 SKU 必填' }); } const product = { id: Date.now(), name, sku, category: category || '', price: parseFloat(price) || 0, cost: parseFloat(cost) || 0, minStock: parseInt(minStock) || 10, description: description || '', status: 'active', totalStock: 0, created_at: new Date().toISOString(), updated_at: new Date().toISOString() }; db.products.push(product); saveDB(db); res.json({ success: true, data: { id: product.id }, message: '商品创建成功' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 更新商品 app.put('/api/products/:id', (req, res) => { try { const index = db.products.findIndex(p => p.id == req.params.id); if (index === -1) { return res.status(404).json({ success: false, error: '商品不存在' }); } const { name, sku, category, price, cost, minStock, description, status } = req.body; db.products[index] = { ...db.products[index], name, sku, category, price, cost, minStock, description, status, updated_at: new Date().toISOString() }; saveDB(db); res.json({ success: true, message: '商品更新成功' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 删除商品 app.delete('/api/products/:id', (req, res) => { try { const index = db.products.findIndex(p => p.id == req.params.id); if (index === -1) { return res.status(404).json({ success: false, error: '商品不存在' }); } db.products.splice(index, 1); db.stockRecords = db.stockRecords.filter(r => r.product_id != req.params.id); saveDB(db); res.json({ success: true, message: '商品删除成功' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // ============ 库存管理 ============ // 获取库存记录 app.get('/api/stock-records', (req, res) => { try { const { product_id, type, platform } = req.query; let records = db.stockRecords; if (product_id) { records = records.filter(r => r.product_id == product_id); } if (type) { records = records.filter(r => r.type === type); } if (platform) { records = records.filter(r => r.platform === platform); } records.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); res.json({ success: true, data: records.slice(0, 100) }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 添加入库 app.post('/api/stock-in', (req, res) => { try { const { product_id, quantity, platform, note } = req.body; if (!product_id || !quantity) { return res.status(400).json({ success: false, error: '商品 ID 和数量必填' }); } const product = db.products.find(p => p.id == product_id); if (!product) { return res.status(404).json({ success: false, error: '商品不存在' }); } // 添加入库记录 const record = { id: Date.now(), product_id, type: 'in', quantity: parseInt(quantity), platform: platform || '总仓', note: note || '', created_at: new Date().toISOString() }; db.stockRecords.push(record); // 更新商品总库存 const platformStock = db.stockRecords .filter(r => r.product_id == product_id && r.platform === record.platform) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); product.totalStock = db.stockRecords .filter(r => r.product_id == product_id) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); product.updated_at = new Date().toISOString(); saveDB(db); res.json({ success: true, data: { id: record.id, totalStock: product.totalStock, platformStock }, message: '入库成功' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 出库 app.post('/api/stock-out', (req, res) => { try { const { product_id, quantity, platform, note } = req.body; if (!product_id || !quantity) { return res.status(400).json({ success: false, error: '商品 ID 和数量必填' }); } const product = db.products.find(p => p.id == product_id); if (!product) { return res.status(404).json({ success: false, error: '商品不存在' }); } // 检查库存是否充足 const currentStock = db.stockRecords .filter(r => r.product_id == product_id) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); if (currentStock < quantity) { return res.status(400).json({ success: false, error: '库存不足' }); } // 添加出库记录 const record = { id: Date.now(), product_id, type: 'out', quantity: parseInt(quantity), platform: platform || '总仓', note: note || '', created_at: new Date().toISOString() }; db.stockRecords.push(record); // 更新商品总库存 product.totalStock = currentStock - quantity; product.updated_at = new Date().toISOString(); saveDB(db); res.json({ success: true, data: { id: record.id, totalStock: product.totalStock }, message: '出库成功' }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // ============ 平台库存同步 ============ // 获取平台库存 app.get('/api/platform-stock/:product_id', (req, res) => { try { const product = db.products.find(p => p.id == req.params.product_id); if (!product) { return res.status(404).json({ success: false, error: '商品不存在' }); } const platforms = ['淘宝', '京东', '拼多多', '抖音', '总仓']; const stockByPlatform = {}; platforms.forEach(platform => { const stock = db.stockRecords .filter(r => r.product_id == req.params.product_id && r.platform === platform) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); stockByPlatform[platform] = stock; }); res.json({ success: true, data: { product_id: product.id, name: product.name, sku: product.sku, totalStock: product.totalStock, byPlatform: stockByPlatform } }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 同步平台库存 app.post('/api/sync-platform/:product_id', (req, res) => { try { const { platform, quantity } = req.body; if (!platform || quantity === undefined) { return res.status(400).json({ success: false, error: '平台和数量必填' }); } const product = db.products.find(p => p.id == req.params.product_id); if (!product) { return res.status(404).json({ success: false, error: '商品不存在' }); } // 获取当前该平台库存 const currentPlatformStock = db.stockRecords .filter(r => r.product_id == req.params.product_id && r.platform === platform) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); const diff = quantity - currentPlatformStock; // 添加调整记录 const record = { id: Date.now(), product_id: product.id, type: diff > 0 ? 'in' : 'out', quantity: Math.abs(diff), platform, note: `平台库存同步 (目标:${quantity}, 当前:${currentPlatformStock})`, created_at: new Date().toISOString() }; db.stockRecords.push(record); // 更新总库存 product.totalStock = db.stockRecords .filter(r => r.product_id == product.id) .reduce((sum, r) => sum + (r.type === 'in' ? r.quantity : -r.quantity), 0); product.updated_at = new Date().toISOString(); saveDB(db); res.json({ success: true, data: { totalStock: product.totalStock, platformStock: quantity }, message: `库存同步成功 (调整:${diff > 0 ? '+' : ''}${diff})` }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // ============ 统计数据 ============ app.get('/api/stats', (req, res) => { try { const totalProducts = db.products.length; const activeProducts = db.products.filter(p => p.status === 'active').length; const lowStock = db.products.filter(p => p.totalStock <= p.minStock).length; const totalValue = db.products.reduce((sum, p) => sum + (p.cost * p.totalStock), 0); // 今日出入库 const today = new Date().toDateString(); const todayIn = db.stockRecords .filter(r => r.type === 'in' && new Date(r.created_at).toDateString() === today) .reduce((sum, r) => sum + r.quantity, 0); const todayOut = db.stockRecords .filter(r => r.type === 'out' && new Date(r.created_at).toDateString() === today) .reduce((sum, r) => sum + r.quantity, 0); res.json({ success: true, data: { totalProducts, activeProducts, lowStock, totalValue, todayIn, todayOut } }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); // 库存预警 app.get('/api/alerts', (req, res) => { try { const alerts = db.products .filter(p => p.totalStock <= p.minStock) .map(p => ({ product_id: p.id, name: p.name, sku: p.sku, currentStock: p.totalStock, minStock: p.minStock, level: p.totalStock === 0 ? 'critical' : 'warning' })); res.json({ success: true, data: alerts }); } catch (error) { res.status(500).json({ success: false, error: error.message }); } }); app.listen(PORT, () => { console.log(`🚀 库存管理 API 已启动:http://localhost:${PORT}`); });