|
|
|
@ -404,27 +404,94 @@ |
|
|
|
max-height: 80vh; |
|
|
|
object-fit: contain; |
|
|
|
border-radius: 4px; |
|
|
|
transition: transform 0.2s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.close-preview { |
|
|
|
/* 可缩放的图片容器 */ |
|
|
|
.preview-media { |
|
|
|
position: relative; |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
max-width: 100%; |
|
|
|
max-height: 80vh; |
|
|
|
overflow: visible; |
|
|
|
} |
|
|
|
|
|
|
|
/* 可缩放的图片样式 */ |
|
|
|
.preview-media img { |
|
|
|
cursor: grab; |
|
|
|
transform-origin: center center; |
|
|
|
user-select: none; |
|
|
|
} |
|
|
|
|
|
|
|
.preview-media img:active { |
|
|
|
cursor: grabbing; |
|
|
|
} |
|
|
|
|
|
|
|
/* 缩放控制按钮 */ |
|
|
|
.zoom-controls { |
|
|
|
position: absolute; |
|
|
|
top: -30px; |
|
|
|
right: -30px; |
|
|
|
bottom: -40px; |
|
|
|
left: 50%; |
|
|
|
transform: translateX(-50%); |
|
|
|
display: flex; |
|
|
|
gap: 10px; |
|
|
|
background-color: rgba(0, 0, 0, 0.5); |
|
|
|
padding: 8px 16px; |
|
|
|
border-radius: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.zoom-btn { |
|
|
|
background-color: rgba(255, 255, 255, 0.2); |
|
|
|
color: white; |
|
|
|
border: none; |
|
|
|
font-size: 24px; |
|
|
|
cursor: pointer; |
|
|
|
border-radius: 50%; |
|
|
|
width: 30px; |
|
|
|
height: 30px; |
|
|
|
font-size: 16px; |
|
|
|
cursor: pointer; |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.zoom-btn:hover { |
|
|
|
background-color: rgba(255, 255, 255, 0.4); |
|
|
|
} |
|
|
|
|
|
|
|
.zoom-value { |
|
|
|
color: white; |
|
|
|
font-size: 14px; |
|
|
|
align-self: center; |
|
|
|
min-width: 50px; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
|
|
|
|
/* 关闭按钮 */ |
|
|
|
.close-preview { |
|
|
|
position: fixed; |
|
|
|
top: 20px; |
|
|
|
right: 20px; |
|
|
|
background-color: rgba(0, 0, 0, 0.5); |
|
|
|
color: white; |
|
|
|
border: none; |
|
|
|
font-size: 24px; |
|
|
|
cursor: pointer; |
|
|
|
width: 36px; |
|
|
|
height: 36px; |
|
|
|
border-radius: 50%; |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
transition: all 0.3s ease; |
|
|
|
z-index: 1001; /* 确保关闭按钮在最上层 */ |
|
|
|
} |
|
|
|
|
|
|
|
.close-preview:hover { |
|
|
|
background-color: rgba(0, 0, 0, 0.8); |
|
|
|
transform: scale(1.1); |
|
|
|
} |
|
|
|
|
|
|
|
/* 点击图片时的光标样式 */ |
|
|
|
@ -476,6 +543,131 @@ |
|
|
|
transform: translateY(0); |
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
|
|
} |
|
|
|
|
|
|
|
/* 货源卡片优化样式 */ |
|
|
|
.supply-media { |
|
|
|
width: 100%; |
|
|
|
height: 250px; |
|
|
|
object-fit: contain; |
|
|
|
border-radius: 4px; |
|
|
|
margin-bottom: 10px; |
|
|
|
cursor: pointer; |
|
|
|
background-color: #f5f5f5; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-card { |
|
|
|
border: 1px solid #e8e8e8; |
|
|
|
border-radius: 8px; |
|
|
|
padding: 15px; |
|
|
|
transition: all 0.3s ease; |
|
|
|
width: 100%; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-card:hover { |
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); |
|
|
|
transform: translateY(-2px); |
|
|
|
} |
|
|
|
|
|
|
|
.supply-header { |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-title { |
|
|
|
font-weight: bold; |
|
|
|
font-size: 16px; |
|
|
|
margin: 10px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-meta { |
|
|
|
margin: 5px 0 10px 0; |
|
|
|
font-size: 14px; |
|
|
|
line-height: 1.4; |
|
|
|
color: #666; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-info { |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-info p { |
|
|
|
margin: 5px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.spec-section { |
|
|
|
margin: 10px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.spec-item { |
|
|
|
background-color: #f5f5f5; |
|
|
|
padding: 8px 12px; |
|
|
|
border-radius: 4px; |
|
|
|
margin: 5px 0; |
|
|
|
font-size: 13px; |
|
|
|
display: block; |
|
|
|
word-break: break-all; |
|
|
|
} |
|
|
|
|
|
|
|
.description-section { |
|
|
|
margin: 10px 0; |
|
|
|
font-size: 14px; |
|
|
|
background-color: #f5f5f5; |
|
|
|
padding: 10px 12px; |
|
|
|
border-radius: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.description-section strong { |
|
|
|
display: block; |
|
|
|
margin-bottom: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.log-section { |
|
|
|
margin: 10px 0; |
|
|
|
} |
|
|
|
|
|
|
|
.log-section h4 { |
|
|
|
margin: 0 0 10px 0; |
|
|
|
font-size: 14px; |
|
|
|
font-weight: bold; |
|
|
|
color: #333; |
|
|
|
padding-bottom: 5px; |
|
|
|
border-bottom: 2px solid #ff4d4f; |
|
|
|
} |
|
|
|
|
|
|
|
.log-item { |
|
|
|
margin: 8px 0; |
|
|
|
padding: 8px 12px; |
|
|
|
background-color: #f9f0f0; |
|
|
|
border-radius: 4px; |
|
|
|
font-size: 13px; |
|
|
|
line-height: 1.4; |
|
|
|
} |
|
|
|
|
|
|
|
.log-badge { |
|
|
|
display: inline-block; |
|
|
|
background-color: #ff4d4f; |
|
|
|
color: white; |
|
|
|
font-size: 10px; |
|
|
|
font-weight: bold; |
|
|
|
padding: 2px 6px; |
|
|
|
border-radius: 3px; |
|
|
|
margin-right: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-status { |
|
|
|
display: inline-block; |
|
|
|
padding: 2px 8px; |
|
|
|
border-radius: 10px; |
|
|
|
font-size: 12px; |
|
|
|
margin-top: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.empty-state { |
|
|
|
text-align: center; |
|
|
|
color: #666; |
|
|
|
grid-column: 1 / -1; |
|
|
|
} |
|
|
|
</style> |
|
|
|
</head> |
|
|
|
<body> |
|
|
|
@ -800,8 +992,26 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 缩放相关变量 |
|
|
|
let currentScale = 1; |
|
|
|
let minScale = 0.5; |
|
|
|
let maxScale = 5; |
|
|
|
let isDragging = false; |
|
|
|
let startX = 0; |
|
|
|
let startY = 0; |
|
|
|
let translateX = 0; |
|
|
|
let translateY = 0; |
|
|
|
let currentMedia = null; |
|
|
|
|
|
|
|
// 显示媒体预览 |
|
|
|
function showPreview(mediaUrl) { |
|
|
|
// 重置缩放相关变量 |
|
|
|
currentScale = 1; |
|
|
|
translateX = 0; |
|
|
|
translateY = 0; |
|
|
|
isDragging = false; |
|
|
|
currentMedia = null; |
|
|
|
|
|
|
|
// 清空预览内容 |
|
|
|
previewMedia.innerHTML = ''; |
|
|
|
|
|
|
|
@ -814,22 +1024,156 @@ |
|
|
|
video.src = mediaUrl; |
|
|
|
video.controls = true; |
|
|
|
previewMedia.appendChild(video); |
|
|
|
currentMedia = video; |
|
|
|
} else { |
|
|
|
// 图片预览 |
|
|
|
const img = document.createElement('img'); |
|
|
|
img.src = mediaUrl; |
|
|
|
previewMedia.appendChild(img); |
|
|
|
currentMedia = img; |
|
|
|
|
|
|
|
// 添加缩放控制按钮 |
|
|
|
const zoomControls = document.createElement('div'); |
|
|
|
zoomControls.className = 'zoom-controls'; |
|
|
|
zoomControls.innerHTML = ` |
|
|
|
<button class="zoom-btn" id="zoomOutBtn" title="缩小">−</button> |
|
|
|
<span class="zoom-value" id="zoomValue">100%</span> |
|
|
|
<button class="zoom-btn" id="zoomInBtn" title="放大">+</button> |
|
|
|
<button class="zoom-btn" id="resetZoomBtn" title="重置">⟲</button> |
|
|
|
`; |
|
|
|
previewMedia.appendChild(zoomControls); |
|
|
|
|
|
|
|
// 等待图片加载完成后添加事件监听器 |
|
|
|
img.onload = function() { |
|
|
|
addZoomEvents(img); |
|
|
|
addDragEvents(img); |
|
|
|
setupZoomControls(); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 显示预览模态框 |
|
|
|
previewModal.classList.add('active'); |
|
|
|
} |
|
|
|
|
|
|
|
// 添加缩放事件 |
|
|
|
function addZoomEvents(img) { |
|
|
|
// 鼠标滚轮缩放 |
|
|
|
img.addEventListener('wheel', function(e) { |
|
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
// 计算缩放比例 |
|
|
|
const delta = e.deltaY > 0 ? -0.1 : 0.1; |
|
|
|
const newScale = Math.max(minScale, Math.min(maxScale, currentScale + delta)); |
|
|
|
|
|
|
|
// 计算鼠标在图片上的相对位置 |
|
|
|
const rect = img.getBoundingClientRect(); |
|
|
|
const mouseX = e.clientX - rect.left; |
|
|
|
const mouseY = e.clientY - rect.top; |
|
|
|
|
|
|
|
// 计算缩放中心点 |
|
|
|
const centerX = mouseX / rect.width; |
|
|
|
const centerY = mouseY / rect.height; |
|
|
|
|
|
|
|
// 计算新的偏移量,使缩放中心点保持在鼠标位置 |
|
|
|
const oldScale = currentScale; |
|
|
|
currentScale = newScale; |
|
|
|
|
|
|
|
translateX += (mouseX - rect.width * centerX) * (1 - currentScale / oldScale); |
|
|
|
translateY += (mouseY - rect.height * centerY) * (1 - currentScale / oldScale); |
|
|
|
|
|
|
|
// 应用变换 |
|
|
|
applyTransform(img); |
|
|
|
updateZoomValue(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 添加拖拽事件 |
|
|
|
function addDragEvents(img) { |
|
|
|
// 鼠标按下开始拖拽 |
|
|
|
img.addEventListener('mousedown', function(e) { |
|
|
|
if (currentScale === 1) return; // 只有在缩放后才能拖拽 |
|
|
|
|
|
|
|
isDragging = true; |
|
|
|
startX = e.clientX - translateX; |
|
|
|
startY = e.clientY - translateY; |
|
|
|
}); |
|
|
|
|
|
|
|
// 鼠标移动时拖拽 |
|
|
|
document.addEventListener('mousemove', function(e) { |
|
|
|
if (!isDragging) return; |
|
|
|
|
|
|
|
translateX = e.clientX - startX; |
|
|
|
translateY = e.clientY - startY; |
|
|
|
|
|
|
|
applyTransform(img); |
|
|
|
}); |
|
|
|
|
|
|
|
// 鼠标释放结束拖拽 |
|
|
|
document.addEventListener('mouseup', function() { |
|
|
|
isDragging = false; |
|
|
|
}); |
|
|
|
|
|
|
|
// 鼠标离开窗口结束拖拽 |
|
|
|
document.addEventListener('mouseleave', function() { |
|
|
|
isDragging = false; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 设置缩放控制按钮 |
|
|
|
function setupZoomControls() { |
|
|
|
const zoomInBtn = document.getElementById('zoomInBtn'); |
|
|
|
const zoomOutBtn = document.getElementById('zoomOutBtn'); |
|
|
|
const resetZoomBtn = document.getElementById('resetZoomBtn'); |
|
|
|
|
|
|
|
// 放大按钮 |
|
|
|
zoomInBtn.addEventListener('click', function() { |
|
|
|
if (currentScale < maxScale) { |
|
|
|
currentScale += 0.1; |
|
|
|
applyTransform(currentMedia); |
|
|
|
updateZoomValue(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 缩小按钮 |
|
|
|
zoomOutBtn.addEventListener('click', function() { |
|
|
|
if (currentScale > minScale) { |
|
|
|
currentScale -= 0.1; |
|
|
|
applyTransform(currentMedia); |
|
|
|
updateZoomValue(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 重置按钮 |
|
|
|
resetZoomBtn.addEventListener('click', function() { |
|
|
|
currentScale = 1; |
|
|
|
translateX = 0; |
|
|
|
translateY = 0; |
|
|
|
applyTransform(currentMedia); |
|
|
|
updateZoomValue(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 应用变换 |
|
|
|
function applyTransform(media) { |
|
|
|
if (!media || media.tagName === 'VIDEO') return; |
|
|
|
|
|
|
|
media.style.transform = `translate(${translateX}px, ${translateY}px) scale(${currentScale})`; |
|
|
|
} |
|
|
|
|
|
|
|
// 更新缩放值显示 |
|
|
|
function updateZoomValue() { |
|
|
|
const zoomValue = document.getElementById('zoomValue'); |
|
|
|
if (zoomValue) { |
|
|
|
zoomValue.textContent = `${Math.round(currentScale * 100)}%`; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 关闭媒体预览 |
|
|
|
function closePreviewModal() { |
|
|
|
previewModal.classList.remove('active'); |
|
|
|
// 清空预览内容,释放资源 |
|
|
|
previewMedia.innerHTML = ''; |
|
|
|
currentMedia = null; |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化事件监听器 |
|
|
|
@ -880,6 +1224,15 @@ |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 为预览模态框添加鼠标滚轮事件监听器,阻止页面滚动 |
|
|
|
previewModal.addEventListener('wheel', (e) => { |
|
|
|
// 只在模态框激活时阻止滚动 |
|
|
|
if (previewModal.classList.contains('active')) { |
|
|
|
e.preventDefault(); |
|
|
|
e.stopPropagation(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 滚动事件,用于显示/隐藏回到顶部按钮 |
|
|
|
window.addEventListener('scroll', () => { |
|
|
|
const backToTopBtn = document.getElementById('backToTop'); |
|
|
|
@ -902,6 +1255,9 @@ |
|
|
|
function setFilter(filter) { |
|
|
|
currentFilter = filter; |
|
|
|
|
|
|
|
// 重置当前卖家ID,确保切换时间筛选时显示所有货源 |
|
|
|
currentSellerId = null; |
|
|
|
|
|
|
|
// 更新按钮状态 |
|
|
|
[todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active')); |
|
|
|
document.getElementById(filter + 'Btn').classList.add('active'); |
|
|
|
@ -928,6 +1284,9 @@ |
|
|
|
// 更新当前筛选条件为自定义 |
|
|
|
currentFilter = 'custom'; |
|
|
|
|
|
|
|
// 重置当前卖家ID,确保切换时间筛选时显示所有货源 |
|
|
|
currentSellerId = null; |
|
|
|
|
|
|
|
// 清除预设筛选的active状态 |
|
|
|
[todayBtn, yesterdayBtn, beforeYesterdayBtn, weekBtn, monthBtn, allBtn].forEach(btn => btn.classList.remove('active')); |
|
|
|
|
|
|
|
@ -1324,7 +1683,25 @@ |
|
|
|
title = `${creatorName} (${sellerId}) 创建的货源`; |
|
|
|
} |
|
|
|
|
|
|
|
suppliesTitle.textContent = title; |
|
|
|
// 添加"查看全部货源"按钮 |
|
|
|
suppliesTitle.innerHTML = ` |
|
|
|
${title} |
|
|
|
<button id="showAllBtn" style=" |
|
|
|
margin-left: 10px; |
|
|
|
padding: 4px 12px; |
|
|
|
background-color: #1677ff; |
|
|
|
color: white; |
|
|
|
border: none; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: normal; |
|
|
|
">查看全部货源</button> |
|
|
|
`; |
|
|
|
|
|
|
|
// 为"查看全部货源"按钮添加点击事件 |
|
|
|
document.getElementById('showAllBtn').addEventListener('click', showAllSupplies); |
|
|
|
|
|
|
|
renderSupplies(data.data.supplies); |
|
|
|
|
|
|
|
// 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排 |
|
|
|
@ -1355,13 +1732,11 @@ |
|
|
|
|
|
|
|
// 渲染货源卡片 |
|
|
|
function renderSupplies(supplies) { |
|
|
|
console.log('renderSupplies函数被调用,supplies数量:', supplies.length); |
|
|
|
|
|
|
|
// 不过滤任何状态的货源,显示所有货源 |
|
|
|
const filteredSupplies = supplies; |
|
|
|
|
|
|
|
if (filteredSupplies.length === 0) { |
|
|
|
suppliesGrid.innerHTML = '<p style="text-align: center; color: #666; grid-column: 1 / -1;">暂无货源数据</p>'; |
|
|
|
suppliesGrid.innerHTML = '<p class="empty-state">暂无货源数据</p>'; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1376,120 +1751,96 @@ |
|
|
|
// 创建DocumentFragment,用于构建DOM结构,减少页面重排 |
|
|
|
const fragment = document.createDocumentFragment(); |
|
|
|
|
|
|
|
filteredSupplies.forEach((supply, index) => { |
|
|
|
console.log(`渲染第${index + 1}个货源,ID:`, supply.productId); |
|
|
|
|
|
|
|
filteredSupplies.forEach((supply) => { |
|
|
|
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;'; |
|
|
|
card.style.width = '100%'; |
|
|
|
card.style.boxSizing = 'border-box'; |
|
|
|
card.dataset.productId = supply.productId; // 添加产品ID作为数据属性 |
|
|
|
card.innerHTML = ''; |
|
|
|
|
|
|
|
// 解析媒体URL |
|
|
|
let mediaUrl = ''; |
|
|
|
try { |
|
|
|
// 使用更快的JSON.parse替代复杂的字符串处理 |
|
|
|
const imageUrls = JSON.parse(supply.imageUrls || '[]'); |
|
|
|
if (imageUrls.length > 0) { |
|
|
|
if (imageUrls && Array.isArray(imageUrls) && imageUrls.length > 0) { |
|
|
|
mediaUrl = imageUrls[0]; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error('解析媒体URL失败:', e); |
|
|
|
// 解析失败时不打印错误,避免性能影响 |
|
|
|
} |
|
|
|
|
|
|
|
// 状态样式 |
|
|
|
// 状态文本映射,避免switch语句 |
|
|
|
const statusMap = { |
|
|
|
'published': '已发布', |
|
|
|
'sold_out': '已下架', |
|
|
|
'hidden': '已隐藏' |
|
|
|
}; |
|
|
|
const statusClass = `status-${supply.status}`; |
|
|
|
let statusText = '待审核'; |
|
|
|
switch (supply.status) { |
|
|
|
case 'published': |
|
|
|
statusText = '已发布'; |
|
|
|
break; |
|
|
|
case 'sold_out': |
|
|
|
statusText = '已下架'; |
|
|
|
break; |
|
|
|
case 'hidden': |
|
|
|
statusText = '已隐藏'; |
|
|
|
break; |
|
|
|
} |
|
|
|
const statusText = statusMap[supply.status] || '待审核'; |
|
|
|
|
|
|
|
// 检查是否为视频文件 |
|
|
|
// 检查是否为视频文件(使用更简单的正则表达式) |
|
|
|
let mediaElement = ''; |
|
|
|
if (mediaUrl) { |
|
|
|
const isVideo = mediaUrl.startsWith('data:video/') || mediaUrl.match(/\.(mp4|mov|avi|wmv|flv|webm|mkv)$/i); |
|
|
|
const isVideo = /\.(mp4|mov|avi|wmv|flv|webm|mkv)$/i.test(mediaUrl) || mediaUrl.startsWith('data:video/'); |
|
|
|
if (isVideo) { |
|
|
|
// 视频文件 |
|
|
|
mediaElement = `<video src="${mediaUrl}" alt="${supply.productName}" controls style="width: 100%; height: 250px; object-fit: contain; cursor: pointer; background-color: #f5f5f5; border-radius: 4px; margin-bottom: 10px;" onclick="showPreview('${mediaUrl}')"></video>`; |
|
|
|
mediaElement = `<video src="${mediaUrl}" alt="${supply.productName}" controls class="supply-media"></video>`; |
|
|
|
} else { |
|
|
|
// 图片文件 |
|
|
|
mediaElement = `<img src="${mediaUrl}" alt="${supply.productName}" style="width: 100%; height: 250px; object-fit: contain; border-radius: 4px; margin-bottom: 10px; cursor: pointer; background-color: #f5f5f5;" onclick="showPreview('${mediaUrl}')">`; |
|
|
|
mediaElement = `<img src="${mediaUrl}" alt="${supply.productName}" class="supply-media" onclick="showPreview('${mediaUrl}')">`; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 第一行展示:种类|蛋黄|货源类型|产品包装|新鲜程度 |
|
|
|
const firstLineParts = []; |
|
|
|
if (supply.category) firstLineParts.push(supply.category); |
|
|
|
if (supply.yolk) firstLineParts.push(supply.yolk); |
|
|
|
if (supply.sourceType) firstLineParts.push(supply.sourceType); |
|
|
|
if (supply.producting) firstLineParts.push(supply.producting); |
|
|
|
if (supply.freshness) firstLineParts.push(supply.freshness); |
|
|
|
const firstLineHTML = firstLineParts.length > 0 ? |
|
|
|
`<p class="supply-meta">${firstLineParts.join(' | ')}</p>` : ''; |
|
|
|
|
|
|
|
// 构建详细信息HTML |
|
|
|
let detailsHTML = ''; |
|
|
|
const detailsParts = []; |
|
|
|
|
|
|
|
// 产品ID |
|
|
|
if (supply.productId) { |
|
|
|
detailsHTML += `<p style="margin: 5px 0; font-size: 14px;"><strong>产品ID:</strong> ${supply.productId}</p>`; |
|
|
|
detailsParts.push(`<p><strong>产品ID:</strong> ${supply.productId}</p>`); |
|
|
|
} |
|
|
|
|
|
|
|
// 规格+件数+采购价+销售价组合展示 |
|
|
|
let specifications = []; |
|
|
|
let quantities = []; |
|
|
|
let costprices = []; |
|
|
|
let prices = []; |
|
|
|
|
|
|
|
// 处理规格 |
|
|
|
const specifications = []; |
|
|
|
if (supply.specification) { |
|
|
|
if (typeof supply.specification === 'string') { |
|
|
|
// 规格可能用逗号或中文逗号分隔 |
|
|
|
specifications = supply.specification.split(/[,,]/).filter(spec => spec.trim()); |
|
|
|
specifications.push(...supply.specification.split(/[,,]/).filter(spec => spec.trim())); |
|
|
|
} else if (Array.isArray(supply.specification)) { |
|
|
|
specifications = supply.specification; |
|
|
|
specifications.push(...supply.specification); |
|
|
|
} else { |
|
|
|
specifications = [supply.specification]; |
|
|
|
specifications.push(String(supply.specification)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 处理件数 |
|
|
|
if (supply.quantity) { |
|
|
|
if (typeof supply.quantity === 'string') { |
|
|
|
quantities = supply.quantity.split(',').filter(qty => qty.trim()); |
|
|
|
} else if (Array.isArray(supply.quantity)) { |
|
|
|
quantities = supply.quantity; |
|
|
|
} else { |
|
|
|
quantities = [supply.quantity]; |
|
|
|
} |
|
|
|
} |
|
|
|
// 处理数量、采购价、销售价 |
|
|
|
const quantities = Array.isArray(supply.quantity) ? supply.quantity : |
|
|
|
(typeof supply.quantity === 'string' ? supply.quantity.split(',').filter(qty => qty.trim()) : |
|
|
|
(supply.quantity ? [String(supply.quantity)] : [])); |
|
|
|
|
|
|
|
// 处理采购价 |
|
|
|
if (supply.costprice) { |
|
|
|
if (typeof supply.costprice === 'string') { |
|
|
|
costprices = supply.costprice.split(',').filter(cp => cp.trim()); |
|
|
|
} else if (Array.isArray(supply.costprice)) { |
|
|
|
costprices = supply.costprice; |
|
|
|
} else { |
|
|
|
costprices = [supply.costprice]; |
|
|
|
} |
|
|
|
} |
|
|
|
const costprices = Array.isArray(supply.costprice) ? supply.costprice : |
|
|
|
(typeof supply.costprice === 'string' ? supply.costprice.split(',').filter(cp => cp.trim()) : |
|
|
|
(supply.costprice ? [String(supply.costprice)] : [])); |
|
|
|
|
|
|
|
// 处理销售价 |
|
|
|
if (supply.price) { |
|
|
|
if (typeof supply.price === 'string') { |
|
|
|
prices = supply.price.split(',').filter(p => p.trim()); |
|
|
|
} else if (Array.isArray(supply.price)) { |
|
|
|
prices = supply.price; |
|
|
|
} else { |
|
|
|
prices = [supply.price]; |
|
|
|
} |
|
|
|
} |
|
|
|
const prices = Array.isArray(supply.price) ? supply.price : |
|
|
|
(typeof supply.price === 'string' ? supply.price.split(',').filter(p => p.trim()) : |
|
|
|
(supply.price ? [String(supply.price)] : [])); |
|
|
|
|
|
|
|
// 计算最大长度,确保每个规格都有对应的数据 |
|
|
|
const maxLength = Math.max(specifications.length, quantities.length, costprices.length, prices.length); |
|
|
|
|
|
|
|
// 生成组合展示HTML |
|
|
|
if (maxLength > 0) { |
|
|
|
detailsHTML += `<div style="margin: 10px 0;">`; |
|
|
|
|
|
|
|
const specDetails = []; |
|
|
|
for (let i = 0; i < maxLength; i++) { |
|
|
|
const spec = specifications[i] || ''; |
|
|
|
const quantity = quantities[i] || ''; |
|
|
|
@ -1498,30 +1849,31 @@ |
|
|
|
|
|
|
|
// 只显示有数据的行 |
|
|
|
if (spec || quantity || costprice || price) { |
|
|
|
let specHtml = `规格${i+1}: ${spec}`; |
|
|
|
let parts = []; |
|
|
|
if (spec) parts.push(specHtml); |
|
|
|
const parts = []; |
|
|
|
if (spec) parts.push(`规格${i+1}: ${spec}`); |
|
|
|
if (quantity) parts.push(`件数: ${quantity}件`); |
|
|
|
if (costprice) parts.push(`采购价: ¥${costprice}`); |
|
|
|
if (price) parts.push(`销售价: ¥${price}`); |
|
|
|
|
|
|
|
detailsHTML += `<div style="background-color: #f5f5f5; padding: 8px 12px; border-radius: 4px; margin: 5px 0; font-size: 13px; display: block; word-break: break-all;"> |
|
|
|
${parts.join(' - ')} |
|
|
|
</div>`; |
|
|
|
if (parts.length > 0) { |
|
|
|
specDetails.push(`<div class="spec-item">${parts.join(' - ')}</div>`); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
detailsHTML += `</div>`; |
|
|
|
if (specDetails.length > 0) { |
|
|
|
detailsParts.push(`<div class="spec-section">${specDetails.join('')}</div>`); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 商品地区 |
|
|
|
if (supply.region) { |
|
|
|
detailsHTML += `<p style="margin: 5px 0; font-size: 14px;"><strong>商品地区:</strong> ${supply.region}</p>`; |
|
|
|
detailsParts.push(`<p><strong>商品地区:</strong> ${supply.region}</p>`); |
|
|
|
} |
|
|
|
|
|
|
|
// 商品联系人和联系电话一行展示,只显示联系人名称和电话号码 |
|
|
|
// 商品联系人和联系电话 |
|
|
|
if (supply.product_contact || supply.contact_phone) { |
|
|
|
let contactText = `<strong>商品联系人:</strong> `; |
|
|
|
let contactText = '<strong>商品联系人:</strong> '; |
|
|
|
if (supply.product_contact) { |
|
|
|
contactText += supply.product_contact; |
|
|
|
} |
|
|
|
@ -1532,39 +1884,35 @@ |
|
|
|
contactText += supply.contact_phone; |
|
|
|
} |
|
|
|
} |
|
|
|
detailsHTML += `<p style="margin: 5px 0; font-size: 14px;">${contactText}</p>`; |
|
|
|
detailsParts.push(`<p>${contactText}</p>`); |
|
|
|
} |
|
|
|
|
|
|
|
// 创建时间 |
|
|
|
detailsHTML += `<p style="margin: 5px 0; font-size: 14px;"><strong>创建时间:</strong> ${new Date(supply.created_at).toLocaleString()}</p>`; |
|
|
|
detailsParts.push(`<p><strong>创建时间:</strong> ${new Date(supply.created_at).toLocaleString()}</p>`); |
|
|
|
|
|
|
|
// 修改时间 |
|
|
|
if (supply.updated_at) { |
|
|
|
detailsHTML += `<p style="margin: 5px 0; font-size: 14px;"><strong>修改时间:</strong> ${new Date(supply.updated_at).toLocaleString()}</p>`; |
|
|
|
detailsParts.push(`<p><strong>修改时间:</strong> ${new Date(supply.updated_at).toLocaleString()}</p>`); |
|
|
|
} |
|
|
|
|
|
|
|
// 货源描述(限制显示长度)- 灰色背景放在修改时间后面 |
|
|
|
// 货源描述(限制显示长度) |
|
|
|
if (supply.description) { |
|
|
|
const shortDesc = supply.description.length > 50 ? `${supply.description.substring(0, 50)}...` : supply.description; |
|
|
|
detailsHTML += `<div style="margin: 10px 0; font-size: 14px; background-color: #f5f5f5; padding: 10px 12px; border-radius: 4px;"> |
|
|
|
<strong style="display: block; margin-bottom: 5px;">货源描述:</strong> |
|
|
|
<div>${shortDesc}</div> |
|
|
|
</div>`; |
|
|
|
detailsParts.push(`<div class="description-section"><strong>货源描述:</strong><div>${shortDesc}</div></div>`); |
|
|
|
} |
|
|
|
|
|
|
|
// 无论product_log是什么类型,都显示日志区域 |
|
|
|
detailsHTML += `<div style="margin: 10px 0;"> |
|
|
|
<h4 style="margin: 0 0 10px 0; font-size: 14px; font-weight: bold; color: #333; padding-bottom: 5px; border-bottom: 2px solid #ff4d4f;">价格变更日志</h4>`; |
|
|
|
// 价格变更日志 |
|
|
|
let logHTML = `<div class="log-section"><h4>价格变更日志</h4>`; |
|
|
|
|
|
|
|
try { |
|
|
|
let logs = []; |
|
|
|
let hasLogs = false; |
|
|
|
|
|
|
|
// 检查product_log是否有值 |
|
|
|
if (supply.product_log !== null && supply.product_log !== undefined && supply.product_log !== '') { |
|
|
|
if (supply.product_log != null && supply.product_log != undefined && supply.product_log != '') { |
|
|
|
// 有值,处理日志 |
|
|
|
if (typeof supply.product_log === 'string') { |
|
|
|
// 清理JSON字符串中的特殊字符(换行符、制表符等) |
|
|
|
// 清理JSON字符串中的特殊字符 |
|
|
|
const cleanLogStr = supply.product_log.replace(/\s+/g, ' ').trim(); |
|
|
|
|
|
|
|
// 检查是否为JSON格式 |
|
|
|
@ -1572,7 +1920,6 @@ |
|
|
|
try { |
|
|
|
logs = JSON.parse(cleanLogStr); |
|
|
|
} catch (parseError) { |
|
|
|
console.error('JSON解析失败:', parseError); |
|
|
|
// 解析失败,作为单个日志处理 |
|
|
|
logs = [supply.product_log]; |
|
|
|
} |
|
|
|
@ -1593,66 +1940,35 @@ |
|
|
|
// 显示日志 |
|
|
|
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>`; |
|
|
|
logHTML += `<div class="log-item"><span class="log-badge">日志${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>`; |
|
|
|
logHTML += `<div class="log-item"><span>暂无价格变更日志</span></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>`; |
|
|
|
logHTML += `<div class="log-item"><span>${supply.product_log || '暂无价格变更日志'}</span></div>`; |
|
|
|
} |
|
|
|
|
|
|
|
detailsHTML += `</div>`; |
|
|
|
logHTML += `</div>`; |
|
|
|
detailsParts.push(logHTML); |
|
|
|
|
|
|
|
// 状态 |
|
|
|
detailsHTML += `<span class="supply-status ${statusClass}" style="display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 12px; margin-top: 5px;">${statusText}</span>`; |
|
|
|
|
|
|
|
// 第一行展示:种类|蛋黄|货源类型|产品包装|新鲜程度,只展示数据 |
|
|
|
let firstLineParts = []; |
|
|
|
if (supply.category) firstLineParts.push(supply.category); |
|
|
|
if (supply.yolk) firstLineParts.push(supply.yolk); |
|
|
|
if (supply.sourceType) firstLineParts.push(supply.sourceType); |
|
|
|
if (supply.producting) firstLineParts.push(supply.producting); |
|
|
|
if (supply.freshness) firstLineParts.push(supply.freshness); |
|
|
|
|
|
|
|
let firstLineHTML = ''; |
|
|
|
if (firstLineParts.length > 0) { |
|
|
|
firstLineHTML = `<p style="margin: 5px 0 10px 0; font-size: 14px; line-height: 1.4; color: #666; font-weight: 500;">${firstLineParts.join(' | ')}</p>`; |
|
|
|
} |
|
|
|
detailsParts.push(`<span class="supply-status ${statusClass}">${statusText}</span>`); |
|
|
|
|
|
|
|
// 构建完整卡片HTML |
|
|
|
card.innerHTML = ` |
|
|
|
<div style="margin-bottom: 15px;"> |
|
|
|
<div class="supply-header"> |
|
|
|
${mediaElement} |
|
|
|
<div class="supply-title" style="font-weight: bold; font-size: 16px; margin: 10px 0;">${supply.productName}</div> |
|
|
|
<div class="supply-title">${supply.productName}</div> |
|
|
|
${firstLineHTML} |
|
|
|
</div> |
|
|
|
<div class="supply-info" style="font-size: 14px;"> |
|
|
|
${detailsHTML} |
|
|
|
<div class="supply-info"> |
|
|
|
${detailsParts.join('')} |
|
|
|
</div> |
|
|
|
`; |
|
|
|
|
|
|
|
// 悬停效果 |
|
|
|
card.addEventListener('mouseenter', () => { |
|
|
|
card.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)'; |
|
|
|
card.style.transform = 'translateY(-2px)'; |
|
|
|
}); |
|
|
|
|
|
|
|
card.addEventListener('mouseleave', () => { |
|
|
|
card.style.boxShadow = 'none'; |
|
|
|
card.style.transform = 'translateY(0)'; |
|
|
|
}); |
|
|
|
|
|
|
|
// 添加到DocumentFragment |
|
|
|
fragment.appendChild(card); |
|
|
|
}); |
|
|
|
|