|
|
@ -375,6 +375,9 @@ |
|
|
let usersData = []; |
|
|
let usersData = []; |
|
|
let chartData = []; |
|
|
let chartData = []; |
|
|
|
|
|
|
|
|
|
|
|
// 货源详情相关变量 |
|
|
|
|
|
let currentSellerId = null; // 当前正在显示的卖家ID |
|
|
|
|
|
|
|
|
// WebSocket相关变量 |
|
|
// WebSocket相关变量 |
|
|
let ws = null; |
|
|
let ws = null; |
|
|
let wsReconnectAttempts = 0; |
|
|
let wsReconnectAttempts = 0; |
|
|
@ -520,6 +523,8 @@ |
|
|
// 对于任何类型的WebSocket消息,都重新加载数据,确保实时更新 |
|
|
// 对于任何类型的WebSocket消息,都重新加载数据,确保实时更新 |
|
|
if (data.type) { |
|
|
if (data.type) { |
|
|
console.log('收到WebSocket消息,刷新数据:', data.type); |
|
|
console.log('收到WebSocket消息,刷新数据:', data.type); |
|
|
|
|
|
|
|
|
|
|
|
// 重新加载统计数据 |
|
|
if (currentFilter === 'custom') { |
|
|
if (currentFilter === 'custom') { |
|
|
// 如果是自定义筛选,获取当前日期输入值 |
|
|
// 如果是自定义筛选,获取当前日期输入值 |
|
|
const startDate = startDateInput.value; |
|
|
const startDate = startDateInput.value; |
|
|
@ -528,6 +533,12 @@ |
|
|
} else { |
|
|
} else { |
|
|
loadStats(currentFilter); |
|
|
loadStats(currentFilter); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果正在显示货源详情,重新加载货源数据 |
|
|
|
|
|
if (currentSellerId) { |
|
|
|
|
|
console.log('正在显示货源详情,重新加载数据'); |
|
|
|
|
|
showSuppliesBySeller(currentSellerId); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.warn('收到未知格式的WebSocket消息'); |
|
|
console.warn('收到未知格式的WebSocket消息'); |
|
|
} |
|
|
} |
|
|
@ -906,6 +917,9 @@ |
|
|
|
|
|
|
|
|
// 显示指定卖家的货源 |
|
|
// 显示指定卖家的货源 |
|
|
async function showSuppliesBySeller(sellerId) { |
|
|
async function showSuppliesBySeller(sellerId) { |
|
|
|
|
|
// 保存当前正在显示的卖家ID |
|
|
|
|
|
currentSellerId = sellerId; |
|
|
|
|
|
|
|
|
// 获取当前筛选条件和日期范围 |
|
|
// 获取当前筛选条件和日期范围 |
|
|
let startDate = ''; |
|
|
let startDate = ''; |
|
|
let endDate = ''; |
|
|
let endDate = ''; |
|
|
@ -917,17 +931,14 @@ |
|
|
endDate = endDateInput.value; |
|
|
endDate = endDateInput.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 构建缓存键,包含自定义日期信息 |
|
|
// 构建API请求URL,包含自定义日期参数 |
|
|
const cacheKey = `supplies_${sellerId}_${filter}_${startDate}_${endDate}`; |
|
|
let url = `/api/admin/supplies?sellerId=${sellerId}&filter=${filter}`; |
|
|
|
|
|
if (filter === 'custom') { |
|
|
|
|
|
if (startDate) url += `&startDate=${startDate}`; |
|
|
|
|
|
if (endDate) url += `&endDate=${endDate}`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
// 构建API请求URL,包含自定义日期参数 |
|
|
|
|
|
let url = `/api/admin/supplies?sellerId=${sellerId}&filter=${filter}`; |
|
|
|
|
|
if (filter === 'custom') { |
|
|
|
|
|
if (startDate) url += `&startDate=${startDate}`; |
|
|
|
|
|
if (endDate) url += `&endDate=${endDate}`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const response = await fetch(url); |
|
|
const response = await fetch(url); |
|
|
const data = await response.json(); |
|
|
const data = await response.json(); |
|
|
|
|
|
|
|
|
@ -956,78 +967,40 @@ |
|
|
suppliesSection.style.display = 'block'; |
|
|
suppliesSection.style.display = 'block'; |
|
|
// 滚动到货源详情区域 |
|
|
// 滚动到货源详情区域 |
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
|
|
|
|
|
|
// 保存到缓存 |
|
|
|
|
|
try { |
|
|
|
|
|
const cached = localStorage.getItem(CACHE_KEY); |
|
|
|
|
|
let cache = cached ? JSON.parse(cached) : {}; |
|
|
|
|
|
cache[cacheKey] = { |
|
|
|
|
|
data: data.data, |
|
|
|
|
|
title: title, |
|
|
|
|
|
timestamp: Date.now() |
|
|
|
|
|
}; |
|
|
|
|
|
localStorage.setItem(CACHE_KEY, JSON.stringify(cache)); |
|
|
|
|
|
console.log('保存货源详情到缓存:', cacheKey); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('保存货源详情缓存失败:', error); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
console.error('加载货源数据失败:', data.message); |
|
|
console.error('加载货源数据失败:', data.message); |
|
|
|
|
|
suppliesGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">加载货源数据失败,请刷新页面重试</p>'; |
|
|
// 尝试使用缓存数据 |
|
|
suppliesSection.style.display = 'block'; |
|
|
try { |
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
const cached = localStorage.getItem(CACHE_KEY); |
|
|
|
|
|
if (cached) { |
|
|
|
|
|
const cache = JSON.parse(cached); |
|
|
|
|
|
if (cache[cacheKey] && (Date.now() - cache[cacheKey].timestamp < CACHE_EXPIRY)) { |
|
|
|
|
|
const cachedData = cache[cacheKey]; |
|
|
|
|
|
suppliesTitle.textContent = cachedData.title; |
|
|
|
|
|
renderSupplies(cachedData.data.supplies); |
|
|
|
|
|
suppliesSection.style.display = 'block'; |
|
|
|
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
|
|
|
console.log('使用缓存的货源详情:', cacheKey); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('读取货源详情缓存失败:', error); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('加载货源数据出错:', error); |
|
|
console.error('加载货源数据出错:', error); |
|
|
|
|
|
suppliesGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">加载货源数据失败,请刷新页面重试</p>'; |
|
|
// 尝试使用缓存数据 |
|
|
suppliesSection.style.display = 'block'; |
|
|
try { |
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
const cached = localStorage.getItem(CACHE_KEY); |
|
|
|
|
|
if (cached) { |
|
|
|
|
|
const cache = JSON.parse(cached); |
|
|
|
|
|
if (cache[cacheKey] && (Date.now() - cache[cacheKey].timestamp < CACHE_EXPIRY)) { |
|
|
|
|
|
const cachedData = cache[cacheKey]; |
|
|
|
|
|
suppliesTitle.textContent = cachedData.title; |
|
|
|
|
|
renderSupplies(cachedData.data.supplies); |
|
|
|
|
|
suppliesSection.style.display = 'block'; |
|
|
|
|
|
suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
|
|
|
console.log('使用缓存的货源详情:', cacheKey); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('读取货源详情缓存失败:', error); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 渲染货源卡片 |
|
|
// 渲染货源卡片 |
|
|
function renderSupplies(supplies) { |
|
|
function renderSupplies(supplies) { |
|
|
|
|
|
console.log('renderSupplies函数被调用,supplies数量:', supplies.length); |
|
|
|
|
|
console.log('完整supplies数据:', supplies); |
|
|
suppliesGrid.innerHTML = ''; |
|
|
suppliesGrid.innerHTML = ''; |
|
|
|
|
|
|
|
|
// 过滤掉hidden状态的货源 |
|
|
// 过滤掉hidden状态的货源 |
|
|
const filteredSupplies = supplies.filter(supply => supply.status !== 'hidden'); |
|
|
const filteredSupplies = supplies.filter(supply => supply.status !== 'hidden'); |
|
|
|
|
|
console.log('过滤后的supplies数量:', filteredSupplies.length); |
|
|
|
|
|
console.log('过滤后的supplies数据:', filteredSupplies); |
|
|
|
|
|
|
|
|
if (filteredSupplies.length === 0) { |
|
|
if (filteredSupplies.length === 0) { |
|
|
suppliesGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">暂无货源数据</p>'; |
|
|
suppliesGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">暂无货源数据</p>'; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
filteredSupplies.forEach(supply => { |
|
|
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'); |
|
|
const card = document.createElement('div'); |
|
|
card.className = 'supply-card'; |
|
|
card.className = 'supply-card'; |
|
|
card.style.cssText = 'border: 1px solid #e8e8e8; border-radius: 8px; padding: 15px; transition: all 0.3s;'; |
|
|
card.style.cssText = 'border: 1px solid #e8e8e8; border-radius: 8px; padding: 15px; transition: all 0.3s;'; |
|
|
@ -1200,36 +1173,84 @@ |
|
|
<div>${shortDesc}</div> |
|
|
<div>${shortDesc}</div> |
|
|
</div>`; |
|
|
</div>`; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 产品日志展示 - 添加调试信息 |
|
|
|
|
|
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是什么类型,都显示日志区域 |
|
|
if (supply.product_log) { |
|
|
detailsHTML += `<div style="margin: 10px 0;"> |
|
|
try { |
|
|
<h4 style="margin: 0 0 10px 0; font-size: 14px; font-weight: bold; color: #333; padding-bottom: 5px; border-bottom: 2px solid #ff4d4f;">价格变更日志</h4>`; |
|
|
// 解析产品日志JSON |
|
|
|
|
|
const productLogs = JSON.parse(supply.product_log); |
|
|
try { |
|
|
if (Array.isArray(productLogs) && productLogs.length > 0) { |
|
|
let logs = []; |
|
|
detailsHTML += `<div style="margin: 10px 0; font-size: 14px;"> |
|
|
let hasLogs = false; |
|
|
<h4 style="margin: 0 0 10px 0; padding-bottom: 5px; border-bottom: 2px solid #ff4d4f; color: #333; font-size: 16px;">价格变更日志</h4> |
|
|
|
|
|
<div style="display: flex; flex-direction: column; gap: 8px;"> |
|
|
console.log('开始处理product_log:', supply.product_log); |
|
|
${productLogs.map((log, index) => ` |
|
|
|
|
|
<div style="display: flex; align-items: flex-start; gap: 8px; padding: 10px; background-color: #fff1f0; border-radius: 4px;"> |
|
|
// 检查product_log是否有值 |
|
|
<div style="background-color: #ff4d4f; color: white; padding: 2px 6px; border-radius: 4px; font-size: 12px; font-weight: bold; min-width: 40px; text-align: center;">日志${index + 1}</div> |
|
|
if (supply.product_log !== null && supply.product_log !== undefined && supply.product_log !== '') { |
|
|
<div style="font-size: 13px; color: #666; flex: 1;">${log}</div> |
|
|
// 有值,处理日志 |
|
|
</div> |
|
|
if (typeof supply.product_log === 'string') { |
|
|
`).join('')} |
|
|
// 清理JSON字符串中的特殊字符(换行符、制表符等) |
|
|
</div> |
|
|
const cleanLogStr = supply.product_log.replace(/\s+/g, ' ').trim(); |
|
|
</div>`; |
|
|
console.log('清理后的product_log:', cleanLogStr); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否为JSON格式 |
|
|
|
|
|
if (cleanLogStr.startsWith('[') && cleanLogStr.endsWith(']')) { |
|
|
|
|
|
try { |
|
|
|
|
|
logs = JSON.parse(cleanLogStr); |
|
|
|
|
|
console.log('解析成功,logs:', logs); |
|
|
|
|
|
} catch (parseError) { |
|
|
|
|
|
console.error('JSON解析失败:', parseError); |
|
|
|
|
|
// 解析失败,作为单个日志处理 |
|
|
|
|
|
logs = [supply.product_log]; |
|
|
|
|
|
console.log('作为单个日志处理,logs:', logs); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 不是JSON数组,作为单个日志处理 |
|
|
|
|
|
logs = [supply.product_log]; |
|
|
|
|
|
console.log('不是JSON数组,作为单个日志处理,logs:', logs); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (Array.isArray(supply.product_log)) { |
|
|
|
|
|
logs = supply.product_log; |
|
|
|
|
|
console.log('是数组,直接使用,logs:', logs); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 其他类型,转换为字符串数组 |
|
|
|
|
|
logs = [String(supply.product_log)]; |
|
|
|
|
|
console.log('转换为字符串数组,logs:', logs); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
|
|
|
// 解析失败,直接展示原始日志 |
|
|
hasLogs = logs.length > 0; |
|
|
detailsHTML += `<div style="margin: 10px 0; font-size: 14px;"> |
|
|
console.log('hasLogs:', hasLogs); |
|
|
<h4 style="margin: 0 0 10px 0; padding-bottom: 5px; border-bottom: 2px solid #ff4d4f; color: #333; font-size: 16px;">价格变更日志</h4> |
|
|
} |
|
|
<div style="padding: 10px; background-color: #fff1f0; border-radius: 4px; font-size: 13px; color: #666;"> |
|
|
|
|
|
${supply.product_log} |
|
|
// 显示日志 |
|
|
</div> |
|
|
if (hasLogs) { |
|
|
|
|
|
logs.forEach((log, index) => { |
|
|
|
|
|
// 每条日志的样式 |
|
|
|
|
|
detailsHTML += `<div style="margin: 8px 0; padding: 8px 12px; background-color: #f9f0f0; border-radius: 4px; font-size: 13px; line-height: 1.4;"> |
|
|
|
|
|
<span style="display: inline-block; background-color: #ff4d4f; color: white; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 3px; margin-right: 8px;">日志${index + 1}</span> |
|
|
|
|
|
<span>${log}</span> |
|
|
|
|
|
</div>`; |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 没有日志,显示提示 |
|
|
|
|
|
detailsHTML += `<div style="margin: 8px 0; padding: 8px 12px; background-color: #f9f0f0; border-radius: 4px; font-size: 13px; line-height: 1.4;"> |
|
|
|
|
|
<span>暂无价格变更日志</span> |
|
|
</div>`; |
|
|
</div>`; |
|
|
} |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
// 如果解析失败,直接显示日志内容 |
|
|
|
|
|
console.error('解析product_log失败:', error); |
|
|
|
|
|
detailsHTML += `<div style="margin: 8px 0; padding: 8px 12px; background-color: #f9f0f0; border-radius: 4px; font-size: 13px; line-height: 1.4;"> |
|
|
|
|
|
<span>${supply.product_log || '暂无价格变更日志'}</span> |
|
|
|
|
|
</div>`; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
detailsHTML += `</div>`; |
|
|
|
|
|
|
|
|
// 状态 |
|
|
// 状态 |
|
|
detailsHTML += `<span class="supply-status ${statusClass}" style="display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 12px; margin-top: 5px;">${statusText}</span>`; |
|
|
detailsHTML += `<span class="supply-status ${statusClass}" style="display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 12px; margin-top: 5px;">${statusText}</span>`; |
|
|
|
|
|
|
|
|
|