2025-09-01 03:40:59 +08:00
|
|
|
const express = require('express');
|
|
|
|
|
const router = express.Router();
|
|
|
|
|
const dbConnector = require('../utils/dbConnector');
|
|
|
|
|
|
2025-09-02 23:41:32 +08:00
|
|
|
/**
|
|
|
|
|
* @swagger
|
|
|
|
|
* /api/v1/cart:
|
|
|
|
|
* get:
|
|
|
|
|
* summary: 获取用户购物车
|
|
|
|
|
* description: 获取当前用户的购物车商品列表及总计信息
|
|
|
|
|
* tags:
|
|
|
|
|
* - 购物车管理
|
|
|
|
|
* security:
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: 成功获取购物车信息
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 200
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 获取成功
|
|
|
|
|
* data:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* items:
|
|
|
|
|
* type: array
|
|
|
|
|
* items:
|
|
|
|
|
* $ref: '#/components/schemas/CartItem'
|
|
|
|
|
* total_amount:
|
|
|
|
|
* type: number
|
|
|
|
|
* example: 99.9
|
|
|
|
|
* total_quantity:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 3
|
|
|
|
|
* 401:
|
|
|
|
|
* description: 未授权访问
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 401
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 未授权访问
|
|
|
|
|
* 500:
|
|
|
|
|
* description: 服务器内部错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 500
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 服务器内部错误
|
|
|
|
|
*/
|
2025-09-01 03:40:59 +08:00
|
|
|
// 获取用户购物车
|
|
|
|
|
router.get('/', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const userId = req.user.id;
|
|
|
|
|
|
|
|
|
|
const cartItems = await dbConnector.query(`
|
|
|
|
|
SELECT ci.*, p.name as product_name, p.price, p.image as product_image, p.stock
|
|
|
|
|
FROM cart_items ci
|
|
|
|
|
JOIN products p ON ci.product_id = p.id
|
|
|
|
|
WHERE ci.user_id = ?
|
|
|
|
|
`, [userId]);
|
|
|
|
|
|
|
|
|
|
const totalAmount = cartItems.reduce((sum, item) => sum + (item.price * item.quantity), 0);
|
|
|
|
|
const totalQuantity = cartItems.reduce((sum, item) => sum + item.quantity, 0);
|
|
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
|
code: 200,
|
|
|
|
|
message: '获取成功',
|
|
|
|
|
data: {
|
|
|
|
|
items: cartItems,
|
|
|
|
|
total_amount: totalAmount,
|
|
|
|
|
total_quantity: totalQuantity
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取购物车失败:', error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
code: 500,
|
|
|
|
|
message: '服务器内部错误',
|
|
|
|
|
error: error.message
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-02 23:41:32 +08:00
|
|
|
/**
|
|
|
|
|
* @swagger
|
|
|
|
|
* /api/v1/cart/items:
|
|
|
|
|
* post:
|
|
|
|
|
* summary: 添加商品到购物车
|
|
|
|
|
* description: 将指定商品添加到当前用户的购物车中
|
|
|
|
|
* tags:
|
|
|
|
|
* - 购物车管理
|
|
|
|
|
* security:
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
* requestBody:
|
|
|
|
|
* required: true
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* required:
|
|
|
|
|
* - product_id
|
|
|
|
|
* - quantity
|
|
|
|
|
* properties:
|
|
|
|
|
* product_id:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 1
|
|
|
|
|
* description: 商品ID
|
|
|
|
|
* quantity:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 2
|
|
|
|
|
* description: 商品数量
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: 成功添加到购物车
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 200
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 添加成功
|
|
|
|
|
* 400:
|
|
|
|
|
* description: 请求参数错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 400
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 商品数量必须大于0
|
|
|
|
|
* 401:
|
|
|
|
|
* description: 未授权访问
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 401
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 未授权访问
|
|
|
|
|
* 404:
|
|
|
|
|
* description: 商品不存在
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 404
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 商品不存在
|
|
|
|
|
* 500:
|
|
|
|
|
* description: 服务器内部错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 500
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 服务器内部错误
|
|
|
|
|
*/
|
2025-09-01 03:40:59 +08:00
|
|
|
// 添加商品到购物车
|
|
|
|
|
router.post('/items', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { product_id, quantity } = req.body;
|
|
|
|
|
const userId = req.user.id;
|
|
|
|
|
|
|
|
|
|
// 检查商品是否存在
|
|
|
|
|
const product = await dbConnector.query('SELECT * FROM products WHERE id = ? AND status = 1', [product_id]);
|
|
|
|
|
if (product.length === 0) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
code: 404,
|
|
|
|
|
message: '商品不存在'
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-02 23:41:32 +08:00
|
|
|
|
|
|
|
|
if (quantity <= 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
code: 400,
|
|
|
|
|
message: '商品数量必须大于0'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查购物车中是否已存在该商品
|
2025-09-01 03:40:59 +08:00
|
|
|
const existingItem = await dbConnector.query(
|
|
|
|
|
'SELECT * FROM cart_items WHERE user_id = ? AND product_id = ?',
|
|
|
|
|
[userId, product_id]
|
|
|
|
|
);
|
2025-09-02 23:41:32 +08:00
|
|
|
|
2025-09-01 03:40:59 +08:00
|
|
|
if (existingItem.length > 0) {
|
|
|
|
|
// 更新数量
|
2025-09-02 23:41:32 +08:00
|
|
|
const newQuantity = existingItem[0].quantity + quantity;
|
2025-09-01 03:40:59 +08:00
|
|
|
await dbConnector.query(
|
2025-09-02 23:41:32 +08:00
|
|
|
'UPDATE cart_items SET quantity = ? WHERE id = ?',
|
|
|
|
|
[newQuantity, existingItem[0].id]
|
2025-09-01 03:40:59 +08:00
|
|
|
);
|
|
|
|
|
} else {
|
2025-09-02 23:41:32 +08:00
|
|
|
// 添加新商品到购物车
|
2025-09-01 03:40:59 +08:00
|
|
|
await dbConnector.query(
|
2025-09-02 23:41:32 +08:00
|
|
|
'INSERT INTO cart_items (user_id, product_id, quantity) VALUES (?, ?, ?)',
|
2025-09-01 03:40:59 +08:00
|
|
|
[userId, product_id, quantity]
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-09-02 23:41:32 +08:00
|
|
|
|
2025-09-01 03:40:59 +08:00
|
|
|
res.json({
|
|
|
|
|
code: 200,
|
2025-09-02 23:41:32 +08:00
|
|
|
message: '添加成功'
|
2025-09-01 03:40:59 +08:00
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('添加购物车失败:', error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
code: 500,
|
|
|
|
|
message: '服务器内部错误',
|
|
|
|
|
error: error.message
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-02 23:41:32 +08:00
|
|
|
/**
|
|
|
|
|
* @swagger
|
|
|
|
|
* /api/v1/cart/items/{id}:
|
|
|
|
|
* put:
|
|
|
|
|
* summary: 更新购物车商品数量
|
|
|
|
|
* description: 更新购物车中指定商品的数量
|
|
|
|
|
* tags:
|
|
|
|
|
* - 购物车管理
|
|
|
|
|
* security:
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
* parameters:
|
|
|
|
|
* - in: path
|
|
|
|
|
* name: id
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: integer
|
|
|
|
|
* description: 购物车商品项ID
|
|
|
|
|
* requestBody:
|
|
|
|
|
* required: true
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* required:
|
|
|
|
|
* - quantity
|
|
|
|
|
* properties:
|
|
|
|
|
* quantity:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 3
|
|
|
|
|
* description: 新的商品数量
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: 成功更新购物车商品数量
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 200
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 更新成功
|
|
|
|
|
* 400:
|
|
|
|
|
* description: 请求参数错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 400
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 商品数量必须大于0
|
|
|
|
|
* 401:
|
|
|
|
|
* description: 未授权访问
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 401
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 未授权访问
|
|
|
|
|
* 404:
|
|
|
|
|
* description: 购物车商品项不存在
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 404
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 购物车商品项不存在
|
|
|
|
|
* 500:
|
|
|
|
|
* description: 服务器内部错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 500
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 服务器内部错误
|
|
|
|
|
*/
|
2025-09-01 03:40:59 +08:00
|
|
|
// 更新购物车商品数量
|
|
|
|
|
router.put('/items/:id', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const { quantity } = req.body;
|
|
|
|
|
const userId = req.user.id;
|
2025-09-02 23:41:32 +08:00
|
|
|
|
|
|
|
|
if (quantity <= 0) {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
code: 400,
|
|
|
|
|
message: '商品数量必须大于0'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查购物车商品项是否存在且属于当前用户
|
2025-09-01 03:40:59 +08:00
|
|
|
const cartItem = await dbConnector.query(
|
|
|
|
|
'SELECT * FROM cart_items WHERE id = ? AND user_id = ?',
|
|
|
|
|
[id, userId]
|
|
|
|
|
);
|
2025-09-02 23:41:32 +08:00
|
|
|
|
2025-09-01 03:40:59 +08:00
|
|
|
if (cartItem.length === 0) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
code: 404,
|
2025-09-02 23:41:32 +08:00
|
|
|
message: '购物车商品项不存在'
|
2025-09-01 03:40:59 +08:00
|
|
|
});
|
|
|
|
|
}
|
2025-09-02 23:41:32 +08:00
|
|
|
|
|
|
|
|
// 更新数量
|
2025-09-01 03:40:59 +08:00
|
|
|
await dbConnector.query(
|
2025-09-02 23:41:32 +08:00
|
|
|
'UPDATE cart_items SET quantity = ? WHERE id = ?',
|
2025-09-01 03:40:59 +08:00
|
|
|
[quantity, id]
|
|
|
|
|
);
|
2025-09-02 23:41:32 +08:00
|
|
|
|
2025-09-01 03:40:59 +08:00
|
|
|
res.json({
|
|
|
|
|
code: 200,
|
|
|
|
|
message: '更新成功'
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('更新购物车失败:', error);
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
code: 500,
|
|
|
|
|
message: '服务器内部错误',
|
|
|
|
|
error: error.message
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-02 23:41:32 +08:00
|
|
|
/**
|
|
|
|
|
* @swagger
|
|
|
|
|
* /api/v1/cart/items/{id}:
|
|
|
|
|
* delete:
|
|
|
|
|
* summary: 删除购物车商品
|
|
|
|
|
* description: 从购物车中删除指定商品
|
|
|
|
|
* tags:
|
|
|
|
|
* - 购物车管理
|
|
|
|
|
* security:
|
|
|
|
|
* - bearerAuth: []
|
|
|
|
|
* parameters:
|
|
|
|
|
* - in: path
|
|
|
|
|
* name: id
|
|
|
|
|
* required: true
|
|
|
|
|
* schema:
|
|
|
|
|
* type: integer
|
|
|
|
|
* description: 购物车商品项ID
|
|
|
|
|
* responses:
|
|
|
|
|
* 200:
|
|
|
|
|
* description: 成功删除购物车商品
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 200
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 删除成功
|
|
|
|
|
* 401:
|
|
|
|
|
* description: 未授权访问
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 401
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 未授权访问
|
|
|
|
|
* 404:
|
|
|
|
|
* description: 购物车商品项不存在
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 404
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 购物车商品项不存在
|
|
|
|
|
* 500:
|
|
|
|
|
* description: 服务器内部错误
|
|
|
|
|
* content:
|
|
|
|
|
* application/json:
|
|
|
|
|
* schema:
|
|
|
|
|
* type: object
|
|
|
|
|
* properties:
|
|
|
|
|
* code:
|
|
|
|
|
* type: integer
|
|
|
|
|
* example: 500
|
|
|
|
|
* message:
|
|
|
|
|
* type: string
|
|
|
|
|
* example: 服务器内部错误
|
|
|
|
|
*/
|
2025-09-01 03:40:59 +08:00
|
|
|
// 删除购物车商品
|
|
|
|
|
router.delete('/items/:id', async (req, res) => {
|
|
|
|
|
try {
|
|
|
|
|
const { id } = req.params;
|
|
|
|
|
const userId = req.user.id;
|
2025-09-02 23:41:32 +08:00
|
|
|
|
|
|
|
|
// 检查购物车商品项是否存在且属于当前用户
|
|
|
|
|
const cartItem = await dbConnector.query(
|
|
|
|
|
'SELECT * FROM cart_items WHERE id = ? AND user_id = ?',
|
2025-09-01 03:40:59 +08:00
|
|
|
[id, userId]
|
|
|
|
|
);
|
2025-09-02 23:41:32 +08:00
|
|
|
|
|
|
|
|
if (cartItem.length === 0) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
code: 404,
|
|
|
|
|
message: '购物车商品项不存在'
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除购物车商品项
|
|
|
|
|
await dbConnector.query('DELETE FROM cart_items WHERE id = ?', [id]);
|
|
|
|
|
|
2025-09-01 03:40:59 +08:00
|
|
|
res.json({
|
|
|
|
|
code: 200,
|
|
|
|
|
message: '删除成功'
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
2025-09-02 23:41:32 +08:00
|
|
|
console.error('删除购物车商品失败:', error);
|
2025-09-01 03:40:59 +08:00
|
|
|
res.status(500).json({
|
|
|
|
|
code: 500,
|
|
|
|
|
message: '服务器内部错误',
|
|
|
|
|
error: error.message
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
module.exports = router;
|