From 06cc8aa24849c9b019678141c09910203f8aefdd Mon Sep 17 00:00:00 2001 From: Default User Date: Tue, 3 Feb 2026 09:55:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Management.html=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=EF=BC=8C=E6=B7=BB=E5=8A=A0=E9=98=B2=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E3=80=81=E6=95=B0=E6=8D=AE=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E3=80=81=E5=A2=9E=E9=87=8F=E6=B8=B2=E6=9F=93=E3=80=81=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E5=92=8C=E8=99=9A=E6=8B=9F=E6=BB=9A=E5=8A=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Management.html | 883 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 770 insertions(+), 113 deletions(-) diff --git a/Management.html b/Management.html index 38f97a3..6da6f46 100644 --- a/Management.html +++ b/Management.html @@ -747,6 +747,23 @@ let suppliesData = []; let usersData = []; let chartData = []; + let isLoading = false; // 防重复点击标志 + + // 缓存相关变量 + let suppliesCache = {}; // 货源数据缓存 + let cacheExpiry = 5 * 60 * 1000; // 缓存过期时间(5分钟) + + // 分页相关变量 + let currentPage = 1; // 当前页码 + let pageSize = 20; // 每页显示数量 + let totalItems = 0; // 总数据量 + let totalPages = 0; // 总页数 + + // 虚拟滚动相关变量 + let virtualScrollEnabled = false; // 是否启用虚拟滚动 + let itemHeight = 600; // 估计的卡片高度 + let visibleCount = 5; // 可见区域显示的卡片数量 + let bufferCount = 2; // 缓冲区卡片数量 // 货源详情相关变量 let currentSellerId = null; // 当前正在显示的卖家ID @@ -795,6 +812,7 @@ checkLoginAndRole(); initEventListeners(); + optimizeEventListeners(); // 优化事件监听器 initWebSocket(); loadStats(currentFilter); @@ -1253,6 +1271,12 @@ // 设置筛选条件 function setFilter(filter) { + // 防重复点击检查 + if (isLoading) { + console.log('数据正在加载中,请勿重复点击'); + return; + } + currentFilter = filter; // 重置当前卖家ID,确保切换时间筛选时显示所有货源 @@ -1272,6 +1296,12 @@ // 应用自定义时间筛选 function applyCustomFilter() { + // 防重复点击检查 + if (isLoading) { + console.log('数据正在加载中,请勿重复点击'); + return; + } + const startDate = startDateInput.value; const endDate = endDateInput.value; @@ -1327,9 +1357,72 @@ } } + // 封装API调用函数 + async function fetchSuppliesData(filter, startDate = '', endDate = '', sellerId = null) { + // 构建缓存键 + const cacheKey = sellerId ? + `seller_${sellerId}_${filter}_${startDate}_${endDate}` : + `${filter}_${startDate}_${endDate}`; + + // 检查缓存 + if (suppliesCache[cacheKey] && (Date.now() - suppliesCache[cacheKey].timestamp < cacheExpiry)) { + console.log('使用内存缓存数据:', cacheKey); + return suppliesCache[cacheKey].data; + } + + try { + // 构建API请求URL + let url = `/api/admin/supplies?filter=${filter}`; + if (sellerId) url += `&sellerId=${sellerId}`; + if (filter === 'custom') { + if (startDate) url += `&startDate=${startDate}`; + if (endDate) url += `&endDate=${endDate}`; + } + + console.log('fetchSuppliesData - 正在请求API:', 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) { + // 保存到内存缓存 + suppliesCache[cacheKey] = { + data: data.data.supplies || [], + timestamp: Date.now() + }; + + return suppliesCache[cacheKey].data; + } else { + console.error('加载货源数据失败:', data.message); + return []; + } + } catch (error) { + console.error('fetchSuppliesData - 加载货源数据出错:', error); + return []; + } + } + // 加载统计数据 async function loadStats(filter, startDate = '', endDate = '') { + // 防重复点击检查 + if (isLoading) { + console.log('数据正在加载中,请勿重复点击'); + return; + } + try { + isLoading = true; + // 构建API请求URL,包含自定义日期参数 let url = `/api/admin/stats/supplies?filter=${filter}`; if (filter === 'custom') { @@ -1397,6 +1490,8 @@ showAllSupplies(); } } + } finally { + isLoading = false; } } @@ -1518,6 +1613,9 @@ // 清空当前正在显示的卖家ID currentSellerId = null; + // 重置页码 + currentPage = 1; + // 构建标题 let title = '当天所有货源'; @@ -1565,50 +1663,23 @@ } 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}`; - } + // 使用封装的API调用函数获取数据 + const startDate = currentFilter === 'custom' ? startDateInput.value : ''; + const endDate = currentFilter === 'custom' ? endDateInput.value : ''; - console.log('showAllSupplies - 正在请求API:', url); - const response = await fetch(url, { - method: 'GET', - timeout: 10000, // 添加10秒超时设置 - headers: { - 'Content-Type': 'application/json' - } - }); + const supplies = await fetchSuppliesData(currentFilter, startDate, endDate); - // 检查响应状态 - if (!response.ok) { - throw new Error(`HTTP错误! 状态: ${response.status}`); - } + // 更新总数据量和总页数 + totalItems = supplies.length; + totalPages = Math.ceil(totalItems / pageSize); - const data = await response.json(); + console.log('showAllSupplies - 数据请求成功,总数量:', totalItems, '总页数:', totalPages); - console.log('showAllSupplies - API返回数据:', data); + // 渲染当前页数据 + renderSuppliesWithPagination(supplies); - // 仅在数据成功返回且有变化时才更新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 = '

