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

130 lines
4.6 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 jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');
const Rider = require('../models/Rider');
const Order = require('../models/Order');
const { comparePassword } = require('../utils/password');
const { authMiddleware, requireRole } = require('../middleware/auth');
const { validate } = require('../middleware/validate');
const { schemas } = require('../middleware/validate');
// 登录限流(单独,更严格)
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 20,
standardHeaders: true,
legacyHeaders: false,
message: { success: false, message: '登录尝试过于频繁请15分钟后再试' }
});
// 骑手登录(无需鉴权)
router.post('/login', loginLimiter, validate(schemas.login), async (req, res) => {
try {
const { phone, password } = req.body;
// 用 select(false) 主动拉取 password 字段
const rider = await Rider.findOne({ phone }).select('+password');
if (!rider) {
return res.status(401).json({ success: false, message: '手机号或密码错误' });
}
// bcrypt 比对密码
const isMatch = await comparePassword(password, rider.password);
if (!isMatch) {
return res.status(401).json({ success: false, message: '手机号或密码错误' });
}
// 签发 JWT包含 id、role、jti
const token = jwt.sign(
{ id: rider._id, role: rider.role, type: 'rider', phone: rider.phone, jti: Math.random().toString(36) },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
);
res.json({
success: true,
data: {
id: rider._id,
riderId: rider.riderId,
name: rider.name,
phone: rider.phone,
status: rider.status,
role: rider.role,
rating: rider.rating,
totalOrders: rider.totalOrders,
totalIncome: rider.totalIncome,
token
}
});
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 获取骑手信息需登录且只能查看自己admin/store 可查看任意骑手)
router.get('/:id', authMiddleware, async (req, res) => {
try {
const isSelf = req.params.id === req.user.id;
const isPrivileged = ['admin', 'store'].includes(req.user.role);
if (!isSelf && !isPrivileged) {
return res.status(403).json({ success: false, message: '无权查看该骑手信息' });
}
const rider = await Rider.findById(req.params.id);
if (!rider) {
return res.status(404).json({ success: false, message: '骑手不存在' });
}
res.json({ success: true, data: rider });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
// 更新骑手信息(需登录本人,或 admin/store
router.put('/:id', authMiddleware, async (req, res) => {
try {
const isSelf = req.params.id === req.user.id;
const isPrivileged = ['admin', 'store'].includes(req.user.role);
if (!isSelf && !isPrivileged) {
return res.status(403).json({ success: false, message: '无权修改该骑手信息' });
}
// 不允许通过 PUT 修改密码和 role仅 admin 可改 role
const { password, ...safeBody } = req.body;
if (req.body.role && !isPrivileged) {
return res.status(403).json({ success: false, message: '无权修改角色' });
}
const updateData = isPrivileged ? req.body : safeBody;
const rider = await Rider.findByIdAndUpdate(
req.params.id,
updateData,
{ new: true, runValidators: true }
);
if (!rider) {
return res.status(404).json({ success: false, message: '骑手不存在' });
}
res.json({ success: true, data: rider });
} catch (error) {
res.status(400).json({ success: false, message: "服务器内部错误" });
}
});
// 获取骑手的订单(需登录本人,或 admin/store
router.get('/:id/orders', authMiddleware, async (req, res) => {
try {
const isSelf = req.params.id === req.user.id;
const isPrivileged = ['admin', 'store'].includes(req.user.role);
if (!isSelf && !isPrivileged) {
return res.status(403).json({ success: false, message: '无权查看该骑手的订单' });
}
const orders = await Order.find({ rider: req.params.id })
.populate('customer', 'name phone')
.populate('vehicle', 'vehicleId model color')
.sort({ createdAt: -1 });
res.json({ success: true, data: orders });
} catch (error) {
res.status(500).json({ success: false, message: "服务器内部错误" });
}
});
module.exports = router;