/** * 订单控制器 * * 功能:处理订单管理的业务逻辑 */ const Order = require('../models/Order'); const Dish = require('../models/Dish'); const User = require('../models/User'); const { validateRequired, validateBatch } = require('../utils/validator'); const { success } = require('../utils/response'); const { BusinessError, ValidationError } = require('../middleware/errorHandler'); /** * 获取订单列表(分页、筛选) * GET /api/orders */ const getOrders = async (req, res, next) => { try { const { page = 1, pageSize = 10, customer_id, waiter_id, status, order_type, start_date, end_date } = req.query; // 如果是顾客角色,只能查看自己的订单 const userId = req.user.id; const userRole = req.user.role; let filterCustomerId = customer_id; if (userRole === 'customer') { filterCustomerId = userId; } const result = await Order.findAll({ page: parseInt(page), pageSize: parseInt(pageSize), customer_id: filterCustomerId, waiter_id, status, order_type, start_date, end_date }); res.json(success({ list: result.list, pagination: { total: result.total, page: result.page, pageSize: result.pageSize, totalPages: Math.ceil(result.total / result.pageSize) } }, '获取订单列表成功')); } catch (err) { next(err); } }; /** * 获取单个订单详情(含订单明细) * GET /api/orders/:id */ const getOrderById = async (req, res, next) => { try { const { id } = req.params; const order = await Order.getOrderWithItems(id); if (!order) { throw new BusinessError('订单不存在', 404); } // 权限检查:顾客只能查看自己的订单 if (req.user.role === 'customer' && order.customer_id !== req.user.id) { throw new BusinessError('无权查看此订单', 403); } res.json(success(order, '获取订单详情成功')); } catch (err) { next(err); } }; /** * 创建订单 * POST /api/orders */ const createOrder = async (req, res, next) => { try { const { table_number, order_type = 'dine_in', special_request, items // 订单明细数组 } = req.body; // 数据验证 if (!items || !Array.isArray(items) || items.length === 0) { throw new ValidationError('订单必须包含至少一个菜品'); } // 验证订单类型 const validTypes = ['dine_in', 'takeaway']; if (!validTypes.includes(order_type)) { throw new ValidationError('订单类型必须是 dine_in 或 takeaway'); } // 堂食必须有桌号 if (order_type === 'dine_in' && !table_number) { throw new ValidationError('堂食订单必须提供桌号'); } // 验证并处理订单明细 const processedItems = []; for (const item of items) { // 验证必填字段 const validation = validateBatch([ validateRequired(item.dish_id, '菜品ID'), validateRequired(item.quantity, '数量') ]); if (!validation.valid) { throw new ValidationError('订单明细数据不完整', validation.errors); } // 验证数量 const quantity = parseInt(item.quantity); if (quantity <= 0) { throw new ValidationError('菜品数量必须大于0'); } // 查询菜品信息 const dish = await Dish.findById(item.dish_id); if (!dish) { throw new BusinessError(`菜品ID ${item.dish_id} 不存在`, 404); } // 检查菜品是否可售 if (!dish.is_available || !dish.status) { throw new BusinessError(`菜品 ${dish.name} 当前不可售`, 400); } // 添加到处理后的明细列表 processedItems.push({ dish_id: dish.id, dish_name: dish.name, price: parseFloat(dish.price), quantity: quantity, special_request: item.special_request || null }); } // 创建订单 // customer_id 使用当前登录用户 // waiter_id 可以由服务员设置,或者为null const order = await Order.create({ customer_id: req.user.id, waiter_id: req.body.waiter_id || null, table_number, order_type, special_request, discount_amount: 0 }, processedItems); // 获取完整订单信息(含明细) const fullOrder = await Order.getOrderWithItems(order.id); res.status(201).json(success(fullOrder, '创建订单成功')); } catch (err) { next(err); } }; /** * 更新订单状态 * PUT /api/orders/:id/status * 需要服务员或管理员权限 */ const updateOrderStatus = async (req, res, next) => { try { const { id } = req.params; const { status } = req.body; // 验证状态值 const validStatuses = ['pending', 'confirmed', 'cooking', 'served', 'paid', 'cancelled']; if (!validStatuses.includes(status)) { throw new ValidationError('无效的订单状态'); } // 检查订单是否存在 const order = await Order.findById(id); if (!order) { throw new BusinessError('订单不存在', 404); } // 检查状态流转是否合理 if (order.status === 'cancelled') { throw new BusinessError('已取消的订单不能更改状态', 400); } if (order.status === 'paid' && status !== 'cancelled') { throw new BusinessError('已支付的订单不能更改状态', 400); } const updatedOrder = await Order.updateStatus(id, status); res.json(success(updatedOrder, '更新订单状态成功')); } catch (err) { next(err); } }; /** * 取消订单 * PUT /api/orders/:id/cancel */ const cancelOrder = async (req, res, next) => { try { const { id } = req.params; // 检查订单是否存在 const order = await Order.findById(id); if (!order) { throw new BusinessError('订单不存在', 404); } // 权限检查:顾客只能取消自己的订单 if (req.user.role === 'customer' && order.customer_id !== req.user.id) { throw new BusinessError('无权取消此订单', 403); } // 检查订单状态 if (order.status === 'cancelled') { throw new BusinessError('订单已经取消', 400); } if (order.status === 'paid') { throw new BusinessError('已支付的订单不能取消', 400); } if (order.status === 'served') { throw new BusinessError('已上菜的订单不能取消', 400); } const cancelledOrder = await Order.cancel(id); res.json(success(cancelledOrder, '取消订单成功')); } catch (err) { next(err); } }; /** * 应用折扣到订单 * PUT /api/orders/:id/discount * 需要服务员或管理员权限 */ const applyDiscount = async (req, res, next) => { try { const { id } = req.params; const { discount_amount } = req.body; // 验证折扣金额 if (discount_amount === undefined || discount_amount === null) { throw new ValidationError('请提供折扣金额'); } const discountValue = parseFloat(discount_amount); if (discountValue < 0) { throw new ValidationError('折扣金额不能为负数'); } // 检查订单是否存在 const order = await Order.findById(id); if (!order) { throw new BusinessError('订单不存在', 404); } // 检查订单状态 if (order.status === 'paid') { throw new BusinessError('已支付的订单不能修改折扣', 400); } if (order.status === 'cancelled') { throw new BusinessError('已取消的订单不能修改折扣', 400); } // 验证折扣金额不能超过总金额 if (discountValue > order.total_amount) { throw new ValidationError('折扣金额不能超过订单总金额'); } const updatedOrder = await Order.updateAmount(id, discountValue); res.json(success(updatedOrder, '应用折扣成功')); } catch (err) { next(err); } }; /** * 获取订单统计数据 * GET /api/orders/statistics * 需要管理员权限 */ const getOrderStatistics = async (req, res, next) => { try { const { start_date, end_date, status } = req.query; const statistics = await Order.getStatistics({ start_date, end_date, status }); const statusStats = await Order.getStatusStatistics(); res.json(success({ overall: statistics, by_status: statusStats }, '获取订单统计成功')); } catch (err) { next(err); } }; /** * 获取我的订单(当前登录用户) * GET /api/orders/my */ const getMyOrders = async (req, res, next) => { try { const { page = 1, pageSize = 10, status } = req.query; const result = await Order.findAll({ page: parseInt(page), pageSize: parseInt(pageSize), customer_id: req.user.id, status }); res.json(success({ list: result.list, pagination: { total: result.total, page: result.page, pageSize: result.pageSize, totalPages: Math.ceil(result.total / result.pageSize) } }, '获取我的订单成功')); } catch (err) { next(err); } }; // 导出所有控制器函数 module.exports = { getOrders, getOrderById, createOrder, updateOrderStatus, cancelOrder, applyDiscount, getOrderStatistics, getMyOrders };