const express = require('express'); const router = express.Router(); const Material = require('../models/Material'); const WarehouseTransaction = require('../models/WarehouseTransaction'); const { Op } = require('sequelize'); // 仓库物资列表(支持分页、搜索和筛选) router.get('/', async (req, res) => { try { const { keyword = '', category = '', status = '', page = 1, pageSize = 10 } = req.query; const where = {}; // 搜索条件 if (keyword) { where[Op.or] = [ { code: { [Op.like]: `%${keyword}%` } }, { name: { [Op.like]: `%${keyword}%` } } ]; } // 类别筛选 if (category) { where.category = category; } // 状态筛选 if (status) { where.status = status; } const offset = (parseInt(page) - 1) * parseInt(pageSize); const limit = parseInt(pageSize); const { count, rows } = await Material.findAndCountAll({ where, offset, limit, order: [['update_time', 'DESC']] }); res.json({ code: 200, data: rows, total: count, page: parseInt(page), pageSize: limit, totalPages: Math.ceil(count / limit) }); } catch (error) { res.status(500).json({ code: 500, message: '获取物资列表失败', error: error.message }); } }); // 获取单个物资详情 router.get('/:id', async (req, res) => { try { const { id } = req.params; const material = await Material.findByPk(id); if (!material) { return res.status(404).json({ code: 404, message: '物资不存在' }); } res.json({ code: 200, data: material }); } catch (error) { res.status(500).json({ code: 500, message: '获取物资详情失败', error: error.message }); } }); // 创建新物资 router.post('/', async (req, res) => { try { const { code, name, category, unit, stockQuantity, warningQuantity, supplier, remark } = req.body; // 检查物资编号是否已存在 const existingMaterial = await Material.findOne({ where: { code } }); if (existingMaterial) { return res.status(400).json({ code: 400, message: '物资编号已存在' }); } const material = await Material.create({ code, name, category, unit, stockQuantity, warningQuantity, supplier, remark }); res.json({ code: 200, message: '创建物资成功', data: material }); } catch (error) { res.status(500).json({ code: 500, message: '创建物资失败', error: error.message }); } }); // 更新物资信息 router.put('/:id', async (req, res) => { try { const { id } = req.params; const { code, name, category, unit, stockQuantity, warningQuantity, supplier, remark } = req.body; const material = await Material.findByPk(id); if (!material) { return res.status(404).json({ code: 404, message: '物资不存在' }); } // 检查物资编号是否已存在(排除当前物资) if (code && code !== material.code) { const existingMaterial = await Material.findOne({ where: { code } }); if (existingMaterial) { return res.status(400).json({ code: 400, message: '物资编号已存在' }); } } await material.update({ code, name, category, unit, stockQuantity, warningQuantity, supplier, remark }); res.json({ code: 200, message: '更新物资成功', data: material }); } catch (error) { res.status(500).json({ code: 500, message: '更新物资失败', error: error.message }); } }); // 删除物资 router.delete('/:id', async (req, res) => { try { const { id } = req.params; const material = await Material.findByPk(id); if (!material) { return res.status(404).json({ code: 404, message: '物资不存在' }); } await material.destroy(); res.json({ code: 200, message: '删除物资成功' }); } catch (error) { res.status(500).json({ code: 500, message: '删除物资失败', error: error.message }); } }); // 物资入库 router.post('/in', async (req, res) => { try { const { materialId, quantity, operator, remark } = req.body; // 开始事务 const transaction = await Material.sequelize.transaction(); try { // 查找物资 const material = await Material.findByPk(materialId, { transaction }); if (!material) { await transaction.rollback(); return res.status(404).json({ code: 404, message: '物资不存在' }); } // 更新库存 material.stockQuantity += parseInt(quantity); await material.save({ transaction }); // 记录入库记录 await WarehouseTransaction.create({ materialId, type: 'in', quantity, operator, remark }, { transaction }); // 提交事务 await transaction.commit(); res.json({ code: 200, message: '入库成功', data: { materialId, quantity, newStock: material.stockQuantity } }); } catch (err) { // 回滚事务 await transaction.rollback(); throw err; } } catch (error) { res.status(500).json({ code: 500, message: '入库失败', error: error.message }); } }); // 物资出库 router.post('/out', async (req, res) => { try { const { materialId, quantity, operator, remark } = req.body; // 开始事务 const transaction = await Material.sequelize.transaction(); try { // 查找物资 const material = await Material.findByPk(materialId, { transaction }); if (!material) { await transaction.rollback(); return res.status(404).json({ code: 404, message: '物资不存在' }); } // 检查库存是否足够 if (material.stockQuantity < parseInt(quantity)) { await transaction.rollback(); return res.status(400).json({ code: 400, message: '库存不足' }); } // 更新库存 material.stockQuantity -= parseInt(quantity); await material.save({ transaction }); // 记录出库记录 await WarehouseTransaction.create({ materialId, type: 'out', quantity, operator, remark }, { transaction }); // 提交事务 await transaction.commit(); res.json({ code: 200, message: '出库成功', data: { materialId, quantity, newStock: material.stockQuantity } }); } catch (err) { // 回滚事务 await transaction.rollback(); throw err; } } catch (error) { res.status(500).json({ code: 500, message: '出库失败', error: error.message }); } }); // 获取库存统计信息 router.get('/stats', async (req, res) => { try { // 统计总类别数 const totalCategories = await Material.count({ distinct: true, col: 'category' }); // 统计库存总量 const totalQuantityResult = await Material.sum('stockQuantity'); const totalQuantity = totalQuantityResult || 0; // 统计低库存物资数 const lowStockCount = await Material.count({ where: { status: 'low' } }); // 统计缺货物资数 const outOfStockCount = await Material.count({ where: { status: 'out' } }); // 统计各类别物资数量 const categoryStats = await Material.findAll({ attributes: [ 'category', [Material.sequelize.fn('COUNT', Material.sequelize.col('id')), 'count'], [Material.sequelize.fn('SUM', Material.sequelize.col('stockQuantity')), 'totalQuantity'] ], group: ['category'], raw: true }); res.json({ code: 200, data: { totalCategories, totalQuantity, lowStockCount, outOfStockCount, categoryStats } }); } catch (error) { res.status(500).json({ code: 500, message: '获取统计信息失败', error: error.message }); } }); module.exports = router;