forked from p4b8lshcr/ChefTronic
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
10 KiB
391 lines
10 KiB
/**
|
|
* 订单数据模型
|
|
*
|
|
* 功能:封装订单表和订单明细表的数据库操作
|
|
*/
|
|
|
|
const { pool } = require('../config/database');
|
|
|
|
/**
|
|
* 订单模型类
|
|
*/
|
|
class Order {
|
|
/**
|
|
* 生成订单编号
|
|
* @returns {string} 订单编号
|
|
*/
|
|
static generateOrderNo() {
|
|
// 格式: ORD + 年月日 + 时分秒 + 随机数
|
|
const now = new Date();
|
|
const dateStr = now.toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
|
|
return `ORD${dateStr}${random}`;
|
|
}
|
|
|
|
/**
|
|
* 根据ID查找订单
|
|
* @param {number} id - 订单ID
|
|
* @returns {Promise<object|null>} 订单对象或null
|
|
*/
|
|
static async findById(id) {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT o.*,
|
|
u1.username as customer_name,
|
|
u2.username as waiter_name
|
|
FROM orders o
|
|
LEFT JOIN users u1 ON o.customer_id = u1.id
|
|
LEFT JOIN users u2 ON o.waiter_id = u2.id
|
|
WHERE o.id = ?`,
|
|
[id]
|
|
);
|
|
return rows[0] || null;
|
|
} catch (error) {
|
|
throw new Error('查询订单失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据订单编号查找订单
|
|
* @param {string} orderNo - 订单编号
|
|
* @returns {Promise<object|null>} 订单对象或null
|
|
*/
|
|
static async findByOrderNo(orderNo) {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT o.*,
|
|
u1.username as customer_name,
|
|
u2.username as waiter_name
|
|
FROM orders o
|
|
LEFT JOIN users u1 ON o.customer_id = u1.id
|
|
LEFT JOIN users u2 ON o.waiter_id = u2.id
|
|
WHERE o.order_no = ?`,
|
|
[orderNo]
|
|
);
|
|
return rows[0] || null;
|
|
} catch (error) {
|
|
throw new Error('查询订单失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取订单列表(分页、筛选)
|
|
* @param {object} options - 查询选项
|
|
* @returns {Promise<object>} 订单列表和总数
|
|
*/
|
|
static async findAll(options = {}) {
|
|
try {
|
|
const {
|
|
page = 1,
|
|
pageSize = 10,
|
|
customer_id,
|
|
waiter_id,
|
|
status,
|
|
order_type,
|
|
start_date,
|
|
end_date
|
|
} = options;
|
|
|
|
const offset = (page - 1) * pageSize;
|
|
|
|
// 构建WHERE条件
|
|
const conditions = [];
|
|
const params = [];
|
|
|
|
if (customer_id) {
|
|
conditions.push('o.customer_id = ?');
|
|
params.push(customer_id);
|
|
}
|
|
if (waiter_id) {
|
|
conditions.push('o.waiter_id = ?');
|
|
params.push(waiter_id);
|
|
}
|
|
if (status) {
|
|
conditions.push('o.status = ?');
|
|
params.push(status);
|
|
}
|
|
if (order_type) {
|
|
conditions.push('o.order_type = ?');
|
|
params.push(order_type);
|
|
}
|
|
if (start_date) {
|
|
conditions.push('DATE(o.created_at) >= ?');
|
|
params.push(start_date);
|
|
}
|
|
if (end_date) {
|
|
conditions.push('DATE(o.created_at) <= ?');
|
|
params.push(end_date);
|
|
}
|
|
|
|
const whereClause = conditions.length > 0
|
|
? 'WHERE ' + conditions.join(' AND ')
|
|
: '';
|
|
|
|
// 查询总数
|
|
const [countResult] = await pool.query(
|
|
`SELECT COUNT(*) as total FROM orders o ${whereClause}`,
|
|
params
|
|
);
|
|
const total = countResult[0].total;
|
|
|
|
// 查询列表
|
|
const [rows] = await pool.query(
|
|
`SELECT o.*,
|
|
u1.username as customer_name,
|
|
u2.username as waiter_name
|
|
FROM orders o
|
|
LEFT JOIN users u1 ON o.customer_id = u1.id
|
|
LEFT JOIN users u2 ON o.waiter_id = u2.id
|
|
${whereClause}
|
|
ORDER BY o.created_at DESC
|
|
LIMIT ? OFFSET ?`,
|
|
[...params, pageSize, offset]
|
|
);
|
|
|
|
return {
|
|
list: rows,
|
|
total,
|
|
page: parseInt(page),
|
|
pageSize: parseInt(pageSize)
|
|
};
|
|
} catch (error) {
|
|
throw new Error('查询订单列表失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建新订单
|
|
* @param {object} orderData - 订单数据
|
|
* @param {array} items - 订单明细数组
|
|
* @returns {Promise<object>} 创建的订单
|
|
*/
|
|
static async create(orderData, items) {
|
|
const connection = await pool.getConnection();
|
|
|
|
try {
|
|
await connection.beginTransaction();
|
|
|
|
const {
|
|
customer_id,
|
|
waiter_id,
|
|
table_number,
|
|
order_type = 'dine_in',
|
|
special_request
|
|
} = orderData;
|
|
|
|
// 生成订单编号
|
|
const order_no = this.generateOrderNo();
|
|
|
|
// 计算订单金额
|
|
let total_amount = 0;
|
|
for (const item of items) {
|
|
total_amount += item.price * item.quantity;
|
|
}
|
|
|
|
const discount_amount = orderData.discount_amount || 0;
|
|
const final_amount = total_amount - discount_amount;
|
|
|
|
// 插入订单主表
|
|
const [orderResult] = await connection.query(
|
|
`INSERT INTO orders (order_no, customer_id, waiter_id, table_number,
|
|
total_amount, discount_amount, final_amount, order_type, special_request, status)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')`,
|
|
[order_no, customer_id, waiter_id, table_number,
|
|
total_amount, discount_amount, final_amount, order_type, special_request]
|
|
);
|
|
|
|
const orderId = orderResult.insertId;
|
|
|
|
// 插入订单明细
|
|
for (const item of items) {
|
|
const subtotal = item.price * item.quantity;
|
|
await connection.query(
|
|
`INSERT INTO order_items (order_id, dish_id, dish_name, price, quantity, subtotal, special_request)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
[orderId, item.dish_id, item.dish_name, item.price, item.quantity, subtotal, item.special_request || null]
|
|
);
|
|
}
|
|
|
|
await connection.commit();
|
|
|
|
// 返回创建的订单
|
|
return await this.findById(orderId);
|
|
} catch (error) {
|
|
await connection.rollback();
|
|
throw new Error('创建订单失败: ' + error.message);
|
|
} finally {
|
|
connection.release();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新订单状态
|
|
* @param {number} id - 订单ID
|
|
* @param {string} status - 新状态
|
|
* @returns {Promise<object>} 更新后的订单
|
|
*/
|
|
static async updateStatus(id, status) {
|
|
try {
|
|
await pool.query(
|
|
'UPDATE orders SET status = ? WHERE id = ?',
|
|
[status, id]
|
|
);
|
|
return await this.findById(id);
|
|
} catch (error) {
|
|
throw new Error('更新订单状态失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 取消订单
|
|
* @param {number} id - 订单ID
|
|
* @returns {Promise<object>} 更新后的订单
|
|
*/
|
|
static async cancel(id) {
|
|
try {
|
|
await pool.query(
|
|
'UPDATE orders SET status = ? WHERE id = ?',
|
|
['cancelled', id]
|
|
);
|
|
return await this.findById(id);
|
|
} catch (error) {
|
|
throw new Error('取消订单失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取订单明细
|
|
* @param {number} orderId - 订单ID
|
|
* @returns {Promise<array>} 订单明细列表
|
|
*/
|
|
static async getOrderItems(orderId) {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT oi.*, d.image, d.category_id
|
|
FROM order_items oi
|
|
LEFT JOIN dishes d ON oi.dish_id = d.id
|
|
WHERE oi.order_id = ?
|
|
ORDER BY oi.id`,
|
|
[orderId]
|
|
);
|
|
return rows;
|
|
} catch (error) {
|
|
throw new Error('查询订单明细失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取订单完整信息(包含明细)
|
|
* @param {number} id - 订单ID
|
|
* @returns {Promise<object>} 订单完整信息
|
|
*/
|
|
static async getOrderWithItems(id) {
|
|
try {
|
|
const order = await this.findById(id);
|
|
if (!order) {
|
|
return null;
|
|
}
|
|
|
|
const items = await this.getOrderItems(id);
|
|
|
|
return {
|
|
...order,
|
|
items
|
|
};
|
|
} catch (error) {
|
|
throw new Error('查询订单详情失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新订单金额(添加折扣等)
|
|
* @param {number} id - 订单ID
|
|
* @param {number} discountAmount - 折扣金额
|
|
* @returns {Promise<object>} 更新后的订单
|
|
*/
|
|
static async updateAmount(id, discountAmount) {
|
|
try {
|
|
const order = await this.findById(id);
|
|
if (!order) {
|
|
throw new Error('订单不存在');
|
|
}
|
|
|
|
const final_amount = order.total_amount - discountAmount;
|
|
|
|
await pool.query(
|
|
'UPDATE orders SET discount_amount = ?, final_amount = ? WHERE id = ?',
|
|
[discountAmount, final_amount, id]
|
|
);
|
|
|
|
return await this.findById(id);
|
|
} catch (error) {
|
|
throw new Error('更新订单金额失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 统计订单数据
|
|
* @param {object} conditions - 统计条件
|
|
* @returns {Promise<object>} 统计结果
|
|
*/
|
|
static async getStatistics(conditions = {}) {
|
|
try {
|
|
const { start_date, end_date, status } = conditions;
|
|
|
|
const whereConditions = [];
|
|
const params = [];
|
|
|
|
if (start_date) {
|
|
whereConditions.push('DATE(created_at) >= ?');
|
|
params.push(start_date);
|
|
}
|
|
if (end_date) {
|
|
whereConditions.push('DATE(created_at) <= ?');
|
|
params.push(end_date);
|
|
}
|
|
if (status) {
|
|
whereConditions.push('status = ?');
|
|
params.push(status);
|
|
}
|
|
|
|
const whereClause = whereConditions.length > 0
|
|
? 'WHERE ' + whereConditions.join(' AND ')
|
|
: '';
|
|
|
|
const [rows] = await pool.query(
|
|
`SELECT
|
|
COUNT(*) as total_orders,
|
|
SUM(final_amount) as total_revenue,
|
|
AVG(final_amount) as avg_order_value,
|
|
MAX(final_amount) as max_order_value,
|
|
MIN(final_amount) as min_order_value
|
|
FROM orders ${whereClause}`,
|
|
params
|
|
);
|
|
|
|
return rows[0];
|
|
} catch (error) {
|
|
throw new Error('统计订单数据失败: ' + error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 按状态统计订单数量
|
|
* @returns {Promise<array>} 各状态的订单数量
|
|
*/
|
|
static async getStatusStatistics() {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT status, COUNT(*) as count
|
|
FROM orders
|
|
GROUP BY status`
|
|
);
|
|
return rows;
|
|
} catch (error) {
|
|
throw new Error('统计订单状态失败: ' + error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Order;
|