quanwei
2 days ago 04102f7237efefa744090ed7c25f7b5d0807b679
mobile/pages/plus/business/chat/chat.vue
@@ -59,12 +59,12 @@
                              <text class="message-text">{{ message.content }}</text>
                           </view>
                        </view>
                        <view class="message-status" :class="message.is_read ? 'read-read' : 'read-sent​'">
                        <!-- <view class="message-status" :class="message.is_read ? 'read-read' : 'read-sent'">
                           <text class="icon iconfont icon-eye "></text>
                        </view>
                        </view> -->
                     </view>
                     <view class="message-info">
                        <text class="message-time">{{ formatTime(message.create_time) }}</text>
                        <text class="message-time">{{ formatTime(message.send_time||message.create_time) }}</text>
                     </view>
                  </view>
               </view>
@@ -73,7 +73,7 @@
               <view class="message-mine" v-else>
                  <view class="message-content">
                     <view class="d-s-e">
                        <view class="message-status" :class="message.is_read ? 'read-read' : 'read-sent​'">
                        <view class="message-status" :class="message.is_read ? 'read-read' : 'read-sent'">
                        </view>
                        <view class="d-f">
                           <view class="message-bubble">
@@ -86,7 +86,7 @@
                     </view>
                     <view class="message-info">
                        <text class="message-time">{{ formatTime(message.create_time) }}</text>
                        <text class="message-time">{{ formatTime(message.send_time||message.create_time) }}</text>
                     </view>
                  </view>
@@ -193,6 +193,7 @@
               avatarUrl: ''
            },
            card: {},
            wsUrl:"",
            // 聊天数据
            messages: [],
@@ -214,7 +215,12 @@
            // 定时器
            typingTimer: null,
            readTimer: null
            readTimer: null,
            reconnectTimer: null,
            reconnectAttempts: 0,
            maxReconnectAttempts: 5,
            heartbeatTimer: null,
            is_exit: false //是否退出
         };
      },
      onLoad(options) {
@@ -224,24 +230,29 @@
         this.businessCardId = parseInt(options.business_card_id) || 0;
         this.conversationId = parseInt(options.conversation_id) || 0;
         this.targetUser.nickName = options.nickName || '用户';
         // 获取当前用户信息
         this.getCurrentUser();
         if (!this.conversationId) {
            // 初始化会话
            this.initConversation();
         }else{
            // 加载消息
            this.loadMessages();
            this.initWebSocket();
         }
         // 加载消息
         this.loadMessages();
      },
      onUnload() {
         this.is_exit = true;
         // 清理定时器
         if (this.typingTimer) {
            clearTimeout(this.typingTimer);
         }
         if (this.readTimer) {
            clearTimeout(this.readTimer);
         }
         if (this.reconnectTimer) {
            clearTimeout(this.reconnectTimer);
         }
         // 关闭WebSocket
         this.closeWebSocket();
@@ -257,8 +268,6 @@
            let self = this;
            self._get('user.user/detail', {}, res => {
               self.currentUser = res.data.userInfo;
               // 初始化WebSocket连接
               self.initWebSocket();
            })
         },
@@ -269,6 +278,10 @@
               business_card_id: this.businessCardId
            }, res => {
               this.conversationId = res.data.conversation.conversation_id;
               this.loadMessages();
               this.wsUrl = res.data.wsUrl;
               // 初始化WebSocket连接
               this.initWebSocket();
            });
         },
@@ -296,31 +309,24 @@
                  if (self.page === 1) {
                     // First page - sort messages by create_time ascending, newest at bottom
                     self.messages = newMessages.sort((a, b) => {
                        return new Date(a.create_time) - new Date(b.create_time);
                        return a.send_time - b.send_time;
                     });
                  } else {
                     // For pagination, prepend older messages
                     const sortedMessages = newMessages.sort((a, b) => {
                        return new Date(a.create_time) - new Date(b.create_time);
                        return a.send_time - b.send_time;
                     });
                     self.messages = [...sortedMessages, ...self.messages];
                  }
                  self.hasMore = self.messages.length < res.data.messages.total;
                  self.loadMore = false;
                  // 滚动到底部
                  self.$nextTick(() => {
                     self.scrollToBottom();
                  });
                  self.page++;
                  if (self.page == 2) {
                     console.log(res.data.heUser);
                     // 获取目标用户信息
                     this.targetUser = res.data.heUser;
                     this.card = res.data.card;
                     // 滚动到底部
                     self.$nextTick(() => {
                        self.scrollToBottom();
                     });
                     // 标记整个会话为已读
                     if (self.conversationId) {
                        self._post('plus.business.chat.chat/markAsRead', {
@@ -333,6 +339,11 @@
                                 if (msg.sender_id !== self.currentUser.user_id) {
                                    msg.is_read = true;
                                 }
                              });
                              // 滚动到底部
                              self.$nextTick(() => {
                                 self.scrollToBottom();
                              });
                           }
                        });
