937 lines
28 KiB
JavaScript
937 lines
28 KiB
JavaScript
const express = require('express');
|
||
const { getDB } = require('../database');
|
||
const { auth } = require('../middleware/auth');
|
||
|
||
const router = express.Router();
|
||
|
||
/**
|
||
* @swagger
|
||
* tags:
|
||
* name: Cart
|
||
* description: 购物车管理相关接口
|
||
*/
|
||
|
||
/**
|
||
* @swagger
|
||
* components:
|
||
* schemas:
|
||
* CartItem:
|
||
* type: object
|
||
* properties:
|
||
* id:
|
||
* type: integer
|
||
* description: 购物车项ID
|
||
* user_id:
|
||
* type: integer
|
||
* description: 用户ID
|
||
* product_id:
|
||
* type: integer
|
||
* description: 商品ID
|
||
* quantity:
|
||
* type: integer
|
||
* description: 商品数量
|
||
* spec_combination_id:
|
||
* type: integer
|
||
* description: 商品规格组合ID
|
||
* created_at:
|
||
* type: string
|
||
* format: date-time
|
||
* description: 创建时间
|
||
* updated_at:
|
||
* type: string
|
||
* format: date-time
|
||
* description: 更新时间
|
||
* product:
|
||
* type: object
|
||
* properties:
|
||
* id:
|
||
* type: integer
|
||
* name:
|
||
* type: string
|
||
* price:
|
||
* type: integer
|
||
* points_price:
|
||
* type: integer
|
||
* rongdou_price:
|
||
* type: integer
|
||
* image_url:
|
||
* type: string
|
||
* stock:
|
||
* type: integer
|
||
* status:
|
||
* type: string
|
||
*/
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart:
|
||
* get:
|
||
* summary: 获取购物车列表
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* responses:
|
||
* 200:
|
||
* description: 获取购物车成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* data:
|
||
* type: object
|
||
* properties:
|
||
* items:
|
||
* type: array
|
||
* items:
|
||
* $ref: '#/components/schemas/CartItem'
|
||
* total_count:
|
||
* type: integer
|
||
* description: 购物车商品总数量
|
||
* total_amount:
|
||
* type: integer
|
||
* description: 购物车总金额
|
||
* total_points:
|
||
* type: integer
|
||
* description: 购物车总积分
|
||
* total_rongdou:
|
||
* type: integer
|
||
* description: 购物车总融豆
|
||
* 401:
|
||
* description: 未授权
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.get('/', auth, async (req, res) => {
|
||
try {
|
||
const userId = req.user.id;
|
||
|
||
// 获取购物车商品列表
|
||
const query = `
|
||
SELECT
|
||
c.id, c.user_id, c.product_id, c.quantity, c.specification_id,
|
||
c.created_at, c.updated_at,
|
||
p.name, p.price, p.points_price, p.rongdou_price, p.image_url,
|
||
p.stock, p.status, p.shop_name, p.shop_avatar,
|
||
psc.combination_key, psc.price_adjustment,
|
||
psc.points_adjustment, psc.rongdou_adjustment, psc.stock as spec_stock,
|
||
GROUP_CONCAT(CONCAT(sn.display_name, ':', sv.display_value) ORDER BY sn.sort_order SEPARATOR ' | ') as spec_display
|
||
FROM cart_items c
|
||
LEFT JOIN products p ON c.product_id = p.id
|
||
LEFT JOIN product_spec_combinations psc ON c.specification_id = psc.id
|
||
LEFT JOIN JSON_TABLE(psc.spec_values, '$[*]' COLUMNS (spec_value_id INT PATH '$')) jt ON psc.id IS NOT NULL
|
||
LEFT JOIN spec_values sv ON jt.spec_value_id = sv.id
|
||
LEFT JOIN spec_names sn ON sv.spec_name_id = sn.id
|
||
WHERE c.user_id = ? AND p.status = 'active'
|
||
GROUP BY c.id
|
||
ORDER BY c.created_at DESC
|
||
`;
|
||
|
||
const [cartItems] = await getDB().execute(query, [userId]);
|
||
|
||
// 计算总计信息
|
||
let totalCount = 0;
|
||
let totalAmount = 0;
|
||
let totalPoints = 0;
|
||
let totalRongdou = 0;
|
||
|
||
const items = cartItems.map(item => {
|
||
const finalPrice = item.price + (item.price_adjustment || 0);
|
||
const finalPointsPrice = item.points_price + (item.points_adjustment || 0);
|
||
const finalRongdouPrice = item.rongdou_price + (item.rongdou_adjustment || 0);
|
||
|
||
totalCount += item.quantity;
|
||
totalAmount += finalPrice * item.quantity;
|
||
totalPoints += finalPointsPrice * item.quantity;
|
||
totalRongdou += finalRongdouPrice * item.quantity;
|
||
|
||
return {
|
||
id: item.id,
|
||
user_id: item.user_id,
|
||
product_id: item.product_id,
|
||
quantity: item.quantity,
|
||
spec_combination_id: item.spec_combination_id,
|
||
created_at: item.created_at,
|
||
updated_at: item.updated_at,
|
||
product: {
|
||
id: item.product_id,
|
||
name: item.name,
|
||
price: finalPrice,
|
||
points_price: finalPointsPrice,
|
||
rongdou_price: finalRongdouPrice,
|
||
image_url: item.image_url,
|
||
stock: item.spec_combination_id ? item.spec_stock : item.stock,
|
||
status: item.status,
|
||
shop_name: item.shop_name,
|
||
shop_avatar: item.shop_avatar
|
||
},
|
||
specification: item.spec_combination_id ? {
|
||
id: item.spec_combination_id,
|
||
combination_key: item.combination_key,
|
||
spec_display: item.spec_display,
|
||
price_adjustment: item.price_adjustment,
|
||
points_adjustment: item.points_adjustment,
|
||
rongdou_adjustment: item.rongdou_adjustment
|
||
} : null
|
||
};
|
||
});
|
||
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
items,
|
||
total_count: totalCount,
|
||
total_amount: totalAmount,
|
||
total_points: totalPoints,
|
||
total_rongdou: totalRongdou
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('获取购物车失败:', error);
|
||
res.status(500).json({ success: false, message: '获取购物车失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart:
|
||
* post:
|
||
* summary: 添加商品到购物车
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* product_id:
|
||
* type: integer
|
||
* description: 商品ID
|
||
* quantity:
|
||
* type: integer
|
||
* description: 商品数量
|
||
* minimum: 1
|
||
* spec_combination_id:
|
||
* type: integer
|
||
* description: 商品规格组合ID(可选)
|
||
* required:
|
||
* - product_id
|
||
* - quantity
|
||
* responses:
|
||
* 201:
|
||
* description: 添加到购物车成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* data:
|
||
* type: object
|
||
* properties:
|
||
* cart_item_id:
|
||
* type: integer
|
||
* 400:
|
||
* description: 参数错误或库存不足
|
||
* 401:
|
||
* description: 未授权
|
||
* 404:
|
||
* description: 商品不存在或已下架
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.post('/add', auth, async (req, res) => {
|
||
const db = getDB();
|
||
await db.query('START TRANSACTION');
|
||
|
||
try {
|
||
const { productId, quantity, specificationId } = req.body;
|
||
const userId = req.user.id;
|
||
|
||
|
||
// 验证必填字段
|
||
if (!productId || !quantity || quantity < 1) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '请填写正确的商品信息和数量' });
|
||
}
|
||
|
||
// 检查商品是否存在且有效
|
||
const [products] = await db.execute(
|
||
'SELECT id, name, stock, status FROM products WHERE id = ?',
|
||
[productId]
|
||
);
|
||
|
||
if (products.length === 0 || products[0].status !== 'active') {
|
||
await db.query('ROLLBACK');
|
||
return res.status(404).json({ success: false, message: '商品不存在或已下架' });
|
||
}
|
||
|
||
const product = products[0];
|
||
let availableStock = product.stock;
|
||
|
||
// 如果指定了规格组合,检查规格组合库存
|
||
if (specificationId) {
|
||
const [specs] = await db.execute(
|
||
'SELECT id, stock, status FROM product_spec_combinations WHERE id = ? AND product_id = ?',
|
||
[specificationId, productId]
|
||
);
|
||
|
||
if (specs.length === 0 || specs[0].status !== 'active') {
|
||
await db.query('ROLLBACK');
|
||
return res.status(404).json({ success: false, message: '商品规格组合不存在或已下架' });
|
||
}
|
||
|
||
availableStock = specs[0].stock;
|
||
}
|
||
|
||
// 检查购物车中是否已存在相同商品和规格组合
|
||
const [existingItems] = await db.execute(
|
||
'SELECT id, quantity FROM cart_items WHERE user_id = ? AND product_id = ? AND (specification_id = ? OR (specification_id IS NULL AND ? IS NULL))',
|
||
[userId, productId, specificationId, specificationId]
|
||
);
|
||
|
||
let finalQuantity = quantity;
|
||
if (existingItems.length > 0) {
|
||
finalQuantity += existingItems[0].quantity;
|
||
}
|
||
|
||
// 检查库存是否足够
|
||
if (availableStock < finalQuantity) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '库存不足' });
|
||
}
|
||
|
||
let cartItemId;
|
||
|
||
if (existingItems.length > 0) {
|
||
// 更新现有购物车项的数量
|
||
await db.execute(
|
||
'UPDATE cart_items SET quantity = ?, updated_at = NOW() WHERE id = ?',
|
||
[finalQuantity, existingItems[0].id]
|
||
);
|
||
cartItemId = existingItems[0].id;
|
||
} else {
|
||
// 添加新的购物车项
|
||
const [result] = await db.execute(
|
||
'INSERT INTO cart_items (user_id, product_id, quantity, specification_id, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())',
|
||
[userId, productId, quantity, specificationId]
|
||
);
|
||
cartItemId = result.insertId;
|
||
}
|
||
|
||
await db.query('COMMIT');
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
message: '添加到购物车成功',
|
||
data: { cart_item_id: cartItemId }
|
||
});
|
||
} catch (error) {
|
||
await db.query('ROLLBACK');
|
||
console.error('添加到购物车失败:', error);
|
||
res.status(500).json({ success: false, message: '添加到购物车失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/{id}:
|
||
* put:
|
||
* summary: 更新购物车商品数量
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* parameters:
|
||
* - in: path
|
||
* name: id
|
||
* required: true
|
||
* schema:
|
||
* type: integer
|
||
* description: 购物车项ID
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* quantity:
|
||
* type: integer
|
||
* description: 新的商品数量
|
||
* minimum: 1
|
||
* required:
|
||
* - quantity
|
||
* responses:
|
||
* 200:
|
||
* description: 更新购物车成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* 400:
|
||
* description: 参数错误或库存不足
|
||
* 401:
|
||
* description: 未授权
|
||
* 404:
|
||
* description: 购物车项不存在
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.put('/:id', auth, async (req, res) => {
|
||
const db = getDB();
|
||
await db.query('START TRANSACTION');
|
||
|
||
try {
|
||
const cartItemId = req.params.id;
|
||
const { quantity } = req.body;
|
||
const userId = req.user.id;
|
||
|
||
// 验证数量
|
||
if (!quantity || quantity < 1) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '商品数量必须大于0' });
|
||
}
|
||
|
||
// 检查购物车项是否存在且属于当前用户
|
||
const [cartItems] = await db.execute(
|
||
'SELECT id, product_id, specification_id FROM cart_items WHERE id = ? AND user_id = ?',
|
||
[cartItemId, userId]
|
||
);
|
||
console.log(cartItems,'cartItems');
|
||
|
||
|
||
if (cartItems.length === 0) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(404).json({ success: false, message: '购物车项不存在' });
|
||
}
|
||
|
||
const cartItem = cartItems[0];
|
||
|
||
// 检查商品库存
|
||
const [products] = await db.execute(
|
||
'SELECT stock, status FROM products WHERE id = ?',
|
||
[cartItem.product_id]
|
||
);
|
||
|
||
if (products.length === 0 || products[0].status !== 'active') {
|
||
await db.query('ROLLBACK');
|
||
return res.status(404).json({ success: false, message: '商品不存在或已下架' });
|
||
}
|
||
|
||
let availableStock = products[0].stock;
|
||
|
||
// 如果有规格,检查规格库存
|
||
if (cartItem.specification_id) {
|
||
const [specs] = await db.execute(
|
||
'SELECT stock, status FROM product_spec_combinations WHERE id = ?',
|
||
[cartItem.specification_id]
|
||
);
|
||
|
||
if (specs.length === 0 || specs[0].status !== 'active') {
|
||
await db.query('ROLLBACK');
|
||
return res.status(404).json({ success: false, message: '商品规格不存在或已下架' });
|
||
}
|
||
|
||
availableStock = specs[0].stock;
|
||
}
|
||
|
||
// 检查库存是否足够
|
||
if (availableStock < quantity) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '库存不足' });
|
||
}
|
||
|
||
// 更新购物车项数量
|
||
await db.execute(
|
||
'UPDATE cart_items SET quantity = ?, updated_at = NOW() WHERE id = ?',
|
||
[quantity, cartItemId]
|
||
);
|
||
|
||
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: '更新购物车失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/batch:
|
||
* delete:
|
||
* summary: 批量删除购物车商品
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* cart_item_ids:
|
||
* type: array
|
||
* items:
|
||
* type: integer
|
||
* description: 购物车项ID数组
|
||
* required:
|
||
* - cart_item_ids
|
||
* responses:
|
||
* 200:
|
||
* description: 批量删除购物车商品成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* data:
|
||
* type: object
|
||
* properties:
|
||
* deleted_count:
|
||
* type: integer
|
||
* description: 删除的商品数量
|
||
* 400:
|
||
* description: 参数错误
|
||
* 401:
|
||
* description: 未授权
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.delete('/batch', auth, async (req, res) => {
|
||
try {
|
||
const { cart_item_ids } = req.body;
|
||
const userId = req.user.id;
|
||
|
||
// 验证参数
|
||
if (!cart_item_ids || !Array.isArray(cart_item_ids) || cart_item_ids.length === 0) {
|
||
return res.status(400).json({ success: false, message: '请选择要删除的商品' });
|
||
}
|
||
|
||
// 构建删除条件
|
||
const placeholders = cart_item_ids.map(() => '?').join(',');
|
||
const query = `DELETE FROM cart_items WHERE id IN (${placeholders}) AND user_id = ?`;
|
||
const params = [...cart_item_ids, userId];
|
||
|
||
const [result] = await getDB().execute(query, params);
|
||
|
||
res.json({
|
||
success: true,
|
||
message: '批量删除购物车商品成功',
|
||
data: {
|
||
deleted_count: result.affectedRows
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('批量删除购物车商品失败:', error);
|
||
res.status(500).json({ success: false, message: '批量删除购物车商品失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/clear:
|
||
* delete:
|
||
* summary: 清空购物车
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* responses:
|
||
* 200:
|
||
* description: 清空购物车成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* 401:
|
||
* description: 未授权
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.delete('/clear', auth, async (req, res) => {
|
||
try {
|
||
const userId = req.user.id;
|
||
|
||
// 清空用户购物车
|
||
await getDB().execute(
|
||
'DELETE FROM cart_items WHERE user_id = ?',
|
||
[userId]
|
||
);
|
||
|
||
res.json({
|
||
success: true,
|
||
message: '清空购物车成功'
|
||
});
|
||
console.log(11111111111111)
|
||
} catch (error) {
|
||
console.error('清空购物车失败:', error);
|
||
res.status(500).json({ success: false, message: '清空购物车失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/count:
|
||
* get:
|
||
* summary: 获取购物车商品数量
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* responses:
|
||
* 200:
|
||
* description: 获取购物车商品数量成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* data:
|
||
* type: object
|
||
* properties:
|
||
* count:
|
||
* type: integer
|
||
* description: 购物车商品总数量
|
||
* 401:
|
||
* description: 未授权
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.get('/count', auth, async (req, res) => {
|
||
try {
|
||
const userId = req.user.id;
|
||
|
||
// 获取购物车商品总数量
|
||
const [result] = await getDB().execute(
|
||
'SELECT SUM(quantity) as count FROM cart_items WHERE user_id = ?',
|
||
[userId]
|
||
);
|
||
|
||
const count = result[0].count || 0;
|
||
|
||
res.json({
|
||
success: true,
|
||
data: { count }
|
||
});
|
||
} catch (error) {
|
||
console.error('获取购物车商品数量失败:', error);
|
||
res.status(500).json({ success: false, message: '获取购物车商品数量失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/checkout:
|
||
* post:
|
||
* summary: 购物车结账
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* cart_item_ids:
|
||
* type: array
|
||
* items:
|
||
* type: integer
|
||
* description: 要结账的购物车项ID数组
|
||
* shipping_address:
|
||
* type: string
|
||
* description: 收货地址
|
||
* required:
|
||
* - cart_item_ids
|
||
* - shipping_address
|
||
* responses:
|
||
* 201:
|
||
* description: 结账成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* data:
|
||
* type: object
|
||
* properties:
|
||
* order_id:
|
||
* type: integer
|
||
* order_no:
|
||
* type: string
|
||
* total_amount:
|
||
* type: integer
|
||
* total_points:
|
||
* type: integer
|
||
* total_rongdou:
|
||
* type: integer
|
||
* 400:
|
||
* description: 参数错误或库存不足
|
||
* 401:
|
||
* description: 未授权
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.post('/checkout', auth, async (req, res) => {
|
||
const db = getDB();
|
||
await db.query('START TRANSACTION');
|
||
|
||
try {
|
||
const { cart_item_ids, shipping_address } = req.body;
|
||
const userId = req.user.id;
|
||
|
||
// 验证参数
|
||
if (!cart_item_ids || !Array.isArray(cart_item_ids) || cart_item_ids.length === 0) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '请选择要结账的商品' });
|
||
}
|
||
|
||
if (!shipping_address) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '请填写收货地址' });
|
||
}
|
||
|
||
// 获取购物车商品信息
|
||
const placeholders = cart_item_ids.map(() => '?').join(',');
|
||
const cartQuery = `
|
||
SELECT
|
||
c.id, c.product_id, c.quantity, c.spec_combination_id,
|
||
p.name, p.price, p.points_price, p.rongdou_price, p.stock, p.status,
|
||
psc.price_adjustment, psc.points_adjustment, psc.rongdou_adjustment, psc.stock as spec_stock
|
||
FROM cart_items c
|
||
LEFT JOIN products p ON c.product_id = p.id
|
||
LEFT JOIN product_spec_combinations psc ON c.spec_combination_id = psc.id
|
||
WHERE c.id IN (${placeholders}) AND c.user_id = ?
|
||
`;
|
||
|
||
const [cartItems] = await db.execute(cartQuery, [...cart_item_ids, userId]);
|
||
|
||
if (cartItems.length === 0) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '购物车商品不存在' });
|
||
}
|
||
|
||
// 验证商品状态和库存
|
||
let totalAmount = 0;
|
||
let totalPoints = 0;
|
||
let totalRongdou = 0;
|
||
|
||
for (const item of cartItems) {
|
||
if (item.status !== 'active') {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: `商品 ${item.name} 已下架` });
|
||
}
|
||
|
||
const availableStock = item.spec_combination_id ? item.spec_stock : item.stock;
|
||
if (availableStock < item.quantity) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: `商品 ${item.name} 库存不足` });
|
||
}
|
||
|
||
const finalPrice = item.price + (item.price_adjustment || 0);
|
||
const finalPointsPrice = item.points_price + (item.points_adjustment || 0);
|
||
const finalRongdouPrice = item.rongdou_price + (item.rongdou_adjustment || 0);
|
||
|
||
totalAmount += finalPrice * item.quantity;
|
||
totalPoints += finalPointsPrice * item.quantity;
|
||
totalRongdou += finalRongdouPrice * item.quantity;
|
||
}
|
||
|
||
// 检查用户积分和融豆是否足够
|
||
const [users] = await db.execute(
|
||
'SELECT points, rongdou FROM users WHERE id = ?',
|
||
[userId]
|
||
);
|
||
|
||
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: '积分不足' });
|
||
}
|
||
|
||
if (user.rongdou < totalRongdou) {
|
||
await db.query('ROLLBACK');
|
||
return res.status(400).json({ success: false, message: '融豆不足' });
|
||
}
|
||
|
||
// 生成订单号
|
||
const orderNo = 'ORD' + Date.now() + Math.random().toString(36).substr(2, 5).toUpperCase();
|
||
|
||
// 创建订单
|
||
const [orderResult] = await db.execute(
|
||
`INSERT INTO orders (order_no, user_id, total_amount, total_points, total_rongdou,
|
||
status, shipping_address, created_at, updated_at)
|
||
VALUES (?, ?, ?, ?, ?, 'pending', ?, NOW(), NOW())`,
|
||
[orderNo, userId, totalAmount, totalPoints, totalRongdou, shipping_address]
|
||
);
|
||
|
||
const orderId = orderResult.insertId;
|
||
|
||
// 创建订单项
|
||
for (const item of cartItems) {
|
||
const finalPrice = item.price + (item.price_adjustment || 0);
|
||
const finalPointsPrice = item.points_price + (item.points_adjustment || 0);
|
||
const finalRongdouPrice = item.rongdou_price + (item.rongdou_adjustment || 0);
|
||
|
||
await db.execute(
|
||
`INSERT INTO order_items (order_id, product_id, spec_combination_id, quantity,
|
||
price, points_price, rongdou_price, created_at)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`,
|
||
[orderId, item.product_id, item.spec_combination_id, item.quantity,
|
||
finalPrice, finalPointsPrice, finalRongdouPrice]
|
||
);
|
||
|
||
// 更新库存
|
||
if (item.spec_combination_id) {
|
||
await db.execute(
|
||
'UPDATE product_spec_combinations SET stock = stock - ? WHERE id = ?',
|
||
[item.quantity, item.spec_combination_id]
|
||
);
|
||
} else {
|
||
await db.execute(
|
||
'UPDATE products SET stock = stock - ? WHERE id = ?',
|
||
[item.quantity, item.product_id]
|
||
);
|
||
}
|
||
}
|
||
|
||
// 扣除用户积分和融豆
|
||
await db.execute(
|
||
'UPDATE users SET points = points - ?, rongdou = rongdou - ? WHERE id = ?',
|
||
[totalPoints, totalRongdou, userId]
|
||
);
|
||
|
||
// 删除已结账的购物车项
|
||
const deletePlaceholders = cart_item_ids.map(() => '?').join(',');
|
||
await db.execute(
|
||
`DELETE FROM cart_items WHERE id IN (${deletePlaceholders}) AND user_id = ?`,
|
||
[...cart_item_ids, userId]
|
||
);
|
||
|
||
await db.query('COMMIT');
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
message: '结账成功',
|
||
data: {
|
||
order_id: orderId,
|
||
order_no: orderNo,
|
||
total_amount: totalAmount,
|
||
total_points: totalPoints,
|
||
total_rongdou: totalRongdou
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
await db.query('ROLLBACK');
|
||
console.error('购物车结账失败:', error);
|
||
res.status(500).json({ success: false, message: '结账失败' });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* @swagger
|
||
* /api/cart/{id}:
|
||
* delete:
|
||
* summary: 删除购物车商品
|
||
* tags: [Cart]
|
||
* security:
|
||
* - bearerAuth: []
|
||
* parameters:
|
||
* - in: path
|
||
* name: id
|
||
* required: true
|
||
* schema:
|
||
* type: integer
|
||
* description: 购物车项ID
|
||
* responses:
|
||
* 200:
|
||
* description: 删除购物车商品成功
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* success:
|
||
* type: boolean
|
||
* message:
|
||
* type: string
|
||
* 401:
|
||
* description: 未授权
|
||
* 404:
|
||
* description: 购物车项不存在
|
||
* 500:
|
||
* description: 服务器错误
|
||
*/
|
||
router.delete('/:id', auth, async (req, res) => {
|
||
try {
|
||
console.log(111111111)
|
||
const cartItemId = req.params.id;
|
||
const userId = req.user.id;
|
||
|
||
// 检查购物车项是否存在且属于当前用户
|
||
const [cartItems] = await getDB().execute(
|
||
'SELECT id FROM cart_items WHERE id = ? AND user_id = ?',
|
||
[cartItemId, userId]
|
||
);
|
||
|
||
if (cartItems.length === 0) {
|
||
return res.status(404).json({ success: false, message: '购物车项不存在' });
|
||
}
|
||
|
||
// 删除购物车项
|
||
await getDB().execute(
|
||
'DELETE FROM cart_items WHERE id = ?',
|
||
[cartItemId]
|
||
);
|
||
|
||
res.json({
|
||
success: true,
|
||
message: '删除购物车商品成功'
|
||
});
|
||
} catch (error) {
|
||
console.error('删除购物车商品失败:', error);
|
||
res.status(500).json({ success: false, message: '删除购物车商品失败' });
|
||
}
|
||
});
|
||
|
||
module.exports = router; |