diff --git a/Management.html b/Management.html
index 38f97a3..527a973 100644
--- a/Management.html
+++ b/Management.html
@@ -698,6 +698,7 @@
+
@@ -751,6 +752,13 @@
// 货源详情相关变量
let currentSellerId = null; // 当前正在显示的卖家ID
+ // 分页相关变量
+ let currentPage = 1;
+ const pageSize = 20;
+ let totalSupplies = 0;
+ let hasMoreData = true;
+ let isLoading = false;
+
// WebSocket相关变量
let ws = null;
let wsReconnectAttempts = 0;
@@ -762,6 +770,7 @@
// 缓存相关变量
const CACHE_KEY = 'management_stats_cache';
const CACHE_EXPIRY = 5 * 60 * 1000; // 缓存5分钟
+ const MAX_CACHE_SIZE = 50; // 最大缓存条目数
// 定时刷新相关
const REFRESH_INTERVAL = 30 * 1000; // 每30秒自动刷新一次
@@ -773,6 +782,7 @@
const beforeYesterdayBtn = document.getElementById('beforeYesterdayBtn');
const weekBtn = document.getElementById('weekBtn');
const monthBtn = document.getElementById('monthBtn');
+ const lastMonthBtn = document.getElementById('lastMonthBtn');
const allBtn = document.getElementById('allBtn');
const startDateInput = document.getElementById('startDate');
const endDateInput = document.getElementById('endDate');
@@ -1189,6 +1199,7 @@
beforeYesterdayBtn.addEventListener('click', () => setFilter('beforeYesterday'));
weekBtn.addEventListener('click', () => setFilter('week'));
monthBtn.addEventListener('click', () => setFilter('month'));
+ lastMonthBtn.addEventListener('click', () => setFilter('lastMonth'));
allBtn.addEventListener('click', () => setFilter('all'));
// 自定义时间筛选按钮
@@ -1197,13 +1208,13 @@
// 日期输入框改变时,自动清除预设筛选的active状态
startDateInput.addEventListener('change', () => {
if (startDateInput.value || endDateInput.value) {
- [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
+ [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, lastMonthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
}
});
endDateInput.addEventListener('change', () => {
if (startDateInput.value || endDateInput.value) {
- [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
+ [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, lastMonthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
}
});
@@ -1258,8 +1269,13 @@
// 重置当前卖家ID,确保切换时间筛选时显示所有货源
currentSellerId = null;
+ // 重置分页参数
+ currentPage = 1;
+ hasMoreData = true;
+ suppliesData = [];
+
// 更新按钮状态
- [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
+ [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, lastMonthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
document.getElementById(filter + 'Btn').classList.add('active');
// 清空自定义日期输入
@@ -1287,8 +1303,13 @@
// 重置当前卖家ID,确保切换时间筛选时显示所有货源
currentSellerId = null;
+ // 重置分页参数
+ currentPage = 1;
+ hasMoreData = true;
+ suppliesData = [];
+
// 清除预设筛选的active状态
- [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
+ [todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, lastMonthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
// 重新加载数据,传递自定义日期范围
loadStats('custom', startDate, endDate);
@@ -1316,10 +1337,24 @@
try {
const cached = localStorage.getItem(CACHE_KEY);
let cache = cached ? JSON.parse(cached) : {};
+
+ // 添加新缓存
cache[filter] = {
data: data,
timestamp: Date.now()
};
+
+ // 管理缓存大小,移除最旧的缓存条目
+ const cacheEntries = Object.entries(cache);
+ if (cacheEntries.length > MAX_CACHE_SIZE) {
+ // 按时间戳排序,移除最旧的
+ cacheEntries.sort((a, b) => a[1].timestamp - b[1].timestamp);
+ const entriesToRemove = cacheEntries.slice(0, cacheEntries.length - MAX_CACHE_SIZE);
+ entriesToRemove.forEach(([key]) => {
+ delete cache[key];
+ });
+ }
+
localStorage.setItem(CACHE_KEY, JSON.stringify(cache));
console.log('保存数据到缓存:', filter);
} catch (error) {
@@ -1330,6 +1365,24 @@
// 加载统计数据
async function loadStats(filter, startDate = '', endDate = '') {
try {
+ // 先尝试从缓存获取数据,提高响应速度
+ const cacheKey = filter === 'custom' ? `custom_${startDate}_${endDate}` : filter;
+ const cachedData = getCachedData(cacheKey);
+
+ if (cachedData) {
+ // 使用缓存数据更新UI,提高响应速度
+ updateStatsInfo(cachedData.stats);
+ renderChart(cachedData.chartData);
+ chartData = cachedData.chartData;
+ suppliesData = cachedData.suppliesData;
+ usersData = cachedData.usersData;
+
+ // 只有在当前没有显示特定卖家的货源时才显示当天所有货源
+ if (!currentSellerId) {
+ showAllSupplies();
+ }
+ }
+
// 构建API请求URL,包含自定义日期参数
let url = `/api/admin/stats/supplies?filter=${filter}`;
if (filter === 'custom') {
@@ -1337,7 +1390,18 @@
if (endDate) url += `&endDate=${endDate}`;
}
- const response = await fetch(url);
+ const response = await fetch(url, {
+ method: 'GET',
+ timeout: 10000,
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP错误! 状态: ${response.status}`);
+ }
+
const data = await response.json();
if (data.success) {
@@ -1353,7 +1417,6 @@
usersData = data.data.usersData;
// 保存到缓存,自定义日期使用特殊的缓存键
- const cacheKey = filter === 'custom' ? `custom_${startDate}_${endDate}` : filter;
saveCachedData(cacheKey, data.data);
// 只有在当前没有显示特定卖家的货源时才显示当天所有货源
@@ -1362,22 +1425,7 @@
}
} else {
console.error('加载统计数据失败:', data.message);
-
- // 尝试使用缓存数据
- const cacheKey = filter === 'custom' ? `custom_${startDate}_${endDate}` : filter;
- const cachedData = getCachedData(cacheKey);
- if (cachedData) {
- updateStatsInfo(cachedData.stats);
- renderChart(cachedData.chartData);
- chartData = cachedData.chartData;
- suppliesData = cachedData.suppliesData;
- usersData = cachedData.usersData;
-
- // 只有在当前没有显示特定卖家的货源时才显示当天所有货源
- if (!currentSellerId && suppliesSection.style.display === 'block') {
- showAllSupplies();
- }
- }
+ // 已经尝试过使用缓存数据,这里可以不再处理
}
} catch (error) {
console.error('加载统计数据出错:', error);
@@ -1510,7 +1558,7 @@
});
// 显示当天所有货源
- async function showAllSupplies() {
+ async function showAllSupplies(reset = true) {
// 保存当前滚动位置和货源列表高度
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
const originalHeight = suppliesGrid.clientHeight;
@@ -1518,6 +1566,13 @@
// 清空当前正在显示的卖家ID
currentSellerId = null;
+ // 重置分页参数
+ if (reset) {
+ currentPage = 1;
+ hasMoreData = true;
+ suppliesData = [];
+ }
+
// 构建标题
let title = '当天所有货源';
@@ -1538,6 +1593,9 @@
case 'month':
title = '本月所有货源';
break;
+ case 'lastMonth':
+ title = '上月所有货源';
+ break;
case 'all':
title = '全部货源';
break;
@@ -1564,9 +1622,16 @@
suppliesSection.style.display = 'block';
}
+ // 如果已经没有更多数据或正在加载,直接返回
+ if (!hasMoreData || isLoading) {
+ return;
+ }
+
+ isLoading = true;
+
try {
// 直接从API获取所有货源数据
- let url = `/api/admin/supplies?filter=${currentFilter}`;
+ let url = `/api/admin/supplies?filter=${currentFilter}&page=${currentPage}&pageSize=${pageSize}`;
if (currentFilter === 'custom') {
const startDate = startDateInput.value;
const endDate = endDateInput.value;
@@ -1595,13 +1660,30 @@
// 仅在数据成功返回且有变化时才更新DOM,减少视觉闪烁
if (data.success) {
console.log('showAllSupplies - 数据请求成功,supplies数量:', data.data.supplies ? data.data.supplies.length : 0);
+
+ // 更新分页信息
+ if (data.data.pagination) {
+ totalSupplies = data.data.pagination.total;
+ hasMoreData = currentPage < data.data.pagination.totalPages;
+ }
+
+ // 添加新数据
if (data.data.supplies && data.data.supplies.length > 0) {
- renderSupplies(data.data.supplies);
- } else {
+ suppliesData = reset ? data.data.supplies : [...suppliesData, ...data.data.supplies];
+ renderSupplies(suppliesData);
+ currentPage++;
+ } else if (reset) {
// 显示空状态
console.log('showAllSupplies - 没有找到货源数据');
suppliesGrid.innerHTML = '
暂无货源数据
';
}
+
+ // 添加加载更多按钮或提示
+ if (hasMoreData) {
+ addLoadMoreButton();
+ } else if (suppliesData.length > 0) {
+ addNoMoreDataHint();
+ }
} else {
console.error('加载货源数据失败:', data.message);
// 只在当前不是错误状态时才显示错误信息
@@ -1616,11 +1698,72 @@
suppliesGrid.innerHTML = '
网络异常,请检查网络连接后重试
';
}
} finally {
+ isLoading = false;
// 恢复滚动位置
window.scrollTo(0, scrollPosition);
}
}
+ // 添加加载更多按钮
+ function addLoadMoreButton() {
+ // 检查是否已经有加载更多按钮
+ if (document.getElementById('loadMoreBtn')) {
+ return;
+ }
+
+ const loadMoreBtn = document.createElement('div');
+ loadMoreBtn.id = 'loadMoreBtn';
+ loadMoreBtn.style.cssText = `
+ text-align: center;
+ padding: 15px;
+ grid-column: 1 / -1;
+ `;
+ loadMoreBtn.innerHTML = `
+
+ `;
+ suppliesGrid.appendChild(loadMoreBtn);
+ }
+
+ // 添加没有更多数据的提示
+ function addNoMoreDataHint() {
+ // 移除加载更多按钮
+ const loadMoreBtn = document.getElementById('loadMoreBtn');
+ if (loadMoreBtn) {
+ loadMoreBtn.remove();
+ }
+
+ // 检查是否已经有提示
+ if (document.getElementById('noMoreDataHint')) {
+ return;
+ }
+
+ const hint = document.createElement('div');
+ hint.id = 'noMoreDataHint';
+ hint.style.cssText = `
+ text-align: center;
+ padding: 15px;
+ color: #999;
+ grid-column: 1 / -1;
+ `;
+ hint.textContent = '没有更多数据了';
+ suppliesGrid.appendChild(hint);
+ }
+
+ // 加载更多货源
+ function loadMoreSupplies() {
+ showAllSupplies(false);
+ }
+
// 显示指定卖家的货源
async function showSuppliesBySeller(sellerId) {
// 保存当前正在显示的卖家ID
diff --git a/Reject.js b/Reject.js
index 300f8eb..51b59bd 100644
--- a/Reject.js
+++ b/Reject.js
@@ -1965,9 +1965,14 @@ app.get('/api/admin/stats/supplies', async (req, res) => {
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
timeCondition = `AND created_at >= '${weekAgo.toISOString().slice(0, 19).replace('T', ' ')}'`;
} else if (filter === 'month') {
- // 本月
- const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
- timeCondition = `AND created_at >= '${monthAgo.toISOString().slice(0, 19).replace('T', ' ')}'`;
+ // 本月(从本月1日到当前日期)
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
+ timeCondition = `AND created_at >= '${monthStart.toISOString().slice(0, 19).replace('T', ' ')}'`;
+ } else if (filter === 'lastMonth') {
+ // 上个月(从上月1日到上月最后一天)
+ const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
+ const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999);
+ timeCondition = `AND created_at >= '${lastMonthStart.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at <= '${lastMonthEnd.toISOString().slice(0, 19).replace('T', ' ')}'`;
} else if (filter === 'custom') {
// 自定义时间范围
const { startDate, endDate } = req.query;
@@ -2012,12 +2017,6 @@ app.get('/api/admin/stats/supplies', async (req, res) => {
connection.release();
- // 调试日志:检查API返回数据结构
- console.log('stats API返回的chartData:', chartData);
- console.log('stats API返回的totalSupplies:', totalSupplies);
- console.log('stats API返回的totalUsers:', totalUsers);
- console.log('stats API返回的avgPerUser:', avgPerUser);
-
sendResponse(res, true, {
chartData,
stats: {
@@ -2064,9 +2063,14 @@ app.get('/api/admin/supplies', async (req, res) => {
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
timeCondition = `AND created_at >= '${weekAgo.toISOString().slice(0, 19).replace('T', ' ')}'`;
} else if (filter === 'month') {
- // 本月
- const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
- timeCondition = `AND created_at >= '${monthAgo.toISOString().slice(0, 19).replace('T', ' ')}'`;
+ // 本月(从本月1日到当前日期)
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
+ timeCondition = `AND created_at >= '${monthStart.toISOString().slice(0, 19).replace('T', ' ')}'`;
+ } else if (filter === 'lastMonth') {
+ // 上个月(从上月1日到上月最后一天)
+ const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
+ const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59, 999);
+ timeCondition = `AND created_at >= '${lastMonthStart.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at <= '${lastMonthEnd.toISOString().slice(0, 19).replace('T', ' ')}'`;
} else if (filter === 'custom') {
// 自定义时间范围
const { startDate, endDate } = req.query;
@@ -2107,23 +2111,6 @@ app.get('/api/admin/supplies', async (req, res) => {
connection.release();
- // 调试日志:检查查询结果中是否包含product_log字段
- console.log('查询到的货源数量:', supplies.length);
- if (supplies.length > 0) {
- console.log('第一个货源的所有字段和值:', JSON.stringify(supplies[0], null, 2));
- console.log('第一个货源的字段:', Object.keys(supplies[0]));
- console.log('第一个货源是否包含product_log字段:', 'product_log' in supplies[0]);
- if ('product_log' in supplies[0]) {
- console.log('第一个货源的product_log值:', supplies[0].product_log);
- console.log('第一个货源的product_log类型:', typeof supplies[0].product_log);
- } else {
- console.log('第一个货源不包含product_log字段,可能的原因:');
- console.log('1. 数据库中products表可能没有product_log字段');
- console.log('2. 字段名称可能拼写错误');
- console.log('3. 查询语句可能有问题');
- }
- }
-
sendResponse(res, true, { supplies }, '获取货源列表成功');
} catch (error) {
console.error('获取货源列表失败:', error.message);
@@ -2159,9 +2146,6 @@ app.post('/api/supplies/log', async (req, res) => {
);
userLoginConnection.release();
- // 打印查询结果,查看是否包含company和organization字段
- console.log('查询到的personnel信息:', personnelResult[0]);
-
// 自动计算变更字段
let calculatedChangedFields = changedFields;
if (operationEvent.includes('编辑') && originalData && modifiedData && !changedFields) {
@@ -2199,9 +2183,6 @@ app.post('/api/supplies/log', async (req, res) => {
// 如果找到了员工信息,使用真实的员工数据
if (personnelResult.length > 0) {
const personnelInfo = personnelResult[0];
- // 检查personnelInfo中的字段名,确保使用正确的字段名
- console.log('personnelInfo的所有字段:', Object.keys(personnelInfo));
-
// 使用正确的字段名:managercompany(公司)、managerdepartment(部门)、organization(组织)
logData.tracompany = personnelInfo.managercompany || personnelInfo.managerCompany || personnelInfo.MANAGERCOMPANY || '';
logData.tradepartment = personnelInfo.managerdepartment || personnelInfo.managerDepartment || personnelInfo.MANAGERDEPARTMENT || '';