消息处理

This commit is contained in:
@zuopngfei 2025-11-06 17:19:33 +08:00
parent 1d4ab75441
commit bb20e4ea87
3 changed files with 96 additions and 158 deletions

View File

@ -1,106 +1,31 @@
const request = require('./request.js')
const uploadFile = async (file, callback) => {
const policyData = await request('admin/policy_token', 'post') function uploadFile(filePath) {
const res = JSON.parse(policyData.token) return new Promise((resolve, reject) => {
if (!filePath) {
const fileName = file.tempFilePath.split('/').pop(); // hello.png const err = new Error('uploadFile requires a filePath parameter');
// const fileName = fileNameWithExt.split('.').slice(0, -1).join('.'); // hello console.error('上传失败:未提供文件路径', err);
return reject(err);
const formData = {
key: 'upload_file/' + fileName, //上传文件名称
policy: res.policy, //表单域
'x-oss-signature-version': res.x_oss_signature_version, //指定签名的版本和算法
'x-oss-credential': res.x_oss_credential, //指明派生密钥的参数集
'x-oss-date': res.x_oss_date, //请求的时间
'x-oss-signature': res.signature, //签名认证描述信息
'x-oss-security-token': res.security_token, //安全令牌
success_action_status: "200" //上传成功后响应状态码
};
// console.log(filePath)
// return
// 发送请求上传文件
wx.uploadFile({
url: 'https://image-fudan.oss-cn-beijing.aliyuncs.com/',
method: 'put',
filePath: file.tempFilePath,
name: 'file', //固定值为file
formData: formData,
success(res) {
console.log('上传响应:', res);
if (res.statusCode === 200) {
callback(null, 'https://image-fudan.oss-cn-beijing.aliyuncs.com/upload_file/' + fileName); // 上传成功
} else {
console.error('上传失败,状态码:', res.statusCode);
console.error('失败响应:', res);
callback(res); // 上传失败,返回响应
}
},
fail(err) {
console.error('上传失败:', err); // 输出错误信息
wx.showToast({
title: '上传失败,请重试!',
icon: 'none'
});
callback(err); // 调用回调处理错误
} }
});
wx.uploadFile({
filePath: filePath, // 图片临时文件路径(由调用方传入)
name: 'file', // 服务器接收文件的字段名,需与后端对应
url: 'https://mini-chat.1024tool.vip/api/admin/upload/image', // 服务器接收图片的接口地址
success: (res) => {
const data = JSON.parse(res.data);
resolve('https://mini-chat.1024tool.vip/' + data.preview_image_url);
},
fail: (err) => {
console.error('上传失败', err);
reject(err);
}
});
})
} }
const uploadFileToOSS = () => { // 导出请求和服务地址CommonJS 兼容)
module.exports = uploadFile;
return new Promise((resolve, reject) => {
wx.chooseMedia({
count: 1, // 选择一个文件
mediaType: ['image'],
sourceType: ['album', 'camera'],
// type: 'all', // 支持所有类型的文件
success: (res) => {
wx.showToast({
title: '文件上传中,请稍等!',
icon: 'none'
});
console.log('选择的文件:', res.tempFiles); // 输出选择的文件信息
if (res.tempFiles.length > 0) {
const tempFilePath = res.tempFiles[0];
console.log('选择的文件路径:', tempFilePath); // 输出文件路径
uploadFile(tempFilePath, (error, data) => {
if (error) {
wx.showToast({
title: '上传失败!',
icon: 'none'
});
console.error('上传失败:', error); // 输出具体的错误信息
reject(error)
} else {
resolve(data)
console.log('上传成功:', data); // 输出上传成功后的数据
}
});
} else {
wx.showToast({
title: '未选择文件!',
icon: 'none'
});
reject('未选择文件!')
}
},
fail: (err) => {
wx.showToast({
title: '选择文件失败!',
icon: 'none'
});
console.error('选择文件失败:', err); // 输出选择文件的错误信息
reject('选择文件失败!')
}
});
});
};
// CommonJS 导出,适配微信开发者工具当前解析能力
module.exports = uploadFileToOSS;

View File