@@ -348,28 +359,9 @@
         async sendMessage() {
            let self = this;
            if (!this.inputMessage.trim()) return;
            const content = self.inputMessage.trim();
            console.log(content);
            self.sendWebSocketMessage(content);
            /* self._post('plus.business.chat.chat/sendMessage', {
               conversation_id: self.conversationId,
               business_card_id: self.businessCardId,
               content: content
            }, res => {
               if (res.code === 1) {
                  // 添加到消息列表
                  self.messages.push(res.data.message);
                  self.inputMessage = '';
                  // 滚动到底部
                  self.$nextTick(() => {
                     self.scrollToBottom();
                  });
                  // 发送WebSocket消息
                  self.sendWebSocketMessage(res.data.ws_message);
               } else {
                  self.showError(res.msg || '发送失败');
               }
            }); */
         },
         // WebSocket相关方法
@@ -383,26 +375,26 @@
            const currentUserId = this.currentUser.user_id;
            // 构建WebSocket连接URL - 使用名片聊天专用端口2349
            const wsUrl = `ws://localhost:2349?user_id=${currentUserId}`;
            const wsUrl = `${this.wsUrl}:2349?user_id=${currentUserId}&usertype=supplier `;
            try {
               // 创建WebSocket连接
               this.socketTask = uni.connectSocket({
                  url: wsUrl,
                  success: () => {
                     console.log('WebSocket连接成功');
                  },
                  success: () => {},
                  fail: (err) => {
                     console.error('WebSocket连接失败:', err);
                     // 尝试重连
                     this.reconnectWebSocket();
                  }
               });
               // 监听WebSocket打开事件
               this.socketTask.onOpen(() => {
                  console.log('WebSocket已打开');
                  this.isOnline = true;
                  this.reconnectAttempts = 0; // 重置重连计数
                  // 发送心跳包
                  this.startHeartbeat();
                  // 绑定用户ID
                  this.bindUserId();
               });
               // 监听WebSocket消息事件
@@ -425,6 +417,8 @@
               this.socketTask.onError((err) => {
                  console.error('WebSocket错误:', err);
                  this.isOnline = false;
                  // 尝试重连
                  this.reconnectWebSocket();
               });
               // 监听WebSocket关闭事件
@@ -438,11 +432,55 @@
                     clearInterval(this.heartbeatTimer);
                     this.heartbeatTimer = null;
                  }
                  // 尝试重连
                  this.reconnectWebSocket();
               });
            } catch (error) {
               console.error('初始化WebSocket失败:', error);
               // 尝试重连
               this.reconnectWebSocket();
            }
         },
         // 绑定用户ID
         bindUserId() {
            if (this.socketTask && this.currentUser.user_id) {
               const bindMsg = {
                  type: 'bind',
                  user_id: this.currentUser.user_id
               };
               try {
                  this.socketTask.send({
                     data: JSON.stringify(bindMsg)
                  });
                  console.log('用户ID绑定消息已发送');
               } catch (error) {
                  console.log('发送用户ID绑定消息失败:', error);
               }
            }
         },
         // WebSocket重连机制
         reconnectWebSocket() {
            if (this.is_exit) {
               console.log(this.is_exit);
               return false;
            }
            this.reconnectAttempts++;
            console.log(`尝试第${this.reconnectAttempts}次重连WebSocket`);
            // 清除之前的重连定时器
            if (this.reconnectTimer) {
               clearTimeout(this.reconnectTimer);
            }
            // 设置重连延迟,指数退避策略
            const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 10000);
            this.reconnectTimer = setTimeout(() => {
               this.initWebSocket();
            }, delay);
         },
         // 处理WebSocket消息
@@ -451,6 +489,10 @@
               case 'message':
                  // 收到新消息
                  this.handleNewMessage(data);
                  break;
               case 'read':
                  // 收到已读确认
                  this.handleReadMessage(data);
                  break;
               case 'ping':
                  // 心跳响应
