|
|
@ -178,6 +178,69 @@ |
|
|
padding: 40px; |
|
|
padding: 40px; |
|
|
color: #666; |
|
|
color: #666; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 标题栏操作按钮样式 */ |
|
|
|
|
|
.title-bar-actions { |
|
|
|
|
|
display: flex; |
|
|
|
|
|
gap: 8px; |
|
|
|
|
|
align-items: center; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title-bar-actions button { |
|
|
|
|
|
padding: 8px 16px; |
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.3); |
|
|
|
|
|
border-radius: 20px; |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.1); |
|
|
|
|
|
color: white; |
|
|
|
|
|
cursor: pointer; |
|
|
|
|
|
font-size: 14px; |
|
|
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
font-weight: 500; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title-bar-actions button:hover { |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.2); |
|
|
|
|
|
border-color: rgba(255, 255, 255, 0.5); |
|
|
|
|
|
transform: translateY(-1px); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title-bar-actions button.active { |
|
|
|
|
|
background-color: white; |
|
|
|
|
|
color: #1677ff; |
|
|
|
|
|
border-color: white; |
|
|
|
|
|
box-shadow: 0 2px 8px rgba(22, 119, 255, 0.3); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 日期输入框样式 */ |
|
|
|
|
|
.title-bar-actions input[type="date"] { |
|
|
|
|
|
padding: 6px 12px; |
|
|
|
|
|
border: 1px solid rgba(255, 255, 255, 0.3); |
|
|
|
|
|
border-radius: 20px; |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.1); |
|
|
|
|
|
color: white; |
|
|
|
|
|
font-size: 14px; |
|
|
|
|
|
transition: all 0.3s ease; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title-bar-actions input[type="date"]::-webkit-calendar-picker-indicator { |
|
|
|
|
|
filter: invert(1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title-bar-actions input[type="date"]:hover { |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.2); |
|
|
|
|
|
border-color: rgba(255, 255, 255, 0.5); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* 自定义按钮样式 */ |
|
|
|
|
|
#customBtn { |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.2); |
|
|
|
|
|
border-color: rgba(255, 255, 255, 0.4); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#customBtn:hover { |
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.3); |
|
|
|
|
|
border-color: rgba(255, 255, 255, 0.6); |
|
|
|
|
|
} |
|
|
</style> |
|
|
</style> |
|
|
<!-- 图片预览样式 --> |
|
|
<!-- 图片预览样式 --> |
|
|
<style> |
|
|
<style> |
|
|
@ -360,7 +423,14 @@ |
|
|
|
|
|
|
|
|
// 设置定时刷新 |
|
|
// 设置定时刷新 |
|
|
setInterval(() => { |
|
|
setInterval(() => { |
|
|
|
|
|
if (currentFilter === 'custom') { |
|
|
|
|
|
// 如果是自定义筛选,获取当前日期输入值 |
|
|
|
|
|
const startDate = startDateInput.value; |
|
|
|
|
|
const endDate = endDateInput.value; |
|
|
|
|
|
loadStats('custom', startDate, endDate); |
|
|
|
|
|
} else { |
|
|
loadStats(currentFilter); |
|
|
loadStats(currentFilter); |
|
|
|
|
|
} |
|
|
}, REFRESH_INTERVAL); |
|
|
}, REFRESH_INTERVAL); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
@ -450,7 +520,14 @@ |
|
|
// 对于任何类型的WebSocket消息,都重新加载数据,确保实时更新 |
|
|
// 对于任何类型的WebSocket消息,都重新加载数据,确保实时更新 |
|
|
if (data.type) { |
|
|
if (data.type) { |
|
|
console.log('收到WebSocket消息,刷新数据:', data.type); |
|
|
console.log('收到WebSocket消息,刷新数据:', data.type); |
|
|
|
|
|
if (currentFilter === 'custom') { |
|
|
|
|
|
// 如果是自定义筛选,获取当前日期输入值 |
|
|
|
|
|
const startDate = startDateInput.value; |
|
|
|
|
|
const endDate = endDateInput.value; |
|
|
|
|
|
loadStats('custom', startDate, endDate); |
|
|
|
|
|
} else { |
|
|
loadStats(currentFilter); |
|
|
loadStats(currentFilter); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.warn('收到未知格式的WebSocket消息'); |
|
|
console.warn('收到未知格式的WebSocket消息'); |
|
|
} |
|
|
} |
|
|
@ -614,6 +691,9 @@ |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新当前筛选条件为自定义 |
|
|
|
|
|
currentFilter = 'custom'; |
|
|
|
|
|
|
|
|
// 清除预设筛选的active状态 |
|
|
// 清除预设筛选的active状态 |
|
|
[todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active')); |
|
|
[todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active')); |
|
|
|
|
|
|
|
|
@ -719,7 +799,7 @@ |
|
|
function updateStatsInfo(stats) { |
|
|
function updateStatsInfo(stats) { |
|
|
totalSuppliesEl.textContent = stats.totalSupplies; |
|
|
totalSuppliesEl.textContent = stats.totalSupplies; |
|
|
totalUsersEl.textContent = stats.totalUsers; |
|
|
totalUsersEl.textContent = stats.totalUsers; |
|
|
avgPerUserEl.textContent = stats.avgPerUser.toFixed(1); |
|
|
avgPerUserEl.textContent = Math.round(stats.avgPerUser); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 渲染图表 |
|
|
// 渲染图表 |
|
|
|