|
|
/**
|
|
|
* 菜品数据模型
|
|
|
*
|
|
|
* 功能:封装菜品表的数据库操作
|
|
|
*/
|
|
|
|
|
|
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;
|