加载货源数据失败,请稍后重试

'; - } - } + // 添加分页控件 + addPaginationControls(); } catch (error) { console.error('加载货源数据出错:', error); // 只在当前不是错误状态时才显示错误信息 @@ -1626,6 +1697,9 @@ // 保存当前正在显示的卖家ID currentSellerId = sellerId; + // 重置页码 + currentPage = 1; + // 获取当前筛选条件和日期范围 let startDate = ''; let endDate = ''; @@ -1637,87 +1711,68 @@ endDate = endDateInput.value; } - // 构建API请求URL,包含自定义日期参数 - let url = `/api/admin/supplies?sellerId=${sellerId}&filter=${filter}`; - if (filter === 'custom') { - if (startDate) url += `&startDate=${startDate}`; - if (endDate) url += `&endDate=${endDate}`; - } - // 显示加载状态 suppliesGrid.innerHTML = '

加载中...

'; try { - const response = await fetch(url, { - method: 'GET', - timeout: 10000, // 添加10秒超时设置 - headers: { - 'Content-Type': 'application/json' - } - }); + // 使用封装的API调用函数获取数据 + const supplies = await fetchSuppliesData(filter, startDate, endDate, sellerId); - // 检查响应状态 - if (!response.ok) { - throw new Error(`HTTP错误! 状态: ${response.status}`); + // 更新总数据量和总页数 + totalItems = supplies.length; + totalPages = Math.ceil(totalItems / pageSize); + + console.log('showSuppliesBySeller - 数据请求成功,总数量:', totalItems, '总页数:', totalPages); + + // 获取创建人的姓名 + let creatorName = ''; + + // 从chartData中查找对应的nickName + const chartItem = chartData.find(item => item.sellerId === sellerId); + if (chartItem && chartItem.nickName) { + creatorName = chartItem.nickName; + } + // 如果chartData中没有,从返回的supplies中获取 + else if (supplies.length > 0 && supplies[0].nickName) { + creatorName = supplies[0].nickName; } - const data = await response.json(); + // 构建标题 + let title = `${sellerId} 创建的货源`; + if (creatorName) { + title = `${creatorName} (${sellerId}) 创建的货源`; + } - if (data.success) { - // 获取创建人的姓名 - let creatorName = ''; - - // 从chartData中查找对应的nickName - const chartItem = chartData.find(item => item.sellerId === sellerId); - if (chartItem && chartItem.nickName) { - creatorName = chartItem.nickName; - } - // 如果chartData中没有,从返回的supplies中获取 - else if (data.data.supplies && data.data.supplies.length > 0 && data.data.supplies[0].nickName) { - creatorName = data.data.supplies[0].nickName; - } - - // 构建标题 - let title = `${sellerId} 创建的货源`; - if (creatorName) { - title = `${creatorName} (${sellerId}) 创建的货源`; - } - - // 添加"查看全部货源"按钮 - suppliesTitle.innerHTML = ` - ${title} - - `; - - // 为"查看全部货源"按钮添加点击事件 - document.getElementById('showAllBtn').addEventListener('click', showAllSupplies); - - renderSupplies(data.data.supplies); - - // 只有在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的display属性不是block时才设置,避免不必要的布局重排 - if (suppliesSection.style.display !== 'block') { - suppliesSection.style.display = 'block'; - } + // 添加"查看全部货源"按钮 + suppliesTitle.innerHTML = ` + ${title} + + `; + + // 为"查看全部货源"按钮添加点击事件 + document.getElementById('showAllBtn').addEventListener('click', showAllSupplies); + + // 渲染当前页数据 + renderSuppliesWithPagination(supplies); + + // 添加分页控件 + addPaginationControls(); + + // 只有在suppliesSection的display属性不是block时才设置,避免不必要的布局重排 + if (suppliesSection.style.display !== 'block') { + suppliesSection.style.display = 'block'; + // 只有在第一次显示suppliesSection时才滚动到该区域 + suppliesSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } catch (error) { console.error('加载货源数据出错:', error); @@ -1787,7 +1842,7 @@ mediaElement = ``; } else { // 图片文件 - mediaElement = `${supply.productName}`; + mediaElement = `${supply.productName}`; } } @@ -1982,6 +2037,608 @@ suppliesGrid.style.overflow = ''; window.scrollTo(0, scrollPosition); } + + // 创建货源卡片 + function createSupplyCard(supply) { + const card = document.createElement('div'); + card.className = 'supply-card'; + card.dataset.productId = supply.productId; // 添加产品ID作为数据属性 + + // 解析媒体URL + let mediaUrl = ''; + try { + // 使用更快的JSON.parse替代复杂的字符串处理 + const imageUrls = JSON.parse(supply.imageUrls || '[]'); + if (imageUrls && Array.isArray(imageUrls) && imageUrls.length > 0) { + mediaUrl = imageUrls[0]; + } + } catch (e) { + // 解析失败时不打印错误,避免性能影响 + } + + // 状态文本映射,避免switch语句 + const statusMap = { + 'published': '已发布', + 'sold_out': '已下架', + 'hidden': '已隐藏' + }; + const statusClass = `status-${supply.status}`; + const statusText = statusMap[supply.status] || '待审核'; + + // 检查是否为视频文件(使用更简单的正则表达式) + let mediaElement = ''; + if (mediaUrl) { + const isVideo = /\.(mp4|mov|avi|wmv|flv|webm|mkv)$/i.test(mediaUrl) || mediaUrl.startsWith('data:video/'); + if (isVideo) { + // 视频文件 + mediaElement = ``; + } else { + // 图片文件 + mediaElement = `${supply.productName}`; + } + } + + // 第一行展示:种类|蛋黄|货源类型|产品包装|新鲜程度 + 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 ? + `

