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.

295 lines
7.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 菜品数据模型
*
* 功能:封装菜品表的数据库操作
*/
const { pool } = require('../config/database');
/**
* 菜品模型类
*/
class Dish {
/**
* 根据ID查找菜品
* @param {number} id - 菜品ID
* @returns {Promise<object|null>} 菜品对象或null
*/
static async findById(id) {
try {
const [rows] = await pool.query(
`SELECT d.*, dc.name as category_name
FROM dishes d
LEFT JOIN dish_categories dc ON d.category_id = dc.id
WHERE d.id = ?`,
[id]
);
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,
category_id,
is_available,
status,
search
} = options;
const offset = (page - 1) * pageSize;
// 构建WHERE条件
const conditions = [];
const params = [];
if (category_id) {
conditions.push('d.category_id = ?');
params.push(category_id);
}
if (is_available !== undefined) {
conditions.push('d.is_available = ?');
params.push(is_available);
}
if (status !== undefined) {
conditions.push('d.status = ?');
params.push(status);
}
if (search) {
conditions.push('(d.name LIKE ? OR d.description LIKE ?)');
params.push(`%${search}%`, `%${search}%`);
}
const whereClause = conditions.length > 0
? 'WHERE ' + conditions.join(' AND ')
: '';
// 查询总数
const [countResult] = await pool.query(
`SELECT COUNT(*) as total FROM dishes d ${whereClause}`,
params
);
const total = countResult[0].total;
// 查询列表
const [rows] = await pool.query(
`SELECT d.*, dc.name as category_name
FROM dishes d
LEFT JOIN dish_categories dc ON d.category_id = dc.id
${whereClause}
ORDER BY d.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} dishData - 菜品数据
* @returns {Promise<object>} 创建的菜品
*/
static async create(dishData) {
try {
const {
category_id,
name,
price,
image,
description,
taste,
ingredients,
cooking_time,
is_available = 1
} = dishData;
const [result] = await pool.query(
`INSERT INTO dishes (category_id, name, price, image, description, taste, ingredients, cooking_time, is_available)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[category_id, name, price, image, description, taste, ingredients, cooking_time, is_available]
);
return await this.findById(result.insertId);
} catch (error) {
throw new Error('创建菜品失败: ' + error.message);
}
}
/**
* 更新菜品
* @param {number} id - 菜品ID
* @param {object} dishData - 要更新的数据
* @returns {Promise<object>} 更新后的菜品
*/
static async update(id, dishData) {
try {
const {
category_id,
name,
price,
image,
description,
taste,
ingredients,
cooking_time,
is_available,
status
} = dishData;
const updates = [];
const values = [];
if (category_id !== undefined) {
updates.push('category_id = ?');
values.push(category_id);
}
if (name !== undefined) {
updates.push('name = ?');
values.push(name);
}
if (price !== undefined) {
updates.push('price = ?');
values.push(price);
}
if (image !== undefined) {
updates.push('image = ?');
values.push(image);
}
if (description !== undefined) {
updates.push('description = ?');
values.push(description);
}
if (taste !== undefined) {
updates.push('taste = ?');
values.push(taste);
}
if (ingredients !== undefined) {
updates.push('ingredients = ?');
values.push(ingredients);
}
if (cooking_time !== undefined) {
updates.push('cooking_time = ?');
values.push(cooking_time);
}
if (is_available !== undefined) {
updates.push('is_available = ?');
values.push(is_available);
}
if (status !== undefined) {
updates.push('status = ?');
values.push(status);
}
if (updates.length === 0) {
throw new Error('没有要更新的数据');
}
values.push(id);
await pool.query(
`UPDATE dishes SET ${updates.join(', ')} WHERE id = ?`,
values
);
return await this.findById(id);
} catch (error) {
throw new Error('更新菜品失败: ' + error.message);
}
}
/**
* 删除菜品
* @param {number} id - 菜品ID
* @returns {Promise<boolean>} 是否成功
*/
static async delete(id) {
try {
await pool.query('DELETE FROM dishes WHERE id = ?', [id]);
return true;
} catch (error) {
throw new Error('删除菜品失败: ' + error.message);
}
}
/**
* 更新菜品可售状态
* @param {number} id - 菜品ID
* @param {number} is_available - 是否可售1是/0否
* @returns {Promise<boolean>} 是否成功
*/
static async updateAvailability(id, is_available) {
try {
await pool.query(
'UPDATE dishes SET is_available = ? WHERE id = ?',
[is_available, id]
);
return true;
} catch (error) {
throw new Error('更新菜品状态失败: ' + error.message);
}
}
/**
* 根据分类ID获取菜品列表
* @param {number} categoryId - 分类ID
* @returns {Promise<array>} 菜品列表
*/
static async findByCategory(categoryId) {
try {
const [rows] = await pool.query(
`SELECT * FROM dishes
WHERE category_id = ? AND status = 1
ORDER BY created_at DESC`,
[categoryId]
);
return rows;
} catch (error) {
throw new Error('查询分类菜品失败: ' + error.message);
}
}
/**
* 获取热门菜品
* @param {number} limit - 数量限制
* @returns {Promise<array>} 菜品列表
*/
static async findPopular(limit = 10) {
try {
// 这里简化处理,实际应该根据订单数据统计
// 暂时返回最新的菜品
const [rows] = await pool.query(
`SELECT d.*, dc.name as category_name
FROM dishes d
LEFT JOIN dish_categories dc ON d.category_id = dc.id
WHERE d.status = 1 AND d.is_available = 1
ORDER BY d.created_at DESC
LIMIT ?`,
[limit]
);
return rows;
} catch (error) {
throw new Error('查询热门菜品失败: ' + error.message);
}
}
}
module.exports = Dish;