| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- 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}`);
- });
|