const { User, PointRecord, PointProduct, PointOrder, Store } = require('../models'); const { ORDER_STATUS } = require('../config/constants'); const { generateOrderNo, generateExchangeCode, success, error, getPagination, pageResult, formatDateTime } = require('../utils/helper'); const { Op } = require('sequelize'); const sequelize = require('../config/database'); const QRCode = require('qrcode'); class PointsController { // 获取积分余额 async getBalance(req, res) { try { const user = req.user; res.json(success({ balance: user.total_points })); } catch (err) { console.error('获取积分余额失败:', err); res.status(500).json(error('获取失败')); } } // 获取积分记录 async getRecords(req, res) { try { const { page = 1, pageSize = 20 } = req.query; const { limit, offset } = getPagination(page, pageSize); const user = req.user; const { rows, count } = await PointRecord.findAndCountAll({ where: { user_id: user.id }, include: [{ model: Store, as: 'store', attributes: ['id', 'name'] }], order: [['created_at', 'DESC']], limit, offset }); res.json(pageResult(rows.map(record => ({ id: record.id, actionName: record.action_name, points: record.points, balance: record.balance, consumeAmount: record.consume_amount, storeName: record.store?.name, remark: record.remark, createdAt: formatDateTime(record.created_at) })), count, page, pageSize)); } catch (err) { console.error('获取积分记录失败:', err); res.status(500).json(error('获取失败')); } } // 获取积分商城商品 async getProducts(req, res) { try { const { page = 1, pageSize = 20, store_id } = req.query; const { limit, offset } = getPagination(page, pageSize); const where = { status: 1, stock: { [Op.gt]: 0 } }; if (store_id) { where.store_id = store_id; } const { rows, count } = await PointProduct.findAndCountAll({ where, include: [{ model: Store, as: 'store', attributes: ['id', 'name'] }], order: [['sort_order', 'ASC'], ['created_at', 'DESC']], limit, offset }); res.json(pageResult(rows.map(product => ({ id: product.id, name: product.name, description: product.description, image: product.image, pointsRequired: product.points_required, originalPrice: product.original_price, stock: product.stock, storeId: product.store_id, storeName: product.store?.name })), count, page, pageSize)); } catch (err) { console.error('获取商品列表失败:', err); res.status(500).json(error('获取失败')); } } // 获取商品详情 async getProductDetail(req, res) { try { const { id } = req.params; const product = await PointProduct.findByPk(id, { include: [{ model: Store, as: 'store' }] }); if (!product || product.status !== 1) { return res.status(404).json(error('商品不存在', 404)); } res.json(success({ id: product.id, name: product.name, description: product.description, image: product.image, pointsRequired: product.points_required, originalPrice: product.original_price, stock: product.stock, exchangeCount: product.exchange_count, storeId: product.store_id, storeName: product.store?.name, storeAddress: product.store?.address })); } catch (err) { console.error('获取商品详情失败:', err); res.status(500).json(error('获取失败')); } } // 兑换商品 async exchangeProduct(req, res) { const t = await sequelize.transaction(); try { const { product_id } = req.body; const user = req.user; const product = await PointProduct.findByPk(product_id, { include: [{ model: Store, as: 'store' }] }); if (!product || product.status !== 1) { await t.rollback(); return res.status(404).json(error('商品不存在', 404)); } if (product.stock <= 0) { await t.rollback(); return res.status(400).json(error('商品库存不足', 400)); } if (user.total_points < product.points_required) { await t.rollback(); return res.status(400).json(error('积分不足', 400)); } // 扣减积分 const newBalance = user.total_points - product.points_required; await user.update({ total_points: newBalance }, { transaction: t }); // 扣减库存 await product.update({ stock: product.stock - 1, exchange_count: product.exchange_count + 1 }, { transaction: t }); // 创建订单 const order = await PointOrder.create({ order_no: generateOrderNo(), user_id: user.id, product_id: product.id, store_id: product.store_id, product_name: product.name, points_used: product.points_required, exchange_code: generateExchangeCode(), status: ORDER_STATUS.PENDING }, { transaction: t }); // 记录积分变动 await PointRecord.create({ user_id: user.id, store_id: product.store_id, action_name: '积分兑换', points: -product.points_required, balance: newBalance, remark: `兑换商品: ${product.name}` }, { transaction: t }); await t.commit(); res.json(success({ orderId: order.id, orderNo: order.order_no, exchangeCode: order.exchange_code, productName: product.name, storeName: product.store?.name, storeAddress: product.store?.address }, '兑换成功')); } catch (err) { await t.rollback(); console.error('兑换商品失败:', err); res.status(500).json(error('兑换失败')); } } // 获取我的兑换订单 async getOrders(req, res) { try { const { page = 1, pageSize = 20, status } = req.query; const { limit, offset } = getPagination(page, pageSize); const user = req.user; const where = { user_id: user.id }; if (status !== undefined && status !== '') { where.status = status; } const { rows, count } = await PointOrder.findAndCountAll({ where, include: [ { model: PointProduct, as: 'product', attributes: ['id', 'name', 'image'] }, { model: Store, as: 'store', attributes: ['id', 'name', 'address'] } ], order: [['created_at', 'DESC']], limit, offset }); res.json(pageResult(rows.map(order => ({ id: order.id, orderNo: order.order_no, productName: order.product_name, productImage: order.product?.image, pointsUsed: order.points_used, status: order.status, storeName: order.store?.name, storeAddress: order.store?.address, createdAt: formatDateTime(order.created_at), verifiedAt: formatDateTime(order.verified_at) })), count, page, pageSize)); } catch (err) { console.error('获取订单列表失败:', err); res.status(500).json(error('获取失败')); } } // 获取订单详情 async getOrderDetail(req, res) { try { const { id } = req.params; const user = req.user; const order = await PointOrder.findOne({ where: { id, user_id: user.id }, include: [ { model: PointProduct, as: 'product' }, { model: Store, as: 'store' } ] }); if (!order) { return res.status(404).json(error('订单不存在', 404)); } res.json(success({ id: order.id, orderNo: order.order_no, productName: order.product_name, productImage: order.product?.image, productDescription: order.product?.description, pointsUsed: order.points_used, exchangeCode: order.exchange_code, status: order.status, storeId: order.store_id, storeName: order.store?.name, storeAddress: order.store?.address, storeContact: order.store?.contact, storeLatitude: order.store?.latitude, storeLongitude: order.store?.longitude, createdAt: formatDateTime(order.created_at), verifiedAt: formatDateTime(order.verified_at) })); } catch (err) { console.error('获取订单详情失败:', err); res.status(500).json(error('获取失败')); } } // 生成兑换码二维码 async getOrderQrcode(req, res) { try { const { code } = req.query; if (!code) { return res.status(400).json(error('缺少兑换码', 400)); } // 生成二维码配置 const qrOptions = { errorCorrectionLevel: 'M', type: 'image/png', margin: 2, width: 280, color: { dark: '#1A1A1A', light: '#FFFFFF' } }; // 生成二维码为 base64 const qrcodeDataUrl = await QRCode.toDataURL(code, qrOptions); res.json(success({ code: code, qrcode: qrcodeDataUrl })); } catch (err) { console.error('生成二维码失败:', err); res.status(500).json(error('生成二维码失败')); } } } module.exports = new PointsController();