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 // 添加编辑后的图片列表
};
// 验证表单