110 lines
3.3 KiB
JavaScript
110 lines
3.3 KiB
JavaScript
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 { 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)
|
||
const token = jwt.sign(
|
||
{ id: rider._id, role: rider.role, phone: rider.phone },
|
||
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: error.message });
|
||
}
|
||
});
|
||
|
||
// 获取骑手信息(需登录)
|
||
router.get('/:id', async (req, res) => {
|
||
try {
|
||
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: error.message });
|
||
}
|
||
});
|
||
|
||
// 更新骑手信息(如状态切换,需登录本人或管理员)
|
||
router.put('/:id', async (req, res) => {
|
||
try {
|
||
// 不允许通过 PUT 修改密码和 role
|
||
const { password, role, ...safeBody } = req.body;
|
||
const rider = await Rider.findByIdAndUpdate(
|
||
req.params.id,
|
||
safeBody,
|
||
{ 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: error.message });
|
||
}
|
||
});
|
||
|
||
// 获取骑手的订单
|
||
router.get('/:id/orders', async (req, res) => {
|
||
try {
|
||
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: error.message });
|
||
}
|
||
});
|
||
|
||
module.exports = router;
|