Initial commit - Zhangmenu Django project
A menu management application built with Django, featuring: - Dish management with cover images - Order system with party dates and participants - REST API with Django REST Framework - Bootstrap-styled frontend Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
// 菜品卡片组件
|
||||
|
||||
// 渲染菜品卡片
|
||||
function renderDishCard(dish, isInOrder = false) {
|
||||
const indicatorClass = isInOrder ? 'in-order' : 'not-in-order';
|
||||
const indicatorIcon = isInOrder ? '✓' : '+';
|
||||
|
||||
return `
|
||||
<div class="dish-card" data-id="${dish.id}">
|
||||
<div class="img-wrapper">
|
||||
<img src="${dish.cover_image || getDefaultImage()}" alt="${dish.name}">
|
||||
${dish.category_name ? `<span class="category-tag">${dish.category_name}</span>` : ''}
|
||||
<span class="order-indicator ${indicatorClass}">${indicatorIcon}</span>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="dish-name">${dish.name}</div>
|
||||
<div class="dish-meta">${dish.view_count || 0} 次浏览</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 渲染菜品网格
|
||||
function renderDishGrid(dishes, containerSelector, onCardClick) {
|
||||
const container = document.querySelector(containerSelector);
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = dishes.map(dish => renderDishCard(dish)).join('');
|
||||
|
||||
container.querySelectorAll('.dish-card').forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
if (onCardClick) {
|
||||
onCardClick(card.dataset.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 导出
|
||||
window.DishCard = {
|
||||
render: renderDishCard,
|
||||
renderGrid: renderDishGrid
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
// 弹窗组件
|
||||
|
||||
const Modal = {
|
||||
// 显示弹窗
|
||||
show(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
},
|
||||
|
||||
// 隐藏弹窗
|
||||
hide(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
},
|
||||
|
||||
// 切换弹窗
|
||||
toggle(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
if (modal.style.display === 'none') {
|
||||
this.show(modalId);
|
||||
} else {
|
||||
this.hide(modalId);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 显示确认对话框
|
||||
confirm(message) {
|
||||
return confirm(message);
|
||||
},
|
||||
|
||||
// 显示加载状态
|
||||
showLoading(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
const footer = modal.querySelector('.modal-footer');
|
||||
if (footer) {
|
||||
footer.dataset.originalContent = footer.innerHTML;
|
||||
footer.innerHTML = '<span class="loading-text">加载中...</span>';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 隐藏加载状态
|
||||
hideLoading(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
const footer = modal.querySelector('.modal-footer');
|
||||
if (footer && footer.dataset.originalContent) {
|
||||
footer.innerHTML = footer.dataset.originalContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Bootstrap 模态框包装
|
||||
const BootstrapModal = {
|
||||
init(modalId) {
|
||||
return new bootstrap.Modal(document.getElementById(modalId));
|
||||
},
|
||||
|
||||
show(modalId) {
|
||||
const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById(modalId));
|
||||
modal.show();
|
||||
},
|
||||
|
||||
hide(modalId) {
|
||||
const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById(modalId));
|
||||
modal.hide();
|
||||
}
|
||||
};
|
||||
|
||||
// 导出
|
||||
window.Modal = Modal;
|
||||
window.BootstrapModal = BootstrapModal;
|
||||
@@ -0,0 +1,52 @@
|
||||
// 订单卡片组件
|
||||
|
||||
// 渲染订单卡片
|
||||
function renderOrderCard(order) {
|
||||
const statusClass = order.status === 'in_progress' ? 'status-progress' : 'status-done';
|
||||
const statusText = order.status === 'in_progress' ? '进行中' : '已完成';
|
||||
|
||||
// 显示聚会时间或创建时间
|
||||
const displayDate = order.party_date
|
||||
? new Date(order.party_date).toLocaleDateString()
|
||||
: (order.created_at ? new Date(order.created_at).toLocaleDateString() : '');
|
||||
|
||||
const dishCount = order.dishes_detail ? order.dishes_detail.length : 0;
|
||||
|
||||
return `
|
||||
<div class="order-card" data-id="${order.id}">
|
||||
<div class="order-top">
|
||||
<span class="order-name">${order.name}</span>
|
||||
<span class="order-status ${statusClass}">${statusText}</span>
|
||||
</div>
|
||||
<div class="order-date">${displayDate} · ${dishCount} 道菜</div>
|
||||
<div class="dish-list">
|
||||
${(order.dishes_detail || []).map(d => {
|
||||
const isCold = d.category_name && d.category_name.includes('凉菜');
|
||||
return `<span class="dish-tag ${isCold ? 'dish-tag-cold' : ''}">${d.name}</span>`;
|
||||
}).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 渲染订单列表
|
||||
function renderOrderList(orders, containerSelector, onCardClick) {
|
||||
const container = document.querySelector(containerSelector);
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = orders.map(order => renderOrderCard(order)).join('');
|
||||
|
||||
container.querySelectorAll('.order-card').forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
if (onCardClick) {
|
||||
onCardClick(card.dataset.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 导出
|
||||
window.OrderCard = {
|
||||
render: renderOrderCard,
|
||||
renderList: renderOrderList
|
||||
};
|
||||
Reference in New Issue
Block a user