const { query, transaction } = require('../config/database') const { paginate } = require('../utils/pagination') const orderService = require('../services/orderService') const { requireAuth } = require('./users') const ORDER_UPDATEABLE_FIELDS = ['status', 'total_price', 'totalPrice', 'cart'] function allowedUpdateFields(body) { const result = {} for (const key of ORDER_UPDATEABLE_FIELDS) { if (key in body) { result[key] = body[key] } } return result } async function getOrders(ctx) { const operator = await requireAuth(ctx) if (!operator) return const { page, pageSize, status } = ctx.query let sql = ` SELECT o.*, JSON_ARRAYAGG( JSON_OBJECT( 'id', oi.id, 'order_id', oi.order_id, 'goods_id', oi.goods_id, 'goods_name', oi.goods_name, 'price', oi.price, 'quantity', oi.quantity, 'weight', oi.weight, 'subtotal', oi.subtotal, 'unit', oi.unit ) ) as items_json FROM orders o LEFT JOIN order_items oi ON o.id = oi.order_id WHERE 1=1 ` const params = [] if (operator.role !== 1) { sql += ' AND o.user_id = ?' params.push(operator.id) } if (status) { sql += ' AND o.status = ?' params.push(status) } sql += ' GROUP BY o.id ORDER BY o.created_at DESC' const result = await paginate(query, sql, params, page, pageSize) const rows = (result.data || []).map(row => { let items = [] try { const itemsJson = row.items_json if (itemsJson) { items = typeof itemsJson === 'string' ? JSON.parse(itemsJson) : itemsJson if (items.length === 1 && items[0].id === null) { items = [] } } } catch {} const { items_json, ...order } = row return { ...order, items } }) result.data = rows ctx.body = { code: 200, ...result } } async function getOrderById(ctx) { const operator = await requireAuth(ctx) if (!operator) return const orderId = ctx.params.id const orders = await query('SELECT * FROM orders WHERE id = ?', [orderId]) if (orders.length > 0) { const order = orders[0] if (operator.role !== 1 && order.user_id !== operator.id) { ctx.body = { code: 403, message: '无权查看此订单' } return } order.items = await orderService.getOrderItems(orderId) ctx.body = { code: 200, data: order } } else { ctx.body = { code: 404, message: '订单不存在' } } } async function createOrder(ctx) { const operator = await requireAuth(ctx) if (!operator) return const { totalPrice, cart, remark, customerName, customerPhone, orderType, status } = ctx.request.body const userId = ctx.request.body.userId || operator.id if (operator.role !== 1 && userId !== operator.id) { ctx.body = { code: 403, message: '无权为他人创建订单' } return } if (!cart || (Array.isArray(cart) && cart.length === 0)) { ctx.body = { code: 400, message: '购物车不能为空' } return } const items = typeof cart === 'string' ? JSON.parse(cart) : cart const calculatedTotalPrice = await orderService.recalculateTotalPrice(items) const orderId = `ORD${Date.now()}${Math.floor(Math.random() * 10000).toString().padStart(4, '0')}` const orderStatus = status || 'pending' const userInfo = JSON.stringify({ remark: remark || '', customerName: customerName || '', customerPhone: customerPhone || '', orderType: orderType || 'customer' }) await transaction(async (conn) => { for (const item of items) { const goodsId = item.id || item.goods_id || item.goodsId if (!goodsId) continue const qty = item.pricingType === 2 ? 1 : (item.quantity || 1) const [rows] = await conn.execute('SELECT id, name, stock FROM goods WHERE id = ? FOR UPDATE', [goodsId]) if (rows.length === 0) { throw new Error('商品不存在') } if (rows[0].stock < qty) { throw new Error(`${rows[0].name} 库存不足(当前库存: ${rows[0].stock},需要: ${qty})`) } if (orderStatus === 'completed') { await conn.execute('UPDATE goods SET stock = stock - ?, sales = COALESCE(sales, 0) + ? WHERE id = ?', [qty, qty, goodsId]) await conn.execute('UPDATE stock SET quantity = quantity - ? WHERE goods_id = ?', [qty, goodsId]) } } await conn.execute( 'INSERT INTO orders (id, user_id, status, total_price, cart, user_info) VALUES (?, ?, ?, ?, ?, ?)', [orderId, userId || null, orderStatus, calculatedTotalPrice, typeof cart === 'string' ? cart : JSON.stringify(cart), userInfo] ) await orderService.insertOrderItems(conn, orderId, cart) }) const orders = await query('SELECT * FROM orders WHERE id = ?', [orderId]) const created = orders[0] created.items = await orderService.getOrderItems(orderId) if (created.status === 'completed') { setImmediate(() => orderService.processOrderComplete(created)) } ctx.body = { code: 200, data: created } } async function updateOrder(ctx) { const operator = await requireAuth(ctx) if (!operator) return const orderId = ctx.params.id const body = allowedUpdateFields(ctx.request.body) const orders = await query('SELECT * FROM orders WHERE id = ?', [orderId]) if (orders.length > 0) { const order = orders[0] if (operator.role !== 1 && order.user_id !== operator.id) { ctx.body = { code: 403, message: '无权修改此订单' } return } const prevStatus = order.status const updateFields = [] const updateParams = [] if (body.status !== undefined) { updateFields.push('status = ?') updateParams.push(body.status) } const totalPrice = body.total_price !== undefined ? body.total_price : body.totalPrice if (totalPrice !== undefined) { updateFields.push('total_price = ?') updateParams.push(totalPrice) } if (body.cart !== undefined) { const cartStr = typeof body.cart === 'string' ? body.cart : JSON.stringify(body.cart) updateFields.push('cart = ?') updateParams.push(cartStr) } if (updateFields.length === 0) { ctx.body = { code: 400, message: '没有需要更新的字段' } return } const newStatus = body.status !== undefined ? body.status : prevStatus await transaction(async (conn) => { if (newStatus === 'completed' && prevStatus !== 'completed') { const items = body.cart !== undefined ? (typeof body.cart === 'string' ? JSON.parse(body.cart) : body.cart) : JSON.parse(order.cart || '[]') for (const item of items) { const goodsId = item.id || item.goods_id || item.goodsId if (!goodsId) continue const qty = item.pricingType === 2 ? 1 : (item.quantity || 1) const [rows] = await conn.execute('SELECT stock FROM goods WHERE id = ? FOR UPDATE', [goodsId]) if (rows.length > 0 && rows[0].stock >= qty) { await conn.execute('UPDATE goods SET stock = stock - ?, sales = COALESCE(sales, 0) + ? WHERE id = ?', [qty, qty, goodsId]) await conn.execute('UPDATE stock SET quantity = quantity - ? WHERE goods_id = ?', [qty, goodsId]) } } } updateParams.push(orderId) await conn.execute(`UPDATE orders SET ${updateFields.join(', ')} WHERE id = ?`, updateParams) if (body.cart !== undefined) { await conn.execute('DELETE FROM order_items WHERE order_id = ?', [orderId]) await orderService.insertOrderItems(conn, orderId, body.cart) } }) const updatedOrders = await query('SELECT * FROM orders WHERE id = ?', [orderId]) const completed = updatedOrders[0] completed.items = await orderService.getOrderItems(orderId) if (completed.status === 'completed' && prevStatus !== 'completed') { setImmediate(() => orderService.processOrderComplete(completed)) } // 订单状态变更时发送微信订阅消息通知 if (newStatus !== prevStatus && completed.user_id) { setImmediate(() => orderService.sendWechatNotification(completed.user_id, completed.id, newStatus, completed.total_price)) } ctx.body = { code: 200, data: completed } } else { ctx.body = { code: 404, message: '订单不存在' } } } module.exports = { getOrders, getOrderById, createOrder, updateOrder }