// ECS服务器示例代码 - Node.js版 (MySQL版本) const express = require('express'); const crypto = require('crypto'); const bodyParser = require('body-parser'); const { Sequelize, DataTypes, Model, Op } = require('sequelize'); require('dotenv').config(); // 创建Express应用 const app = express(); const PORT = process.env.PORT || 3002; // 中间件 app.use(bodyParser.json()); // 添加请求日志中间件,捕获所有到达服务器的请求(必须放在bodyParser之后) app.use((req, res, next) => { // 将UTC时间转换为北京时间(UTC+8) const now = new Date(); const beijingTime = new Date(now.getTime() + 8 * 60 * 60 * 1000); const formattedTime = beijingTime.toISOString().replace('Z', '+08:00'); console.log(`[${formattedTime}] 收到请求: ${req.method} ${req.url}`); console.log('请求头:', req.headers); console.log('请求体:', req.body); next(); }); // 商品毛重处理中间件 - 确保所有返回的商品数据中毛重字段保持原始值 app.use((req, res, next) => { // 保存原始的json方法 const originalJson = res.json; // 重写json方法来处理响应数据 res.json = function (data) { // 检查数据中是否包含商品列表 if (data && typeof data === 'object') { // 处理/products/list接口的响应 if (data.products && Array.isArray(data.products)) { data.products = data.products.map(product => { // 保持毛重字段的原始值,只做类型转换确保是数字 if (product.grossWeight === null || product.grossWeight === undefined || product.grossWeight === '') { product.grossWeight = 0; // 空值设置为0 } else { product.grossWeight = parseFloat(product.grossWeight); } return product; }); } // 处理/data字段中的商品列表 if (data.data && data.data.products && Array.isArray(data.data.products)) { data.data.products = data.data.products.map(product => { // 保持毛重字段的原始值,只做类型转换确保是数字 if (product.grossWeight === null || product.grossWeight === undefined || product.grossWeight === '') { product.grossWeight = 0; // 空值设置为0 } else { product.grossWeight = parseFloat(product.grossWeight); } return product; }); } } // 调用原始的json方法 return originalJson.call(this, data); }; next(); }); // MySQL数据库连接配置 const sequelize = new Sequelize( process.env.DB_DATABASE || 'wechat_app', process.env.DB_USER || 'root', process.env.DB_PASSWORD === undefined ? null : process.env.DB_PASSWORD, { host: process.env.DB_HOST || 'localhost', port: process.env.DB_PORT || 3306, dialect: 'mysql', pool: { max: 10, min: 0, acquire: 30000, idle: 10000 } } ); // 微信小程序配置 const WECHAT_CONFIG = { APPID: process.env.WECHAT_APPID || 'your-wechat-appid', APPSECRET: process.env.WECHAT_APPSECRET || 'your-wechat-appsecret', TOKEN: process.env.WECHAT_TOKEN || 'your-wechat-token' }; // 显示当前使用的数据库配置(用于调试) console.log('当前数据库连接配置:'); console.log(' 主机:', process.env.DB_HOST || 'localhost'); console.log(' 端口:', process.env.DB_PORT || 3306); console.log(' 数据库名:', process.env.DB_DATABASE || 'wechat_app'); console.log(' 用户名:', process.env.DB_USER || 'root'); console.log(' 密码:', process.env.DB_PASSWORD === undefined || process.env.DB_PASSWORD === '' ? '无密码' : '******'); // 测试数据库连接 async function testDbConnection() { try { await sequelize.authenticate(); console.log('数据库连接成功'); } catch (error) { console.error('数据库连接失败:', error); console.error('\n请检查以下几点:'); console.error('1. MySQL服务是否已经启动'); console.error('2. wechat_app数据库是否已创建'); console.error('3. .env文件中的数据库用户名和密码是否正确'); console.error('4. 用户名是否有足够的权限访问数据库'); console.error('\n如果是首次配置,请参考README文件中的数据库设置指南。'); process.exit(1); } } testDbConnection(); // 定义数据模型 // 用户模型 class User extends Model { } User.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, openid: { type: DataTypes.STRING(100), allowNull: false }, userId: { type: DataTypes.STRING(100), allowNull: false, unique: true }, nickName: { type: DataTypes.STRING(100), allowNull: false // 微信名,必填 }, avatarUrl: { type: DataTypes.TEXT }, phoneNumber: { type: DataTypes.STRING(20), allowNull: false // 电话号码,必填 }, type: { type: DataTypes.STRING(20), allowNull: false // 用户身份(buyer/seller/both),必填 }, gender: { type: DataTypes.INTEGER }, country: { type: DataTypes.STRING(50) }, province: { type: DataTypes.STRING(50) }, city: { type: DataTypes.STRING(50) }, language: { type: DataTypes.STRING(20) }, session_key: { type: DataTypes.STRING(255) }, // 新增字段 company: { type: DataTypes.STRING(255) // 客户公司 }, region: { type: DataTypes.STRING(255) // 客户地区 }, level: { type: DataTypes.STRING(255), defaultValue: 'company-sea-pools' // 客户等级,默认值为company-sea-pools }, demand: { type: DataTypes.TEXT // 基本需求 }, spec: { type: DataTypes.TEXT // 规格 }, created_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW }, updated_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW, onUpdate: Sequelize.NOW } }, { sequelize, modelName: 'User', tableName: 'users', timestamps: false }); // 商品模型 class Product extends Model { } Product.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, productId: { type: DataTypes.STRING(100), allowNull: false }, sellerId: { type: DataTypes.STRING(100), allowNull: false }, productName: { type: DataTypes.STRING(255), allowNull: false }, price: { type: DataTypes.DECIMAL(10, 2), allowNull: false }, quantity: { type: DataTypes.INTEGER, allowNull: false }, grossWeight: { type: DataTypes.DECIMAL(10, 2) }, yolk: { type: DataTypes.STRING(100) }, specification: { type: DataTypes.STRING(255) }, status: { type: DataTypes.STRING(20), defaultValue: 'pending_review', validate: { isIn: [['pending_review', 'reviewed', 'published', 'sold_out', 'rejected', 'hidden']] } }, rejectReason: { type: DataTypes.TEXT }, // 新增预约相关字段 reservedCount: { type: DataTypes.INTEGER, defaultValue: 0, allowNull: false, comment: '已有几人想要' }, created_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW }, updated_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW, onUpdate: Sequelize.NOW } }, { sequelize, modelName: 'Product', tableName: 'products', timestamps: false }); // 购物车模型 class CartItem extends Model { } CartItem.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, userId: { type: DataTypes.STRING(100), allowNull: false, unique: true }, productId: { type: DataTypes.STRING(100), allowNull: false }, productName: { type: DataTypes.STRING(255), allowNull: false }, specification: { type: DataTypes.STRING(255) }, quantity: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 1 }, grossWeight: { type: DataTypes.DECIMAL(10, 2) }, yolk: { type: DataTypes.STRING(100) }, price: { type: DataTypes.DECIMAL(10, 2) }, selected: { type: DataTypes.BOOLEAN, defaultValue: true }, added_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW } }, { sequelize, modelName: 'CartItem', tableName: 'cart_items', timestamps: false }); // 联系人表模型 class Contact extends Model { } Contact.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, userId: { type: DataTypes.STRING(100), allowNull: false, unique: true }, nickName: { type: DataTypes.STRING(100), allowNull: false // 联系人 }, phoneNumber: { type: DataTypes.STRING(20), allowNull: false // 手机号 }, wechat: { type: DataTypes.STRING(100) // 微信号 }, account: { type: DataTypes.STRING(100) // 账户 }, accountNumber: { type: DataTypes.STRING(100) // 账号 }, bank: { type: DataTypes.STRING(100) // 开户行 }, address: { type: DataTypes.TEXT // 地址 }, created_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW }, updated_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW, onUpdate: Sequelize.NOW } }, { sequelize, modelName: 'Contact', tableName: 'contacts', timestamps: false }); // 用户管理表模型 class UserManagement extends Model { } UserManagement.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, userId: { type: DataTypes.STRING(100), allowNull: false, unique: true }, managerId: { type: DataTypes.STRING(100), defaultValue: null // 经理ID,默认值为null }, company: { type: DataTypes.STRING(255), defaultValue: null // 公司,默认值为null }, department: { type: DataTypes.STRING(255), defaultValue: null // 部门,默认值为null }, organization: { type: DataTypes.STRING(255), defaultValue: null // 组织,默认值为null }, role: { type: DataTypes.STRING(100), defaultValue: null // 角色,默认值为null }, root: { type: DataTypes.STRING(100), defaultValue: null // 根节点,默认值为null }, created_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW }, updated_at: { type: DataTypes.DATE, defaultValue: Sequelize.NOW, onUpdate: Sequelize.NOW } }, { sequelize, modelName: 'UserManagement', tableName: 'usermanagements', timestamps: false }); // 定义模型之间的关联关系 // 用户和商品的一对多关系 (卖家发布商品) User.hasMany(Product, { foreignKey: 'sellerId', // 外键字段名 sourceKey: 'userId', // 源键,使用userId字段(STRING类型)而非默认的id字段(INTEGER类型) as: 'products', // 别名,用于关联查询 onDelete: 'CASCADE', // 级联删除 onUpdate: 'CASCADE' // 级联更新 }); Product.belongsTo(User, { foreignKey: 'sellerId', targetKey: 'userId', // 目标键,使用userId字段(STRING类型)而非默认的id字段(INTEGER类型) as: 'seller' // 别名,用于关联查询 }); // 用户和购物车项的一对多关系 (买家的购物需求/购物车) User.hasMany(CartItem, { foreignKey: 'userId', as: 'cartItems', // 用户的购物车(购物需求)列表 onDelete: 'CASCADE', // 级联删除 onUpdate: 'CASCADE' // 级联更新 }); CartItem.belongsTo(User, { foreignKey: 'userId', as: 'buyer' // 别名,明确表示这是购物需求的买家 }); // 商品和购物车项的一对多关系 (商品被添加到购物车) Product.hasMany(CartItem, { foreignKey: 'productId', as: 'cartItems', // 商品出现在哪些购物车中 onDelete: 'CASCADE', // 级联删除 onUpdate: 'CASCADE' // 级联更新 }); CartItem.belongsTo(Product, { foreignKey: 'productId', as: 'product' // 购物车项中的商品 }); // 用户和联系人的一对多关系 User.hasMany(Contact, { foreignKey: 'userId', as: 'contacts', // 用户的联系人列表 onDelete: 'CASCADE', // 级联删除 onUpdate: 'CASCADE' // 级联更新 }); Contact.belongsTo(User, { foreignKey: 'userId', as: 'user' // 联系人所属用户 }); // 用户和用户管理的一对一关系 User.hasOne(UserManagement, { foreignKey: 'userId', as: 'management', // 用户的管理信息 onDelete: 'CASCADE', // 级联删除 onUpdate: 'CASCADE' // 级联更新 }); UserManagement.belongsTo(User, { foreignKey: 'userId', as: 'user' // 管理信息所属用户 }); // 同步数据库模型到MySQL async function syncDatabase() { try { // 不使用alter: true,避免尝试修改已有表结构导致的外键约束问题 await sequelize.sync({ force: false // 不强制重新创建表 }); console.log('数据库模型同步成功'); } catch (error) { console.error('数据库模型同步失败:', error); // 即使同步失败也继续运行,因为我们只需要API功能 console.log('数据库模型同步失败,但服务器继续运行,使用现有表结构'); } } syncDatabase(); // 解密微信加密数据 function decryptData(encryptedData, sessionKey, iv) { try { // Base64解码 const sessionKeyBuf = Buffer.from(sessionKey, 'base64'); const encryptedDataBuf = Buffer.from(encryptedData, 'base64'); const ivBuf = Buffer.from(iv, 'base64'); // AES解密 const decipher = crypto.createDecipheriv('aes-128-cbc', sessionKeyBuf, ivBuf); decipher.setAutoPadding(true); let decoded = decipher.update(encryptedDataBuf, 'binary', 'utf8'); decoded += decipher.final('utf8'); // 解析JSON return JSON.parse(decoded); } catch (error) { console.error('解密失败:', error); // 提供更具体的错误信息 if (error.code === 'ERR_OSSL_BAD_DECRYPT') { throw new Error('登录信息已过期,请重新登录'); } else if (error.name === 'SyntaxError') { throw new Error('数据格式错误,解密结果无效'); } else { throw new Error('解密失败,请重试'); } } } // 获取微信session_key async function getSessionKey(code) { const axios = require('axios'); const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${WECHAT_CONFIG.APPID}&secret=${WECHAT_CONFIG.APPSECRET}&js_code=${code}&grant_type=authorization_code`; try { const response = await axios.get(url); return response.data; } catch (error) { console.error('获取session_key失败:', error); throw new Error('获取session_key失败'); } } // 创建用户关联记录函数 - 自动为用户创建contacts和usermanagements表的关联记录 async function createUserAssociations(user) { try { if (!user || !user.userId) { console.error('无效的用户数据,无法创建关联记录'); return false; } console.log('为用户创建关联记录:', user.userId); // 使用事务确保操作原子性 await sequelize.transaction(async (transaction) => { // 1. 处理联系人记录 - 使用INSERT ... ON DUPLICATE KEY UPDATE确保无论如何都只保留一条记录 await sequelize.query( `INSERT INTO contacts (userId, nickName, phoneNumber, created_at, updated_at) VALUES (?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE nickName = VALUES(nickName), phoneNumber = VALUES(phoneNumber), updated_at = NOW()`, { replacements: [user.userId, user.nickName || '默认联系人', user.phoneNumber || ''], transaction: transaction } ); console.log('联系人记录已处理(创建或更新):', user.userId); // 2. 处理用户管理记录 - 使用相同策略 await sequelize.query( `INSERT INTO usermanagements (userId, created_at, updated_at) VALUES (?, NOW(), NOW()) ON DUPLICATE KEY UPDATE updated_at = NOW()`, { replacements: [user.userId], transaction: transaction } ); console.log('用户管理记录已处理(创建或更新):', user.userId); }); console.log('用户关联记录处理成功:', user.userId); return true; } catch (error) { console.error('创建用户关联记录失败:', error.message); return false; } } // API路由 // 上传用户信息 app.post('/api/user/upload', async (req, res) => { try { const userData = req.body; console.log('收到用户信息上传请求:', userData); // 如果用户信息中包含手机号,检查手机号是否已被其他用户使用 if (userData.phoneNumber && userData.phoneNumber !== '13800138000') { // 排除临时占位手机号 const existingUserWithPhone = await User.findOne({ where: { phoneNumber: userData.phoneNumber, openid: { [Sequelize.Op.ne]: userData.openid } // 排除当前用户 } }); if (existingUserWithPhone) { // 手机号已被其他用户使用,不更新手机号 console.warn(`手机号 ${userData.phoneNumber} 已被其他用户使用,用户ID: ${existingUserWithPhone.userId}`); // 创建新对象,移除手机号字段 const userDataWithoutPhone = { ...userData }; delete userDataWithoutPhone.phoneNumber; // 查找用户是否已存在 let user = await User.findOne({ where: { openid: userData.openid } }); if (user) { // 更新用户信息(不包含手机号) await User.update( { ...userDataWithoutPhone, updated_at: new Date() }, { where: { openid: userData.openid } } ); user = await User.findOne({ where: { openid: userData.openid } }); } else { // 创建新用户(使用临时手机号) user = await User.create({ ...userDataWithoutPhone, phoneNumber: '13800138000', // 临时占位 created_at: new Date(), updated_at: new Date() }); // 使用统一的关联记录创建函数 await createUserAssociations(user); } // 返回成功,但提示手机号已被使用 return res.json({ success: true, code: 200, message: '用户信息保存成功,但手机号已被其他账号绑定', data: { userId: user.userId }, phoneNumberConflict: true }); } } // 查找用户是否已存在 let user = await User.findOne({ where: { openid: userData.openid } }); if (user) { // 更新用户信息 await User.update( { ...userData, updated_at: new Date() }, { where: { openid: userData.openid } } ); user = await User.findOne({ where: { openid: userData.openid } }); // 使用统一的关联记录创建函数 await createUserAssociations(user); } else { // 创建新用户 user = await User.create({ ...userData, created_at: new Date(), updated_at: new Date() }); // 使用统一的关联记录创建函数 await createUserAssociations(user); } res.json({ success: true, code: 200, message: '用户信息保存成功', data: { userId: user.userId }, phoneNumberConflict: false }); } catch (error) { console.error('保存用户信息失败:', error); res.status(500).json({ success: false, code: 500, message: '保存用户信息失败', error: error.message }); } }); // 解密手机号 app.post('/api/user/decodePhone', async (req, res) => { try { const { encryptedData, iv, openid } = req.body; // 参数校验 if (!encryptedData || !iv || !openid) { return res.status(400).json({ success: false, code: 400, message: '缺少必要的参数' }); } // 查找用户的session_key const user = await User.findOne({ where: { openid } }); if (!user || !user.session_key) { return res.status(401).json({ success: false, code: 401, message: '用户未登录,请先登录', needRelogin: true }); } // 解密手机号 let decryptedData, phoneNumber; try { decryptedData = decryptData(encryptedData, user.session_key, iv); phoneNumber = decryptedData.phoneNumber; } catch (decryptError) { // 解密失败,可能是session_key过期,建议重新登录 return res.status(401).json({ success: false, code: 401, message: decryptError.message || '手机号解密失败', needRelogin: true }); } // 检查手机号是否已被其他用户使用 const existingUserWithPhone = await User.findOne({ where: { phoneNumber: phoneNumber, openid: { [Sequelize.Op.ne]: openid } // 排除当前用户 } }); if (existingUserWithPhone) { // 手机号已被其他用户使用,不更新手机号 console.warn(`手机号 ${phoneNumber} 已被其他用户使用,用户ID: ${existingUserWithPhone.userId}`); // 返回成功,但不更新手机号,提示用户 return res.json({ success: true, code: 200, message: '手机号已被其他账号绑定', phoneNumber: user.phoneNumber, // 返回原手机号 isNewPhone: false }); } // 更新用户手机号 await User.update( { phoneNumber: phoneNumber, updated_at: new Date() }, { where: { openid } } ); // 更新用户手机号后,更新关联记录 const updatedUser = await User.findOne({ where: { openid } }); await createUserAssociations(updatedUser); res.json({ success: true, code: 200, message: '手机号解密成功', phoneNumber: phoneNumber, isNewPhone: true }); } catch (error) { console.error('手机号解密失败:', error); res.status(500).json({ success: false, code: 500, message: '手机号解密失败', error: error.message }); } }); // 处理微信登录,获取openid和session_key app.post('/api/wechat/getOpenid', async (req, res) => { try { const { code } = req.body; if (!code) { return res.status(400).json({ success: false, code: 400, message: '缺少code参数' }); } // 获取openid和session_key const wxData = await getSessionKey(code); if (wxData.errcode) { throw new Error(`微信接口错误: ${wxData.errmsg}`); } const { openid, session_key, unionid } = wxData; // 生成userId const userId = `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // 查找用户是否已存在 let user = await User.findOne({ where: { openid } }); if (user) { // 更新用户session_key await User.update( { session_key: session_key, updated_at: new Date() }, { where: { openid } } ); } else { // 创建新用户 // 支持从客户端传入type参数,如果没有则默认为buyer const userType = req.body.type || 'buyer'; await User.create({ openid, userId, session_key, nickName: '微信用户', // 临时占位,等待用户授权 phoneNumber: '13800138000', // 临时占位,等待用户授权 type: userType, // 使用客户端传入的类型或默认买家身份 created_at: new Date(), updated_at: new Date() }); // 为新创建的用户创建关联记录 const newUser = { userId, openid, nickName: '微信用户', phoneNumber: '13800138000' }; await createUserAssociations(newUser); } res.json({ success: true, code: 200, message: '获取openid成功', data: { openid, userId: user ? user.userId : userId } }); } catch (error) { console.error('获取openid失败:', error); res.status(500).json({ success: false, code: 500, message: '获取openid失败', error: error.message }); } }); // 验证用户登录状态 app.post('/api/user/validate', async (req, res) => { try { const { openid } = req.body; if (!openid) { return res.status(400).json({ success: false, code: 400, message: '缺少openid参数' }); } // 查找用户 const user = await User.findOne({ where: { openid }, attributes: ['openid', 'userId', 'nickName', 'avatarUrl', 'phoneNumber', 'type'] }); if (!user) { return res.status(401).json({ success: false, code: 401, message: '用户未登录' }); } res.json({ success: true, code: 200, message: '验证成功', data: user }); } catch (error) { console.error('验证用户登录状态失败:', error); res.status(500).json({ success: false, code: 500, message: '验证失败', error: error.message }); } }); // 获取用户信息 app.post('/api/user/get', async (req, res) => { try { const { openid } = req.body; if (!openid) { return res.status(400).json({ success: false, code: 400, message: '缺少openid参数' }); } // 查找用户 const user = await User.findOne({ where: { openid }, include: [ { model: Contact, as: 'contacts', attributes: ['id', 'nickName', 'phoneNumber', 'wechat', 'account', 'accountNumber', 'bank', 'address'] }, { model: UserManagement, as: 'management', attributes: ['id', 'managerId', 'company', 'department', 'organization', 'role', 'root'] } ] }); if (!user) { return res.status(404).json({ success: false, code: 404, message: '用户不存在' }); } res.json({ success: true, code: 200, message: '获取用户信息成功', data: user }); } catch (error) { console.error('获取用户信息失败:', error); res.status(500).json({ success: false, code: 500, message: '获取用户信息失败', error: error.message }); } }); // 更新用户信息 app.post('/api/user/update', async (req, res) => { try { const { openid, ...updateData } = req.body; if (!openid) { return res.status(400).json({ success: false, code: 400, message: '缺少openid参数' }); } // 查找用户 const user = await User.findOne({ where: { openid } }); if (!user) { return res.status(404).json({ success: false, code: 404, message: '用户不存在' }); } // 更新用户信息 await User.update( { ...updateData, updated_at: new Date() }, { where: { openid } } ); // 获取更新后的用户信息 const updatedUser = await User.findOne({ where: { openid } }); // 使用统一的关联记录创建函数 await createUserAssociations(updatedUser); res.json({ success: true, code: 200, message: '更新用户信息成功', data: updatedUser }); } catch (error) { console.error('更新用户信息失败:', error); res.status(500).json({ success: false, code: 500, message: '更新用户信息失败', error: error.message }); } }); // 获取商品列表 - 优化版本确保状态筛选正确应用 app.post('/api/product/list', async (req, res) => { try { const { openid, status, keyword, page = 1, pageSize = 20, testMode = false } = req.body; // 验证openid参数(测试模式除外) if (!openid && !testMode) { return res.status(400).json({ success: false, code: 400, message: '缺少openid参数' }); } // 构建查询条件 const where = {}; // 查找用户 let user = null; if (!testMode) { user = await User.findOne({ where: { openid } }); if (!user) { return res.status(404).json({ success: false, code: 404, message: '用户不存在' }); } // 只有管理员可以查看所有商品,普通用户只能查看自己的商品 if (user.type !== 'admin') { where.sellerId = user.userId; } } // 状态筛选 - 直接构建到where对象中,确保不会丢失 console.log(`当前用户类型: ${user ? user.type : '未知'},请求状态: ${status || '未指定'},测试模式: ${testMode}`); // 如果有指定status参数,按参数筛选但同时排除hidden if (status) { console.log(`按状态筛选商品: status=${status},并排除hidden状态`); if (status === 'all') { // 特殊情况:请求所有商品但仍然排除hidden where.status = { [Sequelize.Op.not]: 'hidden' }; } else if (Array.isArray(status)) { // 如果status是数组,确保不包含hidden where.status = { [Sequelize.Op.in]: status.filter(s => s !== 'hidden') }; } else { // 单个状态值,确保不是hidden if (status !== 'hidden') { where.status = { [Sequelize.Op.eq]: status }; } else { // 如果明确请求hidden状态,也返回空结果 where.status = { [Sequelize.Op.not]: 'hidden' }; } } } else { // 没有指定status参数时 - 直接在where对象中设置状态筛选 if (user && (user.type === 'seller' || user.type === 'both') && !testMode) { // 卖家用户且非测试模式 console.log(`卖家用户 ${user.userId} (类型:${user.type}) 查看自己的所有商品,但排除hidden状态`); // 卖家可以查看自己的所有商品,但仍然排除hidden状态 where.status = { [Sequelize.Op.not]: 'hidden' }; } else { // 测试模式或非卖家用户 console.log(`测试模式或非卖家用户,使用默认状态筛选: reviewed/published`); // 默认只显示已审核和已发布的商品,排除hidden和sold_out状态 where.status = { [Sequelize.Op.in]: ['reviewed', 'published'] }; } } console.log(`构建的完整查询条件:`, JSON.stringify(where, null, 2)); // 关键词搜索 if (keyword) { where.productName = { [Sequelize.Op.like]: `%${keyword}%` }; } // 计算偏移量 const offset = (page - 1) * pageSize; // 查询商品列表 const { count, rows: products } = await Product.findAndCountAll({ where, include: [ { model: User, as: 'seller', attributes: ['userId', 'nickName', 'avatarUrl'] }, // 添加CartItem关联以获取预约人数 { model: CartItem, as: 'cartItems', // 明确指定别名 attributes: [], required: false // 允许没有购物车项的商品也能返回 } ], // 添加selected字段,计算商品被加入购物车的次数(预约人数) attributes: { include: [ [Sequelize.fn('COUNT', Sequelize.col('cartItems.id')), 'selected'] ] }, order: [['created_at', 'DESC']], limit: pageSize, offset, // 修复分组问题 group: ['Product.productId', 'seller.userId'] // 使用正确的字段名 }); // 添加详细日志,记录查询结果 console.log(`商品列表查询结果 - 商品数量: ${count}, 商品列表长度: ${products.length}`); if (products.length > 0) { console.log(`第一个商品数据:`, JSON.stringify(products[0], null, 2)); // 添加selected字段的专门日志 console.log('商品预约人数(selected字段)统计:'); products.slice(0, 5).forEach(product => { const productJSON = product.toJSON(); console.log(`- ${productJSON.productName}: 预约人数=${productJSON.selected || 0}, 商品ID=${productJSON.productId}`); }); } // 处理商品列表中的grossWeight字段,确保是数字类型 const processedProducts = products.map(product => { const productJSON = product.toJSON(); // 详细分析毛重字段 const grossWeightDetails = { value: productJSON.grossWeight, type: typeof productJSON.grossWeight, isEmpty: productJSON.grossWeight === '' || productJSON.grossWeight === null || productJSON.grossWeight === undefined, isNumeric: productJSON.grossWeight === '' || productJSON.grossWeight === null || productJSON.grossWeight === undefined || !isNaN(parseFloat(productJSON.grossWeight)) && isFinite(productJSON.grossWeight), parsedValue: productJSON.grossWeight === '' || productJSON.grossWeight === null || productJSON.grossWeight === undefined ? 0 : parseFloat(productJSON.grossWeight) }; // 确保grossWeight值是数字类型并保留2位小数(与数据库decimal(10,2)类型保持一致) const finalGrossWeight = parseFloat(grossWeightDetails.parsedValue.toFixed(2)); productJSON.grossWeight = finalGrossWeight; // 确保selected字段存在并设置为数字类型(修复后的代码) if ('selected' in productJSON) { // 确保selected是数字类型 productJSON.selected = parseInt(productJSON.selected, 10); } else { // 如果没有selected字段,设置默认值为0 productJSON.selected = 0; } // 记录第一个商品的转换信息用于调试 if (products.indexOf(product) === 0) { console.log('商品列表 - 第一个商品毛重字段处理:'); console.log('- 原始值:', grossWeightDetails.value, '类型:', grossWeightDetails.type); console.log('- 转换后的值:', finalGrossWeight, '类型:', typeof finalGrossWeight); console.log('- selected字段: 存在=', 'selected' in productJSON, '值=', productJSON.selected, '类型=', typeof productJSON.selected); } return productJSON; });; // 准备响应数据 - 修改格式以匹配前端期望 const responseData = { success: true, code: 200, message: '获取商品列表成功', products: processedProducts, total: count, page: page, pageSize: pageSize, totalPages: Math.ceil(count / pageSize) }; console.log(`准备返回的响应数据格式:`, JSON.stringify(responseData, null, 2).substring(0, 500) + '...'); // 添加详细的查询条件日志 console.log(`最终查询条件:`, JSON.stringify(where, null, 2)); res.json(responseData); } catch (error) { console.error('获取商品列表失败:', error); res.status(500).json({ success: false, code: 500, message: '获取商品列表失败', error: error.message }); } }); // 上传商品 app.post('/api/products/upload', async (req, res) => { try { // 修复毛重字段处理逻辑 let productData = req.body; if (productData && productData.productData) { productData = productData.productData; // 使用正确的productData对象 } // 改进的毛重字段处理逻辑,与编辑API保持一致 // 详细分析毛重字段 const grossWeightDetails = { value: productData.grossWeight, type: typeof productData.grossWeight, isEmpty: productData.grossWeight === '' || productData.grossWeight === null || productData.grossWeight === undefined, isNumeric: productData.grossWeight === '' || productData.grossWeight === null || productData.grossWeight === undefined || !isNaN(parseFloat(productData.grossWeight)) && isFinite(productData.grossWeight), parsedValue: productData.grossWeight === '' || productData.grossWeight === null || productData.grossWeight === undefined ? 0 : parseFloat(productData.grossWeight) }; // 详细的日志记录 console.log('上传商品 - 毛重字段详细分析:'); console.log('- 原始值:', productData.grossWeight, '类型:', typeof productData.grossWeight); console.log('- 是否为空值:', grossWeightDetails.isEmpty); console.log('- 是否为有效数字:', grossWeightDetails.isNumeric); console.log('- 转换后的值:', grossWeightDetails.parsedValue, '类型:', typeof grossWeightDetails.parsedValue); // 确保grossWeight值是数字类型并保留2位小数(与数据库decimal(10,2)类型保持一致) // 使用Math.round进行精确四舍五入,确保3位小数以上的值正确转换 const finalGrossWeight = Math.round(grossWeightDetails.parsedValue * 100) / 100; productData.grossWeight = finalGrossWeight; console.log('上传商品 - 最终存储的毛重值:', finalGrossWeight, '类型:', typeof finalGrossWeight); console.log('收到商品上传请求:', productData); // 验证必要字段 if (!productData.sellerId || !productData.productName || !productData.price || !productData.quantity) { return res.status(400).json({ success: false, code: 400, message: '缺少必要的商品信息' }); } // 检查sellerId是否为openid,如果是则查找对应的userId let actualSellerId = productData.sellerId; // 如果sellerId看起来像一个openid(包含特殊字符如'-'),则尝试查找对应的userId if (productData.sellerId.includes('-')) { console.log('sellerId看起来像openid,尝试查找对应的userId'); const user = await User.findOne({ where: { openid: productData.sellerId } }); if (user && user.userId) { console.log(`找到了对应的userId: ${user.userId}`); actualSellerId = user.userId; } else { console.error(`未找到对应的用户记录,openid: ${productData.sellerId}`); return res.status(400).json({ success: false, code: 400, message: '找不到对应的用户记录' }); } } // 生成商品ID const productId = `product_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // 创建商品,使用实际的sellerId let product = await Product.create({ ...productData, sellerId: actualSellerId, // 使用查找到的userId productId, created_at: new Date(), updated_at: new Date() }); // 查询完整商品信息以确保返回正确的毛重值 product = await Product.findOne({ where: { productId }, include: [ { model: User, as: 'seller', attributes: ['userId', 'nickName', 'avatarUrl'] } ] }); // 确保返回给前端的grossWeight是正确的数字值 // 与编辑API保持一致的处理逻辑 if (product) { console.log('上传商品 - 处理前grossWeight:', product.grossWeight, '类型:', typeof product.grossWeight); // 如果grossWeight是undefined、null或空字符串,设置为0 if (product.grossWeight === undefined || product.grossWeight === null || product.grossWeight === '') { product.grossWeight = 0; console.log('上传商品 - 检测到空值,已设置为0'); } else { // 否则转换为浮点数 product.grossWeight = parseFloat(product.grossWeight); } console.log('上传商品 - 处理后grossWeight:', product.grossWeight, '类型:', typeof product.grossWeight); } res.json({ success: true, code: 200, message: '商品上传成功', data: { productId: product.productId, product: product } }); } catch (error) { console.error('商品上传失败:', error); res.status(500).json({ success: false, code: 500, message: '商品上传失败', error: error.message }); } }); // 获取商品详情 app.post('/api/products/detail', async (req, res) => { try { const { productId } = req.body; if (!productId) { return res.status(400).json({ success: false, code: 400, message: '缺少productId参数' }); } // 查询商品详情 - 排除hidden状态商品 const product = await Product.findOne({ where: { productId, status: { [Sequelize.Op.not]: 'hidden' } }, include: [ { model: User, as: 'seller', attributes: ['userId', 'nickName', 'avatarUrl'] } ] }); if (!product) { return res.status(404).json({ success: false, code: 404, message: '商品不存在' }); } // 对返回的商品数据中的grossWeight字段进行处理,确保是数字类型 let updatedProduct = { ...product.toJSON() }; // 详细分析毛重字段 const grossWeightDetails = { value: updatedProduct.grossWeight, type: typeof updatedProduct.grossWeight, isEmpty: updatedProduct.grossWeight === '' || updatedProduct.grossWeight === null || updatedProduct.grossWeight === undefined, isNumeric: updatedProduct.grossWeight === '' || updatedProduct.grossWeight === null || updatedProduct.grossWeight === undefined || !isNaN(parseFloat(updatedProduct.grossWeight)) && isFinite(updatedProduct.grossWeight), parsedValue: updatedProduct.grossWeight === '' || updatedProduct.grossWeight === null || updatedProduct.grossWeight === undefined ? 0 : parseFloat(updatedProduct.grossWeight) }; // 详细的日志记录 console.log('商品详情 - 毛重字段详细分析:'); console.log('- 原始值:', updatedProduct.grossWeight, '类型:', typeof updatedProduct.grossWeight); console.log('- 是否为空值:', grossWeightDetails.isEmpty); console.log('- 是否为有效数字:', grossWeightDetails.isNumeric); console.log('- 转换后的值:', grossWeightDetails.parsedValue, '类型:', typeof grossWeightDetails.parsedValue); // 确保grossWeight值是数字类型并保留2位小数(与数据库decimal(10,2)类型保持一致) const finalGrossWeight = parseFloat(grossWeightDetails.parsedValue.toFixed(2)); updatedProduct.grossWeight = finalGrossWeight; console.log('商品详情 - 最终返回的毛重值:', finalGrossWeight, '类型:', typeof finalGrossWeight); res.json({ success: true, code: 200, message: '获取商品详情成功', data: updatedProduct }); } catch (error) { console.error('获取商品详情失败:', error); res.status(500).json({ success: false, code: 500, message: '获取商品详情失败', error: error.message }); } }); // 修改商品 app.post('/api/products/edit', async (req, res) => { try { const { productId, ...updateData } = req.body; const { sellerId } = req.body; if (!productId || !sellerId) { return res.status(400).json({ success: false, code: 400, message: '缺少productId或sellerId参数' }); } // 查找商品 const product = await Product.findOne({ where: { productId } }); if (!product) { return res.status(404).json({ success: false, code: 404, message: '商品不存在' }); } // 检查是否为卖家本人 if (product.sellerId !== sellerId) { return res.status(403).json({ success: false, code: 403, message: '您无权修改此商品' }); } // 更新商品信息 await Product.update( { ...updateData, updated_at: new Date() }, { where: { productId } } ); // 获取更新后的商品信息 const updatedProduct = await Product.findOne({ where: { productId } }); res.json({ success: true, code: 200, message: '修改商品成功', data: updatedProduct }); } catch (error) { console.error('修改商品失败:', error); res.status(500).json({ success: false, code: 500, message: '修改商品失败', error: error.message }); } }); // 删除商品 - 将商品状态设置为hidden表示已删除 app.post('/api/products/delete', async (req, res) => { console.log('收到删除商品请求:', req.body); try { const { productId, sellerId } = req.body; if (!productId || !sellerId) { console.error('删除商品失败: 缺少productId或sellerId参数'); return res.status(400).json({ success: false, code: 400, message: '缺少productId或sellerId参数' }); } // 查找商品 const product = await Product.findOne({ where: { productId } }); if (!product) { console.error('删除商品失败: 商品不存在'); return res.status(404).json({ success: false, code: 404, message: '商品不存在' }); } // 检查是否为卖家本人 if (product.sellerId !== sellerId) { console.error('删除商品失败: 权限不足 - 卖家ID不匹配', { expected: product.sellerId, actual: sellerId }); return res.status(403).json({ success: false, code: 403, message: '您无权删除此商品' }); } console.log('准备更新商品状态为hidden,当前状态:', product.status); // 直接使用商品实例更新状态 product.status = 'hidden'; product.updated_at = new Date(); try { // 先尝试保存商品实例 await product.save(); console.log('删除商品成功(使用save方法):', { productId: product.productId, newStatus: product.status }); } catch (saveError) { console.error('使用save方法更新失败,尝试使用update方法:', saveError); // 如果保存失败,尝试使用update方法 try { const updateResult = await Product.update( { status: 'hidden', updated_at: new Date() }, { where: { productId } } ); console.log('删除商品成功(使用update方法):', { productId, updateResult }); } catch (updateError) { console.error('使用update方法也失败:', updateError); // 如果update方法也失败,尝试直接执行SQL语句绕过ORM验证 try { await sequelize.query( 'UPDATE products SET status = :status, updated_at = :updatedAt WHERE productId = :productId', { replacements: { status: 'hidden', updatedAt: new Date(), productId: productId } } ); console.log('删除商品成功(使用原始SQL):', { productId }); } catch (sqlError) { console.error('使用原始SQL也失败:', sqlError); throw new Error('所有更新方法都失败: ' + sqlError.message); } } } // 从购物车中移除该商品 const destroyResult = await CartItem.destroy({ where: { productId } }); console.log('从购物车移除商品结果:', destroyResult); // 重新查询商品以确保返回最新状态 const updatedProduct = await Product.findOne({ where: { productId } }); res.json({ success: true, code: 200, message: '删除商品成功', product: { productId: updatedProduct.productId, status: updatedProduct.status } }); } catch (error) { console.error('删除商品失败:', error); res.status(500).json({ success: false, code: 500, message: '删除商品失败', error: error.message }); } }); // 添加商品到购物车 app.post('/api/cart/add', async (req, res) => { // 增加全局错误捕获,确保即使在try-catch外部的错误也能被处理 try { console.log('收到添加到购物车请求 - 开始处理', req.url); let cartData = req.body; console.log('收到添加到购物车请求数据:', cartData); console.log('请求头:', req.headers); console.log('请求IP:', req.ip); // 兼容客户端请求格式:客户端可能将数据封装在product对象中,并且使用openid而不是userId if (cartData.product && !cartData.productId) { // 从product对象中提取数据 const productData = cartData.product; console.log('从product对象提取数据:', productData); console.log('客户端提供的openid:', cartData.openid); // 使用openid作为userId cartData = { userId: cartData.openid || productData.userId, productId: productData.productId || productData.id, productName: productData.productName || productData.name, quantity: productData.quantity || 1, price: productData.price, specification: productData.specification || productData.spec || '', grossWeight: productData.grossWeight || productData.weight, yolk: productData.yolk || productData.variety || '', testMode: productData.testMode || cartData.testMode }; console.log('转换后的购物车数据:', cartData); // 检查转换后的userId是否存在于users表中 try { console.log('开始查询用户信息,openid:', cartData.userId); const user = await User.findOne({ where: { openid: cartData.userId } }); if (user) { console.log(`找到对应的用户记录: openid=${cartData.userId}, userId=${user.userId}`); // 修正:使用数据库中真实的userId而不是openid cartData.userId = user.userId; console.log('修正后的userId:', cartData.userId); } else { console.error(`未找到openid为 ${cartData.userId} 的用户记录,无法添加到购物车`); // 重要:找不到用户时返回错误,避免使用无效的userId导致外键约束失败 return res.status(400).json({ success: false, code: 400, message: '用户信息无效,请重新登录后重试', error: `未找到用户记录: ${cartData.userId}` }); } } catch (error) { console.error('查询用户信息失败:', error); // 查询失败时也返回错误 return res.status(400).json({ success: false, code: 400, message: '查询用户信息失败', error: error.message }); } } // 验证必要字段 if (!cartData.userId || !cartData.productId || !cartData.productName || !cartData.quantity) { return res.status(400).json({ success: false, code: 400, message: '缺少必要的购物车信息', missingFields: [ !cartData.userId ? 'userId' : '', !cartData.productId ? 'productId' : '', !cartData.productName ? 'productName' : '', !cartData.quantity ? 'quantity' : '' ].filter(Boolean) }); } // 先验证用户ID是否存在于users表中 try { const userExists = await User.findOne({ where: { userId: cartData.userId } }); if (!userExists) { console.error(`用户ID ${cartData.userId} 不存在于users表中`); return res.status(400).json({ success: false, code: 400, message: '用户信息无效,请重新登录后重试', error: `用户ID ${cartData.userId} 不存在` }); } else { console.log(`用户ID ${cartData.userId} 存在于users表中,用户验证通过`); } } catch (error) { console.error('验证用户ID失败:', error); return res.status(400).json({ success: false, code: 400, message: '验证用户信息失败', error: error.message }); } // 检查商品是否存在以及是否为hidden状态 console.log(`检查商品ID: ${cartData.productId} 是否存在于products表中`); const product = await Product.findOne({ where: { productId: cartData.productId } }); if (!product) { console.error(`商品ID ${cartData.productId} 不存在于products表中`); return res.status(400).json({ success: false, code: 400, message: '商品不存在或已被移除', error: `未找到商品ID: ${cartData.productId}` }); } else { console.log(`商品ID ${cartData.productId} 存在于products表中,商品名称: ${product.productName}`); } if (product.status === 'hidden') { return res.status(400).json({ success: false, code: 400, message: '该商品已下架,无法添加到购物车' }); } // 在testMode下,不执行实际的数据库操作,直接返回成功 if (cartData.testMode) { console.log('测试模式:跳过实际的数据库操作'); res.json({ success: true, code: 200, message: '测试模式:添加到购物车成功', data: { userId: cartData.userId, productId: cartData.productId, productName: cartData.productName, quantity: cartData.quantity } }); return; } // 检查是否已存在相同商品 const existingItem = await CartItem.findOne({ where: { userId: cartData.userId, productId: cartData.productId } }); // 添加try-catch捕获外键约束错误 try { console.log(`准备创建/更新购物车项: userId=${cartData.userId}, productId=${cartData.productId}`); if (existingItem) { // 已存在,更新数量 await CartItem.update( { quantity: existingItem.quantity + cartData.quantity, updated_at: new Date() }, { where: { id: existingItem.id } } ); console.log(`更新购物车项成功: id=${existingItem.id}, 新数量=${existingItem.quantity + cartData.quantity}`); } else { // 不存在,创建新购物车项 console.log('创建新购物车项,所有字段:', { userId: cartData.userId, productId: cartData.productId, productName: cartData.productName, quantity: cartData.quantity, price: cartData.price, specification: cartData.specification, grossWeight: cartData.grossWeight, yolk: cartData.yolk }); // 重要:在创建前再次验证数据完整性 if (!cartData.userId || !cartData.productId) { throw new Error(`数据不完整: userId=${cartData.userId}, productId=${cartData.productId}`); } await CartItem.create({ ...cartData, added_at: new Date() }); console.log(`创建购物车项成功: userId=${cartData.userId}, productId=${cartData.productId}`); } } catch (createError) { console.error('创建/更新购物车项失败,可能是外键约束问题:', createError); console.error('详细错误信息:', { name: createError.name, message: createError.message, stack: createError.stack, sql: createError.sql || '无SQL信息', userId: cartData.userId, productId: cartData.productId }); // 检测是否是外键约束错误 if (createError.name === 'SequelizeForeignKeyConstraintError' || createError.message.includes('foreign key')) { // 区分是用户ID还是商品ID问题 let errorField = 'productId'; let errorMessage = '商品信息已更新,请刷新页面后重试'; if (createError.message.includes('userId') || createError.message.includes('user') || createError.message.toLowerCase().includes('user')) { errorField = 'userId'; errorMessage = '用户信息无效,请重新登录后重试'; } return res.status(400).json({ success: false, code: 400, message: errorMessage, error: `外键约束错误: ${errorField} 不存在或已失效`, details: { userId: cartData.userId, productId: cartData.productId } }); } // 其他类型的错误也返回400状态码,避免500错误 return res.status(400).json({ success: false, code: 400, message: '添加购物车项失败,请稍后重试', error: createError.message, details: { userId: cartData.userId, productId: cartData.productId } }); } // 更新商品的预约人数 - 更健壮的实现 try { console.log(`尝试更新商品预约人数: productId=${cartData.productId}`); // 先验证商品是否存在 const productCheck = await Product.findOne({where: {productId: cartData.productId}}); if (productCheck) { // 商品存在,才进行更新 await Product.increment('reservedCount', {by: 1, where: {productId: cartData.productId}}); console.log(`商品预约人数更新成功: productId=${cartData.productId}, 新数量=${productCheck.reservedCount + 1}`); } else { console.error(`更新商品预约人数失败: 商品ID ${cartData.productId} 不存在`); } } catch (updateError) { console.error(`更新商品预约人数失败:`, updateError); // 继续执行,不中断主要流程 } res.json({ success: true, code: 200, message: '添加到购物车成功' }); } catch (error) { console.error('添加到购物车失败:', error); console.error('全局错误捕获,详细信息:', { name: error.name, message: error.message, stack: error.stack, sql: error.sql || '无SQL信息' }); // 增强的错误处理 - 强制所有错误返回400状态码 console.error('全局错误处理 - 捕获到未处理的错误:', error); const statusCode = 400; // 强制所有错误返回400状态码,避免前端显示500错误 let errorMessage = '添加到购物车失败'; // 更精确地检测外键约束错误 if (error.name === 'SequelizeForeignKeyConstraintError' || error.message.toLowerCase().includes('foreign key') || error.message.toLowerCase().includes('constraint fails') || error.message.toLowerCase().includes('constraint')) { errorMessage = '添加到购物车失败:商品或用户信息已更新,请刷新页面后重试'; console.error('检测到外键约束相关错误,返回400状态码'); } console.log(`准备返回错误响应 - 状态码: ${statusCode}, 消息: ${errorMessage}`); // 确保响应能够正确发送 try { res.status(statusCode).json({ success: false, code: statusCode, message: errorMessage, error: error.message, errorDetails: { name: error.name, message: error.message, stack: error.stack, sql: error.sql || '无SQL信息' } }); } catch (resError) { console.error('发送错误响应失败:', resError); // 即使发送响应失败,也尝试以文本格式发送 try { res.status(400).send('添加到购物车失败,请刷新页面后重试'); } catch (finalError) { console.error('无法发送任何响应:', finalError); } } } }); // 获取购物车信息 app.post('/api/cart/get', async (req, res) => { try { const { userId } = req.body; if (!userId) { return res.status(400).json({ success: false, code: 400, message: '缺少userId参数' }); } // 查询购物车信息 - 排除关联商品为hidden或sold_out状态的项 const cartItems = await CartItem.findAll({ where: { userId }, include: [ { model: Product, as: 'product', attributes: ['productName', 'price', 'quantity', 'status', 'specification', 'grossWeight', 'yolk'], where: { status: { [Sequelize.Op.notIn]: ['hidden', 'sold_out'] } } } ], order: [['added_at', 'DESC']] }); res.json({ success: true, code: 200, message: '获取购物车信息成功', data: { cartItems } }); } catch (error) { console.error('获取购物车信息失败:', error); res.status(500).json({ success: false, code: 500, message: '获取购物车信息失败', error: error.message }); } }); // 更新购物车项 app.post('/api/cart/update', async (req, res) => { try { const { id, quantity, selected } = req.body; if (!id) { return res.status(400).json({ success: false, code: 400, message: '缺少id参数' }); } // 构建更新数据 const updateData = {}; if (quantity !== undefined) updateData.quantity = quantity; if (selected !== undefined) updateData.selected = selected; updateData.updated_at = new Date(); // 更新购物车项 await CartItem.update(updateData, { where: { id } }); res.json({ success: true, code: 200, message: '更新购物车成功' }); } catch (error) { console.error('更新购物车失败:', error); res.status(500).json({ success: false, code: 500, message: '更新购物车失败', error: error.message }); } }); // 删除购物车项 app.post('/api/cart/delete', async (req, res) => { try { const { id } = req.body; if (!id) { return res.status(400).json({ success: false, code: 400, message: '缺少id参数' }); } // 删除购物车项 await CartItem.destroy({ where: { id } }); res.json({ success: true, code: 200, message: '删除购物车项成功' }); } catch (error) { console.error('删除购物车项失败:', error); res.status(500).json({ success: false, code: 500, message: '删除购物车项失败', error: error.message }); } }); // 清空购物车 app.post('/api/cart/clear', async (req, res) => { try { const { userId } = req.body; if (!userId) { return res.status(400).json({ success: false, code: 400, message: '缺少userId参数' }); } // 清空购物车 await CartItem.destroy({ where: { userId } }); res.json({ success: true, code: 200, message: '清空购物车成功' }); } catch (error) { console.error('清空购物车失败:', error); res.status(500).json({ success: false, code: 500, message: '清空购物车失败', error: error.message }); } }); // 测试连接接口 app.get('/api/test-connection', async (req, res) => { try { // 检查数据库连接 await sequelize.authenticate(); res.json({ success: true, code: 200, message: '服务器连接成功,数据库可用', timestamp: new Date().toISOString(), serverInfo: { port: PORT, nodeVersion: process.version, database: 'MySQL', status: 'running' } }); } catch (error) { res.status(500).json({ success: false, code: 500, message: '服务器连接失败', error: error.message }); } }); // 用户类型调试接口 - 增强版:用于排查用户类型和商品显示问题 app.post('/api/user/debug', async (req, res) => { try { const { openid } = req.body; console.log('收到用户调试请求,openid:', openid); if (!openid) { return res.status(400).json({ success: false, code: 400, message: '缺少openid参数' }); } // 查询用户信息 const user = await User.findOne({ where: { openid }, attributes: ['openid', 'userId', 'nickName', 'phoneNumber', 'type'] }); if (!user) { return res.status(404).json({ success: false, code: 404, message: '用户不存在', debugInfo: { searchCriteria: { openid }, timestamp: new Date().toISOString() } }); } // 查询该用户的商品统计信息 const totalProducts = await Product.count({ where: { sellerId: user.userId } }); const pendingProducts = await Product.count({ where: { sellerId: user.userId, status: 'pending_review' } }); const reviewedProducts = await Product.count({ where: { sellerId: user.userId, status: 'reviewed' } }); const publishedProducts = await Product.count({ where: { sellerId: user.userId, status: 'published' } }); const soldOutProducts = await Product.count({ where: { sellerId: user.userId, status: 'sold_out' } }); // 判断用户是否有权限查看所有商品 const canViewAllProducts = ['seller', 'both', 'admin'].includes(user.type); // 获取该用户的最新5个商品信息(用于调试) const latestProducts = await Product.findAll({ where: { sellerId: user.userId }, limit: 5, order: [['created_at', 'DESC']], attributes: ['productId', 'productName', 'status', 'created_at'] }); const responseData = { success: true, code: 200, message: '获取用户调试信息成功', userInfo: user, productStats: { total: totalProducts, pendingReview: pendingProducts, reviewed: reviewedProducts, published: publishedProducts, soldOut: soldOutProducts }, permissionInfo: { canViewAllProducts: canViewAllProducts, userType: user.type, allowedTypesForViewingAllProducts: ['seller', 'both', 'admin'] }, latestProducts: latestProducts, debugInfo: { userCount: await User.count(), totalProductsInSystem: await Product.count(), timestamp: new Date().toISOString(), serverTime: new Date().toLocaleString('zh-CN') } }; console.log('调试信息返回数据:', JSON.stringify(responseData, null, 2).substring(0, 500) + '...'); res.json(responseData); } catch (error) { console.error('获取用户调试信息失败:', error); res.status(500).json({ success: false, code: 500, message: '获取用户调试信息失败', error: error.message, debugInfo: { errorStack: error.stack, timestamp: new Date().toISOString() } }); } }); // 下架商品接口 - 将商品状态设置为sold_out表示已下架 app.post('/api/product/hide', async (req, res) => { console.log('收到下架商品请求:', req.body); try { const { openid, productId } = req.body; // 验证请求参数 if (!openid || !productId) { console.error('下架商品失败: 缺少必要参数'); return res.status(400).json({ success: false, code: 400, message: '缺少必要参数: openid和productId都是必需的' }); } // 查找用户 const user = await User.findOne({ where: { openid } }); if (!user) { console.error('下架商品失败: 用户不存在'); return res.status(404).json({ success: false, code: 404, message: '用户不存在' }); } console.log('找到用户信息:', { userId: user.userId, nickName: user.nickName }); // 查找商品并验证所有权 - 直接使用userId,因为商品创建时使用的就是userId const product = await Product.findOne({ where: { productId: productId, sellerId: user.userId } }); if (!product) { console.error('下架商品失败: 商品不存在或不属于当前用户'); return res.status(404).json({ success: false, code: 404, message: '商品不存在或不属于当前用户' }); } // 记录当前状态,用于调试 console.log('当前商品状态:', product.status, '允许的状态列表:', Product.rawAttributes.status.validate.isIn); console.log('商品所属卖家ID:', product.sellerId); console.log('用户ID信息对比:', { userId: user.userId, id: user.id }); console.log('准备更新商品状态为sold_out,当前状态:', product.status); // 更新商品状态为已下架(sold_out) - 尝试多种更新方式确保成功 try { // 方法1: 直接保存实例 product.status = 'sold_out'; product.updated_at = new Date(); await product.save(); console.log('商品下架成功(使用save方法):', { productId: product.productId, newStatus: product.status }); } catch (saveError) { console.error('使用save方法更新失败,尝试使用update方法:', saveError); try { // 方法2: 使用update方法 const updateResult = await Product.update( { status: 'sold_out', updated_at: new Date() }, { where: { productId: productId, sellerId: user.userId } } ); console.log('商品下架成功(使用update方法):', { productId: productId, sellerIdType: typeof user.userId, updateResult }); } catch (updateError) { console.error('使用update方法也失败:', updateError); try { // 方法3: 直接执行SQL语句绕过ORM验证 const replacements = { status: 'sold_out', updatedAt: new Date(), productId: productId, sellerId: user.userId }; await sequelize.query( 'UPDATE products SET status = :status, updated_at = :updatedAt WHERE productId = :productId AND sellerId = :sellerId', { replacements: replacements } ); console.log('商品下架成功(使用原始SQL):', { productId: product.productId, productName: product.productName }); } catch (sqlError) { console.error('使用原始SQL也失败:', sqlError); throw new Error('所有更新方法都失败: ' + sqlError.message); } } } // 重新查询商品以确保返回最新状态 const updatedProduct = await Product.findOne({ where: { productId: productId, sellerId: product.sellerId // 使用找到的商品的sellerId进行查询 } }); res.json({ success: true, code: 200, message: '商品下架成功', product: { productId: updatedProduct.productId, productName: updatedProduct.productName, status: updatedProduct.status } }); } catch (error) { console.error('下架商品过程发生异常:', error); res.status(500).json({ success: false, code: 500, message: '下架商品失败: ' + error.message, error: error.message }); } }); // 发布商品API app.post('/api/product/publish', async (req, res) => { console.log('收到发布商品请求:', req.body); // 记录完整请求体 try { const { openid, product } = req.body; // 验证必填字段 console.log('验证请求参数: openid=', !!openid, ', product=', !!product); if (!openid || !product) { console.error('缺少必要参数: openid=', openid, 'product=', product); return res.status(400).json({ success: false, code: 400, message: '缺少必要的参数(openid或product对象)' }); } // 详细检查每个必填字段并记录其类型和值 console.log('商品字段详细检查:'); console.log('- productName: 存在=', !!product.productName, '类型=', typeof product.productName, '值=', product.productName); console.log('- price: 存在=', !!product.price, '类型=', typeof product.price, '值=', product.price, '转换为数字=', parseFloat(product.price)); console.log('- quantity: 存在=', !!product.quantity, '类型=', typeof product.quantity, '值=', product.quantity, '转换为数字=', parseInt(product.quantity)); console.log('- grossWeight: 存在=', !!product.grossWeight, '类型=', typeof product.grossWeight, '值=', product.grossWeight, '转换为数字=', parseFloat(product.grossWeight)); // 收集所有验证错误和字段值详情 const validationErrors = []; const fieldDetails = {}; // 检查商品名称 fieldDetails.productName = { value: product.productName, type: typeof product.productName, isEmpty: !product.productName || product.productName.trim() === '' }; if (fieldDetails.productName.isEmpty) { console.error('商品名称为空'); validationErrors.push('商品名称为必填项,不能为空或仅包含空格'); } // 检查价格 fieldDetails.price = { value: product.price, type: typeof product.price, isNumber: !isNaN(parseFloat(product.price)) && isFinite(product.price), parsedValue: parseFloat(product.price), isValid: !isNaN(parseFloat(product.price)) && isFinite(product.price) && parseFloat(product.price) > 0 }; if (!product.price) { console.error('价格为空'); validationErrors.push('价格为必填项'); } else if (!fieldDetails.price.isNumber) { console.error('价格不是有效数字: price=', product.price); validationErrors.push('价格必须是有效数字格式'); } else if (fieldDetails.price.parsedValue <= 0) { console.error('价格小于等于0: price=', product.price, '转换为数字后=', fieldDetails.price.parsedValue); validationErrors.push('价格必须大于0'); } // 检查数量 fieldDetails.quantity = { value: product.quantity, type: typeof product.quantity, isNumeric: !isNaN(parseFloat(product.quantity)) && isFinite(product.quantity), parsedValue: Math.floor(parseFloat(product.quantity)), isValid: !isNaN(parseFloat(product.quantity)) && isFinite(product.quantity) && parseFloat(product.quantity) > 0 }; if (!product.quantity) { console.error('数量为空'); validationErrors.push('数量为必填项'); } else if (!fieldDetails.quantity.isNumeric) { console.error('数量不是有效数字: quantity=', product.quantity); validationErrors.push('数量必须是有效数字格式'); } else if (fieldDetails.quantity.parsedValue <= 0) { console.error('数量小于等于0: quantity=', product.quantity, '转换为数字后=', fieldDetails.quantity.parsedValue); validationErrors.push('数量必须大于0'); } // 改进的毛重字段处理逻辑 - 与其他API保持一致 const grossWeightDetails = { value: product.grossWeight, type: typeof product.grossWeight, isEmpty: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined, isNumeric: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined || !isNaN(parseFloat(product.grossWeight)) && isFinite(product.grossWeight), parsedValue: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined ? 0 : parseFloat(product.grossWeight) }; // 详细的日志记录 console.log('发布商品 - 毛重字段详细分析:'); console.log('- 原始值:', product.grossWeight, '类型:', typeof product.grossWeight); console.log('- 是否为空值:', grossWeightDetails.isEmpty); console.log('- 是否为有效数字:', grossWeightDetails.isNumeric); console.log('- 转换后的值:', grossWeightDetails.parsedValue, '类型:', typeof grossWeightDetails.parsedValue); // 验证毛重值 if (!grossWeightDetails.isEmpty && !grossWeightDetails.isNumeric) { console.error('毛重不是有效数字: grossWeight=', product.grossWeight); validationErrors.push('毛重必须是有效数字格式'); } // 确保商品名称不超过数据库字段长度限制 if (product.productName && product.productName.length > 255) { console.error('商品名称过长: 长度=', product.productName.length); validationErrors.push('商品名称不能超过255个字符'); } // 如果有验证错误,一次性返回所有错误信息和字段详情 if (validationErrors.length > 0) { console.error('验证失败 - 详细信息:', JSON.stringify({ errors: validationErrors, fieldDetails: fieldDetails }, null, 2)); return res.status(400).json({ success: false, code: 400, message: '请填写完整信息', errors: validationErrors, detailedMessage: validationErrors.join('; '), fieldDetails: fieldDetails }); } // 查找用户 console.log('开始查找用户: openid=', openid); const user = await User.findOne({ where: { openid } }); if (!user) { console.error('用户不存在: openid=', openid); return res.status(404).json({ success: false, code: 404, message: '用户不存在,请先登录' }); } console.log('找到用户:', { userId: user.userId, nickName: user.nickName, type: user.type }); // 验证用户类型 console.log(`验证用户类型: 用户ID=${user.userId}, 类型=${user.type}`); if (user.type !== 'seller' && user.type !== 'both') { console.error(`商品发布失败: 用户${user.userId}类型为${user.type},需要seller或both类型`); return res.status(403).json({ success: false, code: 403, message: '只有卖家才能发布商品,请在个人资料中修改用户类型' }); } // 生成商品ID const productId = `product_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; console.log('生成商品ID:', productId); // 确保grossWeight值是数字类型并保留2位小数(与数据库decimal(10,2)类型保持一致) // 使用Math.round进行正确的四舍五入 const finalGrossWeight = Math.round(grossWeightDetails.parsedValue * 100) / 100; console.log('发布商品 - 最终存储的毛重值:', finalGrossWeight, '类型:', typeof finalGrossWeight); // 创建商品 console.log('准备创建商品:', { productName: product.productName, price: product.price, quantity: product.quantity, grossWeight: finalGrossWeight, sellerId: user.userId }); const newProduct = await Product.create({ productId: productId, sellerId: user.userId, productName: product.productName, price: product.price, quantity: product.quantity, grossWeight: finalGrossWeight, // 使用最终转换的数字值 yolk: product.yolk || '', specification: product.specification || '', status: 'pending_review', // 默认状态为待审核 created_at: new Date(), updated_at: new Date() }); // 查询完整商品信息以确保返回正确的毛重值 const createdProduct = await Product.findOne({ where: { productId }, include: [ { model: User, as: 'seller', attributes: ['userId', 'nickName', 'avatarUrl'] } ] }); // 确保返回给前端的grossWeight是正确的数字值 if (createdProduct) { console.log('发布商品 - 数据库查询后grossWeight:', createdProduct.grossWeight, '类型:', typeof createdProduct.grossWeight); } res.json({ success: true, code: 200, message: '商品发布成功', product: createdProduct, productId: productId }); } catch (error) { console.error('发布商品失败:', error); res.status(500).json({ success: false, code: 500, message: '发布商品失败: ' + error.message, error: error.message }); } }); // 启动服务器 app.listen(PORT, () => { console.log(`服务器运行在 http://localhost:${PORT}`); console.log('注意:当前服务器已添加详细日志记录,用于排查发布商品问题'); console.log('调试API: POST /api/user/debug - 用于查看用户类型信息'); console.log(`测试连接接口: http://localhost:${PORT}/api/test-connection`); }); // 编辑商品API - 用于审核失败商品重新编辑 app.post('/api/product/edit', async (req, res) => { console.log('收到编辑商品请求 - 详细信息:'); console.log('- 请求路径:', req.url); console.log('- 请求方法:', req.method); console.log('- 请求完整body:', req.body); console.log('- 服务器端口:', PORT); console.log('- 环境变量:', process.env.PORT); try { // 正确解析请求参数,处理嵌套的productData结构 let openid = req.body.openid; let productId = req.body.productId; let status = req.body.status; let testMode = req.body.testMode; let product = req.body.product; // 处理多层嵌套的productData结构 if (!product && req.body.productData) { // 处理第一种情况: { productData: { openid, productId, product: { ... } } } if (req.body.productData.product) { product = req.body.productData.product; openid = req.body.productData.openid || openid; productId = req.body.productData.productId || productId; status = req.body.productData.status || status; testMode = req.body.productData.testMode !== undefined ? req.body.productData.testMode : testMode; } // 处理第二种情况: { productData: { openid, productId, productName, price, ... } } else { product = req.body.productData; openid = req.body.productData.openid || openid; productId = req.body.productData.productId || productId; status = req.body.productData.status || status; testMode = req.body.productData.testMode !== undefined ? req.body.productData.testMode : testMode; } } // 调试日志 console.log('解析后参数:', { openid, productId, status, testMode, product: !!product }); console.log('收到编辑商品请求,包含状态参数:', { openid, productId, status, testMode }); // 验证必填字段 if (!openid || !productId || !product) { console.error('缺少必要参数: openid=', !!openid, 'productId=', !!productId, 'product=', !!product); return res.status(400).json({ success: false, code: 400, message: '缺少必要的参数(openid、productId或product对象)' }); } // 查找用户 let user = null; // 测试模式下的特殊处理 if (testMode) { console.log('测试模式:尝试查找或创建测试用户'); // 首先尝试查找openid为'test_openid'的用户 user = await User.findOne({ where: { openid: 'test_openid' } }); if (!user) { // 如果不存在,创建一个新的测试用户 console.log('测试模式:创建测试用户'); try { user = await User.create({ openid: 'test_openid', userId: 'test_user_id', nickName: '测试用户', phoneNumber: '13800138000', type: 'seller' }); } catch (createError) { console.error('测试模式:创建测试用户失败', createError); // 如果创建失败,尝试查找数据库中的第一个用户 user = await User.findOne({ order: [['id', 'ASC']] }); if (user) { console.log('测试模式:使用数据库中的现有用户', user.userId); } } } else { console.log('测试模式:使用已存在的测试用户', user.userId); } } else { // 非测试模式:按常规方式查找用户 user = await User.findOne({ where: { openid } }); } if (!user) { console.error('用户不存在: openid=', openid); return res.status(404).json({ success: false, code: 404, message: '用户不存在,请先登录' }); } // 查找商品 let existingProduct = null; if (testMode) { // 测试模式:如果找不到商品,尝试使用测试商品或创建一个新的测试商品 existingProduct = await Product.findOne({ where: { productId: productId } }); // 如果找不到指定的商品,创建一个新的测试商品 if (!existingProduct) { console.log('测试模式:创建测试商品'); try { existingProduct = await Product.create({ productId: productId, sellerId: user.userId, productName: '测试商品', price: 99.99, quantity: 100, grossWeight: 0, // 默认为0而不是5,符合用户需求 yolk: '测试描述', specification: '测试规格', status: 'rejected', // 设置为可编辑状态 created_at: new Date(), updated_at: new Date() }); console.log('测试模式:测试商品创建成功'); } catch (createProductError) { console.error('测试模式:创建测试商品失败', createProductError); } } } else { // 非测试模式:验证商品所有权 existingProduct = await Product.findOne({ where: { productId: productId, sellerId: user.userId } }); } if (!existingProduct) { console.error('编辑商品失败: 商品不存在或不属于当前用户'); return res.status(404).json({ success: false, code: 404, message: '商品不存在或不属于当前用户' }); } // 验证商品状态是否允许编辑 if (!['rejected', 'sold_out', 'pending_review', 'reviewed'].includes(existingProduct.status)) { console.error(`编辑商品失败: 商品状态(${existingProduct.status})不允许编辑`, { productId: productId, sellerId: user.userId, allowedStatuses: ['rejected', 'sold_out', 'pending_review', 'reviewed'], actualStatus: existingProduct.status }); return res.status(403).json({ success: false, code: 403, message: '只有审核失败、已下架、审核中或已审核的商品才能编辑', debugInfo: { allowedStatuses: ['rejected', 'sold_out', 'pending_review', 'reviewed'], actualStatus: existingProduct.status } }); } // 记录商品编辑信息,用于调试 console.log(`允许编辑商品: productId=${productId}, status=${existingProduct.status}, sellerId=${user.userId}`); // 详细检查每个必填字段并记录其类型和值 console.log('商品字段详细检查:'); console.log('- productName: 存在=', !!product.productName, '类型=', typeof product.productName, '值=', product.productName); console.log('- price: 存在=', !!product.price, '类型=', typeof product.price, '值=', product.price); console.log('- quantity: 存在=', !!product.quantity, '类型=', typeof product.quantity, '值=', product.quantity); console.log('- grossWeight: 存在=', !!product.grossWeight, '类型=', typeof product.grossWeight, '值=', product.grossWeight, '转换为数字=', parseFloat(product.grossWeight)); // 收集所有验证错误 const validationErrors = []; // 检查商品名称 if (!product.productName || product.productName.trim() === '') { validationErrors.push('商品名称为必填项,不能为空或仅包含空格'); } else if (product.productName.length > 255) { validationErrors.push('商品名称不能超过255个字符'); } // 检查价格 if (!product.price) { validationErrors.push('价格为必填项'); } else if (isNaN(parseFloat(product.price)) || parseFloat(product.price) <= 0) { validationErrors.push('价格必须是大于0的有效数字'); } // 检查数量 if (!product.quantity) { validationErrors.push('数量为必填项'); } else if (isNaN(parseInt(product.quantity)) || parseInt(product.quantity) <= 0) { validationErrors.push('数量必须是大于0的有效数字'); } // 改进的毛重字段处理逻辑,与其他API保持一致,空值默认设为0 const grossWeightDetails = { value: product.grossWeight, type: typeof product.grossWeight, isEmpty: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined, isNumeric: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined || !isNaN(parseFloat(product.grossWeight)) && isFinite(product.grossWeight), parsedValue: product.grossWeight === '' || product.grossWeight === null || product.grossWeight === undefined ? 0 : parseFloat(product.grossWeight) }; // 详细的日志记录 console.log('编辑商品 - 毛重字段详细分析:'); console.log('- 原始值:', product.grossWeight, '类型:', typeof product.grossWeight); console.log('- 是否为空值:', grossWeightDetails.isEmpty); console.log('- 是否为有效数字:', grossWeightDetails.isNumeric); console.log('- 转换后的值:', grossWeightDetails.parsedValue, '类型:', typeof grossWeightDetails.parsedValue); // 验证毛重值 if (!grossWeightDetails.isEmpty && !grossWeightDetails.isNumeric) { console.error('毛重不是有效数字: grossWeight=', product.grossWeight); validationErrors.push('毛重必须是有效数字格式'); } // 确保grossWeight值是数字类型 const finalGrossWeight = Number(grossWeightDetails.parsedValue); console.log('编辑商品 - 最终存储的毛重值:', finalGrossWeight, '类型:', typeof finalGrossWeight); // 如果有验证错误,返回错误信息 if (validationErrors.length > 0) { console.error('验证失败 - 错误:', validationErrors.join('; ')); return res.status(400).json({ success: false, code: 400, message: '请填写完整信息', errors: validationErrors }); } // 准备更新的商品数据 const updatedProductData = { productName: product.productName, price: product.price, quantity: product.quantity, grossWeight: finalGrossWeight, // 使用最终转换的数字值 yolk: product.yolk, specification: product.specification, // 优先使用前端传递的status参数,如果没有传递则使用原来的逻辑 status: status && ['pending_review', 'published'].includes(status) ? status : (product.resubmit && ['rejected', 'sold_out'].includes(existingProduct.status)) ? 'pending_review' : existingProduct.status, rejectReason: (status === 'pending_review' || (product.resubmit && existingProduct.status === 'rejected')) ? null : existingProduct.rejectReason, // 提交审核时清除拒绝原因 updated_at: new Date() }; console.log('准备更新商品数据:', { productId, updatedStatus: updatedProductData.status, fromStatus: existingProduct.status }); // 更新商品 const [updatedCount] = await Product.update(updatedProductData, { where: testMode ? { // 测试模式:只根据productId更新 productId: productId } : { // 非测试模式:验证商品所有权 productId: productId, sellerId: user.userId } }); // 检查更新是否成功 if (updatedCount === 0) { console.error('商品更新失败: 没有找到匹配的商品或权限不足'); return res.status(404).json({ success: false, code: 404, message: '商品更新失败: 没有找到匹配的商品或权限不足' }); } // 获取更新后的商品信息 const updatedProduct = await Product.findOne({ where: { productId: productId } }); console.log('查询数据库后 - 更新的商品信息:', { grossWeight: updatedProduct?.grossWeight, grossWeightType: typeof updatedProduct?.grossWeight, productId: updatedProduct?.productId, status: updatedProduct?.status }); // 确保返回给前端的grossWeight是正确的数字值 // 注意:这里检查undefined和null,并且对于空字符串或5的情况也进行处理 if (updatedProduct) { console.log('处理前 - grossWeight:', updatedProduct.grossWeight, '类型:', typeof updatedProduct.grossWeight); // 如果grossWeight是undefined、null或空字符串,设置为0 if (updatedProduct.grossWeight === undefined || updatedProduct.grossWeight === null || updatedProduct.grossWeight === '') { updatedProduct.grossWeight = 0; console.log('检测到空值 - 已设置为0'); } else { // 否则转换为浮点数 updatedProduct.grossWeight = parseFloat(updatedProduct.grossWeight); } console.log('处理后 - grossWeight:', updatedProduct.grossWeight, '类型:', typeof updatedProduct.grossWeight); } console.log('商品编辑成功:', { productId: productId, productName: product.productName, oldStatus: existingProduct.status, // 记录更新前的状态 newStatus: updatedProduct.status, // 记录更新后的状态 grossWeight: updatedProduct.grossWeight // 记录处理后的毛重值 }); // 根据新的状态生成适当的返回消息 let returnMessage = ''; if (updatedProduct.status === 'pending_review') { returnMessage = '商品编辑成功,已重新提交审核'; } else if (updatedProduct.status === 'published') { returnMessage = '商品编辑成功,已上架'; } else if (updatedProduct.status === existingProduct.status) { returnMessage = '商品编辑成功,状态保持不变'; } else { returnMessage = '商品编辑成功'; } res.json({ success: true, code: 200, message: returnMessage, product: updatedProduct }); } catch (error) { console.error('编辑商品过程发生异常:', error); res.status(500).json({ success: false, code: 500, message: '编辑商品失败: ' + error.message, error: error.message }); } }); // 导出模型和Express应用供其他模块使用 module.exports = { User, Product, CartItem, sequelize, createUserAssociations, app, PORT };