@@ -468,7 +510,7 @@
         // 处理新消息
         handleNewMessage(data) {
            // 检查消息是否属于当前会话
            if (data.business_card_id === this.businessCardId ||
            if ((data.business_card_id && data.business_card_id === this.businessCardId) ||
               (data.conversation_id && data.conversation_id === this.conversationId)) {
               // 添加消息到列表
@@ -477,7 +519,8 @@
                  conversation_id: data.conversation_id,
                  sender_id: data.user_id,
                  content: data.content,
                  create_time: Math.floor(Date.now() / 1000),
                  send_time: data.send_time,
                  create_time: data.create_time || Math.floor(Date.now() / 1000),
                  is_read: false
               };
@@ -492,7 +535,6 @@
               setTimeout(() => {
                  // 通过WebSocket发送已读标记
                  this.markMessageAsRead(newMessage.chat_id);
                  // 调用后端API标记消息为已读
                  this._post('plus.business.chat.chat/markAsRead', {
                     chat_id: newMessage.chat_id,
@@ -512,33 +554,110 @@
            }
         },
         // 处理已读消息
         handleReadMessage(data) {
            // 筛选出当前用户发送的、尚未标记为已读的消息
            const unreadMessages = this.messages.filter(msg => {
               return msg.sender_id === this.currentUser.user_id && !msg.is_read;
            });
            if (unreadMessages.length === 0) {
               console.log('没有需要标记已读的消息');
               return;
            }
            console.log(`找到 ${unreadMessages.length} 条未读消息,开始批量标记`);
            // 对每条未读消息调用markMessageAsRead方法
            unreadMessages.forEach(msg => {
               this.markMessageAsRead(msg.chat_id);
               // 同时更新本地消息状态
               msg.is_read = true;
            });
            console.log('所有未读消息已标记为已读');
         },
         sendMessages(message){
            if(message==''){
               return
            }
            this._post('plus.business.chat.chat/sendMessage',{
               content:this.inputMessage,
               conversation_id: this.conversationId,
               business_card_id: this.businessCardId,
            },res=>{
               // 添加消息到本地列表
               const localMessage = {
                  chat_id: Date.now(),
                  conversation_id: this.conversationId,
                  sender_id: this.currentUser.user_id,
                  content: this.inputMessage,
                  create_time: Math.floor(Date.now() / 1000),
                  send_time: (Date.now() / 1000),
                  is_read: false
               };
               this.messages.push(localMessage);
               this.inputMessage = '';
            })
         },
         // 发送WebSocket消息
         sendWebSocketMessage(message) {
            let self = this;
            if (!this.socketTask || !this.isOnline) {
               console.warn('WebSocket未连接,无法发送消息');
            if (!this.socketTask) {
               self.initWebSocket();
               self.sendMessages(message);
               // 等待连接建立后再发送消息
               setTimeout(() => {
                  self.sendWebSocketMessage('');
               }, 1000);
               return;
            }
            const wsMessage = {
               type: 'message',
               user_id: this.currentUser.user_id,
               to_user_id: this.targetUserId,
               content: message,
               conversation_id: this.conversationId,
               business_card_id: this.businessCardId,
               app_id: this.currentUser.grade.app_id
            };
            // 检查连接状态
            if (!this.isOnline) {
               self.initWebSocket();
               // 等待连接建立后再发送消息
               self.sendMessages(message);
               setTimeout(() => {
                  self.sendWebSocketMessage('');
               }, 1000);
               return;
            }
            if(message==''){
               return
            }
            try {
               self.socketTask.send({
                  data: JSON.stringify(wsMessage)
               });
               self.page = 1
               self.loadMessages()
               // 添加消息到本地列表
               const localMessage = {
                  chat_id: Date.now(),
                  conversation_id: this.conversationId,
                  sender_id: this.currentUser.user_id,
                  content: message,
                  create_time: Math.floor(Date.now() / 1000),
                  send_time: (Date.now() / 1000),
                  is_read: false
               };
               self.messages.push(localMessage);
               self.inputMessage = '';
               console.log('WebSocket消息发送成功:', wsMessage);
               // 滚动到底部 - 使用更强的保证方式
               this.$nextTick(() => {
                  // 延迟一小段时间确保DOM更新完成
                  setTimeout(() => {
                     this.scrollToBottom();
                  }, 50);
               });
            } catch (error) {
               console.error('发送WebSocket消息失败:', error);
               console.log('发送WebSocket消息失败:', error);
               // 尝试重连
               this.reconnectWebSocket();
            }
         },
@@ -562,10 +681,10 @@
                        data: JSON.stringify(heartbeatMsg)
                     });
                  } catch (error) {
                     console.error('发送心跳失败:', error);
                     console.log('发送心跳失败:', error);
                  }
               }
            }, 3000); // 30秒
            }, 30000); // 30秒
         },
         // 标记消息为已读
@@ -587,7 +706,7 @@
                  data: JSON.stringify(readMsg)
               });
            } catch (error) {
               console.error('发送已读标记失败:', error);
               console.log('发送已读标记失败:', error);
            }
         },
@@ -605,7 +724,7 @@
                     data: JSON.stringify(closeMsg)
                  });
               } catch (error) {
                  console.error('发送关闭消息失败:', error);
                  console.log('发送关闭消息失败:', error);
               }
               // 关闭WebSocket连接
@@ -620,16 +739,13 @@
            }
            this.isOnline = false;
            console.log('WebSocket连接已关闭');
         },
         // 滚动相关方法
         scrollToBottom() {
            let self=this;
            this.$nextTick(() => {
               console.log(self.scrollTop);
               self.scrollTop = self.oldScrollTop + 1;
            });
            console.log(this.scrollTop);
            // 增加滚动距离确保到达底部
            this.scrollTop = this.oldScrollTop + 10000;
         },
         onScroll(e) {
@@ -778,7 +894,7 @@
            if (!timeStr) return '';
            // 处理日期字符串,将yyyy-MM-dd转换为yyyy/MM/dd以兼容iOS
            const formattedTimeStr = typeof timeStr === 'string' ? timeStr.replace(/\-/g, '/') : timeStr;
            const formattedTimeStr = typeof timeStr === 'string' ? timeStr.replace(/\-/g, '/') : timeStr * 1000;
            const date = new Date(formattedTimeStr);
            const now = new Date();