Browse Source

修复聊天功能:姓名匹配、消息显示、发送功能

pull/1/head
徐飞洋 3 months ago
parent
commit
23523c276d
  1. 236
      pages/chat-detail/index.js
  2. 26
      pages/chat-detail/index.wxml
  3. 10
      pages/chat/index.js
  4. 1
      pages/chat/index.wxml
  5. 97
      server-example/server-mysql.js
  6. 80
      utils/api.js

236
pages/chat-detail/index.js

@ -16,9 +16,17 @@ Page({
this.setData({ this.setData({
chatId: options.id chatId: options.id
}); });
// 获取聊天标题
// 如果有传递name参数,直接使用该名称作为聊天标题
if (options.name) {
this.setData({
chatTitle: decodeURIComponent(options.name)
});
} else {
// 否则从API获取聊天标题
this.loadChatTitle(); this.loadChatTitle();
} }
}
this.loadMessages(); this.loadMessages();
}, },
@ -87,37 +95,119 @@ Page({
wx.navigateBack(); wx.navigateBack();
}, },
// 格式化时间显示
formatDateTime: function (dateString) {
if (!dateString) return '刚刚';
const now = new Date();
const msgDate = new Date(dateString);
const diffMs = now - msgDate;
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMs / 3600000);
const diffDays = Math.floor(diffMs / 86400000);
if (diffMins < 1) {
return '刚刚';
} else if (diffMins < 60) {
return `${diffMins}分钟前`;
} else if (diffHours < 24) {
return `${diffHours}小时前`;
} else if (diffDays < 7) {
return `${diffDays}天前`;
} else {
// 超过一周显示具体日期
const year = msgDate.getFullYear();
const month = (msgDate.getMonth() + 1).toString().padStart(2, '0');
const day = msgDate.getDate().toString().padStart(2, '0');
const hours = msgDate.getHours().toString().padStart(2, '0');
const minutes = msgDate.getMinutes().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
},
loadMessages: function () { loadMessages: function () {
this.setData({ loading: true }); this.setData({ loading: true });
// 模拟加载聊天记录 // 获取当前用户的手机号
setTimeout(() => { const users = wx.getStorageSync('users') || {};
const messages = [ const userId = wx.getStorageSync('userId');
{ let userPhone = null;
id: 1,
content: '您好,有什么可以帮助您的吗?', // 尝试从users中获取手机号
sender: 'other', if (userId && users[userId]) {
time: '刚刚' if (users[userId].phoneNumber) {
}, userPhone = users[userId].phoneNumber;
{ } else if (users[userId].phone) {
id: 2, userPhone = users[userId].phone;
content: '你好,我想咨询一下产品信息', }
sender: 'me', }
time: '刚刚'
}, // 如果还没有获取到,尝试从全局用户信息获取
{ if (!userPhone) {
id: 3, const userInfo = wx.getStorageSync('userInfo');
content: '当然可以,请问您想了解哪种产品?', if (userInfo) {
sender: 'other', if (userInfo.phoneNumber) {
time: '5分钟前' userPhone = userInfo.phoneNumber;
} else if (userInfo.phone) {
userPhone = userInfo.phone;
}
}
} }
];
// 如果还没有获取到,尝试从直接存储获取
if (!userPhone) {
if (wx.getStorageSync('phoneNumber')) {
userPhone = wx.getStorageSync('phoneNumber');
} else if (wx.getStorageSync('phone')) {
userPhone = wx.getStorageSync('phone');
}
}
// 使用新添加的API获取聊天记录
API.getChatMessages(this.data.chatId, userPhone).then(res => {
if (Array.isArray(res)) {
// 处理每条消息,确定发送者和格式化时间
const processedMessages = res.map(message => {
// 判断消息是发送还是接收
const sender = (message.sender_phone === userPhone) ? 'me' : 'other';
// 格式化时间
const time = this.formatDateTime(message.created_at);
return {
id: message.id,
content: message.content,
sender: sender,
time: time,
originalTime: message.created_at
};
});
// 按时间顺序排序(升序)
processedMessages.sort((a, b) => {
return new Date(a.originalTime) - new Date(b.originalTime);
});
this.setData({ this.setData({
messages: messages, messages: processedMessages,
loading: false loading: false
}); });
}, 1000); } else {
this.setData({
messages: [],
loading: false
});
}
}).catch(error => {
console.error('加载聊天记录失败:', error);
this.setData({
loading: false
});
wx.showToast({
title: '加载聊天记录失败',
icon: 'none'
});
});
}, },
loadMoreMessages: function () { loadMoreMessages: function () {
@ -126,28 +216,92 @@ Page({
this.setData({ loading: true }); this.setData({ loading: true });
// 模拟加载更多历史消息 // 获取当前用户的手机号
setTimeout(() => { const users = wx.getStorageSync('users') || {};
const moreMessages = [ const userId = wx.getStorageSync('userId');
{ let userPhone = null;
id: 4,
content: '你好,我想了解一下你们的鸡蛋产品', // 尝试从users中获取手机号
sender: 'me', if (userId && users[userId]) {
time: '1小时前' if (users[userId].phoneNumber) {
}, userPhone = users[userId].phoneNumber;
{ } else if (users[userId].phone) {
id: 5, userPhone = users[userId].phone;
content: '您好,欢迎咨询我们的鸡蛋产品', }
sender: 'other', }
time: '1小时前'
// 如果还没有获取到,尝试从全局用户信息获取
if (!userPhone) {
const userInfo = wx.getStorageSync('userInfo');
if (userInfo) {
if (userInfo.phoneNumber) {
userPhone = userInfo.phoneNumber;
} else if (userInfo.phone) {
userPhone = userInfo.phone;
} }
]; }
}
// 如果还没有获取到,尝试从直接存储获取
if (!userPhone) {
if (wx.getStorageSync('phoneNumber')) {
userPhone = wx.getStorageSync('phoneNumber');
} else if (wx.getStorageSync('phone')) {
userPhone = wx.getStorageSync('phone');
}
}
// 获取最早的消息时间,用于分页加载
const earliestTime = this.data.messages.length > 0 ? this.data.messages[0].originalTime : null;
// 使用API获取更多聊天记录(带分页参数)
API.getChatMessages(this.data.chatId, userPhone, { before: earliestTime }).then(res => {
if (Array.isArray(res) && res.length > 0) {
// 处理每条消息,确定发送者和格式化时间
const processedMessages = res.map(message => {
// 判断消息是发送还是接收
const sender = (message.sender_phone === userPhone) ? 'me' : 'other';
// 格式化时间
const time = this.formatDateTime(message.created_at);
return {
id: message.id,
content: message.content,
sender: sender,
time: time,
originalTime: message.created_at
};
});
// 按时间顺序排序(升序)
processedMessages.sort((a, b) => {
return new Date(a.originalTime) - new Date(b.originalTime);
});
this.setData({ this.setData({
messages: [...moreMessages, ...this.data.messages], messages: [...processedMessages, ...this.data.messages],
loading: false loading: false
}); });
}, 1000); } else {
this.setData({
loading: false
});
wx.showToast({
title: '没有更多消息了',
icon: 'none'
});
}
}).catch(error => {
console.error('加载更多聊天记录失败:', error);
this.setData({
loading: false
});
wx.showToast({
title: '加载更多消息失败',
icon: 'none'
});
});
}, },
onInputChange: function (e) { onInputChange: function (e) {

26
pages/chat-detail/index.wxml

@ -13,27 +13,29 @@
<scroll-view class="chat-content" scroll-y bindscrolltolower="loadMoreMessages"> <scroll-view class="chat-content" scroll-y bindscrolltolower="loadMoreMessages">
<view class="chat-messages"> <view class="chat-messages">
<block wx:if="{{loading && messages.length === 0}}">
<view class="loading">加载中...</view>
</block>
<block wx:elif="{{messages.length === 0}}">
<view class="empty-messages">暂无聊天记录</view>
</block>
<block wx:else>
<!-- 动态渲染聊天消息 -->
<view wx:for="{{messages}}" wx:key="id" class="message-item {{item.sender}}">
<!-- 对方消息 --> <!-- 对方消息 -->
<view class="message-item other"> <view wx:if="{{item.sender === 'other'}}" class="avatar">
<view class="avatar">
<image src="https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0" mode="aspectFill"></image> <image src="https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0" mode="aspectFill"></image>
</view> </view>
<view class="message-bubble"> <view class="message-bubble">
<text class="message-content">您好,有什么可以帮助您的吗?</text> <text class="message-content">{{item.content}}</text>
<text class="message-time">刚刚</text> <text class="message-time">{{item.time}}</text>
</view> </view>
</view>
<!-- 自己的消息 --> <!-- 自己的消息 -->
<view class="message-item me"> <view wx:if="{{item.sender === 'me'}}" class="avatar">
<view class="message-bubble">
<text class="message-content">你好,我想咨询一下产品信息</text>
<text class="message-time">刚刚</text>
</view>
<view class="avatar">
<image src="https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0" mode="aspectFill"></image> <image src="https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0" mode="aspectFill"></image>
</view> </view>
</view> </view>
</block>
</view> </view>
</scroll-view> </scroll-view>

10
pages/chat/index.js

@ -189,11 +189,15 @@ Page({
// 聊天项点击事件 // 聊天项点击事件
onChatItemTap: function (e) { onChatItemTap: function (e) {
const chatId = e.currentTarget.dataset.id; const index = e.currentTarget.dataset.index;
const chatItem = this.data.filteredChatList[index];
// 跳转到聊天详情页 // 使用对方的电话号码作为聊天ID,而不是会话ID
const chatId = chatItem.manager_phone;
// 跳转到聊天详情页,传递chatId和name参数
wx.navigateTo({ wx.navigateTo({
url: '/pages/chat-detail/index?id=' + chatId, url: '/pages/chat-detail/index?id=' + chatId + '&name=' + encodeURIComponent(chatItem.name),
success: function () { success: function () {
console.log('成功跳转到聊天详情页'); console.log('成功跳转到聊天详情页');
}, },

1
pages/chat/index.wxml

@ -19,6 +19,7 @@
wx:key="id" wx:key="id"
class="chat-item" class="chat-item"
data-id="{{item.id}}" data-id="{{item.id}}"
data-index="{{index}}"
bindtap="onChatItemTap" bindtap="onChatItemTap"
> >
<!-- 头像 --> <!-- 头像 -->

97
server-example/server-mysql.js

@ -6318,6 +6318,103 @@ app.get('/api/conversations/:conversationId/messages', async (req, res) => {
} }
}); });
// REST API接口 - 获取聊天记录(兼容客户端接口)
app.post('/api/chat/messages', async (req, res) => {
try {
const { chat_id, user_phone, before, limit = 50 } = req.body;
console.log('收到聊天记录请求:', { chat_id, user_phone, before, limit });
let query = `SELECT * FROM chat_messages
WHERE (sender_phone = ? AND receiver_phone = ?)
OR (sender_phone = ? AND receiver_phone = ?)`;
let replacements = [user_phone, chat_id, chat_id, user_phone];
// 如果有before参数,添加时间过滤
if (before) {
query += ' AND created_at < ?';
replacements.push(before);
}
// 按时间排序,最新的消息在前
query += ' ORDER BY created_at DESC LIMIT ?';
replacements.push(parseInt(limit));
console.log('执行SQL:', query);
console.log('替换参数:', replacements);
const [messages] = await sequelize.query(query, { replacements });
// 反转顺序,使最早的消息在前
messages.reverse();
console.log('查询到的消息数量:', messages.length);
res.status(200).json({
success: true,
code: 200,
data: messages
});
} catch (error) {
console.error('获取聊天记录失败:', error);
res.status(500).json({
success: false,
code: 500,
message: '获取聊天记录失败: ' + error.message
});
}
});
// REST API接口 - 发送聊天消息
app.post('/api/chat/send', async (req, res) => {
try {
const { sender_phone, receiver_phone, content } = req.body;
console.log('收到发送消息请求:', { sender_phone, receiver_phone, content });
// 验证必填字段
if (!sender_phone || !receiver_phone || !content) {
return res.status(400).json({
success: false,
code: 400,
message: '发送者电话、接收者电话和消息内容不能为空'
});
}
// 插入消息到数据库
const query = `INSERT INTO chat_messages (sender_phone, receiver_phone, content, created_at)
VALUES (?, ?, ?, NOW())`;
const replacements = [sender_phone, receiver_phone, content];
console.log('执行SQL:', query);
console.log('替换参数:', replacements);
const [result] = await sequelize.query(query, { replacements });
console.log('消息发送成功,插入结果:', result);
res.status(200).json({
success: true,
code: 200,
message: '消息发送成功',
data: {
id: result.insertId,
sender_phone,
receiver_phone,
content,
created_at: new Date().toISOString()
}
});
} catch (error) {
console.error('发送消息失败:', error);
res.status(500).json({
success: false,
code: 500,
message: '发送消息失败: ' + error.message
});
}
});
// REST API接口 - 标记消息已读 // REST API接口 - 标记消息已读
app.post('/api/conversations/:conversationId/read', async (req, res) => { app.post('/api/conversations/:conversationId/read', async (req, res) => {
try { try {

80
utils/api.js

@ -3508,6 +3508,86 @@ module.exports = {
}); });
}, },
// 获取聊天记录
getChatMessages: function (chatId, userPhone, options = {}) {
return new Promise((resolve, reject) => {
console.log('API.getChatMessages - chatId:', chatId, 'userPhone:', userPhone, 'options:', options);
// 如果没有传入手机号,尝试从本地存储获取
if (!userPhone) {
// 获取用户信息,包含手机号
const users = wx.getStorageSync('users') || {};
const userId = wx.getStorageSync('userId');
// 尝试从users中获取手机号
if (userId && users[userId] && users[userId].phoneNumber) {
userPhone = users[userId].phoneNumber;
} else {
// 尝试从全局用户信息获取
const userInfo = wx.getStorageSync('userInfo');
if (userInfo && userInfo.phoneNumber) {
userPhone = userInfo.phoneNumber;
} else {
// 尝试从直接存储的phoneNumber获取
userPhone = wx.getStorageSync('phoneNumber');
}
}
}
// 如果没有手机号,直接返回错误
if (!userPhone) {
const error = new Error('请先登录并绑定手机号');
console.error('API.getChatMessages - 错误:', error);
reject(error);
return;
}
// 如果没有chatId,返回空数组
if (!chatId) {
console.log('API.getChatMessages - 没有chatId,返回空数组');
resolve([]);
return;
}
const requestData = {
chat_id: chatId,
user_phone: userPhone
};
// 添加分页参数
if (options.before) {
requestData.before = options.before;
}
if (options.limit) {
requestData.limit = options.limit;
}
console.log('API.getChatMessages - 请求数据:', requestData);
request('/api/chat/messages', 'POST', requestData).then(res => {
console.log('API.getChatMessages - 响应数据:', res);
// 增强数据结构处理
let messages = [];
if (Array.isArray(res)) {
messages = res;
} else if (res && Array.isArray(res.messages)) {
messages = res.messages;
} else if (res && Array.isArray(res.data)) {
messages = res.data;
} else if (res && res.data && Array.isArray(res.data.messages)) {
messages = res.data.messages;
}
console.log('API.getChatMessages - 处理后的消息数量:', messages.length);
resolve(messages);
}).catch(error => {
console.error('API.getChatMessages - 请求失败:', error);
reject(error);
});
});
},
// 获取聊天列表数据 // 获取聊天列表数据
getChatList: function (userPhone) { getChatList: function (userPhone) {
console.log('API.getChatList - userPhone:', userPhone); console.log('API.getChatList - userPhone:', userPhone);

Loading…
Cancel
Save