初次提交

This commit is contained in:
2025-08-26 10:06:23 +08:00
commit a1944a573e
58 changed files with 19131 additions and 0 deletions

459
routes/orders.js Normal file
View File

@@ -0,0 +1,459 @@
const express = require('express');
const { getDB } = require('../database');
const { auth, adminAuth } = require('../middleware/auth');
const router = express.Router();
// 生成订单号
function generateOrderNo() {
const timestamp = Date.now().toString();
const random = Math.random().toString(36).substr(2, 5);
return `ORD${timestamp}${random}`.toUpperCase();
}
// 获取订单列表
router.get('/', auth, async (req, res) => {
try {
const { page = 1, limit = 10, search = '', orderNumber = '', username = '', status = '', startDate = '', endDate = '' } = req.query;
// 确保参数为有效数字
const pageNum = parseInt(page) || 1;
const limitNum = parseInt(limit) || 10;
const offset = (pageNum - 1) * limitNum;
const isAdmin = req.user.role === 'admin';
let whereClause = 'WHERE 1=1';
const params = [];
// 非管理员只能查看自己的订单
if (!isAdmin) {
whereClause += ' AND o.user_id = ?';
params.push(req.user.id);
}
if (search) {
whereClause += ' AND (o.order_no LIKE ? OR u.username LIKE ?)';
params.push(`%${search}%`, `%${search}%`);
}
if (orderNumber) {
whereClause += ' AND o.order_no LIKE ?';
params.push(`%${orderNumber}%`);
}
if (username ) {
whereClause += ' AND u.username LIKE ?';
params.push(`%${username}%`);
}
if (status && status.trim()) {
whereClause += ' AND o.status = ?';
params.push(status);
}
if (startDate && startDate.trim()) {
whereClause += ' AND DATE(o.created_at) >= ?';
params.push(startDate);
}
if (endDate && endDate.trim()) {
whereClause += ' AND DATE(o.created_at) <= ?';
params.push(endDate);
}
// 获取总数
const countQuery = `
SELECT COUNT(*) as total
FROM orders as o
LEFT JOIN users u ON o.user_id = u.id
${whereClause}
`;
console.log(countQuery,params);
const [countResult] = await getDB().execute(countQuery, params);
const total = countResult[0].total;
console.log(total,'数量');
// 获取订单列表
const query = `
SELECT
o.id, o.order_no, o.user_id, o.total_amount, o.total_points,
o.status, o.address, o.created_at, o.updated_at,
u.username
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
${whereClause}
ORDER BY o.created_at DESC
LIMIT ${limitNum} OFFSET ${offset}
`;
const [orders] = await getDB().execute(query, [...params]);
res.json({
success: true,
data: {
orders,
pagination: {
page: pageNum,
limit: limitNum,
total,
pages: Math.ceil(total / limitNum)
}
}
});
} catch (error) {
console.error('获取订单列表失败:', error);
res.status(500).json({ success: false, message: '获取订单列表失败' });
}
});
// 获取单个订单详情
router.get('/:id', auth, async (req, res) => {
try {
const { id } = req.params;
const isAdmin = req.user.role === 'admin';
let whereClause = 'WHERE o.id = ?';
const params = [id];
// 非管理员只能查看自己的订单
if (!isAdmin) {
whereClause += ' AND o.user_id = ?';
params.push(req.user.id);
}
const query = `
SELECT
o.id, o.order_no, o.user_id, o.total_amount, o.total_points,
o.status, o.address, o.created_at, o.updated_at,
u.username, u.phone
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
${whereClause}
`;
const [orders] = await getDB().execute(query, params);
if (orders.length === 0) {
return res.status(404).json({ success: false, message: '订单不存在' });
}
res.json({
success: true,
data: { order: orders[0] }
});
} catch (error) {
console.error('获取订单详情失败:', error);
res.status(500).json({ success: false, message: '获取订单详情失败' });
}
});
// 创建订单
router.post('/', auth, async (req, res) => {
const db = getDB();
await db.query('START TRANSACTION');
try {
const { product_id, quantity, shipping_address } = req.body;
const user_id = req.user.id;
// 验证必填字段
if (!product_id || !quantity || !shipping_address) {
return res.status(400).json({ success: false, message: '请填写所有必填字段' });
}
// 检查商品是否存在且有效
const [products] = await db.execute(
'SELECT id, name, points_price, stock, status FROM products WHERE id = ?',
[product_id]
);
if (products.length === 0 || products[0].status !== 'active') {
await db.query('ROLLBACK');
return res.status(404).json({ success: false, message: '商品不存在或已下架' });
}
const product = products[0];
// 检查库存
if (product.stock < quantity) {
await db.query('ROLLBACK');
return res.status(400).json({ success: false, message: '库存不足' });
}
// 计算总积分
const totalPoints = product.points_price * quantity;
// 检查用户积分是否足够
const [users] = await db.execute(
'SELECT id, username, points FROM users WHERE id = ?',
[user_id]
);
if (users.length === 0) {
await db.query('ROLLBACK');
return res.status(404).json({ success: false, message: '用户不存在' });
}
const user = users[0];
if (user.points < totalPoints) {
await db.query('ROLLBACK');
return res.status(400).json({ success: false, message: '积分不足' });
}
// 生成订单号
const orderNumber = 'ORD' + Date.now() + Math.random().toString(36).substr(2, 4).toUpperCase();
// 创建订单
const [orderResult] = await db.execute(
`INSERT INTO orders (order_no, user_id, total_amount, total_points, status, address, created_at, updated_at)
VALUES (?, ?, ?, ?, 'pending', ?, NOW(), NOW())`,
[orderNumber, user_id, 0, totalPoints, shipping_address]
);
// 扣除用户积分
await db.execute(
'UPDATE users SET points = points - ? WHERE id = ?',
[totalPoints, user_id]
);
// 减少商品库存
await db.execute(
'UPDATE products SET stock = stock - ? WHERE id = ?',
[quantity, product_id]
);
// 记录积分历史
await db.execute(
`INSERT INTO points_history (user_id, amount, type, description, created_at)
VALUES (?, ?, 'spend', ?, NOW())`,
[user_id, -totalPoints, `购买商品:${product.name}`]
);
await db.query('COMMIT');
res.status(201).json({
success: true,
message: '订单创建成功',
data: {
orderId: orderResult.insertId,
orderNumber,
pointsUsed: totalPoints
}
});
} catch (error) {
await db.query('ROLLBACK');
console.error('创建订单失败:', error);
res.status(500).json({ success: false, message: '创建订单失败' });
}
});
// 用户取消订单
router.put('/:id/cancel', auth, async (req, res) => {
const db = getDB();
await db.query('START TRANSACTION');
try {
const orderId = req.params.id;
const userId = req.user.id;
// 检查订单是否存在且属于当前用户
const [orders] = await db.execute(
'SELECT id, user_id, total_points, status FROM orders WHERE id = ? AND user_id = ?',
[orderId, userId]
);
if (orders.length === 0) {
await db.query('ROLLBACK');
return res.status(404).json({ success: false, message: '订单不存在' });
}
const order = orders[0];
if (order.status !== 'pending') {
await db.query('ROLLBACK');
return res.status(400).json({ success: false, message: '只能取消待处理的订单' });
}
// 退还用户积分
await db.execute(
'UPDATE users SET points = points + ? WHERE id = ?',
[order.total_points, userId]
);
// 记录积分历史
await db.execute(
`INSERT INTO points_history (user_id, amount, type, description, created_at)
VALUES (?, ?, 'refund', '订单取消退还积分', NOW())`,
[userId, order.total_points]
);
// 更新订单状态
await db.execute(
'UPDATE orders SET status = "cancelled", updated_at = NOW() WHERE id = ?',
[orderId]
);
await db.query('COMMIT');
res.json({ success: true, message: '订单已取消' });
} catch (error) {
await db.query('ROLLBACK');
console.error('取消订单失败:', error);
res.status(500).json({ success: false, message: '取消订单失败' });
}
});
// 确认收货
router.put('/:id/confirm', auth, async (req, res) => {
try {
const orderId = req.params.id;
const userId = req.user.id;
// 检查订单是否存在且属于当前用户
const [orders] = await getDB().execute(
'SELECT id, status FROM orders WHERE id = ? AND user_id = ?',
[orderId, userId]
);
if (orders.length === 0) {
return res.status(404).json({ success: false, message: '订单不存在' });
}
const order = orders[0];
if (order.status !== 'shipped') {
return res.status(400).json({ success: false, message: '只能确认已发货的订单' });
}
// 更新订单状态
await getDB().execute(
'UPDATE orders SET status = "completed", updated_at = NOW() WHERE id = ?',
[orderId]
);
res.json({ success: true, message: '确认收货成功' });
} catch (error) {
console.error('确认收货失败:', error);
res.status(500).json({ success: false, message: '确认收货失败' });
}
});
// 更新订单状态(管理员)
router.put('/:id/status', auth, adminAuth, async (req, res) => {
const db = getDB();
await db.query('START TRANSACTION');
try {
const orderId = req.params.id;
const { status } = req.body;
const validStatuses = ['pending', 'shipped', 'completed', 'cancelled'];
if (!validStatuses.includes(status)) {
await db.query('ROLLBACK');
return res.status(400).json({ success: false, message: '无效的订单状态' });
}
// 检查订单是否存在
const [orders] = await db.execute(
'SELECT id, user_id, total_points, status FROM orders WHERE id = ?',
[orderId]
);
if (orders.length === 0) {
await db.query('ROLLBACK');
return res.status(404).json({ success: false, message: '订单不存在' });
}
const order = orders[0];
// 如果是取消订单,需要退还积分
if (status === 'cancelled' && order.status !== 'cancelled') {
// 退还用户积分
await db.execute(
'UPDATE users SET points = points + ? WHERE id = ?',
[order.total_points, order.user_id]
);
// 记录积分历史
await db.execute(
`INSERT INTO points_history (user_id, amount, type, description, created_at)
VALUES (?, ?, 'earn', '订单取消退还积分', NOW())`,
[order.user_id, order.points_cost]
);
}
// 更新订单状态
await db.execute(
'UPDATE orders SET status = ?, updated_at = NOW() WHERE id = ?',
[status, orderId]
);
await db.query('COMMIT');
res.json({ success: true, message: '订单状态已更新' });
} catch (error) {
await db.query('ROLLBACK');
console.error('更新订单状态失败:', error);
res.status(500).json({ success: false, message: '更新订单状态失败' });
}
});
// 获取订单统计信息(管理员权限)
router.get('/stats', auth, adminAuth, async (req, res) => {
try {
// 总订单数
const [totalOrders] = await getDB().execute('SELECT COUNT(*) as count FROM orders');
// 待发货订单数
const [pendingOrders] = await getDB().execute('SELECT COUNT(*) as count FROM orders WHERE status = "pending"');
// 已完成订单数
const [completedOrders] = await getDB().execute('SELECT COUNT(*) as count FROM orders WHERE status = "completed"');
// 本月新增订单
const [monthOrders] = await getDB().execute(
'SELECT COUNT(*) as count FROM orders WHERE YEAR(created_at) = YEAR(NOW()) AND MONTH(created_at) = MONTH(NOW())'
);
// 上月订单数(用于计算增长率)
const [lastMonthOrders] = await getDB().execute(
'SELECT COUNT(*) as count FROM orders WHERE YEAR(created_at) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH)) AND MONTH(created_at) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH))'
);
// 计算月增长率
const lastMonthCount = lastMonthOrders[0].count;
const currentMonthCount = monthOrders[0].count;
let monthGrowthRate = 0;
if (lastMonthCount > 0) {
monthGrowthRate = ((currentMonthCount - lastMonthCount) / lastMonthCount * 100).toFixed(1);
}
// 总积分消费
const [totalPointsConsumed] = await getDB().execute('SELECT SUM(points_cost) as total FROM orders WHERE status != "cancelled"');
res.json({
success: true,
data: {
totalOrders: totalOrders[0].count,
pendingOrders: pendingOrders[0].count,
completedOrders: completedOrders[0].count,
monthOrders: monthOrders[0].count,
monthGrowthRate: parseFloat(monthGrowthRate),
totalPointsConsumed: totalPointsConsumed[0].total || 0
}
});
} catch (error) {
console.error('获取订单统计失败:', error);
res.status(500).json({ success: false, message: '获取订单统计失败' });
}
});
module.exports = router;