|
|
@ -211,6 +211,9 @@ app.get('/api/eggbar/posts', async (req, res) => { |
|
|
} |
|
|
} |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
console.log('数据库查询结果数量:', posts.length); |
|
|
|
|
|
console.log('数据库查询结果:', posts); |
|
|
|
|
|
|
|
|
// 关闭临时连接
|
|
|
// 关闭临时连接
|
|
|
await tempSequelize.close(); |
|
|
await tempSequelize.close(); |
|
|
|
|
|
|
|
|
@ -233,20 +236,78 @@ app.get('/api/eggbar/posts', async (req, res) => { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 格式化响应数据
|
|
|
// 格式化响应数据
|
|
|
const formattedPosts = paginatedPosts.map(post => ({ |
|
|
let formattedPosts = paginatedPosts.map(post => { |
|
|
id: post.id, |
|
|
// 解析images字段,确保它是一个数组
|
|
|
user_id: post.user_id, |
|
|
let images = []; |
|
|
phone: post.phone, |
|
|
if (post.images) { |
|
|
content: post.content, |
|
|
if (typeof post.images === 'string') { |
|
|
images: post.images, |
|
|
try { |
|
|
topic: post.topic, |
|
|
images = JSON.parse(post.images); |
|
|
likes: post.likes || 0, |
|
|
if (!Array.isArray(images)) { |
|
|
comments: post.comments || 0, |
|
|
images = []; |
|
|
shares: post.shares || 0, |
|
|
} |
|
|
status: post.status, |
|
|
} catch (e) { |
|
|
created_at: post.created_at, |
|
|
images = []; |
|
|
updated_at: post.updated_at |
|
|
} |
|
|
})); |
|
|
} else if (Array.isArray(post.images)) { |
|
|
|
|
|
images = post.images; |
|
|
|
|
|
} else { |
|
|
|
|
|
images = []; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
id: post.id, |
|
|
|
|
|
user_id: post.user_id, |
|
|
|
|
|
phone: post.phone, |
|
|
|
|
|
content: post.content, |
|
|
|
|
|
images: images, |
|
|
|
|
|
topic: post.topic, |
|
|
|
|
|
likes: post.likes || 0, |
|
|
|
|
|
comments: post.comments || 0, |
|
|
|
|
|
shares: post.shares || 0, |
|
|
|
|
|
status: post.status, |
|
|
|
|
|
created_at: post.created_at, |
|
|
|
|
|
updated_at: post.updated_at |
|
|
|
|
|
}; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否已点赞
|
|
|
|
|
|
const phone = req.query.phone || req.headers['x-phone']; |
|
|
|
|
|
if (phone) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 批量检查点赞状态
|
|
|
|
|
|
const postsWithLikedStatus = await Promise.all(formattedPosts.map(async post => { |
|
|
|
|
|
const existingLike = await EggbarLike.findOne({ |
|
|
|
|
|
where: { |
|
|
|
|
|
post_id: post.id, |
|
|
|
|
|
phone: phone |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
return { |
|
|
|
|
|
...post, |
|
|
|
|
|
liked: !!existingLike |
|
|
|
|
|
}; |
|
|
|
|
|
})); |
|
|
|
|
|
formattedPosts = postsWithLikedStatus; |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.warn('批量检查点赞状态时出错:', error); |
|
|
|
|
|
// 如果出错,给所有帖子添加默认未点赞状态
|
|
|
|
|
|
formattedPosts = formattedPosts.map(post => ({ |
|
|
|
|
|
...post, |
|
|
|
|
|
liked: false |
|
|
|
|
|
})); |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 没有电话号码,给所有帖子添加默认未点赞状态
|
|
|
|
|
|
formattedPosts = formattedPosts.map(post => ({ |
|
|
|
|
|
...post, |
|
|
|
|
|
liked: false |
|
|
|
|
|
})); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log('5. 帖子列表格式化完成,带点赞状态'); |
|
|
|
|
|
console.log('格式化后的数据数量:', formattedPosts.length); |
|
|
|
|
|
|
|
|
res.json({ |
|
|
res.json({ |
|
|
success: true, |
|
|
success: true, |
|
|
@ -422,21 +483,125 @@ app.post('/api/eggbar/upload', upload.single('image'), async (req, res) => { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 使用OSS上传图片
|
|
|
const tempFilePath = req.file.path; |
|
|
const imageUrl = await OssUploader.uploadFile(req.file.path, 'eggbar', 'image'); |
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 使用OSS上传图片
|
|
|
|
|
|
const imageUrl = await OssUploader.uploadFile(tempFilePath, 'eggbar', 'image'); |
|
|
|
|
|
|
|
|
|
|
|
console.log('3. 图片上传成功,URL:', imageUrl); |
|
|
|
|
|
|
|
|
|
|
|
// 删除临时文件
|
|
|
|
|
|
if (fs.existsSync(tempFilePath)) { |
|
|
|
|
|
fs.unlinkSync(tempFilePath); |
|
|
|
|
|
console.log('4. 临时文件已删除:', tempFilePath); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
res.json({ |
|
|
|
|
|
success: true, |
|
|
|
|
|
message: '图片上传成功', |
|
|
|
|
|
imageUrl: imageUrl |
|
|
|
|
|
}); |
|
|
|
|
|
} finally { |
|
|
|
|
|
// 确保临时文件被删除,即使OSS上传失败
|
|
|
|
|
|
if (tempFilePath && fs.existsSync(tempFilePath)) { |
|
|
|
|
|
try { |
|
|
|
|
|
fs.unlinkSync(tempFilePath); |
|
|
|
|
|
console.log('临时文件已清理:', tempFilePath); |
|
|
|
|
|
} catch (cleanupError) { |
|
|
|
|
|
console.warn('清理临时文件时出错:', cleanupError); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('上传图片失败:', error); |
|
|
|
|
|
res.status(500).json({ |
|
|
|
|
|
success: false, |
|
|
|
|
|
message: '上传图片失败: ' + error.message |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Eggbar 点赞接口
|
|
|
|
|
|
app.post('/api/eggbar/posts/:postId/like', async (req, res) => { |
|
|
|
|
|
try { |
|
|
|
|
|
const postId = parseInt(req.params.postId); |
|
|
|
|
|
const { phone } = req.body; |
|
|
|
|
|
|
|
|
|
|
|
console.log('===== 收到点赞请求 ====='); |
|
|
|
|
|
console.log('1. 动态ID:', postId); |
|
|
|
|
|
console.log('2. 电话号码:', phone); |
|
|
|
|
|
|
|
|
|
|
|
// 数据验证
|
|
|
|
|
|
if (!postId || !phone) { |
|
|
|
|
|
return res.status(400).json({ |
|
|
|
|
|
success: false, |
|
|
|
|
|
code: 400, |
|
|
|
|
|
message: '缺少必要参数' |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 检查动态是否存在
|
|
|
|
|
|
const post = await EggbarPost.findByPk(postId); |
|
|
|
|
|
if (!post) { |
|
|
|
|
|
return res.status(404).json({ |
|
|
|
|
|
success: false, |
|
|
|
|
|
code: 404, |
|
|
|
|
|
message: '动态不存在' |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否已经点过赞
|
|
|
|
|
|
const existingLike = await EggbarLike.findOne({ |
|
|
|
|
|
where: { |
|
|
|
|
|
post_id: postId, |
|
|
|
|
|
phone: phone |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
let isLiked = false; |
|
|
|
|
|
let newLikeCount = post.likes || 0; |
|
|
|
|
|
|
|
|
|
|
|
if (existingLike) { |
|
|
|
|
|
// 已经点过赞,取消点赞
|
|
|
|
|
|
await existingLike.destroy(); |
|
|
|
|
|
newLikeCount = Math.max(0, newLikeCount - 1); |
|
|
|
|
|
isLiked = false; |
|
|
|
|
|
console.log('3. 取消点赞成功'); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 没点过赞,添加点赞
|
|
|
|
|
|
await EggbarLike.create({ |
|
|
|
|
|
post_id: postId, |
|
|
|
|
|
phone: phone |
|
|
|
|
|
}); |
|
|
|
|
|
newLikeCount = newLikeCount + 1; |
|
|
|
|
|
isLiked = true; |
|
|
|
|
|
console.log('3. 点赞成功'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新动态的点赞数
|
|
|
|
|
|
await EggbarPost.update( |
|
|
|
|
|
{ likes: newLikeCount }, |
|
|
|
|
|
{ where: { id: postId } } |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
console.log('3. 图片上传成功,URL:', imageUrl); |
|
|
console.log('4. 点赞数更新成功,新点赞数:', newLikeCount); |
|
|
|
|
|
|
|
|
res.json({ |
|
|
res.json({ |
|
|
success: true, |
|
|
success: true, |
|
|
message: '图片上传成功', |
|
|
code: 200, |
|
|
imageUrl: imageUrl |
|
|
message: isLiked ? '点赞成功' : '取消点赞成功', |
|
|
|
|
|
data: { |
|
|
|
|
|
isLiked: isLiked, |
|
|
|
|
|
likes: newLikeCount |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('上传图片失败:', error); |
|
|
console.error('点赞操作失败:', error); |
|
|
res.status(500).json({ |
|
|
res.status(500).json({ |
|
|
success: false, |
|
|
success: false, |
|
|
message: '上传图片失败: ' + error.message |
|
|
code: 500, |
|
|
|
|
|
message: '点赞操作失败: ' + error.message |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
@ -1642,6 +1807,37 @@ EggbarPost.init({ |
|
|
timestamps: false |
|
|
timestamps: false |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Eggbar 点赞模型 - 用于存储用户点赞记录
|
|
|
|
|
|
class EggbarLike extends Model { } |
|
|
|
|
|
EggbarLike.init({ |
|
|
|
|
|
id: { |
|
|
|
|
|
type: DataTypes.INTEGER, |
|
|
|
|
|
primaryKey: true, |
|
|
|
|
|
autoIncrement: true, |
|
|
|
|
|
comment: '点赞记录ID' |
|
|
|
|
|
}, |
|
|
|
|
|
post_id: { |
|
|
|
|
|
type: DataTypes.INTEGER, |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '动态ID' |
|
|
|
|
|
}, |
|
|
|
|
|
phone: { |
|
|
|
|
|
type: DataTypes.STRING(255), |
|
|
|
|
|
allowNull: false, |
|
|
|
|
|
comment: '电话号码' |
|
|
|
|
|
}, |
|
|
|
|
|
created_at: { |
|
|
|
|
|
type: DataTypes.DATE, |
|
|
|
|
|
defaultValue: Sequelize.NOW, |
|
|
|
|
|
comment: '创建时间' |
|
|
|
|
|
} |
|
|
|
|
|
}, { |
|
|
|
|
|
sequelize: eggbarSequelize, |
|
|
|
|
|
modelName: 'EggbarLike', |
|
|
|
|
|
tableName: 'eggbar_likes', |
|
|
|
|
|
timestamps: false |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 定义模型之间的关联关系
|
|
|
// 定义模型之间的关联关系
|
|
|
|
|
|
|
|
|
// 用户和商品的一对多关系 (卖家发布商品)
|
|
|
// 用户和商品的一对多关系 (卖家发布商品)
|
|
|
@ -2907,7 +3103,11 @@ app.post('/api/products/upload', upload.array('images', 10), async (req, res) => |
|
|
const uploadedFileUrls = new Set(); |
|
|
const uploadedFileUrls = new Set(); |
|
|
|
|
|
|
|
|
// 准备文件路径数组
|
|
|
// 准备文件路径数组
|
|
|
const filePaths = uploadedFiles.map(file => file.path); |
|
|
const filePaths = uploadedFiles.map(file => { |
|
|
|
|
|
// 添加到临时文件清理列表
|
|
|
|
|
|
tempFilesToClean.push(file.path); |
|
|
|
|
|
return file.path; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 使用商品名称作为文件夹名,确保每个商品的图片独立存储
|
|
|
// 使用商品名称作为文件夹名,确保每个商品的图片独立存储
|
|
|
// 移除商品名称中的特殊字符,确保可以作为合法的文件夹名
|
|
|
// 移除商品名称中的特殊字符,确保可以作为合法的文件夹名
|
|
|
@ -4081,15 +4281,30 @@ app.post('/api/products/upload', upload.array('images', 10), async (req, res) => |
|
|
code: 500, |
|
|
code: 500, |
|
|
error: err.message |
|
|
error: err.message |
|
|
}); |
|
|
}); |
|
|
|
|
|
} finally { |
|
|
|
|
|
// 确保临时文件被清理
|
|
|
|
|
|
if (tempFilesToClean.length > 0) { |
|
|
|
|
|
try { |
|
|
|
|
|
cleanTempFiles(tempFilesToClean); |
|
|
|
|
|
} catch (cleanupError) { |
|
|
|
|
|
console.warn('清理临时文件时出错:', cleanupError); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 【关键修复】在 handleAddImagesToExistingProduct 函数中加强图片合并逻辑
|
|
|
// 【关键修复】在 handleAddImagesToExistingProduct 函数中加强图片合并逻辑
|
|
|
async function handleAddImagesToExistingProduct(req, res, existingProductId, uploadedFiles) { |
|
|
async function handleAddImagesToExistingProduct(req, res, existingProductId, uploadedFiles) { |
|
|
let transaction; |
|
|
let transaction; |
|
|
|
|
|
let tempFilesToClean = []; |
|
|
try { |
|
|
try { |
|
|
console.log('【图片更新模式】开始处理图片上传到已存在商品,商品ID:', existingProductId); |
|
|
console.log('【图片更新模式】开始处理图片上传到已存在商品,商品ID:', existingProductId); |
|
|
|
|
|
|
|
|
|
|
|
// 收集需要清理的临时文件路径
|
|
|
|
|
|
for (const file of uploadedFiles) { |
|
|
|
|
|
tempFilesToClean.push(file.path); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 使用事务确保数据一致性
|
|
|
// 使用事务确保数据一致性
|
|
|
transaction = await sequelize.transaction(); |
|
|
transaction = await sequelize.transaction(); |
|
|
|
|
|
|
|
|
@ -4247,6 +4462,15 @@ async function handleAddImagesToExistingProduct(req, res, existingProductId, upl |
|
|
code: 500, |
|
|
code: 500, |
|
|
error: error.message |
|
|
error: error.message |
|
|
}); |
|
|
}); |
|
|
|
|
|
} finally { |
|
|
|
|
|
// 确保临时文件被清理
|
|
|
|
|
|
if (tempFilesToClean.length > 0) { |
|
|
|
|
|
try { |
|
|
|
|
|
cleanTempFiles(tempFilesToClean); |
|
|
|
|
|
} catch (cleanupError) { |
|
|
|
|
|
console.warn('清理临时文件时出错:', cleanupError); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -7506,6 +7730,7 @@ app.post('/api/settlement/submit', async (req, res) => { |
|
|
|
|
|
|
|
|
// 上传入驻文件
|
|
|
// 上传入驻文件
|
|
|
app.post('/api/settlement/upload', upload.single('file'), async (req, res) => { |
|
|
app.post('/api/settlement/upload', upload.single('file'), async (req, res) => { |
|
|
|
|
|
let tempFilePath = null; |
|
|
try { |
|
|
try { |
|
|
const { openid, fileType } = req.body; |
|
|
const { openid, fileType } = req.body; |
|
|
|
|
|
|
|
|
@ -7527,12 +7752,13 @@ app.post('/api/settlement/upload', upload.single('file'), async (req, res) => { |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tempFilePath = req.file.path; |
|
|
|
|
|
|
|
|
// 上传文件到OSS - 使用静态方法调用
|
|
|
// 上传文件到OSS - 使用静态方法调用
|
|
|
// 注意:OssUploader.uploadFile直接返回URL字符串,而不是包含url属性的对象
|
|
|
// 注意:OssUploader.uploadFile直接返回URL字符串,而不是包含url属性的对象
|
|
|
const fileUrl = await OssUploader.uploadFile(req.file.path, `settlement/${fileType}/${Date.now()}_${req.file.originalname}`); |
|
|
const fileUrl = await OssUploader.uploadFile(tempFilePath, `settlement/${fileType}/${Date.now()}_${req.file.originalname}`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 删除临时文件
|
|
|
|
|
|
fs.unlinkSync(req.file.path); |
|
|
|
|
|
|
|
|
|
|
|
// 确保返回的URL是干净的字符串,移除可能存在的反引号和空格
|
|
|
// 确保返回的URL是干净的字符串,移除可能存在的反引号和空格
|
|
|
const cleanFileUrl = String(fileUrl).replace(/[` ]/g, ''); |
|
|
const cleanFileUrl = String(fileUrl).replace(/[` ]/g, ''); |
|
|
@ -7549,16 +7775,21 @@ app.post('/api/settlement/upload', upload.single('file'), async (req, res) => { |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('入驻文件上传失败:', error); |
|
|
console.error('入驻文件上传失败:', error); |
|
|
|
|
|
|
|
|
// 清理临时文件
|
|
|
|
|
|
if (req.file && fs.existsSync(req.file.path)) { |
|
|
|
|
|
fs.unlinkSync(req.file.path); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
res.status(500).json({ |
|
|
res.status(500).json({ |
|
|
success: false, |
|
|
success: false, |
|
|
code: 500, |
|
|
code: 500, |
|
|
message: '文件上传失败: ' + error.message |
|
|
message: '文件上传失败: ' + error.message |
|
|
}); |
|
|
}); |
|
|
|
|
|
} finally { |
|
|
|
|
|
// 确保临时文件被清理
|
|
|
|
|
|
if (tempFilePath && fs.existsSync(tempFilePath)) { |
|
|
|
|
|
try { |
|
|
|
|
|
fs.unlinkSync(tempFilePath); |
|
|
|
|
|
console.log('临时文件已清理:', tempFilePath); |
|
|
|
|
|
} catch (cleanupError) { |
|
|
|
|
|
console.warn('清理临时文件时出错:', cleanupError); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|