@@ -511,9 +562,10 @@
// WebSocket相关变量
let ws = null;
let wsReconnectAttempts = 0;
- const maxReconnectAttempts = 5;
- const reconnectDelay = 3000;
+ const maxReconnectAttempts = 10; // 增加最大重连次数
+ const reconnectDelay = 5000; // 增加重连延迟,避免频繁重连
let wsUrl = '';
+ let wsConnecting = false; // 防止重复连接
// 缓存相关变量
const CACHE_KEY = 'management_stats_cache';
@@ -581,7 +633,20 @@
// 初始化WebSocket连接
function initWebSocket() {
+ // 防止重复连接
+ if (wsConnecting) {
+ console.log('WebSocket连接正在建立中,请勿重复调用');
+ return;
+ }
+
+ // 检查是否已经有活跃连接
+ if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
+ console.log('WebSocket连接已存在或正在建立中,无需重新连接');
+ return;
+ }
+
try {
+ wsConnecting = true;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
wsUrl = `${protocol}//${window.location.host}`;
console.log('正在尝试连接WebSocket服务器:', wsUrl);
@@ -592,6 +657,8 @@
ws.close(1000, '重新连接');
} catch (error) {
console.error('关闭旧WebSocket连接失败:', error);
+ } finally {
+ ws = null;
}
}
@@ -602,6 +669,7 @@
ws.onopen = function(event) {
console.log('WebSocket连接已打开');
wsReconnectAttempts = 0; // 重置重连计数器
+ wsConnecting = false;
};
ws.onmessage = function(event) {
@@ -615,6 +683,8 @@
ws.onclose = function(event) {
console.log('WebSocket连接已关闭:', event.code, event.reason);
+ wsConnecting = false;
+ ws = null;
// 尝试重新连接,最多重试maxReconnectAttempts次
if (wsReconnectAttempts < maxReconnectAttempts) {
@@ -629,9 +699,12 @@
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
console.error('WebSocket错误详情:', error.message);
+ wsConnecting = false;
};
} catch (error) {
console.error('WebSocket连接失败:', error);
+ wsConnecting = false;
+ ws = null;
// 尝试重新连接
if (wsReconnectAttempts < maxReconnectAttempts) {
@@ -650,28 +723,34 @@
const data = JSON.parse(message);
console.log('处理WebSocket消息:', data);
- // 对于任何类型的WebSocket消息,都重新加载数据,确保实时更新
- if (data.type) {
- console.log('收到WebSocket消息,刷新数据:', data.type);
-
- // 重新加载统计数据
- if (currentFilter === 'custom') {
- // 如果是自定义筛选,获取当前日期输入值
- const startDate = startDateInput.value;
- const endDate = endDateInput.value;
- loadStats('custom', startDate, endDate);
+ // 只有当消息类型与货源相关时,才重新加载数据
+ if (data.type && (data.type === 'supply_created' || data.type === 'supply_updated' || data.type === 'supply_deleted' || data.type === 'supply_status_change')) {
+ console.log('收到货源相关WebSocket消息,刷新数据:', data.type);
+
+ // 保存当前滚动位置
+ const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
+
+ // 重新加载统计数据
+ if (currentFilter === 'custom') {
+ // 如果是自定义筛选,获取当前日期输入值
+ const startDate = startDateInput.value;
+ const endDate = endDateInput.value;
+ loadStats('custom', startDate, endDate);
+ } else {
+ loadStats(currentFilter);
+ }
+
+ // 如果正在显示货源详情,重新加载货源数据
+ if (currentSellerId) {
+ console.log('正在显示货源详情,重新加载数据');
+ showSuppliesBySeller(currentSellerId);
+ }
+
+ // 恢复滚动位置
+ window.scrollTo(0, scrollPosition);
} else {
- loadStats(currentFilter);
- }
-
- // 如果正在显示货源详情,重新加载货源数据
- if (currentSellerId) {
- console.log('正在显示货源详情,重新加载数据');
- showSuppliesBySeller(currentSellerId);
+ console.warn('收到未知格式的WebSocket消息,不刷新数据:', data.type);
}
- } else {
- console.warn('收到未知格式的WebSocket消息');
- }
} catch (error) {
console.error('解析WebSocket消息失败:', error);
}
@@ -800,6 +879,23 @@
closePreviewModal();
}
});
+
+ // 滚动事件,用于显示/隐藏回到顶部按钮
+ window.addEventListener('scroll', () => {
+ const backToTopBtn = document.getElementById('backToTop');
+ // 当滚动距离超过300px时显示按钮
+ if (window.pageYOffset > 300) {
+ backToTopBtn.style.display = 'flex';
+ } else {
+ backToTopBtn.style.display = 'none';
+ }
+ });
+ }
+
+ // 回到supplies-section顶部
+ function scrollToSuppliesSection() {
+ const suppliesSection = document.getElementById('suppliesSection');
+ suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
// 设置筛选条件
@@ -814,9 +910,6 @@
startDateInput.value = '';
endDateInput.value = '';
- // 隐藏货源详情
- suppliesSection.style.display = 'none';
-
// 重新加载数据
loadStats(filter);
}
@@ -838,9 +931,6 @@
// 清除预设筛选的active状态
[todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active'));
- // 隐藏货源详情
- suppliesSection.style.display = 'none';
-
// 重新加载数据,传递自定义日期范围
loadStats('custom', startDate, endDate);
}
@@ -906,6 +996,11 @@
// 保存到缓存,自定义日期使用特殊的缓存键
const cacheKey = filter === 'custom' ? `custom_${startDate}_${endDate}` : filter;
saveCachedData(cacheKey, data.data);
+
+ // 只有在当前没有显示特定卖家的货源时才显示当天所有货源
+ if (!currentSellerId) {
+ showAllSupplies();
+ }
} else {
console.error('加载统计数据失败:', data.message);
@@ -918,6 +1013,11 @@
chartData = cachedData.chartData;
suppliesData = cachedData.suppliesData;
usersData = cachedData.usersData;
+
+ // 只有在当前没有显示特定卖家的货源时才显示当天所有货源
+ if (!currentSellerId && suppliesSection.style.display === 'block') {
+ showAllSupplies();
+ }
}
}
} catch (error) {
@@ -932,6 +1032,11 @@
chartData = cachedData.chartData;
suppliesData = cachedData.suppliesData;
usersData = cachedData.usersData;
+
+ // 只有在当前没有显示特定卖家的货源时才显示当天所有货源
+ if (!currentSellerId) {
+ showAllSupplies();
+ }
}
}
}
@@ -1045,6 +1150,118 @@
}
});
+ // 显示当天所有货源
+ async function showAllSupplies() {
+ // 保存当前滚动位置和货源列表高度
+ const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
+ const originalHeight = suppliesGrid.clientHeight;
+
+ // 清空当前正在显示的卖家ID
+ currentSellerId = null;
+
+ // 构建标题
+ let title = '当天所有货源';
+
+ // 根据当前筛选条件更新标题
+ switch (currentFilter) {
+ case 'today':
+ title = '今日所有货源';
+ break;
+ case 'yesterday':
+ title = '昨日所有货源';
+ break;
+ case 'beforeYesterday':
+ title = '前日所有货源';
+ break;
+ case 'week':
+ title = '本周所有货源';
+ break;
+ case 'month':
+ title = '本月所有货源';
+ break;
+ case 'all':
+ title = '全部货源';
+ break;
+ case 'custom':
+ const startDate = startDateInput.value;
+ const endDate = endDateInput.value;
+ if (startDate && endDate) {
+ title = `${startDate} 至 ${endDate} 所有货源`;
+ } else if (startDate) {
+ title = `${startDate} 至今所有货源`;
+ } else if (endDate) {
+ title = `截至 ${endDate} 所有货源`;
+ }
+ break;
+ }
+
+ // 只有在标题变化时才更新,减少不必要的DOM操作
+ if (suppliesTitle.textContent !== title) {
+ suppliesTitle.textContent = title;
+ }
+
+ // 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排
+ if (suppliesSection.style.display !== 'block') {
+ suppliesSection.style.display = 'block';
+ }
+
+ try {
+ // 直接从API获取所有货源数据
+ let url = `/api/admin/supplies?filter=${currentFilter}`;
+ if (currentFilter === 'custom') {
+ const startDate = startDateInput.value;
+ const endDate = endDateInput.value;
+ if (startDate) url += `&startDate=${startDate}`;
+ if (endDate) url += `&endDate=${endDate}`;
+ }
+
+ console.log('showAllSupplies - 正在请求API:', url);
+ const response = await fetch(url, {
+ method: 'GET',
+ timeout: 10000, // 添加10秒超时设置
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ // 检查响应状态
+ if (!response.ok) {
+ throw new Error(`HTTP错误! 状态: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ console.log('showAllSupplies - API返回数据:', data);
+
+ // 仅在数据成功返回且有变化时才更新DOM,减少视觉闪烁
+ if (data.success) {
+ console.log('showAllSupplies - 数据请求成功,supplies数量:', data.data.supplies ? data.data.supplies.length : 0);
+ if (data.data.supplies && data.data.supplies.length > 0) {
+ renderSupplies(data.data.supplies);
+ } else {
+ // 显示空状态
+ console.log('showAllSupplies - 没有找到货源数据');
+ suppliesGrid.innerHTML = '
暂无货源数据
';
+ }
+ } else {
+ console.error('加载货源数据失败:', data.message);
+ // 只在当前不是错误状态时才显示错误信息
+ if (!suppliesGrid.innerHTML.includes('加载失败') && !suppliesGrid.innerHTML.includes('网络异常')) {
+ suppliesGrid.innerHTML = '
加载货源数据失败,请稍后重试
';
+ }
+ }
+ } catch (error) {
+ console.error('加载货源数据出错:', error);
+ // 只在当前不是错误状态时才显示错误信息
+ if (!suppliesGrid.innerHTML.includes('加载失败') && !suppliesGrid.innerHTML.includes('网络异常')) {
+ suppliesGrid.innerHTML = '
网络异常,请检查网络连接后重试
';
+ }
+ } finally {
+ // 恢复滚动位置
+ window.scrollTo(0, scrollPosition);
+ }
+ }
+
// 显示指定卖家的货源
async function showSuppliesBySeller(sellerId) {
// 保存当前正在显示的卖家ID
@@ -1068,8 +1285,23 @@
if (endDate) url += `&endDate=${endDate}`;
}
+ // 显示加载状态
+ suppliesGrid.innerHTML = '
加载中...
';
+
try {
- const response = await fetch(url);
+ const response = await fetch(url, {
+ method: 'GET',
+ timeout: 10000, // 添加10秒超时设置
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ // 检查响应状态
+ if (!response.ok) {
+ throw new Error(`HTTP错误! 状态: ${response.status}`);
+ }
+
const data = await response.json();
if (data.success) {
@@ -1094,43 +1326,59 @@
suppliesTitle.textContent = title;
renderSupplies(data.data.supplies);
- suppliesSection.style.display = 'block';
- // 滚动到货源详情区域
- suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
+
+ // 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排
+ if (suppliesSection.style.display !== 'block') {
+ suppliesSection.style.display = 'block';
+ // 只有在第一次显示suppliesSection时才滚动到该区域
+ suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ }
} else {
console.error('加载货源数据失败:', data.message);
- suppliesGrid.innerHTML = '
加载货源数据失败,请刷新页面重试
';
- suppliesSection.style.display = 'block';
- suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ suppliesGrid.innerHTML = '
加载货源数据失败,请稍后重试
';
+
+ // 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排
+ if (suppliesSection.style.display !== 'block') {
+ suppliesSection.style.display = 'block';
+ }
}
} catch (error) {
console.error('加载货源数据出错:', error);
- suppliesGrid.innerHTML = '
加载货源数据失败,请刷新页面重试
';
- suppliesSection.style.display = 'block';
- suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ suppliesGrid.innerHTML = '
网络异常,请检查网络连接后重试
';
+
+ // 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排
+ if (suppliesSection.style.display !== 'block') {
+ suppliesSection.style.display = 'block';
+ }
}
}
// 渲染货源卡片
function renderSupplies(supplies) {
console.log('renderSupplies函数被调用,supplies数量:', supplies.length);
- console.log('完整supplies数据:', supplies);
- suppliesGrid.innerHTML = '';
- // 过滤掉hidden状态的货源
- const filteredSupplies = supplies.filter(supply => supply.status !== 'hidden');
- console.log('过滤后的supplies数量:', filteredSupplies.length);
- console.log('过滤后的supplies数据:', filteredSupplies);
+ // 不过滤任何状态的货源,显示所有货源
+ const filteredSupplies = supplies;
if (filteredSupplies.length === 0) {
suppliesGrid.innerHTML = '
暂无货源数据
';
return;
}
+ // 保存当前滚动位置和容器高度
+ const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
+ const containerHeight = suppliesGrid.clientHeight;
+
+ // 设置容器固定高度,防止清空内容时页面高度变化
+ suppliesGrid.style.height = `${containerHeight}px`;
+ suppliesGrid.style.overflow = 'hidden';
+
+ // 创建DocumentFragment,用于构建DOM结构,减少页面重排
+ const fragment = document.createDocumentFragment();
+
filteredSupplies.forEach((supply, index) => {
console.log(`渲染第${index + 1}个货源,ID:`, supply.productId);
- console.log(`该货源的product_log字段:`, supply.product_log);
- console.log(`该货源的product_log类型:`, typeof supply.product_log);
+
const card = document.createElement('div');
card.className = 'supply-card';
card.style.cssText = 'border: 1px solid #e8e8e8; border-radius: 8px; padding: 15px; transition: all 0.3s;';
@@ -1304,11 +1552,6 @@
`;
}
- // 产品日志展示 - 添加调试信息
- console.log('当前货源的product_log字段:', supply.product_log);
- console.log('product_log类型:', typeof supply.product_log);
- console.log('product_log值是否为null:', supply.product_log === null);
-
// 无论product_log是什么类型,都显示日志区域
detailsHTML += `