${firstLineParts.join(' | ')}

` : ''; + + // 构建详细信息HTML + const detailsParts = []; + + // 产品ID + if (supply.productId) { + detailsParts.push(`

产品ID: ${supply.productId}

`); + } + + // 规格+件数+采购价+销售价组合展示 + const specifications = []; + if (supply.specification) { + if (typeof supply.specification === 'string') { + // 规格可能用逗号或中文逗号分隔 + specifications.push(...supply.specification.split(/[,,]/).filter(spec => spec.trim())); + } else if (Array.isArray(supply.specification)) { + specifications.push(...supply.specification); + } else { + specifications.push(String(supply.specification)); + } + } + + // 处理数量、采购价、销售价 + const quantities = Array.isArray(supply.quantity) ? supply.quantity : + (typeof supply.quantity === 'string' ? supply.quantity.split(',').filter(qty => qty.trim()) : + (supply.quantity ? [String(supply.quantity)] : [])); + + const costprices = Array.isArray(supply.costprice) ? supply.costprice : + (typeof supply.costprice === 'string' ? supply.costprice.split(',').filter(cp => cp.trim()) : + (supply.costprice ? [String(supply.costprice)] : [])); + + 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) { + const specDetails = []; + for (let i = 0; i < maxLength; i++) { + const spec = specifications[i] || ''; + const quantity = quantities[i] || ''; + const costprice = costprices[i] || ''; + const price = prices[i] || ''; + + // 只显示有数据的行 + if (spec || quantity || costprice || price) { + const parts = []; + if (spec) parts.push(`规格${i+1}: ${spec}`); + if (quantity) parts.push(`件数: ${quantity}件`); + if (costprice) parts.push(`采购价: ¥${costprice}`); + if (price) parts.push(`销售价: ¥${price}`); + + if (parts.length > 0) { + specDetails.push(`
${parts.join(' - ')}
`); + } + } + } + + if (specDetails.length > 0) { + detailsParts.push(`
${specDetails.join('')}
`); + } + } + + // 商品地区 + if (supply.region) { + detailsParts.push(`