@ -1,7 +1,7 @@
// pages/contact/index.js // pages/contact/index.js
const request = require('../../api/request.js'); const request = require('../../api/request.js');
const uploadFile = require('../../api/upload.js');
Page({ Page({
/** /**
* 页面的初始数据 * 页面的初始数据
@ -73,18 +73,18 @@ Page({
}).then(res => { }).then(res => {
// 处理消息列表,使用统一的消息处理函数 // 处理消息列表,使用统一的消息处理函数
const list = that.processMessages(res.list); const list = that.processMessages(res.list);
// 根据ID进行排序确保ID最大的最新的消息在最后 // 根据ID进行排序确保ID最大的最新的消息在最后
const sortedList = that.sortMessagesByID(list); const sortedList = that.sortMessagesByID(list);
// 智能滚动逻辑:用户在底部时自动滚动,在上方时保持位置 // 智能滚动逻辑:用户在底部时自动滚动,在上方时保持位置
const updateData = { const updateData = {
messages: sortedList, messages: sortedList,
total: res.total total: res.total
}; };
that.setData(updateData); that.setData(updateData);
// 如果用户在底部延迟设置滚动ID确保滚动生效 // 如果用户在底部延迟设置滚动ID确保滚动生效
if (that.data.isAtBottom && sortedList.length > 0) { if (that.data.isAtBottom && sortedList.length > 0) {
const lastMessageId = sortedList[sortedList.length - 1].id; const lastMessageId = sortedList[sortedList.length - 1].id;
@ -98,7 +98,7 @@ Page({
} else { } else {
console.log('用户不在底部或无消息保持当前位置。isAtBottom:', that.data.isAtBottom, '消息数量:', sortedList.length); console.log('用户不在底部或无消息保持当前位置。isAtBottom:', that.data.isAtBottom, '消息数量:', sortedList.length);
} }
return res; // 返回结果以支持链式调用 return res; // 返回结果以支持链式调用
}); });
}, },
@ -131,7 +131,7 @@ Page({
// 合并新消息和现有消息 // 合并新消息和现有消息
const combined = newList.concat(that.data.messages); const combined = newList.concat(that.data.messages);
// 根据ID进行排序确保ID最大的最新的消息在最后 // 根据ID进行排序确保ID最大的最新的消息在最后
const sortedCombined = that.sortMessagesByID(combined); const sortedCombined = that.sortMessagesByID(combined);
@ -165,41 +165,43 @@ Page({
// 兜底方案:使用当前时间戳 + 索引 // 兜底方案:使用当前时间戳 + 索引
item.id = 'm' + (Date.now() + index); item.id = 'm' + (Date.now() + index);
} }
// 解析消息内容 // 解析消息内容
if (typeof item.content === 'string') { if (typeof item.content === 'string') {
try { try {
item.content = JSON.parse(item.content); item.content = {
message: JSON.parse(item.content).message || JSON.parse(item.content).messages
}
} catch (e) { } catch (e) {
console.warn('消息内容解析失败:', item.content); console.warn('消息内容解析失败:', item.content);
item.content = { messages: item.content }; item.content = { message: item.content };
} }
} }
return item; return item;
}); });
// 检测新消息并显示提醒 // 检测新消息并显示提醒
this.checkNewMessages(processedMessages); this.checkNewMessages(processedMessages);
return processedMessages; return processedMessages;
}, },
// 检测新消息的函数 // 检测新消息的函数
checkNewMessages(newMessages) { checkNewMessages(newMessages) {
if (newMessages.length === 0) return; if (newMessages.length === 0) return;
const currentMessages = this.data.messages; const currentMessages = this.data.messages;
const currentLastMessageId = this.data.lastMessageId; const currentLastMessageId = this.data.lastMessageId;
const sortedNewMessages = this.sortMessagesByID(newMessages); const sortedNewMessages = this.sortMessagesByID(newMessages);
const latestNewMessage = sortedNewMessages[sortedNewMessages.length - 1]; const latestNewMessage = sortedNewMessages[sortedNewMessages.length - 1];
// 如果不在底部且有新消息 // 如果不在底部且有新消息
if (!this.data.isAtBottom && currentMessages.length > 0) { if (!this.data.isAtBottom && currentMessages.length > 0) {
// 找出真正的新消息(在当前消息列表中不存在的消息) // 找出真正的新消息(在当前消息列表中不存在的消息)
const currentMessageIds = new Set(currentMessages.map(msg => msg.id)); const currentMessageIds = new Set(currentMessages.map(msg => msg.id));
const realNewMessages = sortedNewMessages.filter(msg => !currentMessageIds.has(msg.id)); const realNewMessages = sortedNewMessages.filter(msg => !currentMessageIds.has(msg.id));
if (realNewMessages.length > 0) { if (realNewMessages.length > 0) {
// 累加新消息数量(而不是重置) // 累加新消息数量(而不是重置)
const currentCount = this.data.newMessageCount || 0; const currentCount = this.data.newMessageCount || 0;
@ -209,7 +211,7 @@ Page({
}); });
} }
} }
// 更新最后一条消息ID // 更新最后一条消息ID
if (latestNewMessage) { if (latestNewMessage) {
this.setData({ this.setData({
@ -239,7 +241,7 @@ Page({
} }
return 0; return 0;
}; };
const idA = getNumericId(a.id); const idA = getNumericId(a.id);
const idB = getNumericId(b.id); const idB = getNumericId(b.id);
return idA - idB; return idA - idB;
@ -282,7 +284,7 @@ Page({
}); });
}); });
}, },
fail: function(err) { fail: function (err) {
console.error('wx.login失败:', err); console.error('wx.login失败:', err);
} }
}); });
@ -337,7 +339,7 @@ Page({
// user scrolled to bottom (or very near). update state and ensure polling is active // user scrolled to bottom (or very near). update state and ensure polling is active
console.log('用户滚动到底部当前isAtBottom状态:', this.data.isAtBottom); console.log('用户滚动到底部当前isAtBottom状态:', this.data.isAtBottom);
if (!this.data.isAtBottom) { if (!this.data.isAtBottom) {
this.setData({ this.setData({
isAtBottom: true, isAtBottom: true,
showNewMessageTip: false, showNewMessageTip: false,
newMessageCount: 0 newMessageCount: 0
@ -392,7 +394,7 @@ Page({
// 使用用户ID作为标记检查是否已经发送过欢迎消息 // 使用用户ID作为标记检查是否已经发送过欢迎消息
const welcomeKey = `welcome_sent_${this.data.userInfo.openid}`; const welcomeKey = `welcome_sent_${this.data.userInfo.openid}`;
const hasWelcomeSent = wx.getStorageSync(welcomeKey); const hasWelcomeSent = wx.getStorageSync(welcomeKey);
if (hasWelcomeSent) { if (hasWelcomeSent) {
console.log('该用户的欢迎消息已发送过,跳过'); console.log('该用户的欢迎消息已发送过,跳过');
this.setData({ hasWelcomeMessageSent: true }); this.setData({ hasWelcomeMessageSent: true });
@ -402,11 +404,11 @@ Page({
const welcomeText = '你好'; const welcomeText = '你好';
const now = new Date(); const now = new Date();
const id = 'welcome_' + Date.now(); const id = 'welcome_' + Date.now();
const msg = { const msg = {
id, id,
content: { content: {
messages: welcomeText message: welcomeText
}, },
"msg_type": 1, "msg_type": 1,
receiver_id: '', receiver_id: '',
@ -414,11 +416,11 @@ Page({
sender_id: this.data.userInfo.openid, sender_id: this.data.userInfo.openid,
sender_name: this.data.userInfo.user_name sender_name: this.data.userInfo.user_name
}; };
// 添加新消息并重新排序 // 添加新消息并重新排序
const newMessages = this.data.messages.concat(msg); const newMessages = this.data.messages.concat(msg);
const sortedMessages = this.sortMessagesByID(newMessages); const sortedMessages = this.sortMessagesByID(newMessages);
this.setData({ this.setData({
messages: sortedMessages, messages: sortedMessages,
hasWelcomeMessageSent: true // 标记已发送欢迎消息 hasWelcomeMessageSent: true // 标记已发送欢迎消息
@ -426,14 +428,14 @@ Page({
const accountInfo = wx.getAccountInfoSync(); const accountInfo = wx.getAccountInfoSync();
const userInfo = wx.getStorageSync('user_info'); const userInfo = wx.getStorageSync('user_info');
console.log('发送欢迎消息:', welcomeText); console.log('发送欢迎消息:', welcomeText);
// 发送到服务器 // 发送到服务器
request('app/send_message', 'POST', { request('app/send_message', 'POST', {
"app_id": accountInfo.miniProgram.appId, "app_id": accountInfo.miniProgram.appId,
"content": JSON.stringify({ "content": JSON.stringify({
messages: welcomeText message: welcomeText
}), }),
"from_user_id": userInfo.openid, "from_user_id": userInfo.openid,
"from_user_name": userInfo.user_name, "from_user_name": userInfo.user_name,
@ -470,7 +472,7 @@ Page({
const msg = { const msg = {
id, id,
content: { content: {
messages: text message: text
}, },
"msg_type": 1, "msg_type": 1,
receiver_id: '', receiver_id: '',
@ -478,11 +480,11 @@ Page({
sender_id: this.data.userInfo.openid, sender_id: this.data.userInfo.openid,
sender_name: this.data.userInfo.user_name sender_name: this.data.userInfo.user_name
}; };
// 添加新消息并重新排序 // 添加新消息并重新排序
const newMessages = this.data.messages.concat(msg); const newMessages = this.data.messages.concat(msg);
const sortedMessages = this.sortMessagesByID(newMessages); const sortedMessages = this.sortMessagesByID(newMessages);
this.setData({ this.setData({
messages: sortedMessages, messages: sortedMessages,
inputText: '' inputText: ''
@ -492,7 +494,7 @@ Page({
request('app/send_message', 'POST', { request('app/send_message', 'POST', {
"app_id": accountInfo.miniProgram.appId, "app_id": accountInfo.miniProgram.appId,
"content": JSON.stringify({ "content": JSON.stringify({
messages: text message: text
}), }),
"from_user_id": userInfo.openid, "from_user_id": userInfo.openid,
"from_user_name": userInfo.user_name, "from_user_name": userInfo.user_name,
@ -550,7 +552,7 @@ Page({
msg_type: '2', msg_type: '2',
receiver_id: '', receiver_id: '',
content: { content: {
messages: tempFilePaths[0] message: tempFilePaths[0]
}, },
sender_id: userInfo.openid, sender_id: userInfo.openid,
sender_name: userInfo.user_name, sender_name: userInfo.user_name,
@ -567,30 +569,41 @@ Page({
scrollToId: id scrollToId: id
}); });
}, 50); }, 50);
uploadFile(tempFilePaths[0]).then((res) => {
wx.uploadFile({ const accountInfo = wx.getAccountInfoSync();
filePath: tempFilePaths[0], // 图片临时文件路径
name: 'file', // 服务器接收文件的字段名,需与后端对应 request('app/send_message', 'POST', {
url: 'https://dsjhd9s.tbmw.cn/admin/upload/image', // 服务器接收图片的接口地址 "app_id": accountInfo.miniProgram.appId,
success: (res) => { "content": JSON.stringify({
const data = JSON.parse(res.data); message: res
console.log('上传成功', data); }),
const accountInfo = wx.getAccountInfoSync(); "from_user_id": userInfo.openid,
"from_user_name": userInfo.user_name,
request('app/send_message', 'POST', { "msg_type": 2
"app_id": accountInfo.miniProgram.appId, }).catch((err) => {
"content": JSON.stringify({ wx.showToast({
messages: 'https://dsjhd9s.tbmw.cn/'+ data.preview_image_url title: '图片发送失败',
}), icon: 'none'
"from_user_id": userInfo.openid, });
"from_user_name": userInfo.user_name, });
"msg_type": 2 }).catch((err) => {
}) wx.showToast({
}, title: '图片发送失败',
fail: (err) => { icon: 'none'
console.error('上传失败', err); });
}
}); });
// wx.uploadFile({
// filePath: tempFilePaths[0], // 图片临时文件路径
// name: 'file', // 服务器接收文件的字段名,需与后端对应
// url: 'https://mini-chat.1024tool.vip/api/admin/upload/image', // 服务器接收图片的接口地址
// success: (res) => {
// },
// fail: (err) => {
// console.error('上传失败', err);
// }
// });
// 模拟客服返回图片确认 // 模拟客服返回图片确认
// setTimeout(() => { // setTimeout(() => {
@ -674,14 +687,14 @@ Page({
if (messages.length > 0) { if (messages.length > 0) {
const sortedMessages = this.sortMessagesByID(messages); const sortedMessages = this.sortMessagesByID(messages);
const latestMessage = sortedMessages[sortedMessages.length - 1]; const latestMessage = sortedMessages[sortedMessages.length - 1];
this.setData({ this.setData({
scrollToId: latestMessage.id, scrollToId: latestMessage.id,
showNewMessageTip: false, showNewMessageTip: false,
newMessageCount: 0, newMessageCount: 0,
isAtBottom: true isAtBottom: true
}); });
// 延迟一下确保滚动完成 // 延迟一下确保滚动完成
setTimeout(() => { setTimeout(() => {
this.setData({ this.setData({
@ -693,4 +706,4 @@ Page({
onReachBottom() { }, onReachBottom() { },
onShareAppMessage() { } onShareAppMessage() { }
}); });

View File

@ -20,10 +20,10 @@
<view class="bubble-wrap"> <view class="bubble-wrap">
<view class="bubble"> <view class="bubble">
<block wx:if="{{item.msg_type == 1}}"> <block wx:if="{{item.msg_type == 1}}">
<text class="msg-text">{{item.content.messages}}</text> <text class="msg-text">{{item.content.message}}</text>
</block> </block>
<block wx:elif="{{item.msg_type == 2}}"> <block wx:elif="{{item.msg_type == 2}}">
<image src="{{item.content.messages}}" bindtap="previewImage" data-src="{{item.content.messages}}" class="msg-image" mode="aspectFill" /> <image src="{{item.content.message}}" bindtap="previewImage" data-src="{{item.content.message}}" class="msg-image" mode="aspectFill" />
</block> </block>
</view> </view>