From fd310a28814ea7bb21eda0f155cf6dfe1f9066ea Mon Sep 17 00:00:00 2001 From: Default User Date: Mon, 12 Jan 2026 14:55:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E9=A1=B5=E9=9D=A2=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Management.html | 1132 +++++++++++++++++++++++++++++++++++++++++++++++ Reject.html | 19 + Reject.js | 197 ++++++++- login.html | 14 +- supply.html | 52 ++- 5 files changed, 1401 insertions(+), 13 deletions(-) create mode 100644 Management.html diff --git a/Management.html b/Management.html new file mode 100644 index 0000000..879a002 --- /dev/null +++ b/Management.html @@ -0,0 +1,1132 @@ + + + + + + 管理货源页面 + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +

管理员统计页面

+
+
+ + + + + + +
+ + - + + +
+
+
+ +
+
+
+
0
+
总货源数
+
+
+
0
+
活跃用户数
+
+
+
0
+
人均创建数
+
+
+
+ +
+

用户创建货源统计

+
+ +
+
+ + +
+ + + + \ No newline at end of file diff --git a/Reject.html b/Reject.html index 8f7739f..5e7915b 100644 --- a/Reject.html +++ b/Reject.html @@ -1038,6 +1038,7 @@ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; "> + @@ -1308,6 +1309,18 @@ window.location.href = 'login.html'; }); + // 根据角色控制货源管理按钮的显示 + const managementBtnEl = document.getElementById('managementBtn'); + if (managementBtnEl) { + if (parsedUserInfo.projectName === '管理员') { + // 管理员显示按钮 + managementBtnEl.style.display = 'block'; + } else { + // 非管理员隐藏按钮 + managementBtnEl.style.display = 'none'; + } + } + return true; } @@ -1343,6 +1356,7 @@ const statusBtns = document.querySelectorAll('.status-btn'); // 创建货源相关DOM元素 const createSupplyBtnEl = document.getElementById('createSupplyBtn'); + const managementBtnEl = document.getElementById('managementBtn'); const createSupplyModalEl = document.getElementById('createSupplyModal'); const supplyNameEl = document.getElementById('supplyName'); const supplyPriceEl = document.getElementById('supplyPrice'); @@ -1555,6 +1569,11 @@ } }); + // 货源管理按钮点击事件 - 跳转到Management.html页面 + managementBtnEl.addEventListener('click', () => { + window.location.href = 'Management.html'; + }); + // 创建货源按钮点击事件 - 跳转到supply.html页面 createSupplyBtnEl.addEventListener('click', () => { window.location.href = 'supply.html'; diff --git a/Reject.js b/Reject.js index 45ae2c1..234e554 100644 --- a/Reject.js +++ b/Reject.js @@ -104,7 +104,7 @@ setInterval(async () => { // 批量更新商品状态为sold_out for (const product of productsToOffline) { await connection.query( - 'UPDATE products SET status = ?, updated_at = NOW() WHERE id = ?', + 'UPDATE products SET status = ?, label = 1, updated_at = NOW() WHERE id = ?', ['sold_out', product.id] ); @@ -1320,11 +1320,18 @@ app.put('/api/supplies/:id', async (req, res) => { return sendResponse(res, false, null, '货源不存在'); } - // 更新状态 - await connection.query( - 'UPDATE products SET status = ?, updated_at = NOW() WHERE id = ?', - [status, productId] - ); + // 更新状态,当状态为sold_out时同时锁定label + if (status === 'sold_out') { + await connection.query( + 'UPDATE products SET status = ?, label = 1, updated_at = NOW() WHERE id = ?', + [status, productId] + ); + } else { + await connection.query( + 'UPDATE products SET status = ?, updated_at = NOW() WHERE id = ?', + [status, productId] + ); + } // 提交事务 await connection.commit(); @@ -1631,9 +1638,183 @@ app.get('/api/suppliers', async (req, res) => { } }); -// 首页路由 +// 管理员统计 - 获取货源创建统计数据 +app.get('/api/admin/stats/supplies', async (req, res) => { + try { + const { filter } = req.query; + const connection = await pool.getConnection(); + + // 计算时间范围 + let timeCondition = ''; + const now = new Date(); + + if (filter === 'today') { + // 今天 + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + timeCondition = `AND created_at >= '${today.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'yesterday') { + // 昨天 + const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + timeCondition = `AND created_at >= '${yesterday.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at < '${today.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'beforeYesterday') { + // 前天 + const beforeYesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 2); + const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1); + timeCondition = `AND created_at >= '${beforeYesterday.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at < '${yesterday.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'week') { + // 本周 + const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + timeCondition = `AND created_at >= '${weekAgo.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'month') { + // 本月 + const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); + timeCondition = `AND created_at >= '${monthAgo.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'custom') { + // 自定义时间范围 + const { startDate, endDate } = req.query; + if (startDate) { + // 开始日期,格式化为YYYY-MM-DD 00:00:00 + const start = new Date(startDate); + start.setHours(0, 0, 0, 0); + timeCondition += `AND created_at >= '${start.toISOString().slice(0, 19).replace('T', ' ')}'`; + } + if (endDate) { + // 结束日期,格式化为YYYY-MM-DD 23:59:59 + const end = new Date(endDate); + end.setHours(23, 59, 59, 999); + timeCondition += `AND created_at <= '${end.toISOString().slice(0, 19).replace('T', ' ')}'`; + } + } + + // 获取每个卖家创建的货源数量,关联users表获取nickName + // 替换created_at为p.created_at,避免歧义 + const chartTimeCondition = timeCondition.replace(/created_at/g, 'p.created_at'); + const [chartData] = await connection.query(` + SELECT p.sellerId, u.nickName, COUNT(*) as count + FROM products p + LEFT JOIN users u ON p.sellerId = u.userId + WHERE 1=1 ${chartTimeCondition} + GROUP BY p.sellerId, u.nickName + ORDER BY count DESC + `); + + // 获取总体统计信息 + const [totalSuppliesResult] = await connection.query(` + SELECT COUNT(*) as total FROM products WHERE 1=1 ${timeCondition} + `); + const totalSupplies = totalSuppliesResult[0].total; + + const [totalUsersResult] = await connection.query(` + SELECT COUNT(DISTINCT sellerId) as total FROM products WHERE 1=1 ${timeCondition} + `); + const totalUsers = totalUsersResult[0].total; + + const avgPerUser = totalUsers > 0 ? totalSupplies / totalUsers : 0; + + connection.release(); + + sendResponse(res, true, { + chartData, + stats: { + totalSupplies, + totalUsers, + avgPerUser + } + }, '获取统计数据成功'); + } catch (error) { + console.error('获取统计数据失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '获取统计数据失败'); + } +}); + +// 管理员统计 - 获取指定卖家的货源列表 +app.get('/api/admin/supplies', async (req, res) => { + try { + const { sellerId, filter } = req.query; + const connection = await pool.getConnection(); + + // 计算时间范围 + let timeCondition = ''; + const now = new Date(); + + if (filter === 'today') { + // 今天 + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + timeCondition = `AND created_at >= '${today.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'yesterday') { + // 昨天 + const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + timeCondition = `AND created_at >= '${yesterday.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at < '${today.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'beforeYesterday') { + // 前天 + const beforeYesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 2); + const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1); + timeCondition = `AND created_at >= '${beforeYesterday.toISOString().slice(0, 19).replace('T', ' ')}' AND created_at < '${yesterday.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'week') { + // 本周 + const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + timeCondition = `AND created_at >= '${weekAgo.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'month') { + // 本月 + const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); + timeCondition = `AND created_at >= '${monthAgo.toISOString().slice(0, 19).replace('T', ' ')}'`; + } else if (filter === 'custom') { + // 自定义时间范围 + const { startDate, endDate } = req.query; + if (startDate) { + // 开始日期,格式化为YYYY-MM-DD 00:00:00 + const start = new Date(startDate); + start.setHours(0, 0, 0, 0); + timeCondition += `AND created_at >= '${start.toISOString().slice(0, 19).replace('T', ' ')}'`; + } + if (endDate) { + // 结束日期,格式化为YYYY-MM-DD 23:59:59 + const end = new Date(endDate); + end.setHours(23, 59, 59, 999); + timeCondition += `AND created_at <= '${end.toISOString().slice(0, 19).replace('T', ' ')}'`; + } + } + + // 获取指定卖家的货源列表,关联users表获取创建人姓名 + // 替换created_at为p.created_at,避免歧义 + const suppliesTimeCondition = timeCondition.replace(/created_at/g, 'p.created_at'); + const [supplies] = await connection.query(` + SELECT p.*, u.nickName + FROM products p + LEFT JOIN users u ON p.sellerId = u.userId + WHERE p.sellerId = ? ${suppliesTimeCondition} + ORDER BY p.created_at DESC + `, [sellerId]); + + connection.release(); + + sendResponse(res, true, { supplies }, '获取货源列表成功'); + } catch (error) { + console.error('获取货源列表失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '获取货源列表失败'); + } +}); + +// 首页路由 - 根据角色重定向 app.get('/', (req, res) => { - res.sendFile(path.join(__dirname, 'Reject.html')); + // 注意:这里无法直接获取localStorage中的用户信息,因为localStorage是客户端的 + // 实际生产环境中,应该通过cookie或token来获取用户角色信息 + // 这里我们默认跳转到登录页面,让客户端处理角色跳转 + res.sendFile(path.join(__dirname, 'login.html')); +}); + +// 管理员统计页面路由 +app.get('/admin-stats', (req, res) => { + res.sendFile(path.join(__dirname, 'Management.html')); +}); + +// 货源管理页面路由 +app.get('/management', (req, res) => { + res.sendFile(path.join(__dirname, 'Management.html')); }); // 错误处理中间件 diff --git a/login.html b/login.html index 1c14435..a23655d 100644 --- a/login.html +++ b/login.html @@ -227,8 +227,18 @@ localStorage.setItem('userInfo', JSON.stringify(result.data.userInfo)); localStorage.setItem('token', result.data.token); - // 跳转到审核页面 - window.location.href = 'Reject.html'; + // 根据角色跳转到不同页面 + const userInfo = result.data.userInfo; + if (userInfo.projectName === '管理员') { + // 管理员跳转到管理页面 + window.location.href = 'Management.html'; + } else if (userInfo.projectName === '采购员') { + // 采购员跳转到供应页面 + window.location.href = 'supply.html'; + } else { + // 其他角色默认跳转到审核页面 + window.location.href = 'Reject.html'; + } } else { // 登录失败 loginError.textContent = result.message || '登录失败,请检查用户名和密码'; diff --git a/supply.html b/supply.html index b3ed115..77ff557 100644 --- a/supply.html +++ b/supply.html @@ -5023,8 +5023,45 @@ if (freshnessDisplay) freshnessDisplay.textContent = supply.freshness || '请选择新鲜程度'; selectedFreshness = supply.freshness || ''; - // 复制图片 - supplyData.uploadedImages = supply.images || supply.imageUrls || supply.imageList || []; + // 复制图片/视频,确保正确解析JSON字符串 + let mediaUrls = []; + console.log('复制货源时的imageUrls数据:', supply.imageUrls); + console.log('复制货源时的imageUrls类型:', typeof supply.imageUrls); + + if (supply.images) { + mediaUrls = Array.isArray(supply.images) ? supply.images : []; + console.log('使用supply.images:', mediaUrls); + } else if (supply.imageUrls) { + if (Array.isArray(supply.imageUrls)) { + mediaUrls = supply.imageUrls; + console.log('imageUrls是数组:', mediaUrls); + } else if (typeof supply.imageUrls === 'string') { + // 尝试解析JSON字符串 + try { + console.log('尝试解析JSON字符串:', supply.imageUrls); + mediaUrls = JSON.parse(supply.imageUrls); + console.log('解析结果:', mediaUrls); + // 确保解析后是数组 + if (!Array.isArray(mediaUrls)) { + console.log('解析结果不是数组,重置为空数组'); + mediaUrls = []; + } + } catch (e) { + console.error('解析imageUrls失败:', e); + mediaUrls = []; + } + } + } else if (supply.imageList) { + mediaUrls = Array.isArray(supply.imageList) ? supply.imageList : []; + console.log('使用supply.imageList:', mediaUrls); + } + + console.log('最终的mediaUrls:', mediaUrls); + console.log('mediaUrls类型:', typeof mediaUrls); + console.log('mediaUrls是否为数组:', Array.isArray(mediaUrls)); + + supplyData.uploadedImages = mediaUrls; + console.log('supplyData.uploadedImages:', supplyData.uploadedImages); renderUploadedImages(); // 规格、件数和采购价 - 支持中文逗号分隔和英文逗号分隔字符串 @@ -5662,19 +5699,28 @@ const uploadArea = document.getElementById('uploadImages'); uploadArea.innerHTML = ''; + console.log('renderUploadedImages被调用,mediaUrls:', supplyData.uploadedImages); + supplyData.uploadedImages.forEach((mediaUrl, index) => { + console.log('处理媒体URL:', mediaUrl, '索引:', index); + const mediaElement = document.createElement('div'); mediaElement.className = 'upload-image'; let mediaContent; - if (mediaUrl.startsWith('data:video/')) { + // 检查是否为视频文件(支持data:video/和普通视频URL) + const isVideo = mediaUrl.startsWith('data:video/') || mediaUrl.match(/\.(mp4|mov|avi|wmv|flv|webm|mkv)$/i); + + if (isVideo) { // 视频文件 + console.log('检测到视频URL:', mediaUrl); mediaContent = `
`; } else { // 图片文件 + console.log('检测到图片URL:', mediaUrl); mediaContent = ` 商品图片