e-scooter-rental-system/server/routes/orders.js

244 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const router = express.Router();
const Order = require('../models/Order');
const Vehicle = require('../models/Vehicle');
const Customer = require('../models/Customer');
const Store = require('../models/Store');
const { authMiddleware, requireRole } = require('../middleware/auth');
const { validate } = require('../middleware/validate');
const { schemas } = require('../middleware/validate');
// ─── 公开列表查询登录即可admin 可看全部customer 只能看自己的) ───
router.get('/', authMiddleware, async (req, res) => {
try {
const filter = {};
if (req.query.status) filter.status = req.query.status;
// 非 admin 角色只能看自己的订单
if (req.user.role === 'customer') {
// 查找当前 rider 对应的客户手机号(需关联 Customer 表)
// 此处通过 rider id 查找(假设订单中 rider 字段关联骑手)
filter.rider = req.user.id;
} else if (req.user.role === 'store') {
// store 角色永远只能看自己门店的数据,忽略前端传的 storeId 参数
if (req.user.storeId) {
filter.storeId = req.user.storeId;
}
}
const orders = await Order.find(filter)
.populate('customer', 'name phone')
.populate('vehicle', 'model vehicleId');
res.json({ success: true, data: orders });
} catch (error) {
res.status(500).json({ success: false, message: '服务器内部错误' });
}
});
// 获取单个订单(登录即可,检查是否本人或 admin/store
router.get('/:id', authMiddleware, async (req, res) => {
try {
const order = await Order.findById(req.params.id)
.populate('customer')
.populate('vehicle');
if (!order) return res.status(404).json({ success: false, message: '订单不存在' });
// 权限检查:本人骑手 或 admin/store
const isOwner = order.rider?.toString() === req.user.id;
if (req.user.role !== 'admin' && req.user.role !== 'store' && !isOwner) {
return res.status(403).json({ success: false, message: '权限不足' });
}
res.json({ success: true, data: order });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 创建订单store 或 admin
router.post('/', authMiddleware, requireRole('admin', 'store'), validate(schemas.order), async (req, res) => {
try {
const {
customerName, customer,
vehicleId, vehicle,
contractMonths, startDate, endDate, rentalFee, deposit, orderType
} = req.body;
const vehicleObjectId = vehicle || vehicleId;
// 解析客户
let customerObjectId = customer;
if (!customerObjectId && customerName) {
let customerDoc = await Customer.findOne({ name: customerName });
if (!customerDoc) {
customerDoc = await Customer.create({
name: customerName,
phone: '00000000000',
customerId: `CUST${Date.now()}`
});
}
customerObjectId = customerDoc._id;
}
const vehicleDoc = await Vehicle.findById(vehicleObjectId);
if (!vehicleDoc) return res.status(404).json({ success: false, message: '车辆不存在' });
if (vehicleDoc.status !== '空闲') {
return res.status(400).json({ success: false, message: '车辆不可用,当前状态:' + vehicleDoc.status });
}
const start = startDate ? new Date(startDate) : new Date();
let end = endDate ? new Date(endDate) : null;
const months = Number(contractMonths) || 0;
if (!end && months > 0) {
end = new Date(start);
end.setMonth(end.getMonth() + months);
}
const fee = Number(rentalFee) || 0;
const depositAmt = Number(deposit) || 0;
const totalAmount = fee + depositAmt;
const order = new Order({
customer: customerObjectId,
vehicle: vehicleObjectId,
startDate: start,
endDate: end || new Date(start.getTime() + 30 * 24 * 60 * 60 * 1000),
rentalFee: fee,
deposit: depositAmt,
totalAmount,
status: '进行中'
});
await order.save();
vehicleDoc.status = '在租';
vehicleDoc.isRented = true;
vehicleDoc.currentOrderId = order._id;
await vehicleDoc.save();
if (customerObjectId) {
const cust = await Customer.findById(customerObjectId);
if (cust) {
cust.totalRentals += 1;
cust.currentRentals = (cust.currentRentals || 0) + 1;
cust.totalSpent = (cust.totalSpent || 0) + totalAmount;
await cust.save();
}
}
res.status(201).json({ success: true, data: order });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 更新订单admin 或 store
router.put('/:id', authMiddleware, requireRole('admin', 'store'), async (req, res) => {
try {
const order = await Order.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
if (!order) return res.status(404).json({ success: false, message: '订单不存在' });
res.json({ success: true, data: order });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 结束订单admin 或 store
router.patch('/:id/complete', authMiddleware, requireRole('admin', 'store'), async (req, res) => {
try {
const order = await Order.findById(req.params.id);
if (!order) return res.status(404).json({ success: false, message: '订单不存在' });
order.status = '已完成';
order.actualEndDate = new Date();
await order.save();
const vehicle = await Vehicle.findById(order.vehicle);
if (vehicle) {
vehicle.status = '空闲';
vehicle.isRented = false;
vehicle.currentOrderId = null;
vehicle.totalRentDays += Math.ceil((new Date(order.endDate) - new Date(order.startDate)) / (1000 * 60 * 60 * 24));
await vehicle.save();
}
const customer = await Customer.findById(order.customer);
if (customer) {
customer.currentRentals -= 1;
await customer.save();
}
res.json({ success: true, data: order });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 取消订单admin 或 store
router.patch('/:id/cancel', authMiddleware, requireRole('admin', 'store'), async (req, res) => {
try {
const order = await Order.findById(req.params.id);
if (!order) return res.status(404).json({ success: false, message: '订单不存在' });
if (order.status === '已完成' || order.status === '已取消') {
return res.status(400).json({ success: false, message: '当前状态无法取消' });
}
order.status = '已取消';
order.actualEndDate = new Date();
await order.save();
const vehicle = await Vehicle.findById(order.vehicle);
if (vehicle) {
vehicle.status = '空闲';
vehicle.isRented = false;
vehicle.currentOrderId = null;
await vehicle.save();
}
const customer = await Customer.findById(order.customer);
if (customer) {
customer.currentRentals = Math.max((customer.currentRentals || 0) - 1, 0);
await customer.save();
}
res.json({ success: true, data: order });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 逾期订单admin 或 store
router.get('/status/overdue', authMiddleware, requireRole('admin', 'store'), async (req, res) => {
try {
const now = new Date();
const orders = await Order.find({
status: '进行中',
endDate: { $lt: now }
})
.populate('customer', 'name phone')
.populate('vehicle', 'model vehicleId');
for (const order of orders) {
const overdueDays = Math.ceil((now - order.endDate) / (1000 * 60 * 60 * 24));
order.overdueDays = overdueDays;
order.overdueFee = overdueDays * order.rentalFee * 0.1;
order.status = '逾期';
await order.save();
}
res.json({ success: true, data: orders });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 按状态筛选admin 或 store
router.get('/status/:status', authMiddleware, requireRole('admin', 'store'), async (req, res) => {
try {
const orders = await Order.find({ status: req.params.status })
.populate('customer', 'name phone')
.populate('vehicle', 'model vehicleId');
res.json({ success: true, data: orders });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
module.exports = router;