|
|
|
@ -207,6 +207,107 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 设备特定样式 - 电脑端 */ |
|
|
|
@media (min-width: 769px) { |
|
|
|
/* 电脑端货源项目样式 */ |
|
|
|
.supply-item { |
|
|
|
display: flex; |
|
|
|
gap: 20px; |
|
|
|
margin-bottom: 20px; |
|
|
|
padding: 20px; |
|
|
|
border-radius: 12px; |
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-item:hover { |
|
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); |
|
|
|
transform: translateY(-2px); |
|
|
|
} |
|
|
|
|
|
|
|
.supply-images { |
|
|
|
flex: 0 0 150px; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-info { |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 电脑端规格数量框样式 */ |
|
|
|
.spec-quantity-box { |
|
|
|
border: 1px solid #f0f0f0; |
|
|
|
padding: 10px; |
|
|
|
border-radius: 8px; |
|
|
|
background-color: #fafafa; |
|
|
|
margin-bottom: 10px; |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.spec-quantity-box:hover { |
|
|
|
border-color: #1890ff; |
|
|
|
background-color: #f0f8ff; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 设备特定样式 - 手机端 */ |
|
|
|
@media (max-width: 768px) { |
|
|
|
/* 手机端货源项目样式 */ |
|
|
|
.supply-item { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 15px; |
|
|
|
margin-bottom: 15px; |
|
|
|
padding: 15px; |
|
|
|
border-radius: 10px; |
|
|
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-item:hover { |
|
|
|
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.09); |
|
|
|
} |
|
|
|
|
|
|
|
.supply-images { |
|
|
|
width: 100%; |
|
|
|
max-height: 200px; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-info { |
|
|
|
width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
/* 手机端规格数量框样式 */ |
|
|
|
.spec-quantity-box { |
|
|
|
border: 1px solid #f0f0f0; |
|
|
|
padding: 12px; |
|
|
|
border-radius: 10px; |
|
|
|
background-color: #fafafa; |
|
|
|
margin-bottom: 12px; |
|
|
|
text-align: center; |
|
|
|
transition: all 0.3s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.spec-quantity-box:hover { |
|
|
|
border-color: #1890ff; |
|
|
|
background-color: #f0f8ff; |
|
|
|
} |
|
|
|
|
|
|
|
/* 手机端操作按钮样式 */ |
|
|
|
.supply-actions { |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 10px; |
|
|
|
justify-content: center; |
|
|
|
} |
|
|
|
|
|
|
|
.supply-actions button { |
|
|
|
flex: 1; |
|
|
|
min-width: 120px; |
|
|
|
padding: 10px; |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 搜索框 */ |
|
|
|
.search-box { |
|
|
|
position: relative; |
|
|
|
@ -2695,6 +2796,40 @@ |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 设备检测模块 |
|
|
|
const DeviceDetector = { |
|
|
|
// 检测是否为移动设备 |
|
|
|
isMobile() { |
|
|
|
return window.innerWidth <= 768; |
|
|
|
}, |
|
|
|
|
|
|
|
// 检测是否为电脑端 |
|
|
|
isDesktop() { |
|
|
|
return window.innerWidth > 768; |
|
|
|
}, |
|
|
|
|
|
|
|
// 检测是否为小屏幕手机 |
|
|
|
isSmallMobile() { |
|
|
|
return window.innerWidth <= 480; |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取设备类型 |
|
|
|
getDeviceType() { |
|
|
|
if (this.isSmallMobile()) { |
|
|
|
return 'small-mobile'; |
|
|
|
} else if (this.isMobile()) { |
|
|
|
return 'mobile'; |
|
|
|
} else { |
|
|
|
return 'desktop'; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 监听窗口大小变化 |
|
|
|
onResize(callback) { |
|
|
|
window.addEventListener('resize', throttle(callback, 100)); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 应用防抖和节流到搜索输入 |
|
|
|
const debouncedSearch = debounce(function(keyword) { |
|
|
|
console.log('执行搜索:', keyword); |
|
|
|
@ -3034,22 +3169,22 @@ |
|
|
|
case 'supply_update': |
|
|
|
// 货源更新通知,重新加载数据 |
|
|
|
console.log('收到货源更新通知,重新加载数据'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
break; |
|
|
|
case 'supply_lock': |
|
|
|
// 货源锁定状态更新 |
|
|
|
console.log('收到货源锁定状态更新,重新加载数据'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
break; |
|
|
|
case 'supply_status_change': |
|
|
|
// 货源状态变更 |
|
|
|
console.log('收到货源状态变更,重新加载数据'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
break; |
|
|
|
case 'auto_offline': |
|
|
|
// 自动下架通知 |
|
|
|
console.log('收到自动下架通知,重新加载数据'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
break; |
|
|
|
case 'ping': |
|
|
|
// 心跳响应 |
|
|
|
@ -3110,11 +3245,11 @@ |
|
|
|
// 启动自动检查下架时间 |
|
|
|
startAutoOfflineCheck(); |
|
|
|
|
|
|
|
// 启动定期刷新数据,确保label字段变化能实时显示 |
|
|
|
// 优化:减少刷新频率,从5秒改为30秒,降低服务器负载 |
|
|
|
// 启动定期刷新数据,确保其他程序修改数据库时能实时显示 |
|
|
|
// 优化:设置为10秒一次,平衡实时性和性能 |
|
|
|
timers.loadSupplies = setInterval(() => { |
|
|
|
loadSupplies(); |
|
|
|
}, 30000); // 每30秒刷新一次 |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存,确保获取最新数据 |
|
|
|
}, 10000); // 每10秒刷新一次 |
|
|
|
|
|
|
|
// 添加防抖机制,避免短时间内多次调用loadSupplies |
|
|
|
let loadSuppliesTimeout; |
|
|
|
@ -3130,7 +3265,7 @@ |
|
|
|
// 使用防抖机制,避免短时间内多次调用loadSupplies |
|
|
|
clearTimeout(loadSuppliesTimeout); |
|
|
|
loadSuppliesTimeout = setTimeout(() => { |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
}, 1000); // 1秒防抖 |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
@ -3345,7 +3480,7 @@ |
|
|
|
}); |
|
|
|
|
|
|
|
// 重新加载货源列表 |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
console.log(`货源 ${supplyId} 状态已更新为 ${status}`); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
@ -5643,10 +5778,18 @@ |
|
|
|
const costprice = costprices[i] || '0'; |
|
|
|
const specStatus = specStatuses[i] || '0'; |
|
|
|
|
|
|
|
// 添加售空标识 |
|
|
|
const soldOutTag = specStatus === '1' ? '<span style="color: #f5222d; font-size: 12px; font-weight: 600; margin-left: 10px;">已售空</span>' : ''; |
|
|
|
// 添加售空标识,根据设备类型显示不同样式 |
|
|
|
const soldOutTag = specStatus === '1' ? (DeviceDetector.isMobile() ? |
|
|
|
'<div style="display: flex; justify-content: center; margin-top: 8px;"><span style="color: #f5222d; font-size: 12px; font-weight: 600; padding: 2px 12px; background-color: #fff1f0; border-radius: 12px;">已售空</span></div>' : |
|
|
|
'<span style="color: #f5222d; font-size: 12px; font-weight: 600; margin-left: 10px;">已售空</span>' |
|
|
|
) : ''; |
|
|
|
|
|
|
|
specQuantityBoxes += `<div class="spec-quantity-box" style="border: 1px solid #f0f0f0; padding: 10px; border-radius: 8px; background-color: #fafafa; margin-bottom: 10px;">• ${spec}<br>${quantity}件 | ¥${costprice}${soldOutTag}</div>`; |
|
|
|
// 根据设备类型生成不同的spec-quantity-box样式 |
|
|
|
const specQuantityBoxStyle = DeviceDetector.isMobile() ? |
|
|
|
'border: 1px solid #f0f0f0; padding: 10px; border-radius: 10px; background-color: #fafafa; margin-bottom: 6px; text-align: center;' : |
|
|
|
'border: 1px solid #f0f0f0; padding: 10px; border-radius: 8px; background-color: #fafafa; margin-bottom: 10px;'; |
|
|
|
|
|
|
|
specQuantityBoxes += `<div class="spec-quantity-box" style="${specQuantityBoxStyle}">• ${spec}<br>${quantity}件 | ¥${costprice}${soldOutTag}</div>`; |
|
|
|
} |
|
|
|
|
|
|
|
return ` |
|
|
|
@ -5666,7 +5809,7 @@ |
|
|
|
<button class="copy-supply-btn" onclick="copySupply('${supply.id}')">复制</button> |
|
|
|
</div> |
|
|
|
<!-- 详细信息和规格-件数对在同一行,水平对齐 --> |
|
|
|
<div style="display: flex; gap: 20px; align-items: flex-start;"> |
|
|
|
<div style="display: flex; gap: 20px; align-items: flex-start; margin-bottom: 2px;"> |
|
|
|
<!-- 左侧详细信息 --> |
|
|
|
<div style="flex: 1;"> |
|
|
|
<!-- 基本信息 --> |
|
|
|
@ -5677,13 +5820,18 @@ |
|
|
|
<div class="detail-item">${supply.producting || '无'}</div> |
|
|
|
<div class="detail-item">${supply.freshness || '无'}</div> |
|
|
|
<div class="detail-item">${supply.supplyStatus || '未设置'}</div> |
|
|
|
<div class="detail-item">${description || '无'}</div> |
|
|
|
<div class="detail-item">${region || '未设置'}</div> |
|
|
|
<!-- 隐藏独立价格字段,因为每个规格-件数对都有自己的采购价 --> |
|
|
|
<div class="detail-item" style="font-size: 12px; color: #999; grid-column: 1 / -1;">创建时间:${supply.status === 'pending' ? '待创建' : formatDate(supply.created_at)}</div> |
|
|
|
${supply.status === 'pending' && supply.pre_create ? `<div class="detail-item" style="font-size: 12px; color: #1890ff; grid-column: 1 / -1;">预计创建时间:${formatDate(supply.pre_create)}</div>` : ''} |
|
|
|
${supply.status === 'published' ? `<div class="detail-item" style="font-size: 12px; color: #999; grid-column: 1 / -1;">上架时间:${formatDate(getPublishTime(supply))}</div>` : ''} |
|
|
|
${(supply.status === 'hidden' || supply.status === 'sold_out') && supply.updated_at ? `<div class="detail-item" style="font-size: 12px; color: #999; grid-column: 1 / -1;">下架时间:${formatDate(supply.updated_at)}</div>` : ''} |
|
|
|
<!-- 只在管理员模式下显示创建者信息 --> |
|
|
|
${(() => { |
|
|
|
const userInfo = JSON.parse(localStorage.getItem('userInfo')); |
|
|
|
const isAdmin = userInfo?.projectName === '管理员'; |
|
|
|
return isAdmin && supply.nickName ? `<div class="detail-item" style="font-size: 12px; color: #1890ff; font-weight: 500; grid-column: 1 / -1;">创建者:${supply.nickName}</div>` : ''; |
|
|
|
})()} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<!-- 右侧规格-件数对 --> |
|
|
|
@ -5691,6 +5839,14 @@ |
|
|
|
${specQuantityBoxes} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 货源描述 - 独立容器,在手机端铺满宽度 --> |
|
|
|
${description ? ` |
|
|
|
<div class="supply-description" style="padding: 10px; background: #e3f2fd; border-left: 4px solid #1976d2; border-radius: 0 8px 8px 0; margin-top: -8px;"> |
|
|
|
<div style="font-size: 14px; font-weight: 500; color: #1976d2; margin-bottom: 4px;">货源描述</div> |
|
|
|
<div style="font-size: 13px; line-height: 1.4; color: #333;">${description}</div> |
|
|
|
</div> |
|
|
|
` : ''} |
|
|
|
<div class="supply-actions"> |
|
|
|
${actionsHTML} |
|
|
|
</div> |
|
|
|
@ -7445,7 +7601,7 @@ |
|
|
|
data: result.data |
|
|
|
}); |
|
|
|
|
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
} else { |
|
|
|
// 创建失败,保持保存的数据 |
|
|
|
alert('创建失败: ' + (result.message || '未知错误')); |
|
|
|
@ -8056,7 +8212,7 @@ |
|
|
|
}); |
|
|
|
|
|
|
|
alert('规格下架成功'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
hideUnpublishSpecModal(); |
|
|
|
} else { |
|
|
|
alert('规格下架失败: ' + (result.message || '未知错误')); |
|
|
|
@ -8121,7 +8277,7 @@ |
|
|
|
}); |
|
|
|
|
|
|
|
alert('删除成功'); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
} else { |
|
|
|
alert('删除失败: ' + (result.message || '未知错误')); |
|
|
|
} |
|
|
|
@ -9632,7 +9788,7 @@ |
|
|
|
if (!window.currentEditPublishMode) { |
|
|
|
alert('编辑成功'); |
|
|
|
hideEditSupplyModal(); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
} else { |
|
|
|
// 调用上架API |
|
|
|
const publishResponse = await fetch(`/api/supplies/${currentEditSupplyId}/publish`, { |
|
|
|
@ -9642,7 +9798,7 @@ |
|
|
|
if (publishResult.success) { |
|
|
|
alert('上架成功'); |
|
|
|
hideEditSupplyModal(); |
|
|
|
loadSupplies(); |
|
|
|
loadSupplies(true); // 强制刷新,跳过缓存 |
|
|
|
} else { |
|
|
|
alert('上架失败: ' + (publishResult.message || '未知错误')); |
|
|
|
return false; |
|
|
|
|