商品地区: ${supply.region}

`); + } + + // 商品联系人和联系电话 + if (supply.product_contact || supply.contact_phone) { + let contactText = '商品联系人: '; + if (supply.product_contact) { + contactText += supply.product_contact; + } + if (supply.contact_phone) { + if (supply.product_contact) { + contactText += ` ${supply.contact_phone}`; + } else { + contactText += supply.contact_phone; + } + } + detailsParts.push(`

${contactText}

`); + } + + // 创建时间 + detailsParts.push(`

创建时间: ${new Date(supply.created_at).toLocaleString()}

`); + + // 修改时间 + if (supply.updated_at) { + detailsParts.push(`

修改时间: ${new Date(supply.updated_at).toLocaleString()}

`); + } + + // 货源描述(限制显示长度) + if (supply.description) { + const shortDesc = supply.description.length > 50 ? `${supply.description.substring(0, 50)}...` : supply.description; + detailsParts.push(`
货源描述:
${shortDesc}
`); + } + + // 价格变更日志 + let logHTML = `

价格变更日志

`; + + try { + let logs = []; + let hasLogs = false; + + // 检查product_log是否有值 + if (supply.product_log != null && supply.product_log != undefined && supply.product_log != '') { + // 有值,处理日志 + if (typeof supply.product_log === 'string') { + // 清理JSON字符串中的特殊字符 + const cleanLogStr = supply.product_log.replace(/\s+/g, ' ').trim(); + + // 检查是否为JSON格式 + if (cleanLogStr.startsWith('[') && cleanLogStr.endsWith(']')) { + try { + logs = JSON.parse(cleanLogStr); + } catch (parseError) { + // 解析失败,作为单个日志处理 + logs = [supply.product_log]; + } + } else { + // 不是JSON数组,作为单个日志处理 + logs = [supply.product_log]; + } + } else if (Array.isArray(supply.product_log)) { + logs = supply.product_log; + } else { + // 其他类型,转换为字符串数组 + logs = [String(supply.product_log)]; + } + + hasLogs = logs.length > 0; + } + + // 显示日志 + if (hasLogs) { + logs.forEach((log, index) => { + logHTML += `
日志${index + 1}${log}
`; + }); + } else { + // 没有日志,显示提示 + logHTML += `
暂无价格变更日志
`; + } + } catch (error) { + // 如果解析失败,直接显示日志内容 + logHTML += `
${supply.product_log || '暂无价格变更日志'}
`; + } + + logHTML += `
`; + detailsParts.push(logHTML); + + // 状态 + detailsParts.push(`${statusText}`); + + // 构建完整卡片HTML + card.innerHTML = ` +
+ ${mediaElement} +
${supply.productName}
+ ${firstLineHTML} +
+
+ ${detailsParts.join('')} +
+ `; + + return card; + } + + // 渲染带分页的货源卡片 + function renderSuppliesWithPagination(supplies) { + // 计算当前页的数据范围 + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + const currentPageSupplies = supplies.slice(startIndex, endIndex); + + if (currentPageSupplies.length === 0) { + suppliesGrid.innerHTML = '

暂无货源数据

'; + return; + } + + // 保存当前滚动位置 + const scrollPosition = window.pageYOffset || document.documentElement.scrollTop; + + // 检查是否启用虚拟滚动 + if (virtualScrollEnabled && currentPageSupplies.length > visibleCount + bufferCount * 2) { + // 使用虚拟滚动 + renderWithVirtualScroll(currentPageSupplies); + } else { + // 使用增量渲染 + const containerHeight = suppliesGrid.clientHeight; + suppliesGrid.style.height = `${containerHeight}px`; + suppliesGrid.style.overflow = 'hidden'; + incrementalRender(currentPageSupplies); + suppliesGrid.style.height = ''; + suppliesGrid.style.overflow = ''; + } + + // 恢复滚动位置 + window.scrollTo(0, scrollPosition); + } + + // 增量渲染函数 + function incrementalRender(supplies) { + // 创建一个Map来存储当前页的货源 + const currentSuppliesMap = new Map(); + supplies.forEach(supply => { + currentSuppliesMap.set(supply.productId, supply); + }); + + // 存储已存在的卡片 + const existingCards = new Map(); + Array.from(suppliesGrid.children).forEach(child => { + if (child.classList.contains('supply-card')) { + const productId = child.dataset.productId; + if (productId) { + existingCards.set(productId, child); + } + } + }); + + // 创建DocumentFragment,用于构建DOM结构,减少页面重排 + const fragment = document.createDocumentFragment(); + + // 遍历当前页的货源 + supplies.forEach(supply => { + const productId = supply.productId; + + if (existingCards.has(productId)) { + // 卡片已存在,检查是否需要更新 + const existingCard = existingCards.get(productId); + existingCards.delete(productId); // 标记为已处理 + + // 简单的更新检查:比较创建时间和修改时间 + const existingCreatedAt = existingCard.querySelector('.supply-info p:nth-child(6)')?.textContent; + const existingUpdatedAt = existingCard.querySelector('.supply-info p:nth-child(7)')?.textContent; + + const newCreatedAt = `创建时间: ${new Date(supply.created_at).toLocaleString()}`; + const newUpdatedAt = supply.updated_at ? `修改时间: ${new Date(supply.updated_at).toLocaleString()}` : ''; + + if (existingCreatedAt !== newCreatedAt || + (newUpdatedAt && existingUpdatedAt !== newUpdatedAt)) { + // 需要更新,替换为新卡片 + const newCard = createSupplyCard(supply); + fragment.appendChild(newCard); + existingCard.remove(); + } else { + // 不需要更新,保留原卡片 + fragment.appendChild(existingCard); + } + } else { + // 卡片不存在,创建新卡片 + const newCard = createSupplyCard(supply); + fragment.appendChild(newCard); + } + }); + + // 移除不再需要的卡片 + existingCards.forEach(card => { + card.remove(); + }); + + // 清空容器并添加新内容 + suppliesGrid.innerHTML = ''; + suppliesGrid.appendChild(fragment); + } + + // 添加分页控件 + function addPaginationControls() { + // 检查是否已经存在分页控件 + const existingPagination = document.querySelector('.pagination'); + if (existingPagination) { + existingPagination.remove(); + } + + // 如果只有一页,不需要分页控件 + if (totalPages <= 1) { + return; + } + + // 创建分页控件容器 + const pagination = document.createElement('div'); + pagination.className = 'pagination'; + pagination.style.cssText = ` + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + margin-top: 20px; + padding: 10px; + background-color: #f5f5f5; + border-radius: 8px; + `; + + // 添加首页按钮 + const firstBtn = document.createElement('button'); + firstBtn.textContent = '首页'; + firstBtn.style.cssText = ` + padding: 6px 12px; + background-color: #1677ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + `; + firstBtn.disabled = currentPage === 1; + firstBtn.addEventListener('click', () => { + if (currentPage > 1) { + currentPage = 1; + showCurrentPageData(); + } + }); + pagination.appendChild(firstBtn); + + // 添加上一页按钮 + const prevBtn = document.createElement('button'); + prevBtn.textContent = '上一页'; + prevBtn.style.cssText = ` + padding: 6px 12px; + background-color: #1677ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + `; + prevBtn.disabled = currentPage === 1; + prevBtn.addEventListener('click', () => { + if (currentPage > 1) { + currentPage--; + showCurrentPageData(); + } + }); + pagination.appendChild(prevBtn); + + // 添加页码按钮 + const maxVisiblePages = 5; + let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2)); + let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); + + // 调整起始页码,确保显示足够的页码 + if (endPage - startPage + 1 < maxVisiblePages) { + startPage = Math.max(1, endPage - maxVisiblePages + 1); + } + + for (let i = startPage; i <= endPage; i++) { + const pageBtn = document.createElement('button'); + pageBtn.textContent = i; + pageBtn.style.cssText = ` + padding: 6px 12px; + background-color: ${i === currentPage ? '#0958d9' : '#1677ff'}; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + `; + pageBtn.addEventListener('click', () => { + if (i !== currentPage) { + currentPage = i; + showCurrentPageData(); + } + }); + pagination.appendChild(pageBtn); + } + + // 添加下一页按钮 + const nextBtn = document.createElement('button'); + nextBtn.textContent = '下一页'; + nextBtn.style.cssText = ` + padding: 6px 12px; + background-color: #1677ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + `; + nextBtn.disabled = currentPage === totalPages; + nextBtn.addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage++; + showCurrentPageData(); + } + }); + pagination.appendChild(nextBtn); + + // 添加末页按钮 + const lastBtn = document.createElement('button'); + lastBtn.textContent = '末页'; + lastBtn.style.cssText = ` + padding: 6px 12px; + background-color: #1677ff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + `; + lastBtn.disabled = currentPage === totalPages; + lastBtn.addEventListener('click', () => { + if (currentPage < totalPages) { + currentPage = totalPages; + showCurrentPageData(); + } + }); + pagination.appendChild(lastBtn); + + // 添加页码信息 + const pageInfo = document.createElement('span'); + pageInfo.textContent = `第 ${currentPage} / ${totalPages} 页,共 ${totalItems} 条`; + pageInfo.style.cssText = ` + margin-left: 15px; + font-size: 14px; + color: #666; + `; + pagination.appendChild(pageInfo); + + // 添加到页面 + suppliesSection.appendChild(pagination); + } + + // 显示当前页数据 + async function showCurrentPageData() { + try { + const startDate = currentFilter === 'custom' ? startDateInput.value : ''; + const endDate = currentFilter === 'custom' ? endDateInput.value : ''; + + const supplies = await fetchSuppliesData(currentFilter, startDate, endDate, currentSellerId); + + // 预加载图片 + preloadImages(supplies); + + // 渲染当前页数据 + renderSuppliesWithPagination(supplies); + + // 更新分页控件 + addPaginationControls(); + } catch (error) { + console.error('加载当前页数据出错:', error); + } + } + + // 优化事件委托,减少事件监听器数量 + function optimizeEventListeners() { + // 使用事件委托处理图片点击事件 + suppliesGrid.addEventListener('click', function(e) { + const mediaElement = e.target.closest('.supply-media'); + if (mediaElement) { + if (mediaElement.tagName === 'IMG') { + const mediaUrl = mediaElement.src; + showPreview(mediaUrl); + } + } + }); + } + + // 预加载图片,提高用户体验 + function preloadImages(supplies) { + supplies.forEach(supply => { + try { + const imageUrls = JSON.parse(supply.imageUrls || '[]'); + if (imageUrls && Array.isArray(imageUrls) && imageUrls.length > 0) { + const img = new Image(); + img.src = imageUrls[0]; + } + } catch (e) { + // 解析失败,忽略 + } + }); + } + + // 虚拟滚动渲染函数 + function renderWithVirtualScroll(supplies) { + // 清空容器 + suppliesGrid.innerHTML = ''; + + // 设置容器样式 + suppliesGrid.style.cssText = ` + position: relative; + overflow-y: auto; + max-height: 800px; + `; + + // 创建一个容器来存放虚拟元素 + const virtualContainer = document.createElement('div'); + virtualContainer.style.cssText = ` + position: absolute; + top: 0; + left: 0; + width: 100%; + `; + suppliesGrid.appendChild(virtualContainer); + + // 创建占位元素,模拟整个列表的高度 + const placeholder = document.createElement('div'); + placeholder.style.cssText = ` + height: ${supplies.length * itemHeight}px; + width: 100%; + `; + virtualContainer.appendChild(placeholder); + + // 存储当前渲染的元素 + const renderedItems = new Map(); + + // 渲染可视区域内的元素 + function renderVisibleItems() { + // 获取容器的滚动位置和可视区域高度 + const scrollTop = suppliesGrid.scrollTop; + const containerHeight = suppliesGrid.clientHeight; + + // 计算应该渲染的元素范围 + const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferCount); + const endIndex = Math.min(supplies.length, Math.ceil((scrollTop + containerHeight) / itemHeight) + bufferCount); + + // 移除不在可视区域内的元素 + renderedItems.forEach((item, index) => { + if (index < startIndex || index >= endIndex) { + item.remove(); + renderedItems.delete(index); + } + }); + + // 渲染可视区域内的元素 + for (let i = startIndex; i < endIndex; i++) { + if (!renderedItems.has(i)) { + const supply = supplies[i]; + const item = createSupplyCard(supply); + item.style.cssText = ` + position: absolute; + top: ${i * itemHeight}px; + left: 0; + width: 100%; + height: ${itemHeight}px; + box-sizing: border-box; + `; + virtualContainer.appendChild(item); + renderedItems.set(i, item); + } + } + } + + // 初始渲染 + renderVisibleItems(); + + // 监听滚动事件,动态渲染元素 + suppliesGrid.addEventListener('scroll', renderVisibleItems); + } \ No newline at end of file