You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1369 lines
51 KiB

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const mysql = require('mysql2/promise');
const path = require('path');
const app = express();
const PORT = 3000;
// 配置CORS
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
next();
});
app.use(bodyParser.json({ limit: '10mb' }));
app.use(express.static(path.join(__dirname)));
// 数据库配置
const dbConfig = {
host: '1.95.162.61',
user: 'root',
password: 'schl@2025', // 请替换为实际的数据库密码
database: 'wechat_app', // 连接到wechat_app数据库
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
};
// userlogin数据库配置
const userLoginDbConfig = {
host: '1.95.162.61',
user: 'root',
password: 'schl@2025', // 请替换为实际的数据库密码
database: 'userlogin', // 连接到userlogin数据库
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
};
// 创建数据库连接池
let pool;
let userLoginPool;
// 初始化数据库连接
async function initDatabase() {
try {
pool = mysql.createPool(dbConfig);
console.log('wechat_app数据库连接池创建成功');
// 初始化userlogin数据库连接池
userLoginPool = mysql.createPool(userLoginDbConfig);
console.log('userlogin数据库连接池创建成功');
// 测试wechat_app连接
const connection = await pool.getConnection();
console.log('wechat_app数据库连接测试成功');
connection.release();
// 测试userlogin连接
const userLoginConnection = await userLoginPool.getConnection();
console.log('userlogin数据库连接测试成功');
userLoginConnection.release();
// 确保数据库结构
await ensureDatabaseSchema();
} catch (error) {
console.error('数据库初始化失败:', error.message);
console.error('错误详情:', error);
// 如果初始化失败,尝试重新初始化
setTimeout(() => {
console.log('尝试重新初始化数据库连接...');
initDatabase();
}, 5000);
}
}
// 通用响应函数
function sendResponse(res, success, data = null, message = '') {
res.json({
success,
data,
message
});
}
// 导出函数供测试使用
module.exports.sendResponse = sendResponse;
// 获取货源列表API
app.get('/api/supplies', async (req, res) => {
console.log('收到获取货源列表请求:', req.query);
try {
const connection = await pool.getConnection();
// 支持search和keyword两种参数名,确保兼容性
const { page = 1, pageSize = 10, search = '', keyword = '', status = '', phoneNumber = '' } = req.query;
// 如果提供了keyword参数,优先使用keyword
const actualSearch = keyword || search;
const offset = (page - 1) * pageSize;
// 构建基础查询,添加LEFT JOIN获取用户信息
let query = 'SELECT p.*, u.phoneNumber, u.nickName FROM products p LEFT JOIN users u ON p.sellerId = u.userId';
let countQuery = 'SELECT COUNT(*) as total FROM products p LEFT JOIN users u ON p.sellerId = u.userId';
let whereClause = '';
let params = [];
// 添加搜索条件
if (actualSearch) {
whereClause += ` WHERE (p.id LIKE ? OR p.productId LIKE ? OR p.productName LIKE ?)`;
params.push(`%${actualSearch}%`, `%${actualSearch}%`, `%${actualSearch}%`);
}
// 添加手机号搜索
if (phoneNumber) {
whereClause += actualSearch ? ' AND' : ' WHERE';
whereClause += ` u.phoneNumber LIKE ?`;
params.push(`%${phoneNumber}%`);
}
// 添加状态筛选
if (status) {
whereClause += (actualSearch || phoneNumber) ? ' AND' : ' WHERE';
whereClause += ` status = ?`;
params.push(status);
}
// 添加sellerId筛选,只返回指定用户的货源
const { sellerId } = req.query;
if (sellerId) {
whereClause += (actualSearch || phoneNumber || status) ? ' AND' : ' WHERE';
whereClause += ` p.sellerId = ?`;
params.push(sellerId);
}
// 执行查询
const [results] = await connection.query(
`${query}${whereClause} ORDER BY p.id DESC LIMIT ? OFFSET ?`,
[...params, parseInt(pageSize), offset]
);
// 获取总数
const [countResults] = await connection.query(
`${countQuery}${whereClause}`,
params
);
connection.release();
// 处理返回结果中的imageUrls字段
const processedResults = results.map(product => {
// 处理imageUrls字段
let imageUrls = [];
if (product.imageUrls) {
if (typeof product.imageUrls === 'string') {
// 尝试解析为JSON数组
try {
let parsedImages = JSON.parse(product.imageUrls);
// 检查是否是JSON字符串的字符串表示(转义的JSON)
if (typeof parsedImages === 'string' &&
(parsedImages.startsWith('[') || parsedImages.startsWith('{'))) {
// 进行第二次解析
parsedImages = JSON.parse(parsedImages);
}
if (Array.isArray(parsedImages)) {
imageUrls = parsedImages;
} else if (typeof parsedImages === 'string') {
// 如果解析结果是字符串,可能是单个URL
imageUrls = [parsedImages];
}
} catch (e) {
// 解析失败,尝试按逗号分隔
if (product.imageUrls.includes(',')) {
imageUrls = product.imageUrls.split(',').map(url => url.trim());
} else {
// 作为单个URL处理
imageUrls = [product.imageUrls.trim()];
}
}
} else if (Array.isArray(product.imageUrls)) {
// 已经是数组,直接使用
imageUrls = product.imageUrls;
} else {
// 其他类型,转换为字符串数组
imageUrls = [String(product.imageUrls)];
}
}
// 过滤并处理无效的URL:移除反引号并验证
imageUrls = imageUrls
.filter(url => {
if (!url) return false;
const processedUrl = url.replace(/`/g, '').trim();
return processedUrl.startsWith('http://') || processedUrl.startsWith('https://');
})
// 对每个有效URL进行处理,移除反引号
.map(url => url.replace(/`/g, '').trim());
return {
...product,
imageUrls
};
});
// 返回结果
sendResponse(res, true, {
list: processedResults,
total: countResults[0].total,
page: parseInt(page),
pageSize: parseInt(pageSize)
}, '获取货源列表成功');
} catch (error) {
console.error('获取货源列表失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '获取货源列表失败');
}
});
// 审核通过API
app.post('/api/supplies/:id/approve', async (req, res) => {
console.log('收到审核通过请求:', req.params.id, req.body);
try {
const connection = await pool.getConnection();
const { remark = '' } = req.body;
const productId = req.params.id;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 检查状态是否可审核,只允许审核中的状态进行审核操作
if (!['pending_review'].includes(currentProduct[0].status)) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '该货源已审核,无需重复操作');
}
// 更新状态为已审核
await connection.query(
'UPDATE products SET status = ?, audit_time = ? WHERE id = ?',
['published', new Date(), productId]
);
// 记录日志
await connection.query(
'INSERT INTO audit_logs (supply_id, action, user_id, remark, created_at) VALUES (?, ?, ?, ?, ?)',
[productId, 'approve', 'system', remark, new Date()]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '审核通过成功');
} catch (error) {
console.error('审核通过失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '审核通过失败');
}
});
console.log('正在注册拒绝审核API路由: /api/supplies/:id/reject');
// 审核拒绝API
app.post('/api/supplies/:id/reject', async (req, res) => {
console.log('收到审核拒绝请求:', req.params.id, req.body);
try {
const connection = await pool.getConnection();
// 同时支持reason和rejectReason参数,保持向后兼容
const { reason, rejectReason = '', remark = '' } = req.body;
// 如果有reason参数,则使用reason,否则使用rejectReason
const actualRejectReason = reason || rejectReason;
const productId = req.params.id;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 检查状态是否可审核,只允许审核中的状态进行审核操作
if (!['pending_review'].includes(currentProduct[0].status)) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '当前状态不允许审核拒绝');
}
// 更新状态和拒绝理由
await connection.query(
'UPDATE products SET status = ?, rejectReason = ?, audit_time = ? WHERE id = ?',
['rejected', actualRejectReason, new Date(), productId]
);
// 记录日志
await connection.query(
'INSERT INTO audit_logs (supply_id, action, user_id, remark, created_at) VALUES (?, ?, ?, ?, ?)',
[productId, 'reject', 'system', remark, new Date()]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '审核拒绝成功');
} catch (error) {
console.error('审核拒绝失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '审核拒绝失败');
}
});
// 获取供应商列表API已删除
// 供应商审核通过API已删除
// 供应商审核拒绝API已删除
// 供应商开始合作API已删除
// 供应商终止合作API已删除
console.log('正在注册测试API路由: /api/test-db');
// 测试数据库连接API
app.get('/api/test-db', async (req, res) => {
console.log('收到数据库连接测试请求');
try {
const connection = await pool.getConnection();
const [results] = await connection.query('SELECT 1 + 1 as solution');
connection.release();
sendResponse(res, true, results[0], '数据库连接成功');
} catch (error) {
console.error('数据库连接测试失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '数据库连接测试失败');
}
});
// 登录API
app.post('/api/login', async (req, res) => {
try {
const { projectName, userName, password } = req.body;
// 验证参数
if (!projectName || !userName || !password) {
return sendResponse(res, false, null, '职位名称、用户名和密码不能为空');
}
// 1. 在login表中验证登录信息
const userLoginConnection = await userLoginPool.getConnection();
const [loginResult] = await userLoginConnection.query(
'SELECT id, projectName, userName, managerId FROM login WHERE projectName = ? AND userName = ? AND password = ?',
[projectName, userName, password]
);
if (loginResult.length === 0) {
userLoginConnection.release();
return sendResponse(res, false, null, '职位名称、用户名或密码错误');
}
const loginInfo = loginResult[0];
const { managerId } = loginInfo;
// 2. 在personnel表中查询手机号码
const [personnelResult] = await userLoginConnection.query(
'SELECT phoneNumber, name FROM personnel WHERE managerId = ?',
[managerId]
);
userLoginConnection.release();
if (personnelResult.length === 0) {
return sendResponse(res, false, null, '未找到对应的员工信息');
}
const { phoneNumber, name } = personnelResult[0];
// 3. 在users表中查询userId
const connection = await pool.getConnection();
const [userResult] = await connection.query(
'SELECT userId FROM users WHERE phoneNumber = ?',
[phoneNumber]
);
connection.release();
let userId = null;
if (userResult.length > 0) {
userId = userResult[0].userId;
}
// 4. 生成token(简单实现,实际项目中应使用JWT等安全机制)
const token = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
// 5. 返回登录结果
const userInfo = {
id: loginInfo.id,
projectName: loginInfo.projectName,
userName: loginInfo.userName,
managerId: loginInfo.managerId,
name: name,
phoneNumber: phoneNumber,
userId: userId
};
sendResponse(res, true, { userInfo, token }, '登录成功');
} catch (error) {
console.error('登录失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '登录失败,请稍后重试');
}
});
// 获取联系人数据API
app.get('/api/contacts', async (req, res) => {
try {
// 直接从userlogin数据库的Personnel表查询联系人信息,只查询工位名为销售员的联系人
const userLoginConnection = await userLoginPool.getConnection();
const [personnelData] = await userLoginConnection.query(
'SELECT projectName, alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != ""'
);
userLoginConnection.release();
if (personnelData.length === 0) {
sendResponse(res, true, [], '没有找到联系人信息');
return;
}
// 创建联系人数据数组,保持与原API相同的返回格式
const contacts = personnelData.map((person, index) => ({
id: index + 1,
salesPerson: person.projectName, // 销售员
name: person.alias, // 联系人别名
phoneNumber: person.phoneNumber // 电话号码
}));
sendResponse(res, true, contacts, '联系人数据获取成功');
} catch (error) {
console.error('获取联系人数据失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '获取联系人数据失败');
}
});
// 更新产品联系人API
app.put('/api/supplies/:id/contact', async (req, res) => {
try {
const { id } = req.params;
const { productContact, contactPhone } = req.body;
// 移除"联系人"前缀和"销售员 - "前缀
const processedProductContact = productContact.replace(/^(联系人|销售员\s*-\s*)/g, '').trim();
const connection = await pool.getConnection();
// 更新产品的联系人信息
const [result] = await connection.query(
'UPDATE products SET product_contact = ?, contact_phone = ? WHERE id = ?',
[processedProductContact, contactPhone, id]
);
connection.release();
if (result.affectedRows === 0) {
sendResponse(res, false, null, '未找到指定的产品');
return;
}
sendResponse(res, true, null, '产品联系人信息更新成功');
} catch (error) {
console.error('更新产品联系人信息失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '更新产品联系人信息失败');
}
});
// 供应商审核通过API - /api/suppliers/:id/approve
console.log('正在注册供应商审核通过API路由: /api/suppliers/:id/approve');
app.post('/api/suppliers/:id/approve', async (req, res) => {
console.log('收到供应商审核通过请求:', req.params);
try {
const connection = await pool.getConnection();
const userId = req.params.id;
if (!userId) {
connection.release();
return sendResponse(res, false, null, '用户ID不能为空');
}
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentUser] = await connection.query(
'SELECT partnerstatus FROM users WHERE userId = ?',
[userId]
);
if (currentUser.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '供应商不存在');
}
if (currentUser[0].partnerstatus !== 'underreview') {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '当前状态不允许审核通过');
}
// 更新状态和审核时间
await connection.query(
'UPDATE users SET partnerstatus = ?, audit_time = ? WHERE userId = ?',
['approved', new Date(), userId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '供应商审核通过成功');
} catch (error) {
console.error('供应商审核通过失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '供应商审核通过失败');
}
});
// 供应商审核拒绝API - /api/suppliers/:id/reject
console.log('正在注册供应商审核拒绝API路由: /api/suppliers/:id/reject');
app.post('/api/suppliers/:id/reject', async (req, res) => {
console.log('收到供应商审核拒绝请求:', req.params, req.body);
try {
const connection = await pool.getConnection();
const userId = req.params.id;
const { rejectReason } = req.body;
if (!userId) {
connection.release();
return sendResponse(res, false, null, '用户ID不能为空');
}
if (!rejectReason) {
connection.release();
return sendResponse(res, false, null, '审核失败原因不能为空');
}
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentUser] = await connection.query(
'SELECT partnerstatus FROM users WHERE userId = ?',
[userId]
);
if (currentUser.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '供应商不存在');
}
if (currentUser[0].partnerstatus !== 'underreview') {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '当前状态不允许审核拒绝');
}
// 更新状态、审核失败原因和审核时间
await connection.query(
'UPDATE users SET partnerstatus = ?, reasonforfailure = ?, audit_time = ? WHERE userId = ?',
['reviewfailed', rejectReason, new Date(), userId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '供应商审核拒绝成功');
} catch (error) {
console.error('供应商审核拒绝失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '供应商审核拒绝失败');
}
});
// 供应商开始合作API - /api/suppliers/:id/cooperate
console.log('正在注册供应商开始合作API路由: /api/suppliers/:id/cooperate');
app.post('/api/suppliers/:id/cooperate', async (req, res) => {
console.log('收到供应商开始合作请求:', req.params);
try {
const connection = await pool.getConnection();
const userId = req.params.id;
if (!userId) {
connection.release();
return sendResponse(res, false, null, '用户ID不能为空');
}
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentUser] = await connection.query(
'SELECT partnerstatus FROM users WHERE userId = ?',
[userId]
);
if (currentUser.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '供应商不存在');
}
if (currentUser[0].partnerstatus !== 'approved') {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '只有审核通过的供应商才能开始合作');
}
// 更新状态
await connection.query(
'UPDATE users SET partnerstatus = ? WHERE userId = ?',
['incooperation', userId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '供应商开始合作成功');
} catch (error) {
console.error('供应商开始合作失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '供应商开始合作失败');
}
});
// 供应商终止合作API - /api/suppliers/:id/terminate
console.log('正在注册供应商终止合作API路由: /api/suppliers/:id/terminate');
app.post('/api/suppliers/:id/terminate', async (req, res) => {
console.log('收到供应商终止合作请求:', req.params, req.body);
try {
const connection = await pool.getConnection();
const userId = req.params.id;
const { reason } = req.body;
if (!userId) {
connection.release();
return sendResponse(res, false, null, '用户ID不能为空');
}
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentUser] = await connection.query(
'SELECT partnerstatus FROM users WHERE userId = ?',
[userId]
);
if (currentUser.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '供应商不存在');
}
if (currentUser[0].partnerstatus !== 'approved' && currentUser[0].partnerstatus !== 'incooperation') {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '只有审核通过或合作中的供应商才能终止合作');
}
// 更新状态和终止原因
await connection.query(
'UPDATE users SET partnerstatus = ?, terminate_reason = ? WHERE userId = ?',
['notcooperative', reason, userId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '供应商终止合作成功');
} catch (error) {
console.error('供应商终止合作失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '供应商终止合作失败');
}
});
// 导入OSS上传工具
const OssUploader = require('./oss-uploader');
// 导入图片处理工具
const ImageProcessor = require('./image-processor');
// 创建货源API - /api/supplies/create
console.log('正在注册创建货源API路由: /api/supplies/create');
app.post('/api/supplies/create', async (req, res) => {
console.log('收到创建货源请求:', req.body);
let connection;
try {
connection = await pool.getConnection();
const { productName, price, quantity, grossWeight, yolk, specification, quality, region, imageUrls, sellerId, supplyStatus, description, sourceType, contactId, category } = req.body;
// 开始事务
await connection.beginTransaction();
// 验证必填字段
if (!productName || !price || !quantity || !supplyStatus || !sourceType) {
connection.release();
return sendResponse(res, false, null, '商品名称、价格、最小起订量、货源状态和货源类型不能为空');
}
// 如果sellerId为空,设置一个默认值
if (!sellerId) {
sellerId = 'default_seller';
}
// 处理联系人信息
let productContact = '';
let contactPhone = '';
if (contactId) {
console.log('开始处理联系人信息,contactId:', contactId);
// 从userlogin数据库获取联系人信息
const userLoginConnection = await userLoginPool.getConnection();
const [personnelData] = await userLoginConnection.query(
'SELECT alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != "" AND id = ?',
[parseInt(contactId)] // 使用contactId直接查询对应的联系人
);
userLoginConnection.release();
console.log('查询到的联系人数据:', personnelData);
if (personnelData && personnelData.length > 0) {
productContact = personnelData[0].alias || '';
contactPhone = personnelData[0].phoneNumber || '';
console.log('获取到的联系人信息:', productContact, contactPhone);
}
}
console.log('准备插入的联系人信息:', productContact, contactPhone);
// 生成唯一的productId
const productId = `product_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
// 处理图片上传
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 productData = {
productId,
sellerId: sellerId, // 使用前端传入的sellerId
productName,
category: category || '', // 添加种类
price: price.toString(), // 确保是varchar类型
quantity: parseInt(quantity),
grossWeight,
yolk,
specification,
quality,
region,
status: 'published', // 直接上架,而不是审核中
supplyStatus: supplyStatus || '', // 预售/现货
sourceType: sourceType || '', // 平台货源/三方认证/三方未认证
description: description || '',
rejectReason: '',
imageUrls: uploadedImageUrls.length > 0 ? JSON.stringify(uploadedImageUrls) : '[]',
created_at: new Date(),
product_contact: productContact, // 添加联系人名称
contact_phone: contactPhone // 添加联系人电话
};
// 插入商品数据
let result;
try {
// 检查products表是否有quality字段
const [columns] = await connection.query('SHOW COLUMNS FROM products LIKE ?', ['quality']);
let insertQuery;
let insertParams;
if (columns.length === 0) {
// 没有quality字段,不包含quality字段的插入
insertQuery = 'INSERT INTO products (productId, sellerId, productName, category, price, quantity, grossWeight, yolk, specification, region, status, supplyStatus, sourceType, description, rejectReason, imageUrls, created_at, audit_time, product_contact, contact_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
insertParams = [
productId, productData.sellerId, productName, category || '', price.toString(), parseInt(quantity), grossWeight,
yolk, specification, region, productData.status, productData.supplyStatus, productData.sourceType,
productData.description, productData.rejectReason, productData.imageUrls, new Date(), new Date(),
productContact, contactPhone // 添加联系人信息
];
} else {
// 有quality字段,包含quality字段的插入
insertQuery = 'INSERT INTO products (productId, sellerId, productName, category, price, quantity, grossWeight, yolk, specification, quality, region, status, supplyStatus, sourceType, description, rejectReason, imageUrls, created_at, audit_time, product_contact, contact_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
insertParams = [
productId, productData.sellerId, productName, category || '', price.toString(), parseInt(quantity), grossWeight,
yolk, specification, quality, region, productData.status, productData.supplyStatus,
productData.sourceType, productData.description, productData.rejectReason, productData.imageUrls,
new Date(), new Date(), productContact, contactPhone // 添加联系人信息
];
}
result = await connection.query(insertQuery, insertParams);
} catch (insertError) {
await connection.rollback();
connection.release();
console.error('插入商品数据失败:', insertError.message);
console.error('SQL错误:', insertError.sqlMessage);
return sendResponse(res, false, null, `创建货源失败: ${insertError.sqlMessage}`);
}
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, { productId: result.insertId }, '货源创建成功');
} catch (error) {
if (connection) {
try {
await connection.rollback();
connection.release();
} catch (rollbackError) {
console.error('回滚失败:', rollbackError.message);
}
}
console.error('创建货源失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, `创建货源失败: ${error.message}`);
}
});
// 图片上传API - /api/upload-image
console.log('正在注册图片上传API路由: /api/upload-image');
app.post('/api/upload-image', async (req, res) => {
console.log('收到图片上传请求');
// 注意:这里需要实现实际的图片上传逻辑,包括OSS配置
// 由于当前缺少OSS配置,返回模拟数据
sendResponse(res, true, {
imageUrl: 'https://example.com/image.jpg',
message: '图片上传成功'
}, '图片上传成功');
});
// 获取审核失败原因API - /api/supplies/:id/reject-reason
console.log('正在注册获取审核失败原因API路由: /api/supplies/:id/reject-reason');
app.get('/api/supplies/:id/reject-reason', async (req, res) => {
console.log('收到获取审核失败原因请求:', req.params.id);
try {
const connection = await pool.getConnection();
const supplyId = req.params.id;
// 查询该货源的拒绝原因
const [supply] = await connection.query(
'SELECT rejectReason FROM products WHERE id = ?',
[supplyId]
);
connection.release();
if (supply.length === 0) {
return sendResponse(res, false, null, '货源不存在');
}
sendResponse(res, true, {
rejectReason: supply[0].rejectReason
}, '获取审核失败原因成功');
} catch (error) {
console.error('获取审核失败原因失败:', error.message);
sendResponse(res, false, null, '获取审核失败原因失败');
}
});
// 下架货源API - /api/supplies/:id/unpublish
console.log('正在注册下架货源API路由: /api/supplies/:id/unpublish');
app.post('/api/supplies/:id/unpublish', async (req, res) => {
console.log('收到下架货源请求:', req.params.id);
try {
const connection = await pool.getConnection();
const productId = req.params.id;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 更新状态为下架
await connection.query(
'UPDATE products SET status = ? WHERE id = ?',
['hidden', productId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '货源下架成功');
} catch (error) {
console.error('下架货源失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '货源下架失败');
}
});
// 上架货源API - /api/supplies/:id/publish
console.log('正在注册上架货源API路由: /api/supplies/:id/publish');
app.post('/api/supplies/:id/publish', async (req, res) => {
console.log('收到上架货源请求:', req.params.id);
try {
const connection = await pool.getConnection();
const productId = req.params.id;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 更新状态为审核中
await connection.query(
'UPDATE products SET status = ? WHERE id = ?',
['pending_review', productId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '货源已提交审核');
} catch (error) {
console.error('上架货源失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '货源上架失败');
}
});
// 删除货源API - /api/supplies/:id/delete
console.log('正在注册删除货源API路由: /api/supplies/:id/delete');
app.post('/api/supplies/:id/delete', async (req, res) => {
console.log('收到删除货源请求:', req.params.id);
try {
const connection = await pool.getConnection();
const productId = req.params.id;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 删除货源
await connection.query(
'DELETE FROM products WHERE id = ?',
[productId]
);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '货源删除成功');
} catch (error) {
console.error('删除货源失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '货源删除失败');
}
});
// 编辑货源API - /api/supplies/:id/edit
console.log('正在注册编辑货源API路由: /api/supplies/:id/edit');
app.put('/api/supplies/:id/edit', async (req, res) => {
console.log('收到编辑货源请求:', req.params.id, req.body);
try {
const connection = await pool.getConnection();
const productId = req.params.id;
const { productName, price, quantity, grossWeight, yolk, specification, supplyStatus, description, region, contactId } = req.body;
// 开始事务
await connection.beginTransaction();
// 检查当前状态
const [currentProduct] = await connection.query(
'SELECT status FROM products WHERE id = ?',
[productId]
);
if (currentProduct.length === 0) {
await connection.rollback();
connection.release();
return sendResponse(res, false, null, '货源不存在');
}
// 处理联系人信息
let productContact = '';
let contactPhone = '';
if (contactId) {
// 从userlogin数据库获取联系人信息
const userLoginConnection = await userLoginPool.getConnection();
const [personnelData] = await userLoginConnection.query(
'SELECT alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != "" AND id = ?',
[parseInt(contactId)] // 使用contactId直接查询对应的联系人
);
userLoginConnection.release();
if (personnelData && personnelData.length > 0) {
productContact = personnelData[0].alias || '';
contactPhone = personnelData[0].phoneNumber || '';
}
}
// 更新货源信息
const updateQuery = `
UPDATE products
SET productName = ?, price = ?, quantity = ?, grossWeight = ?,
yolk = ?, specification = ?, supplyStatus = ?, description = ?, region = ?,
product_contact = ?, contact_phone = ?
WHERE id = ?
`;
await connection.query(updateQuery, [
productName, price.toString(), parseInt(quantity), grossWeight,
yolk, specification, supplyStatus, description, region,
productContact, contactPhone, productId
]);
// 提交事务
await connection.commit();
connection.release();
sendResponse(res, true, null, '货源编辑成功');
} catch (error) {
console.error('编辑货源失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '货源编辑失败');
}
});
// 供应商列表查询API - /api/suppliers
console.log('正在注册供应商列表查询API路由: /api/suppliers');
app.get('/api/suppliers', async (req, res) => {
console.log('收到供应商列表查询请求:', req.query);
try {
const connection = await pool.getConnection();
const { page = 1, pageSize = 10, status = '', keyword = '', phoneNumber = '' } = req.query;
// 构建查询条件
let whereClause = '';
let params = [];
// 添加状态筛选
if (status) {
whereClause += ` WHERE partnerstatus = ?`;
params.push(status);
}
// 添加关键词搜索
if (keyword) {
whereClause += status ? ' AND' : ' WHERE';
whereClause += ` (username LIKE ? OR company LIKE ? OR phoneNumber LIKE ?)`;
params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`);
}
// 添加手机号搜索(优先级高于keyword中的手机号搜索)
if (phoneNumber) {
whereClause += (status || keyword) ? ' AND' : ' WHERE';
whereClause += ` phoneNumber LIKE ?`;
params.push(`%${phoneNumber}%`);
}
// 获取总数
const [totalResult] = await connection.query(
`SELECT COUNT(*) as total FROM users${whereClause}`,
params
);
const total = totalResult[0].total;
// 计算分页
const offset = (page - 1) * pageSize;
params.push(parseInt(pageSize), offset);
// 查询供应商列表
const [suppliers] = await connection.query(
`SELECT userId, phoneNumber, province, city, district, detailedaddress, company, collaborationid, cooperation, businesslicenseurl, proofurl, brandurl, partnerstatus, reasonforfailure, reject_reason, terminate_reason, audit_time
FROM users${whereClause}
ORDER BY audit_time DESC LIMIT ? OFFSET ?`,
params
);
connection.release();
sendResponse(res, true, {
list: suppliers,
total,
page: parseInt(page),
pageSize: parseInt(pageSize)
}, '查询成功');
} catch (error) {
console.error('供应商列表查询失败:', error.message);
console.error('错误详情:', error);
sendResponse(res, false, null, '供应商列表查询失败');
}
});
// 首页路由
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'Reject.html'));
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error('服务器错误:', err.message);
console.error('错误详情:', err);
res.status(500).json({
success: false,
message: '服务器内部错误'
});
});
// 启动服务器
async function startServer() {
try {
await initDatabase();
app.listen(PORT, () => {
console.log(`服务器已启动,监听端口 ${PORT}`);
console.log(`访问地址: http://localhost:${PORT}`);
});
} catch (error) {
console.error('服务器启动失败:', error.message);
console.error('错误详情:', error);
// 如果启动失败,尝试重新启动
setTimeout(() => {
console.log('尝试重新启动服务器...');
startServer();
}, 5000);
}
}
// 确保数据库结构
async function ensureDatabaseSchema() {
console.log('开始执行数据库结构检查...');
try {
const connection = await pool.getConnection();
console.log('获取数据库连接成功');
// 检查users表是否有必要的字段
console.log('检查users表是否有partnerstatus字段...');
const [partnerStatusColumns] = await connection.query(
'SHOW COLUMNS FROM `users` LIKE ?',
['partnerstatus']
);
console.log('检查表字段结果:', partnerStatusColumns.length > 0 ? '已存在' : '不存在');
if (partnerStatusColumns.length === 0) {
console.log('添加partnerstatus字段到users表...');
await connection.query(
'ALTER TABLE `users` ADD COLUMN partnerstatus VARCHAR(50) DEFAULT "underreview" COMMENT "合作商状态"'
);
console.log('partnerstatus字段添加成功');
}
console.log('检查users表是否有reject_reason字段...');
const [rejectReasonColumns] = await connection.query(
'SHOW COLUMNS FROM `users` LIKE ?',
['reject_reason']
);
console.log('检查表字段结果:', rejectReasonColumns.length > 0 ? '已存在' : '不存在');
if (rejectReasonColumns.length === 0) {
console.log('添加reject_reason字段到users表...');
await connection.query(
'ALTER TABLE `users` ADD COLUMN reject_reason TEXT COMMENT "拒绝理由"'
);
console.log('reject_reason字段添加成功');
}
console.log('检查users表是否有terminate_reason字段...');
const [terminateReasonColumns] = await connection.query(
'SHOW COLUMNS FROM `users` LIKE ?',
['terminate_reason']
);
console.log('检查表字段结果:', terminateReasonColumns.length > 0 ? '已存在' : '不存在');
if (terminateReasonColumns.length === 0) {
console.log('添加terminate_reason字段到users表...');
await connection.query(
'ALTER TABLE `users` ADD COLUMN terminate_reason TEXT COMMENT "终止合作理由"'
);
console.log('terminate_reason字段添加成功');
}
console.log('检查users表是否有audit_time字段...');
const [userAuditTimeColumns] = await connection.query(
'SHOW COLUMNS FROM `users` LIKE ?',
['audit_time']
);
console.log('检查表字段结果:', userAuditTimeColumns.length > 0 ? '已存在' : '不存在');
if (userAuditTimeColumns.length === 0) {
console.log('添加audit_time字段到users表...');
await connection.query(
'ALTER TABLE `users` ADD COLUMN audit_time DATETIME COMMENT "审核时间"'
);
console.log('audit_time字段添加成功');
}
// 检查表是否有rejectReason字段
console.log('检查表products是否有rejectReason字段...');
const [columns] = await connection.query(
'SHOW COLUMNS FROM `products` LIKE ?',
['rejectReason']
);
console.log('检查表字段结果:', columns.length > 0 ? '已存在' : '不存在');
if (columns.length === 0) {
console.log('添加rejectReason字段到products表...');
await connection.query(
'ALTER TABLE `products` ADD COLUMN rejectReason TEXT COMMENT "拒绝理由"'
);
console.log('rejectReason字段添加成功');
}
// 检查表是否有audit_time字段
console.log('检查表products是否有audit_time字段...');
const [auditTimeColumns] = await connection.query(
'SHOW COLUMNS FROM `products` LIKE ?',
['audit_time']
);
console.log('检查表字段结果:', auditTimeColumns.length > 0 ? '已存在' : '不存在');
if (auditTimeColumns.length === 0) {
console.log('添加audit_time字段到products表...');
await connection.query(
'ALTER TABLE `products` ADD COLUMN audit_time DATETIME COMMENT "审核时间"'
);
console.log('audit_time字段添加成功');
}
// 检查audit_logs表是否存在,如果不存在则创建
console.log('检查audit_logs表是否存在...');
const [tables] = await connection.query(
"SHOW TABLES LIKE 'audit_logs'"
);
console.log('检查表存在性结果:', tables.length > 0 ? '已存在' : '不存在');
if (tables.length === 0) {
console.log('创建audit_logs表...');
await connection.query(`
CREATE TABLE audit_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
supply_id VARCHAR(50) NOT NULL,
action VARCHAR(20) NOT NULL COMMENT 'approve或reject',
user_id VARCHAR(50) NOT NULL COMMENT '操作人ID',
remark TEXT COMMENT '备注信息',
created_at DATETIME NOT NULL,
INDEX idx_supply_id (supply_id),
INDEX idx_created_at (created_at)
) COMMENT '审核操作日志表'
`);
console.log('audit_logs表创建成功');
}
connection.release();
console.log('数据库结构检查完成');
} catch (error) {
console.error('数据库结构检查失败:', error.message);
console.error('错误详情:', error);
}
}
// 启动服务器
startServer();
// 优雅关闭
process.on('SIGINT', async () => {
console.log('正在关闭服务器...');
if (pool) {
try {
await pool.end();
console.log('数据库连接池已关闭');
} catch (error) {
console.error('关闭数据库连接池失败:', error.message);
}
}
console.log('服务器已关闭');
process.exit(0);
});
module.exports = app;