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:
Developer
2026-03-12 11:27:23 +08:00
co-authored by Claude Opus 4.6
commit 0a50c09dba
47 changed files with 10268 additions and 0 deletions
+43
View File
@@ -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
};
+82
View File
@@ -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;
+52
View File
@@ -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
};