From 124940e772333583be584fd986135bea1d335ce2 Mon Sep 17 00:00:00 2001 From: Default User Date: Wed, 31 Dec 2025 17:14:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=8D=E5=88=B6=E8=B4=A7?= =?UTF-8?q?=E6=BA=90=E5=8A=9F=E8=83=BD=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=A4=8D=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Reject.js | 65 ++++++++++- supply.html | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 374 insertions(+), 14 deletions(-) diff --git a/Reject.js b/Reject.js index 9624567..54f4691 100644 --- a/Reject.js +++ b/Reject.js @@ -29,7 +29,8 @@ const dbConfig = { database: 'wechat_app', // 连接到wechat_app数据库 waitForConnections: true, connectionLimit: 10, - queueLimit: 0 + queueLimit: 0, + timezone: '+08:00' // 设置为北京时间时区 }; // userlogin数据库配置 @@ -40,7 +41,8 @@ const userLoginDbConfig = { database: 'userlogin', // 连接到userlogin数据库 waitForConnections: true, connectionLimit: 10, - queueLimit: 0 + queueLimit: 0, + timezone: '+08:00' // 设置为北京时间时区 }; // 创建数据库连接池 @@ -373,7 +375,13 @@ app.post('/api/login', async (req, res) => { return sendResponse(res, false, null, '职位名称、用户名和密码不能为空'); } - // 1. 在login表中验证登录信息 + // 1. 验证职位名称是否为允许的类型 + const allowedProjectNames = ['采购员', '管理员']; + if (!allowedProjectNames.includes(projectName)) { + return sendResponse(res, false, null, '仅允许采购员和管理员登录'); + } + + // 2. 在login表中验证登录信息 const userLoginConnection = await userLoginPool.getConnection(); const [loginResult] = await userLoginConnection.query( 'SELECT id, projectName, userName, managerId FROM login WHERE projectName = ? AND userName = ? AND password = ?', @@ -712,6 +720,18 @@ app.post('/api/supplies/create', async (req, res) => { sellerId = 'default_seller'; } + // 检查是否为重复货源 + console.log('检查是否为重复货源...'); + const [existingProducts] = await connection.query( + 'SELECT id FROM products WHERE productName = ? AND specification = ? AND region = ? AND price = ? AND yolk = ?', + [productName, specification, region, price, yolk] + ); + + if (existingProducts.length > 0) { + connection.release(); + return sendResponse(res, false, null, '检测到重复的货源数据,不允许创建'); + } + // 处理联系人信息 let productContact = ''; let contactPhone = ''; @@ -1024,7 +1044,7 @@ app.put('/api/supplies/:id/edit', async (req, res) => { try { const connection = await pool.getConnection(); const productId = req.params.id; - const { productName, price, quantity, grossWeight, yolk, specification, supplyStatus, description, region, contactId, producting } = req.body; + const { productName, price, quantity, grossWeight, yolk, specification, supplyStatus, description, region, contactId, producting, imageUrls } = req.body; // 开始事务 await connection.beginTransaction(); @@ -1059,19 +1079,52 @@ app.put('/api/supplies/:id/edit', async (req, res) => { } } + // 处理图片上传 + let uploadedImageUrls = []; + if (Array.isArray(imageUrls) && imageUrls.length > 0) { + console.log('开始处理编辑图片上传,共', imageUrls.length, '张图片'); + + for (const imageUrl of imageUrls) { + if (imageUrl.startsWith('data:image/')) { + // 处理DataURL + const base64Data = imageUrl.replace(/^data:image\/(png|jpeg|jpg|gif);base64,/, ''); + let buffer = Buffer.from(base64Data, 'base64'); + const ext = imageUrl.match(/^data:image\/(png|jpeg|jpg|gif);base64,/)?.[1] || 'png'; + const filename = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}.${ext}`; + + try { + // 不再添加水印,前端已处理 + console.log('【水印处理】前端已添加水印,跳过后端水印处理'); + + // 使用OSS上传带水印的图片 + const ossUrl = await OssUploader.uploadBuffer(buffer, filename, `products/${productName || 'general'}`, 'image'); + uploadedImageUrls.push(ossUrl); + console.log('图片上传成功:', ossUrl); + } catch (uploadError) { + console.error('图片上传失败:', uploadError.message); + // 继续上传其他图片,不中断流程 + } + } else { + // 已经是URL,直接使用 + uploadedImageUrls.push(imageUrl); + } + } + console.log('图片处理完成,成功上传', uploadedImageUrls.length, '张图片'); + } + // 更新货源信息 const updateQuery = ` UPDATE products SET productName = ?, price = ?, quantity = ?, grossWeight = ?, yolk = ?, specification = ?, producting = ?, supplyStatus = ?, description = ?, region = ?, - product_contact = ?, contact_phone = ? + product_contact = ?, contact_phone = ?, imageUrls = ? WHERE id = ? `; await connection.query(updateQuery, [ productName, price.toString(), parseInt(quantity), grossWeight, yolk, specification, producting, supplyStatus, description, region, - productContact, contactPhone, productId + productContact, contactPhone, JSON.stringify(uploadedImageUrls), productId ]); // 提交事务 diff --git a/supply.html b/supply.html index 962c56d..9ee5434 100644 --- a/supply.html +++ b/supply.html @@ -267,6 +267,23 @@ background-color: #8c8c8c; } + .copy-supply-btn { + display: inline-block; + padding: 4px 12px; + border: 1px solid #d9d9d9; + border-radius: 4px; + font-size: 12px; + background-color: #fff; + color: #333; + cursor: pointer; + margin-left: 8px; + } + + .copy-supply-btn:hover { + border-color: #1677ff; + color: #1677ff; + } + .supply-details { display: grid; grid-template-columns: repeat(2, 1fr); @@ -464,6 +481,29 @@ transition: all 0.3s; } + .delete-image-btn { + position: absolute; + top: 5px; + right: 5px; + width: 24px; + height: 24px; + background-color: rgba(245, 34, 45, 0.9); + color: white; + border: none; + border-radius: 50%; + font-size: 16px; + line-height: 20px; + text-align: center; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + } + + .delete-image-btn:hover { + background-color: #f5222d; + } + .upload-image:hover { transform: scale(1.05); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); @@ -1066,7 +1106,7 @@
3. 敲开鸡蛋后清晰显示蛋清、蛋黄状态,以体现新鲜度;
4. 其他能佐证蛋重、品种的辅助图片。
-
最多上传5张图片
+
最多上传2张图片
@@ -1435,7 +1475,11 @@
-
提示:图片暂不支持编辑
+
最多上传2张图片
+ + @@ -1793,6 +1837,7 @@ let editFilteredProductingOptions = [...editAllProductingOptions]; let editSelectedProducting = ''; let editFilteredContacts = []; + let editCurrentImages = []; // 编辑时当前的图片列表 let editSelectedContactId = ''; // 联系人数据 @@ -1918,8 +1963,8 @@ // 处理拖拽或粘贴的图片 async function handleDroppedImages(imageFiles) { for (let i = 0; i < imageFiles.length; i++) { - if (supplyData.uploadedImages.length >= 5) { - alert('最多只能上传5张图片'); + if (supplyData.uploadedImages.length >= 2) { + alert('最多只能上传2张图片'); break; } @@ -3448,6 +3493,7 @@
${supply.productName} ${status.text} +
蛋黄: ${supply.yolk || '无'}
@@ -3475,6 +3521,183 @@ return `${date.getFullYear()}/${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; } + // 复制货源信息 + function copySupply(supplyId) { + try { + // 查找对应的货源信息 + let supply = null; + + // 1. 首先尝试直接从所有货源数组中查找 + if (supplyData.supplies && supplyData.supplies.length > 0) { + supply = supplyData.supplies.find(item => { + return String(item.id) === String(supplyId) || String(item.productId) === String(supplyId) || String(item._id) === String(supplyId); + }); + } + + // 2. 如果没找到,遍历所有状态的货源列表查找 + if (!supply) { + const allSupplies = [ + ...supplyData.publishedSupplies, + ...supplyData.pendingSupplies, + ...supplyData.rejectedSupplies, + ...supplyData.draftSupplies + ]; + + supply = allSupplies.find(item => { + return String(item.id) === String(supplyId) || String(item.productId) === String(supplyId) || String(item._id) === String(supplyId); + }); + } + + // 3. 如果没找到,遍历所有分页货源列表查找 + if (!supply) { + const paginatedSupplies = [ + ...(supplyData.paginatedSupplies.published || []), + ...(supplyData.paginatedSupplies.pending || []), + ...(supplyData.paginatedSupplies.rejected || []), + ...(supplyData.paginatedSupplies.draft || []) + ]; + + supply = paginatedSupplies.find(item => { + return String(item.id) === String(supplyId) || String(item.productId) === String(supplyId) || String(item._id) === String(supplyId); + }); + } + + // 4. 如果还是没找到,尝试从DOM中获取 + if (!supply) { + const supplyItem = document.querySelector(`[data-id="${supplyId}"]`); + if (supplyItem) { + // 从DOM中提取关键信息 + const productName = supplyItem.querySelector('.supply-name').textContent.replace(/已上架|审核中|审核失败|已隐藏|已下架|复制/g, '').trim(); + const priceText = supplyItem.querySelector('.detail-item:last-child').textContent; + const price = priceText.replace(/价格: ¥/, '').trim(); + + // 创建一个简化的supply对象 + supply = { + id: supplyId, + productName: productName, + price: price + }; + } + } + + // 调试日志 + console.log('复制货源信息:', { + supplyId: supplyId, + supplyFound: !!supply, + allSuppliesCount: (supplyData.supplies ? supplyData.supplies.length : 0) + + supplyData.publishedSupplies.length + + supplyData.pendingSupplies.length + + supplyData.rejectedSupplies.length + + supplyData.draftSupplies.length, + paginatedSuppliesCount: + (supplyData.paginatedSupplies.published ? supplyData.paginatedSupplies.published.length : 0) + + (supplyData.paginatedSupplies.pending ? supplyData.paginatedSupplies.pending.length : 0) + + (supplyData.paginatedSupplies.rejected ? supplyData.paginatedSupplies.rejected.length : 0) + + (supplyData.paginatedSupplies.draft ? supplyData.paginatedSupplies.draft.length : 0), + supplyDataKeys: supply ? Object.keys(supply) : 'none', + supplyData: supply + }); + + if (!supply) { + alert('未找到对应的货源信息'); + return; + } + + // 保存到全局变量 + supplyData.copiedSupply = supply; + + // 打开创建货源弹窗 + showAddSupplyModal(); + + // 填充表单数据 + fillFormWithSupplyData(supply); + + alert('货源信息已复制到创建表单'); + } catch (error) { + console.error('复制货源失败:', error); + alert('复制货源失败,请重试'); + } + } + + // 用货源数据填充表单 + function fillFormWithSupplyData(supply) { + // 重置表单 + resetForm(); + + // 填充表单字段 + document.getElementById('price').value = supply.price || ''; + document.getElementById('quantity').value = supply.quantity || ''; + document.getElementById('grossWeight').value = supply.grossWeight || ''; + document.getElementById('description').value = supply.description || ''; + + // 填充选择字段 + // 商品名称 + document.getElementById('productName').value = supply.productName || ''; + document.getElementById('productNameDisplayText').textContent = supply.productName || '请选择商品名称'; + selectedProductName = supply.productName || ''; + + // 货源类型 + document.getElementById('sourceType').value = supply.sourceType || ''; + document.getElementById('sourceTypeDisplayText').textContent = supply.sourceType || '请选择货源类型'; + selectedSourceType = supply.sourceType || ''; + + // 蛋黄类型 + document.getElementById('yolk').value = supply.yolk || ''; + document.getElementById('yolkDisplayText').textContent = supply.yolk || '请选择蛋黄类型'; + selectedYolk = supply.yolk || ''; + + // 地区 + document.getElementById('regionValue').value = supply.region || ''; + document.getElementById('regionDisplayText').textContent = supply.region || '请选择地区'; + + // 规格 + document.getElementById('specValue').value = supply.specification || supply.spec || ''; + document.getElementById('specDisplayText').textContent = (supply.specification || supply.spec) || '请选择规格'; + selectedSpec = supply.specification || supply.spec || ''; + + // 货源状态 + document.getElementById('supplyStatus').value = supply.supplyStatus || ''; + + // 联系人 + document.getElementById('contactId').value = supply.contactId || ''; + document.getElementById('contactIdDisplayText').textContent = supply.product_contact || '请选择联系人'; + selectedContactId = supply.contactId || ''; + + // 产品包装 + document.getElementById('productingValue').value = supply.producting || ''; + document.getElementById('productingDisplayText').textContent = supply.producting || '请选择产品包装'; + selectedProducting = supply.producting || ''; + + // 不复制图片,保持图片列表为空 + supplyData.uploadedImages = []; + renderUploadedImages(); + } + + // 检查是否为重复货源 + async function checkDuplicateSupply(formData) { + try { + // 构建查询参数 + const queryParams = new URLSearchParams({ + productName: formData.productName, + spec: formData.specification || formData.spec, + region: formData.region, + price: formData.price, + checkDuplicate: true + }); + + const response = await fetch(`/api/supplies?${queryParams}`); + const result = await response.json(); + + if (result.success && result.data && result.data.length > 0) { + return true; // 存在重复货源 + } + return false; // 不存在重复货源 + } catch (error) { + console.error('检查重复货源失败:', error); + return false; // 出错时默认允许创建 + } + } + // 切换列表展开/折叠 function toggleSection(type) { const listElement = document.getElementById(`${type}List`); @@ -3730,6 +3953,78 @@ document.getElementById('imageUpload').click(); } + // 触发编辑页面图片上传 + function triggerEditImageUpload() { + document.getElementById('editImageUpload').click(); + } + + // 处理编辑页面图片上传 + function handleEditImageUpload(event) { + const files = event.target.files; + const editUploadImages = document.getElementById('editUploadImages'); + + for (let i = 0; i < files.length; i++) { + if (editCurrentImages.length >= 2) { + alert('最多只能上传2张图片'); + break; + } + + const file = files[i]; + const reader = new FileReader(); + + reader.onload = async function(e) { + let imageUrl = e.target.result; + + try { + // 为图片添加水印 + imageUrl = await addWatermarkToImage(imageUrl); + + // 添加到当前图片列表 + editCurrentImages.push(imageUrl); + + // 更新显示 + updateEditImageDisplay(); + } catch (error) { + console.error('图片处理失败:', error); + alert('图片处理失败,请重试'); + } + }; + + reader.readAsDataURL(file); + } + + // 清空文件输入,以便再次选择同一文件 + event.target.value = ''; + } + + // 删除编辑页面图片 + function deleteEditImage(imageUrl) { + // 从当前图片列表中删除 + const index = editCurrentImages.indexOf(imageUrl); + if (index > -1) { + editCurrentImages.splice(index, 1); + } + + // 更新显示 + updateEditImageDisplay(); + } + + // 更新编辑页面图片显示 + function updateEditImageDisplay() { + const editUploadImages = document.getElementById('editUploadImages'); + editUploadImages.innerHTML = ''; + + editCurrentImages.forEach(imageUrl => { + const imageElement = document.createElement('div'); + imageElement.className = 'upload-image'; + imageElement.innerHTML = ` + 商品图片 + + `; + editUploadImages.appendChild(imageElement); + }); + } + // 为图片添加水印(前端Canvas实现) function addWatermarkToImage(imageUrl) { return new Promise((resolve, reject) => { @@ -3783,8 +4078,8 @@ const uploadArea = document.getElementById('uploadImages'); for (let i = 0; i < files.length; i++) { - if (supplyData.uploadedImages.length >= 5) { - alert('最多只能上传5张图片'); + if (supplyData.uploadedImages.length >= 2) { + alert('最多只能上传2张图片'); break; } @@ -4172,6 +4467,13 @@ return; } + // 检查是否为重复货源 + const isDuplicate = await checkDuplicateSupply(formData); + if (isDuplicate) { + alert('检测到重复的货源数据,不允许创建'); + return; + } + try { // 设置为提交中状态,禁用按钮 isSubmitting = true; @@ -4680,16 +4982,20 @@ const editUploadImages = document.getElementById('editUploadImages'); editUploadImages.innerHTML = ''; if (supply.imageUrls && Array.isArray(supply.imageUrls)) { - supply.imageUrls.forEach(imageUrl => { + supply.imageUrls.forEach((imageUrl, index) => { const imageElement = document.createElement('div'); imageElement.className = 'upload-image'; imageElement.innerHTML = ` 商品图片 + `; editUploadImages.appendChild(imageElement); }); } + // 保存当前图片列表到全局变量,用于编辑时使用 + editCurrentImages = supply.imageUrls && Array.isArray(supply.imageUrls) ? [...supply.imageUrls] : []; + // 根据模式修改保存按钮文本 const saveButton = document.querySelector('#editSupplyModal .modal-btn-primary'); if (saveButton) { @@ -5470,7 +5776,8 @@ supplyStatus: document.getElementById('editSupplyStatus').value, description: document.getElementById('editDescription').value, region: document.getElementById('editRegionValue').value, - contactId: document.getElementById('editContactId').value + contactId: document.getElementById('editContactId').value, + imageUrls: editCurrentImages // 添加编辑后的图片列表 }; // 验证表单