131 lines
4.7 KiB
JavaScript
131 lines
4.7 KiB
JavaScript
// 统计页面模块
|
|||
|
|
|
||
|
|
const StatsPage = {
|
||
|
|
// 初始化
|
||
|
|
init() {
|
||
|
|
this.loadStats();
|
||
|
|
},
|
||
|
|
|
||
|
|
// 加载统计数据
|
||
|
|
async loadStats() {
|
||
|
|
try {
|
||
|
|
const [dishesRes, ordersRes] = await Promise.all([
|
||
|
|
fetch(`${API_BASE}/dishes/`),
|
||
|
|
fetch(`${API_BASE}/orders/`)
|
||
|
|
]);
|
||
|
|
|
||
|
|
const allDishes = await dishesRes.json();
|
||
|
|
const allOrders = await ordersRes.json();
|
||
|
|
|
||
|
|
// 计算菜品出现次数
|
||
|
|
const dishCompletedCounts = {};
|
||
|
|
allOrders
|
||
|
|
.filter(o => o.status === 'completed')
|
||
|
|
.forEach(order => {
|
||
|
|
(order.dishes_detail || []).forEach(dish => {
|
||
|
|
dishCompletedCounts[dish.id] = (dishCompletedCounts[dish.id] || 0) + 1;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
AppState.setDishCompletedCounts(dishCompletedCounts);
|
||
|
|
|
||
|
|
// 统计数据
|
||
|
|
const totalDishes = allDishes.length;
|
||
|
|
const completedOrders = allOrders.filter(o => o.status === 'completed').length;
|
||
|
|
const inProgressOrders = allOrders.filter(o => o.status === 'in_progress').length;
|
||
|
|
|
||
|
|
// 统计参与人员
|
||
|
|
const participantCounts = {};
|
||
|
|
allOrders.forEach(order => {
|
||
|
|
(order.participants || []).forEach(p => {
|
||
|
|
participantCounts[p] = (participantCounts[p] || 0) + 1;
|
||
|
|
});
|
||
|
|
});
|
||
|
|
const uniqueParticipants = Object.keys(participantCounts).length;
|
||
|
|
|
||
|
|
// 渲染统计卡片
|
||
|
|
this.renderStatCards({ totalDishes, completedOrders, inProgressOrders, uniqueParticipants });
|
||
|
|
|
||
|
|
// 渲染菜品排行榜
|
||
|
|
this.renderDishRank(allDishes, dishCompletedCounts);
|
||
|
|
|
||
|
|
} catch (e) {
|
||
|
|
console.error('加载统计失败:', e);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
|
||
|
|
// 渲染统计卡片
|
||
|
|
renderStatCards(stats) {
|
||
|
|
const container = document.getElementById('stats-cards');
|
||
|
|
if (!container) return;
|
||
|
|
|
||
|
|
container.innerHTML = `
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="stat-icon" style="background: linear-gradient(135deg, var(--primary-soft), #fef3c7); color: var(--primary);">
|
||
|
|
<i class="bi bi-book"></i>
|
||
|
|
</div>
|
||
|
|
<div class="stat-value">${stats.totalDishes}</div>
|
||
|
|
<div class="stat-label">菜品总数</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="stat-icon" style="background: var(--secondary-soft); color: var(--secondary);">
|
||
|
|
<i class="bi bi-check-circle"></i>
|
||
|
|
</div>
|
||
|
|
<div class="stat-value">${stats.completedOrders}</div>
|
||
|
|
<div class="stat-label">已完成聚会</div>
|
||
|
|
</div>
|
||
|
|
<div class="stat-card">
|
||
|
|
<div class="stat-icon" style="background: var(--accent-soft); color: #b45309;">
|
||
|
|
<i class="bi bi-clock"></i>
|
||
|
|
</div>
|
||
|
|
<div class="stat-value">${stats.inProgressOrders}</div>
|
||
|
|
<div class="stat-label">进行中</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
},
|
||
|
|
|
||
|
|
// 渲染菜品排行榜
|
||
|
|
renderDishRank(dishes, counts) {
|
||
|
|
const container = document.getElementById('dish-rank-list');
|
||
|
|
if (!container) return;
|
||
|
|
|
||
|
|
// 按出现次数排序
|
||
|
|
const dishesWithCounts = dishes.map(dish => ({
|
||
|
|
...dish,
|
||
|
|
orderCount: counts[dish.id] || 0
|
||
|
|
})).filter(d => d.orderCount > 0)
|
||
|
|
.sort((a, b) => b.orderCount - a.orderCount);
|
||
|
|
|
||
|
|
if (dishesWithCounts.length === 0) {
|
||
|
|
container.innerHTML = `
|
||
|
|
<div class="empty-rank">
|
||
|
|
<i class="bi bi-trophy"></i>
|
||
|
|
<p>暂无数据</p>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
container.innerHTML = dishesWithCounts.slice(0, 10).map((dish, index) => {
|
||
|
|
let rankClass = 'default';
|
||
|
|
if (index === 0) rankClass = 'gold';
|
||
|
|
else if (index === 1) rankClass = 'silver';
|
||
|
|
else if (index === 2) rankClass = 'bronze';
|
||
|
|
|
||
|
|
return `
|
||
|
|
<div class="rank-item">
|
||
|
|
<span class="rank-number ${rankClass}">${index + 1}</span>
|
||
|
|
<img class="rank-img" src="${dish.cover_image || getDefaultImage()}" alt="${dish.name}">
|
||
|
|
<div class="rank-info">
|
||
|
|
<div class="rank-name">${dish.name}</div>
|
||
|
|
<div class="rank-count">出现 ${dish.orderCount} 次</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}).join('');
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// 导出
|
||
|
|
window.StatsPage = StatsPage;
|