<template>
  <view class="chat-page">
	  <!-- 更多选项弹窗 -->
	  <view v-if="showMoreOptionsModal" class="modal-mask" @click="closeMoreOptions">
	    <view class="modal-content" @click.stop>
	      <view class="modal-header">
	        <text class="modal-title">{{ targetUserName }}</text>
	        <text class="modal-subtitle">好友操作</text>
	      </view>
	      <view class="modal-body">
	        <!-- <view class="modal-item" @click="goToUserProfile">
	          <text class="item-icon">👤</text>
	          <text class="item-text">查看资料</text>
	        </view> -->
	        <view class="modal-item" @click="blockFriend" :class="{ danger: true }">
	          <text class="item-icon">🚫</text>
	          <text class="item-text">拉黑好友</text>
	        </view>
	       <!-- <view class="modal-item" @click="reportUser" :class="{ danger: true }">
	          <text class="item-icon">🚨</text>
	          <text class="item-text">举报用户</text>
	        </view> -->
	      </view>
	      <view class="modal-footer">
	        <button class="modal-close-btn" @click="closeMoreOptions">取消</button>
	      </view>
	    </view>
	  </view>
	  
	  <!-- 拉黑确认弹窗 -->
	  <view v-if="showBlockConfirmModal" class="modal-mask" @click="closeBlockConfirm">
	    <view class="confirm-modal" @click.stop>
	      <view class="confirm-title">确认拉黑</view>
	      <view class="confirm-content">
	        <text>拉黑后将无法接收该用户的消息，是否确定？</text>
	      </view>
	      <view class="confirm-buttons">
	        <button class="confirm-btn cancel" @click="closeBlockConfirm">取消</button>
	        <button class="confirm-btn confirm" @click="confirmBlockFriend">确认</button>
	      </view>
	    </view>
	  </view>
	  
	  
	  
    <!-- 顶部导航 -->
    <view class="chat-header" :style="{paddingTop: statusBarHeight + 'px', height: navBarHeight + 'px'}">
      <view class="header-left" @click="goBack">
        <text class="icon-back">←</text>
      </view>
      <view class="header-center">
        <view class="title-wrapper" @click="showMoreOptions">
          <text class="chat-title">{{ targetUserName }}</text>
          <text class="title-arrow">▾</text>
        </view>
        <text class="online-status" :class="{ online: isTargetOnline }">
          {{ isTargetOnline ? '在线' : '离线' }}
        </text>
      </view>
      <view class="header-right"></view>
    </view>

    <!-- 消息列表 -->
    <scroll-view 
      class="message-list" 
      scroll-y 
      :scroll-into-view="scrollToView"
      @scrolltoupper="loadMoreMessages">
      
      <!-- 加载更多提示 -->
      <view v-if="loading" class="loading-tip">加载中...</view>
      <view v-else-if="noMore" class="loading-tip">没有更多消息了</view>

      <!-- 时间分组和消息项 -->
      <view v-for="(msg, index) in messages" :key="msg.messageId">
        <!-- 时间分隔线 (每5分钟显示一次) -->
        <view v-if="shouldShowTime(msg, index)" class="time-divider">
          <text class="time-text">{{ formatMessageTime(msg.sendTime) }}</text>
        </view>
        
        <!-- 消息项 -->
        <view 
          :id="'msg-' + index"
          class="message-item"
          :class="{ 'message-self': msg.fromUserId === userId }"
          @longpress="showMessageMenu(msg, index)">
          
          <!-- 头像 -->
          <image 
            class="avatar" 
            :src="msg.fromUserId === userId ? userAvatar : targetUserAvatar" 
            mode="aspectFill"
            @click="goToUserDetail(msg.fromUserId)" />
          
          <!-- 消息内容 -->
          <view class="message-content-wrapper">
            <!-- 用户名（对方消息时显示） -->
            <text v-if="msg.fromUserId !== userId" class="message-name">
              {{ msg.fromUserName }}
            </text>
            
            <!-- 消息气泡 -->
            <view 
              class="message-bubble" 
              :class="{ 'bubble-self': msg.fromUserId === userId, 'bubble-failed': msg.sendStatus === 4 }"
              @click="handleMessageClick(msg)">
              <!-- 文本消息 -->
              <text v-if="msg.messageType === 1" class="message-text">
                {{ msg.content }}
              </text>
              
              <!-- 图片消息 -->
              <image 
                v-else-if="msg.messageType === 2"
                class="message-image"
                :src="msg.mediaUrl"
                mode="widthFix"
                lazy-load
                @click.stop="previewImage(msg.mediaUrl)" />
              
              <!-- 语音消息 -->
              <view 
                v-else-if="msg.messageType === 3" 
                class="message-voice" 
                :style="{width: getVoiceWidth(msg.duration)}"
                @click.stop="toggleVoicePlay(msg)">
                <text class="voice-duration">{{ msg.duration }}''</text>
                <view class="voice-icon-wrapper" :class="{playing: playingVoiceId === msg.messageId}">
                  <image 
                    class="voice-icon" 
                    :src="msg.fromUserId === userId ? 'http://115.190.125.125:9000/static-images/%E6%88%91%E6%96%B9%E8%AF%AD%E9%9F%B3%E6%B6%88%E6%81%AF' : 'http://115.190.125.125:9000/static-images/%E5%AF%B9%E6%96%B9%E8%AF%AD%E9%9F%B3%E6%B6%88%E6%81%AF'" 
                    mode="aspectFit"></image>
                </view>
                <!-- 暂停后的继续播放按钮 -->
                <view 
                  v-if="pausedVoiceId === msg.messageId" 
                  class="voice-resume-btn" 
                  :class="{'resume-btn-left': msg.fromUserId === userId, 'resume-btn-right': msg.fromUserId !== userId}"
                  @click.stop="resumeVoice">
                  <text class="resume-icon">▶</text>
                </view>
              </view>
              
              <!-- 视频消息 -->
              <video 
                v-else-if="msg.messageType === 4"
                class="message-video"
                :src="msg.mediaUrl"
                controls />
              
              <!-- 撤回消息 -->
              <text v-if="msg.isRecalled" class="message-recalled">
                消息已撤回
              </text>
            </view>
            
            <!-- 消息状态（自己的消息） -->
            <view v-if="msg.fromUserId === userId" class="message-status">
              <text v-if="msg.sendStatus === 4" class="status-failed">发送失败</text>
              <text v-else-if="msg.isPeerRead" class="status-read">已读</text>
              <text v-else class="status-unread">未读</text>
            </view>
          </view>
        </view>
      </view>
    </scroll-view>
		<!-- 新增：消息发送限制提示（双方都不是红娘，且不是从红娘工作台进入时才显示） -->
		<view class="message-limit-tip" v-if="!(String(userId).startsWith('m_') || String(targetUserId).startsWith('m_') || fromMatchmaker)">
		  <!-- 同时判断isVip和hasMessageLimit，增强可靠性     -->
		  <text v-if="isVip || !hasMessageLimit" class="vip-tip">✨ VIP特权：无发送次数限制</text>
		  <text v-else class="limit-tip">
		    今日剩余可发送消息：{{ Math.max(remainingCount, 0) }} 条<text class="vip-link" @click="goToVipPage">（非VIP每日限5条）</text>
		  </text>
		</view>
		
    <!-- 输入框 -->
    <view class="input-bar">
      <!-- 语音按钮 -->
      <view class="input-icon" @click="switchInputType">
        <image 
          v-if="inputType === 'text'"
          class="icon-image"
          src="http://115.190.125.125:9000/static-images/%E8%AF%AD%E9%9F%B3%E6%B6%88%E6%81%AF%E6%8C%89%E9%92%AE"
          mode="aspectFit" />
        <text v-else>⌨️</text>
      </view>
      
      <!-- 文本输入 -->
      <input 
        v-if="inputType === 'text'"
        class="input-field"
        v-model="inputText"
        placeholder="说点什么..."
        confirm-type="send"
        @confirm="sendTextMessage"
        @input="onInputChange" />
      
      <!-- 语音按钮 -->
      <button 
        v-else
        class="voice-button"
        @touchstart="startVoiceRecord"
        @touchmove="onVoiceTouchMove"
        @touchend="stopVoiceRecord"
        @touchcancel="cancelVoiceRecord">
        按住说话
      </button>
      
      <!-- 表情按钮 -->
      <view v-if="inputType === 'text'" class="input-icon" @click="showEmojiPanel = !showEmojiPanel">
        <text>😊</text>
      </view>
      
      <!-- 发送按钮 -->
      <view v-if="inputType === 'text'" class="send-button" :class="{disabled: !inputText.trim()}" @click="sendTextMessage">
        <text>发送</text>
      </view>
    </view>

    <!-- 表情面板 -->
    <view v-if="showEmojiPanel" class="emoji-panel">
      <text 
        v-for="emoji in emojis" 
        :key="emoji"
        class="emoji-item"
        @click="insertEmoji(emoji)">
        {{ emoji }}
      </text>
    </view>
    
    <!-- 消息操作菜单 -->
    <view v-if="showMessageAction" class="message-action-mask" @click="hideMessageMenu">
      <view class="message-action-menu" @click.stop>
        <view class="menu-item" @click="copyMessage" v-if="selectedMessage && selectedMessage.messageType === 1">
          <text class="menu-icon">📋</text>
          <text>复制</text>
        </view>
        <view class="menu-item" @click="recallMessage" v-if="selectedMessage && selectedMessage.fromUserId === userId && canRecall(selectedMessage)">
          <text class="menu-icon">↩️</text>
          <text>撤回</text>
        </view>
        <view class="menu-item" @click="deleteMessage">
          <text class="menu-icon">🗑️</text>
          <text>删除</text>
        </view>
        <view class="menu-item cancel" @click="hideMessageMenu">
          <text>取消</text>
        </view>
      </view>
    </view>
    
    <!-- 录音中提示 -->
    <view v-if="showVoiceRecording" class="voice-recording-mask">
      <view class="voice-recording-box" :class="{'canceling': voiceCanceling}">
        <view class="voice-wave-container">
          <view class="voice-wave-bar bar1" :style="{transform: `scaleY(${voiceVolume})`}"></view>
          <view class="voice-wave-bar bar2" :style="{transform: `scaleY(${voiceVolume * 1.2})`}"></view>
          <view class="voice-wave-bar bar3" :style="{transform: `scaleY(${voiceVolume * 1.5})`}"></view>
          <view class="voice-wave-bar bar4" :style="{transform: `scaleY(${voiceVolume * 1.3})`}"></view>
          <view class="voice-wave-bar bar5" :style="{transform: `scaleY(${voiceVolume})`}"></view>
        </view>
        <text class="voice-text">{{ voiceCanceling ? '松开取消发送' : '正在录音...' }}</text>
        <text class="voice-time">{{ voiceRecordingTime }}''</text>
        <text class="voice-tip" v-if="!voiceCanceling">松开发送，上滑取消</text>
      </view>
    </view>
  </view>
</template>

<script>
import timManager from '@/utils/tim-manager.js';
import TIM from 'tim-wx-sdk';

export default {
  data() {
    return {
	  statusBarHeight: 0, // 状态栏高度，用于适配刘海屏
	  navBarHeight: 44, // 导航栏高度
	  isBlockedByTarget: false,
      userId: null,
      userAvatar: '',
      targetUserId: null,
      targetUserName: '',
      targetUserAvatar: '',
      
      messages: [],
      inputText: '',
      inputType: 'text',
      conversationID: '',
      
      scrollToView: '',
      showEmojiPanel: false,
      
      isLogin: false,
      
      // 消息操作菜单
      showMessageAction: false,
      selectedMessage: null,
      selectedMessageIndex: -1,
      menuTop: 0,
      
      // 加载更多
      loading: false,
      noMore: false,
      nextReqMessageID: '',
      isTargetOnline: false,
      
      emojis: ['😀', '😃', '😄', '😁', '😆', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚', '😋', '😛', '😝', '😜', '🤪', '🤨', '🧐', '🤓', '😎', '🤩', '🥳'],
		showMoreOptionsModal: false, // 控制更多选项弹窗显示
	    showBlockConfirmModal: false, // 控制拉黑确认弹窗显示
		isVip: false, // 是否VIP用户
	    remainingCount: 5, // 剩余可发送消息数（非VIP默认5）
	    hasMessageLimit: true, // 是否有发送限制（VIP为false）
	    fromMatchmaker: false, // 是否来自红娘详情页的会话（用户与红娘聊天）
	    
	    // 语音录制相关
	    recorderManager: null, // 录音管理器
	    isRecording: false, // 是否正在录音
	    voiceStartTime: 0, // 录音开始时间
	    voiceDuration: 0, // 录音时长
	    voiceTempPath: '', // 录音临时文件路径
	    showVoiceRecording: false, // 显示录音中提示
	    voiceRecordingTime: 0, // 录音计时（秒）
	    voiceRecordingTimer: null, // 录音计时器
	    voiceTouchStartY: 0, // 录音按下时的Y坐标
	    voiceCanceling: false, // 是否正在取消录音
	    voiceVolume: 0.3, // 录音音量（0-1），控制波形高度
	    playingVoiceId: null, // 当前播放的语音消息ID
	    pausedVoiceId: null, // 当前暂停的语音消息ID
	    currentAudioContext: null // 当前音频上下文
	};
  },
  
  async onLoad(options) {
    console.log('=== 聊天页面加载 ===');
    
    // 获取系统信息，适配刘海屏
    const systemInfo = uni.getSystemInfoSync();
    this.statusBarHeight = systemInfo.statusBarHeight || 0;
    
    // #ifdef MP-WEIXIN
    // 微信小程序获取胶囊按钮位置，计算导航栏高度
    try {
      const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
      // 导航栏高度 = 胶囊按钮底部 + 胶囊按钮顶部距离状态栏的距离
      this.navBarHeight = (menuButtonInfo.top - this.statusBarHeight) * 2 + menuButtonInfo.height;
      console.log('胶囊按钮信息:', menuButtonInfo);
      console.log('导航栏高度:', this.navBarHeight);
    } catch (e) {
      console.log('获取胶囊按钮信息失败:', e);
      this.navBarHeight = 44;
    }
    // #endif
    
    console.log('状态栏高度:', this.statusBarHeight);
    
    // 严格验证登录状态
    const token = uni.getStorageSync('token');
    const userInfo = uni.getStorageSync('userInfo');
    const storedUserId = uni.getStorageSync('userId');
    
    console.log('登录状态检查:');
    console.log('- token:', token ? '存在' : '不存在');
    console.log('- userInfo:', userInfo);
    console.log('- storedUserId:', storedUserId);
    
    if (!token || !userInfo) {
      console.error('❌ 未登录或登录信息不完整');
      uni.showModal({
        title: '需要登录',
        content: '请先登录后再进行聊天',
        showCancel: false,
        success: () => {
          uni.reLaunch({
            url: '/pages/page3/page3'
          });
        }
      });
      return;
    }
    
    // 优先使用 storage 中的 userId，确保一致性
    let rawUserId = storedUserId || userInfo.userId || userInfo.id || userInfo.user_id;
    
    // 转换为数字类型（确保与消息列表页面一致）
    if (typeof rawUserId === 'string') {
      rawUserId = parseInt(rawUserId);
    }
    
    // 标记是否为用户与红娘的聊天，用于跳过每日5条限制和文本审核
    // 支持两种格式：'1' 或 'true'
    this.fromMatchmaker = options.fromMatchmaker === '1' || options.fromMatchmaker === 'true';
    
    // 根据入口来源确定当前会话中的“自己”是谁
    if (this.fromMatchmaker) {
      // 红娘工作台入口：使用当前 TIM 登录账号作为 userId（例如 m_22）
      const imUserId = timManager.getCurrentUserId();
      if (!imUserId) {
        console.error('❌ TIM 未登录，无法获取红娘IM账号');
        return;
      }
      this.userId = String(imUserId);
    } else {
      // 普通用户入口：仍然使用本地存储的 userId
      if (!rawUserId || isNaN(rawUserId)) {
        console.error('❌ 无法获取有效的用户ID');
        uni.showModal({
          title: '用户信息错误',
          content: '无法获取用户ID，请重新登录',
          showCancel: false,
          success: () => {
            uni.removeStorageSync('token');
            uni.removeStorageSync('userInfo');
            uni.removeStorageSync('userId');
            uni.reLaunch({
              url: '/pages/page3/page3'
            });
          }
        });
        return;
      }
      this.userId = String(rawUserId);
    }
    
    // 头像：默认先用用户信息中的头像（红娘入口会被 loadMatchmakerAvatar 覆盖）
    this.userAvatar = userInfo.avatar || userInfo.avatarUrl || '/static/default-avatar.svg';
    // 如果是红娘入口，再从红娘后台加载一次头像覆盖默认值
    if (this.fromMatchmaker) {
      await this.loadMatchmakerAvatar();
    }
    
    // 获取对方用户信息（确保是字符串格式）
    this.targetUserId = String(options.targetUserId);
    this.targetUserName = decodeURIComponent(options.targetUserName || '用户');
    this.targetUserAvatar = decodeURIComponent(options.targetUserAvatar || '/static/default-avatar.svg');
    
    // 生成会话 ID
    this.conversationID = `C2C${this.targetUserId}`;
    
    console.log('✅ 聊天页面初始化成功:');
    console.log('   - 当前用户ID:', this.userId);
    console.log('   - 对方用户ID:', this.targetUserId);
    console.log('   - 会话ID:', this.conversationID);

    // 初始化 TIM
    await this.initTIM();

    // 获取用户消息发送限制（VIP 状态 + 剩余次数）
    await this.getUserMessageLimit();

    // 等待 SDK Ready 后再加载消息
    await this.waitForSDKReady();

    // 先检查拉黑状态
    this.isBlockedByTarget = await this.checkIsBlockedByTarget();
    if (this.isBlockedByTarget) {
      uni.showToast({
        title: '你已被对方拉黑，无法发送消息',
        icon: 'none',
        duration: 3000
      });
    }

    // 加载历史消息
    await this.loadMessages();

    // 监听新消息
    this.listenMessages();

    // 监听已读回执
    this.listenMessageReadReceipt && this.listenMessageReadReceipt();

    // 标记当前会话的消息为已读
    this.markConversationRead && this.markConversationRead();

    // 初始化在线状态轮询
    this.initOnlineStatusPolling && this.initOnlineStatusPolling();

    // 如果有预设消息，自动发送
    if (options.message) {
      const message = decodeURIComponent(options.message);
      console.log('检测到预设消息，准备自动发送:', message);
      setTimeout(() => {
        this.inputText = message;
        this.sendTextMessage();
      }, 1500);
    }
  },

  methods: {
    /**
     * 根据语音时长计算语音气泡宽度
     */
    getVoiceWidth(duration) {
      // 基础宽度 120rpx，每秒增加 10rpx，最大 300rpx
      const baseWidth = 120;
      const perSecondWidth = 10;
      const maxWidth = 300;
      const minWidth = 120;
      
      const seconds = parseInt(duration) || 0;
      let width = baseWidth + seconds * perSecondWidth;
      
      // 限制在最小和最大范围内
      width = Math.max(minWidth, Math.min(maxWidth, width));
      
      return width + 'rpx';
    },
    
    /**
     * 红娘入口：根据当前登录用户ID获取红娘资料并设置头像
     */
    async loadMatchmakerAvatar() {
      try {
        const userId = uni.getStorageSync('userId');
        if (!userId) {
          console.warn('⚠️ 红娘聊天页：本地无 userId，无法加载红娘头像');
          return;
        }
        const res = await uni.request({
          url: 'http://localhost:8081/api/matchmaker/current',
          method: 'GET',
          data: { userId }
        });
        if (!res[1] || res[1].statusCode !== 200 || res[1].data.code !== 200) {
          console.warn('⚠️ 红娘聊天页：获取红娘信息失败');
          return;
        }
        const info = res[1].data.data || {};
        if (info.avatarUrl) {
          this.userAvatar = info.avatarUrl;
        }
      } catch (e) {
        console.error('❌ 红娘聊天页加载头像失败:', e);
      }
    },

    /**
     * 初始化 TIM
     */
    async initTIM() {
      try {
        // 如果未初始化，先初始化
        if (!timManager.tim) {
          timManager.init(1600109674); // 使用正确的 SDKAppID
        }

        // 如果未登录，获取 userSig 并登录
        if (!timManager.isLogin) {
          // 先导入当前用户和目标用户到腾讯云 IM
          await this.importUsers();

          // 从后端获取 userSig
          const userSig = await this.getUserSig();
          await timManager.login(this.userId, userSig);
        }

        this.isLogin = true;
        console.log('✅ TIM 初始化完成');
      } catch (error) {
        console.error('❌ TIM 初始化失败:', error);
        uni.showToast({
          title: '连接失败，请重试',
          icon: 'none'
        });
      }
    },

    /**
     * 跳转到VIP页面
     */
    goToVipPage() {
      console.log('点击跳转VIP页面');
      // 替换为你的实际VIP页面路径（例如会员开通页面）
      uni.navigateTo({
        url: '/pages/vip/index', // 请根据项目实际路径修改
        success: () => {
          console.log('跳转VIP页面成功');
        },
        fail: (err) => {
          console.error('跳转VIP页面失败:', err);
          uni.showToast({
            title: 'VIP页面不存在',
            icon: 'none'
          });
        }
      });
    },
    more(userid) {
      console.log('点击了更多按钮，开始跳转...', userid);
      // 如果目标页面是普通页面，用navigateTo（保留当前页面）；如果是tabbar页面，用switchTab
      uni.navigateTo({
        url: `/pages/message/more?userid=${userid}`,
        success: () => {
          console.log('跳转成功');
        },
        fail: (err) => {
          console.error('跳转失败:', err);
          uni.showToast({
            title: '页面不存在或路径错误',
            icon: 'none'
          });
        }
      });
    },
    /**
     * 导入用户到腾讯云IM
     */
    async importUsers() {
      try {
        console.log('📥 开始导入用户到腾讯云IM...');
        console.log('   - 当前用户ID:', this.userId, '(类型:', typeof this.userId, ')');
        console.log('   - 目标用户ID:', this.targetUserId, '(类型:', typeof this.targetUserId, ')');
        
        // 验证用户ID
        if (!this.userId || this.userId === 'undefined' || this.userId === 'null') {
          throw new Error('当前用户ID无效: ' + this.userId);
        }
        if (!this.targetUserId || this.targetUserId === 'undefined' || this.targetUserId === 'null') {
          throw new Error('目标用户ID无效: ' + this.targetUserId);
        }
        
        // 导入当前用户（确保userId是字符串）
        const currentUserRes = await uni.request({
          url: 'https://api.zhongruanke.cn/api/im/importUser',
          method: 'POST',
          data: {
            userId: String(this.userId),
            nickname: '用户' + this.userId
          },
          header: {
            'Content-Type': 'application/json'
          }
        });
        
        console.log('   - 当前用户导入结果:', currentUserRes[1].data);
        
        // 导入目标用户（确保userId是字符串）
        const targetUserRes = await uni.request({
          url: 'https://api.zhongruanke.cn/api/im/importUser',
          method: 'POST',
          data: {
            userId: String(this.targetUserId),
            nickname: this.targetUserName || '用户' + this.targetUserId
          },
          header: {
            'Content-Type': 'application/json'
          }
        });
        
        console.log('   - 目标用户导入结果:', targetUserRes[1].data);
        console.log('✅ 用户导入成功');
      } catch (error) {
        console.log('⚠️ 用户导入失败（可能已存在）:', error);
        // 导入失败不影响登录，因为用户可能已经存在
      }
    },
    
    /**
     * 获取 UserSig
     */
    async getUserSig() {
      try {
        const [err, res] = await uni.request({
          url: 'https://api.zhongruanke.cn/api/im/getUserSig',
          method: 'GET',
          data: {
            userId: this.userId
          }
        });
        
        if (err) {
          throw new Error('请求失败');
        }
        
        if (res.data && res.data.code === 200) {
          return res.data.data.userSig;
        } else {
          throw new Error('获取 UserSig 失败');
        }
      } catch (error) {
        console.error('❌ 获取 UserSig 失败:', error);
        throw error;
      }
    },
    
    /**
     * 等待 SDK Ready
     */
    async waitForSDKReady() {
      return new Promise((resolve) => {
        // 如果已经 ready，立即返回
        if (timManager.isLogin) {
          console.log('✅ SDK 已就绪');
          resolve();
          return;
        }
        
        // 否则等待 SDK ready 事件
        console.log('⏳ 等待 SDK 就绪...');
        const checkReady = setInterval(() => {
          if (timManager.isLogin) {
            console.log('✅ SDK 已就绪');
            clearInterval(checkReady);
            resolve();
          }
        }, 100); // 每 100ms 检查一次
        
        // 超时保护（10秒后强制继续）
        setTimeout(() => {
          console.log('⚠️ 等待 SDK 就绪超时，继续执行');
          clearInterval(checkReady);
          resolve();
        }, 10000);
      });
    },
    
    /**
     * 加载历史消息
     */
    async loadMessages() {
      try {
        const res = await timManager.tim.getMessageList({
          conversationID: this.conversationID,
          count: 20
        });
        
        const messageList = res.data.messageList;
        this.nextReqMessageID = res.data.nextReqMessageID;
        this.noMore = !res.data.isCompleted;
        
        // 转换为我们的消息格式
        this.messages = messageList.map(msg => this.convertMessage(msg));
        
        // 🔥 获取会话对象，用 peerReadTime 更新已读状态
        await this.updateMessageReadStatusByConversation();
        
        // 滚动到底部
        this.$nextTick(() => {
          this.scrollToBottom();
        });
        
        // 标记已读
        await timManager.setMessageRead(this.conversationID);
      } catch (error) {
        console.error('❌ 加载消息失败:', error);
      }
    },
    
    /**
     * 加载更多消息（上拉）
     */
    async loadMoreMessages() {
      if (this.loading || !this.nextReqMessageID) {
        return;
      }
      
      this.loading = true;
      
      try {
        const res = await timManager.tim.getMessageList({
          conversationID: this.conversationID,
          nextReqMessageID: this.nextReqMessageID,
          count: 20
        });
        
        const messageList = res.data.messageList;
        this.nextReqMessageID = res.data.nextReqMessageID;
        this.noMore = !res.data.isCompleted;
        
        // 转换并添加到消息列表前面
        const newMessages = messageList.map(msg => this.convertMessage(msg));
        this.messages = [...newMessages, ...this.messages];
        
        // 🔥 更新已读状态
        await this.updateMessageReadStatusByConversation();
        
      } catch (error) {
        console.error('❌ 加载更多消息失败:', error);
      } finally {
        this.loading = false;
      }
    },
    
    /**
     * 监听新消息
     */
    listenMessages() {
      const handleNewMessage = (event) => {
        // 兼容不同格式的事件数据
        const messageList = event.data || event || [];
        
        // 确保是数组格式
        const messagesToProcess = Array.isArray(messageList) ? messageList : [messageList];
        
        messagesToProcess.forEach(msg => {
          // 只处理当前会话的消息
          if (msg.conversationID === this.conversationID) {
            // 查找消息在本地列表中的位置
            const existingIndex = this.messages.findIndex(m => m.messageId === msg.ID);
            
            if (existingIndex > -1) {
              // 更新现有消息状态（使用$set确保视图更新）
              this.$set(this.messages, existingIndex, this.convertMessage(msg));
            } else {
              // 添加新消息
              this.messages.push(this.convertMessage(msg));
              this.$nextTick(() => {
                this.scrollToBottom();
              });
            }
            
            // 标记已读（通知对方：我已阅读他发送的消息）
            console.log('📖 收到新消息，标记会话已读:', this.conversationID);
            timManager.setMessageRead(this.conversationID);
          }
        });
      };
      
      this.handleNewMessage = handleNewMessage;
      timManager.onMessage(handleNewMessage);
      
      // 添加消息状态变更监听
      // 注释原因：TIM.EVENT.MESSAGE_STATUS_CHANGED 在当前SDK版本中可能不存在，导致参数验证失败
      // 消息状态更新已通过 handleNewMessage 处理，暂时不需要单独监听
      /*
      if (timManager.tim) {
        const handleStatusChange = (event) => {
          console.log('📝 消息状态变更:', event);
          // MESSAGE_STATUS_CHANGED 事件的数据结构不同
          if (event && event.data && Array.isArray(event.data)) {
            event.data.forEach(msg => {
              if (msg.conversationID === this.conversationID) {
                const existingIndex = this.messages.findIndex(m => m.messageId === msg.ID);
                if (existingIndex > -1) {
                  this.$set(this.messages, existingIndex, this.convertMessage(msg));
                }
              }
            });
          }
        };
        
        this.handleStatusChange = handleStatusChange;
        timManager.tim.on(TIM.EVENT.MESSAGE_STATUS_CHANGED, handleStatusChange);
      }
      */
    },
    
    /**
     * 转换消息格式
     */
    convertMessage(timMsg) {
      let sendStatus = 1; // 默认发送中
      
      // 完善的状态判断逻辑
      if (timMsg.status === TIM.TYPES.MSG_STATUS_SEND_SUCC || 
          timMsg.status === 'success' ||
          timMsg.status === TIM.TYPES.MSG_STATUS_RECEIVED) {
        sendStatus = 2; // 已送达
      } else if (timMsg.status === TIM.TYPES.MSG_STATUS_SEND_FAIL || 
                 timMsg.status === 'fail') {
        sendStatus = 4; // 发送失败
      } else if (timMsg.status === TIM.TYPES.MSG_STATUS_HAS_READ || 
                 timMsg.status === 'read') {
        sendStatus = 3; // 已读
      } else if (timMsg.status === TIM.TYPES.MSG_STATUS_SENDING) {
        sendStatus = 1; // 发送中
      }
    
      // 处理不同类型消息的URL和时长
      let mediaUrl = '';
      let duration = 0;
      let messageType = 1;
      let content = '';
      
      if (timMsg.type === TIM.TYPES.MSG_TEXT) {
        messageType = 1;
        content = timMsg.payload.text;
      } else if (timMsg.type === TIM.TYPES.MSG_IMAGE && timMsg.payload.imageInfoArray) {
        messageType = 2;
        content = '[图片]';
        mediaUrl = timMsg.payload.imageInfoArray[0]?.url || '';
      } else if (timMsg.type === TIM.TYPES.MSG_SOUND) {
        // 原生语音消息
        messageType = 3;
        content = '[语音]';
        mediaUrl = timMsg.payload.url || timMsg.payload.remoteAudioUrl || '';
        duration = timMsg.payload.second || 0;
      } else if (timMsg.type === TIM.TYPES.MSG_CUSTOM) {
        // 自定义消息（我们的语音消息）
        try {
          const customData = JSON.parse(timMsg.payload.data);
          if (customData.type === 'voice') {
            messageType = 3;
            content = '[语音]';
            mediaUrl = customData.url;
            // duration已经是秒数，直接使用
            duration = parseInt(customData.duration) || 0;
          }
        } catch (e) {
          console.error('解析自定义消息失败:', e);
        }
      } else if (timMsg.type === TIM.TYPES.MSG_VIDEO) {
        messageType = 4;
        content = '[视频]';
      }
      
      // 对于自己发送的消息，使用 TIM SDK 的 isPeerRead 值
      // TIM SDK 会根据 peerReadTime 自动更新这个字段
      let isPeerRead = false;
      if (timMsg.from === this.userId) {
        // 自己发送的消息，使用 TIM SDK 的 isPeerRead 值
        isPeerRead = timMsg.isPeerRead || false;
      } else {
        // 对方发送的消息，不需要 isPeerRead 字段
        isPeerRead = false;
      }
      
      return {
        messageId: timMsg.ID,
        fromUserId: timMsg.from,
        toUserId: timMsg.to,
        messageType: messageType,
        content: content || '[消息]',
        mediaUrl: mediaUrl,
        duration: duration,
        payload: timMsg.payload, // 保留原始payload
        sendStatus: sendStatus,
        sendTime: new Date(timMsg.time * 1000),
        isRecalled: timMsg.isRevoked,
        fromUserName: timMsg.from === this.userId ? '我' : this.targetUserName,
        isPeerRead: isPeerRead // 对方是否已读（只对自己发送的消息有意义）
      };
    },
    
    /**
     * 根据会话的 peerReadTime 更新消息的已读状态
     * 这是解决"退出重进后消息变未读"问题的关键方法
     */
    async updateMessageReadStatusByConversation() {
      try {
        console.log('🔄 开始根据会话 peerReadTime 更新已读状态...');
        
        // 获取当前会话对象
        const conversationRes = await timManager.tim.getConversationProfile(this.conversationID);
        
        if (!conversationRes || !conversationRes.data || !conversationRes.data.conversation) {
          console.warn('⚠️ 无法获取会话对象');
          return;
        }
        
        const conversation = conversationRes.data.conversation;
        const peerReadTime = conversation.peerReadTime; // 对方最后阅读时间（秒级时间戳）
        
        console.log('   会话ID:', this.conversationID);
        console.log('   对方最后阅读时间:', peerReadTime, new Date(peerReadTime * 1000).toLocaleString());
        
        if (!peerReadTime || peerReadTime === 0) {
          console.log('   对方尚未阅读任何消息');
          return;
        }
        
        // 更新消息列表中的已读状态
        let updatedCount = 0;
        this.messages.forEach((msg, index) => {
          // 只处理自己发送的消息
          if (msg.fromUserId === this.userId) {
            // 如果消息的发送时间 <= 对方最后阅读时间，说明对方已读
            const msgTime = Math.floor(msg.sendTime.getTime() / 1000); // 转换为秒级时间戳
            
            if (msgTime <= peerReadTime) {
              // 只更新未标记为已读的消息
              if (!msg.isPeerRead) {
                this.$set(this.messages[index], 'isPeerRead', true);
                updatedCount++;
                console.log(`   ✅ 消息 ${msg.messageId} 标记为已读 (发送时间: ${new Date(msgTime * 1000).toLocaleString()})`);
              }
            }
          }
        });
        
        console.log(`✅ 根据 peerReadTime 更新了 ${updatedCount} 条消息为已读状态`);
        
      } catch (error) {
        console.error('❌ 更新消息已读状态失败:', error);
      }
    },
    
    /**
     * 检查对方是否拉黑自己
     */
    async checkIsBlockedByTarget() {
      try {
        const [err, res] = await uni.request({
          url: 'https://api.zhongruanke.cn/api/chatfriend/checkBlock',
          method: 'POST',
          data: {
            userId: this.userId,       // 自己的ID
            targetUserId: this.targetUserId // 对方的ID
          },
          header: {
            'Content-Type': 'application/json'
          }
        });
    
        console.log('拉黑检查接口响应:', res.data); // 方便调试
        
        if (err) {
          console.error('网络请求失败:', err);
          return false; // 网络错误时默认按“未被拉黑”处理（避免误拦截）
        }
        
        // 严格校验接口返回格式
        if (!res.data || res.data.code !== 200) {
          console.error('接口返回格式错误:', res.data);
          return false;
        }
        
        // 关键修复：后端返回 data:true 表示“已被拉黑”，直接返回该值
        // 你的接口中 data 就是布尔值，无需额外解析
        const isBlocked = res.data.data; 
        console.log('是否被拉黑:', isBlocked); // 确认这里输出为 true（被拉黑时）
        return isBlocked;
        
      } catch (error) {
        console.error('检查拉黑状态失败:', error);
        return false;
      }
    },
    
    /**
     * 监听已读回执
     */
    listenMessageReadReceipt() {
      console.log('🔔 开始注册已读回执监听器...');
      
      if (!timManager.tim) {
        console.warn('⚠️ TIM 未初始化，无法监听已读回执');
        return;
      }
      
      console.log('✅ TIM 对象已就绪，使用全局已读回执监听');
      
      // 🔥 使用 timManager 的全局已读回执监听
      const handleMessageReadByPeer = async (event) => {
        console.log('=== 📖 [chat.vue] 收到已读回执事件 ===');
        console.log('   - 触发时间:', new Date().toLocaleString());
        console.log('   - 事件数据:', JSON.stringify(event.data));
        console.log('   - 当前会话ID:', this.conversationID);
        console.log('   - 当前用户ID:', this.userId);
        
        // event.data 包含已读的消息列表
        if (event.data && Array.isArray(event.data)) {
          let updatedCount = 0;
          
          // 🔥 直接使用事件数据中的消息对象（它们已经带有 isPeerRead: true）
          event.data.forEach(readMessage => {
            console.log('   - 处理消息:', readMessage.ID, '会话:', readMessage.conversationID);
            
            // 只处理当前会话的消息
            if (readMessage.conversationID === this.conversationID) {
              // 在本地消息列表中查找对应的消息
              const localMsgIndex = this.messages.findIndex(msg => msg.messageId === readMessage.ID);
              
              if (localMsgIndex > -1) {
                const localMsg = this.messages[localMsgIndex];
                
                // 只更新自己发送的未读消息
                if (localMsg.fromUserId === this.userId && !localMsg.isPeerRead) {
                  this.$set(this.messages[localMsgIndex], 'isPeerRead', true);
                  updatedCount++;
                  console.log(`   - ✅ 消息 ${readMessage.ID} 已标记为已读`);
                }
              } else {
                console.log(`   - ⚠️ 本地未找到消息 ${readMessage.ID}`);
              }
            }
          });
          
          if (updatedCount > 0) {
            console.log(`✅ 共更新 ${updatedCount} 条消息为已读状态`);
          } else {
            console.log('⚠️ 没有消息需要更新');
          }
        }
      };
      
      // 🔥 使用 timManager 的全局已读回执监听
      this.handleMessageReadByPeer = handleMessageReadByPeer;
      timManager.onMessageRead(handleMessageReadByPeer);
      console.log('✅ 已通过 timManager 注册消息已读回执监听');
    },
    
    /**
     * 标记当前会话的消息为已读
     * 注意：这会通知对方"我已阅读他发送的消息"，触发对方的 MESSAGE_READ_BY_PEER 事件
     */
    async markConversationRead() {
      try {
        if (!timManager.tim || !this.conversationID) {
          console.warn('⚠️ TIM 未初始化或会话ID为空');
          return;
        }
        
        console.log('📖 标记会话已读:', this.conversationID);
        
        // 调用 TIM SDK 标记会话已读
        // 这会通知对方：他发送给我的消息已被阅读
        await timManager.tim.setMessageRead({ conversationID: this.conversationID });
        
        console.log('✅ 会话已标记为已读，已通知对方');
      } catch (error) {
        console.error('❌ 标记会话已读失败:', error);
      }
    },
    
    /**
     * 发送文本消息
     */
    async sendTextMessage() {
		  // 判断是否为涉及红娘的会话：任一方ID以 m_ 开头，或来自红娘工作台
		  const isMatchmakerChat = this.fromMatchmaker || String(this.userId).startsWith('m_') || String(this.targetUserId).startsWith('m_');
		
		  // 仅普通用户之间的会话才做消息次数限制
		  if (!isMatchmakerChat && this.hasMessageLimit && this.remainingCount <= 0) {
		    uni.showToast({
		      title: '今日消息发送次数已用完，开通VIP无限制',
		      icon: 'none',
		      duration: 2000
		    });
		    return;
		  }
		  
      if (!this.inputText.trim()) {
        return;
      }
      
      const content = this.inputText;
      this.inputText = '';
      
      // 1. 先进行消息内容审核（只要有一方是红娘就跳过审核）
      if (!isMatchmakerChat) {
        try {
          const checkRes = await uni.request({
            url: 'https://api.zhongruanke.cn/api/chat/checkMessage',
            method: 'POST',
            data: {
              userId: String(this.userId),
              content: content
            },
            header: {
              'Content-Type': 'application/json'
            }
          });
          
          if (checkRes[1].data.code !== 200) {
            // 审核未通过,显示失败消息
            const failedMessage = {
              messageId: 'failed_' + Date.now(),
              fromUserId: this.userId,
              toUserId: this.targetUserId,
              messageType: 1,
              content: content,
              sendStatus: 4, // 4表示发送失败
              failReason: 'audit_failed', // 标记失败原因:审核失败
              sendTime: new Date(),
              fromUserName: '我'
            };
            
            this.messages.push(failedMessage);
            this.scrollToBottom();
            
            uni.showToast({
              title: checkRes[1].data.message || '消息发送失败',
              icon: 'none',
              duration: 2000
            });
            
            return;
          }
        } catch (error) {
          console.error('❌ 消息审核失败:', error);
          // 审核接口失败,为了不影响用户体验,继续发送
        }
      } else {
        console.log('✅ 红娘聊天模式：跳过文本审核');
      }
      
      // 2. 检查是否被拉黑
      const isBlocked = await this.checkIsBlockedByTarget();
      
      if (isBlocked) {
        // 被拉黑时的处理保持不变
        const failedMessage = {
          messageId: 'failed_' + Date.now(),
          fromUserId: this.userId,
          toUserId: this.targetUserId,
          messageType: 1,
          content: content,
          sendStatus: 4, // 4表示发送失败
          sendTime: new Date(),
          fromUserName: '我'
        };
        
        this.messages.push(failedMessage);
        this.scrollToBottom();
        
        uni.showToast({
          title: '消息发送失败',
          icon: 'none'
        });
        
        return;
      }
      
      // 创建临时消息显示"发送中"
      const tempMessageId = 'temp_' + Date.now();
      const tempMessage = {
        messageId: tempMessageId,
        fromUserId: this.userId,
        toUserId: this.targetUserId,
        messageType: 1,
        content: content,
        sendStatus: 1, // 发送中
        sendTime: new Date(),
        fromUserName: '我'
      };
      this.messages.push(tempMessage);
      this.scrollToBottom();
      
      // 未被拉黑，正常发送
      try {
        const sendPromise = timManager.sendTextMessage(this.targetUserId, content);
        const timeoutPromise = new Promise((_, reject) => {
          setTimeout(() => reject(new Error('发送超时')), 15000);
        });
        
        const message = await Promise.race([sendPromise, timeoutPromise]);
        
        // 替换临时消息
        const tempIndex = this.messages.findIndex(m => m.messageId === tempMessageId);
        if (tempIndex > -1) {
          const convertedMsg = this.convertMessage(message);
          // 强制设置为已送达
          convertedMsg.sendStatus = 2;
          this.$set(this.messages, tempIndex, convertedMsg);
        }
        
        console.log('✅ 消息发送成功');
        this.syncMessageToMySQL(message);
		  // 仅普通用户之间的会话才扣减消息次数
		  if (!isMatchmakerChat && !this.isVip) {
		    await this.updateMessageCount();
		  }
      } catch (error) {
        console.error('❌ 消息发送失败:', error);
        
        // 更新临时消息为失败状态
        const tempIndex = this.messages.findIndex(m => m.messageId === tempMessageId);
        if (tempIndex > -1) {
          this.$set(this.messages[tempIndex], 'sendStatus', 4);
        }
        
        // 恢复输入框内容
        this.inputText = content;
        
        uni.showToast({
          title: '发送失败: ' + error.message,
          icon: 'none'
        });
      }
    },
    
    /**
     * 选择图片
     */
    chooseImage() {
      uni.chooseImage({
        count: 1,
        sizeType: ['compressed'],
        sourceType: ['album', 'camera'],
        success: async (res) => {
			// 1. 先检查是否被拉黑
			      const isBlocked = await this.checkIsBlockedByTarget();
			      if (isBlocked) {
			        uni.showToast({
			          title: '你已被对方拉黑，无法发送消息',
			          icon: 'none'
			        });
			        return;
			      }
			
          const tempFilePath = res.tempFilePaths[0];
          
          try {
            uni.showLoading({ title: '发送中...' });
            
            const message = await timManager.sendImageMessage(this.targetUserId, tempFilePath);
            
            this.messages.push(this.convertMessage(message));
            this.scrollToBottom();
            
            uni.hideLoading();
            console.log('✅ 图片发送成功');
          } catch (error) {
            uni.hideLoading();
            console.error('❌ 图片发送失败:', error);
            uni.showToast({
              title: '发送失败',
              icon: 'none'
            });
          }
        }
      });
    },
    
    /**
     * 输入框内容变化
     */
    onInputChange() {
      // 腾讯云 IM 可以实现正在输入状态，这里暂时省略
      console.log('输入中...');
    },
    
    /**
     * 同步消息到MySQL数据库（双重存储保障）
     */
    async syncMessageToMySQL(timMessage) {
      try {
        console.log('🔄 同步消息到MySQL...', timMessage.ID);
        
        // 构建同步参数
        const syncData = {
          messageId: timMessage.ID,
          fromUserId: timMessage.from,
          toUserId: timMessage.to,
          messageType: this.getMessageType(timMessage),
          content: this.getMessageContent(timMessage),
          sendTime: timMessage.time  // TIM返回的是秒级时间戳
        };
        
        // 如果是图片消息，添加媒体信息
        if (timMessage.type === 'TIMImageElem' && timMessage.payload.imageInfoArray) {
          const imageInfo = timMessage.payload.imageInfoArray[0];
          syncData.mediaUrl = imageInfo.imageUrl;
          syncData.thumbnailUrl = imageInfo.imageUrl;
        }
        
        // 如果是语音消息，添加语音信息
        if (timMessage.type === 'TIMSoundElem' && timMessage.payload) {
          syncData.mediaUrl = timMessage.payload.url || timMessage.payload.remoteAudioUrl;
          syncData.duration = timMessage.payload.second || 0;
          syncData.mediaSize = timMessage.payload.size || 0;
        }
        
        // 如果是自定义消息（我们的语音消息）
        if (timMessage.type === 'TIMCustomElem' && timMessage.payload) {
          try {
            const customData = JSON.parse(timMessage.payload.data);
            if (customData.type === 'voice') {
              syncData.mediaUrl = customData.url;
              syncData.duration = customData.duration;
              syncData.mediaSize = customData.size || 0;
            }
          } catch (e) {
            console.error('解析自定义消息失败:', e);
          }
        }
        
        // 调用后端同步接口
        const res = await uni.request({
          url: 'https://api.zhongruanke.cn/api/chat/syncTIMMessage',
          method: 'POST',
          data: syncData,
          header: {
            'Content-Type': 'application/json'
          }
        });
        
        if (res[1].data.code === 200) {
          console.log('✅ 消息已同步到MySQL:', timMessage.ID);
        } else {
          console.warn('⚠️ 消息同步失败:', res[1].data.message);
        }
      } catch (error) {
        console.error('❌ 同步消息到MySQL失败:', error);
        // 同步失败不影响聊天功能，只记录日志
      }
    },
    
    /**
     * 获取消息类型
     */
    getMessageType(timMessage) {
      const typeMap = {
        'TIMTextElem': 1,      // 文本
        'TIMImageElem': 2,     // 图片
        'TIMSoundElem': 3,     // 语音
        'TIMVideoFileElem': 4, // 视频
        'TIMFileElem': 5       // 文件
      };
      
      // 处理自定义消息（我们的语音消息）
      if (timMessage.type === 'TIMCustomElem' && timMessage.payload) {
        try {
          const customData = JSON.parse(timMessage.payload.data);
          if (customData.type === 'voice') {
            return 3; // 语音消息
          }
        } catch (e) {
          console.error('解析自定义消息类型失败:', e);
        }
      }
      
      return typeMap[timMessage.type] || 1;
    },
    
    /**
     * 获取消息内容
     */
    getMessageContent(timMessage) {
      switch (timMessage.type) {
        case 'TIMTextElem':
          return timMessage.payload.text || '';
        case 'TIMImageElem':
          return '[图片]';
        case 'TIMSoundElem':
          return '[语音]';
        case 'TIMVideoFileElem':
          return '[视频]';
        case 'TIMFileElem':
          return '[文件]';
        case 'TIMCustomElem':
          // 处理自定义消息（我们的语音消息）
          try {
            const customData = JSON.parse(timMessage.payload.data);
            if (customData.type === 'voice') {
              return '[语音]';
            }
          } catch (e) {
            console.error('解析自定义消息内容失败:', e);
          }
          return '[未知消息]';
        default:
          return '[未知消息]';
      }
    },
    
    
    /**
     * 滚动到底部
     */
    scrollToBottom() {
      this.$nextTick(() => {
        const lastIndex = this.messages.length - 1;
        this.scrollToView = 'msg-' + lastIndex;
      });
    },
    
    /**
     * 判断是否显示时间分隔线
     */
    shouldShowTime(msg, index) {
      if (index === 0) return true;
      
      const prevMsg = this.messages[index - 1];
      const timeDiff = new Date(msg.sendTime) - new Date(prevMsg.sendTime);
      
      // 超过5分钟显示时间
      return timeDiff > 5 * 60 * 1000;
    },
    
    /**
     * 格式化消息时间（用于时间分隔线）
     */
    formatMessageTime(time) {
      const date = new Date(time);
      const now = new Date();
      const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
      const yesterday = new Date(today - 86400000);
      
      // 今天
      if (date >= today) {
        return date.toLocaleTimeString('zh-CN', {
          hour: '2-digit',
          minute: '2-digit'
        });
      }
      
      // 昨天
      if (date >= yesterday) {
        return '昨天 ' + date.toLocaleTimeString('zh-CN', {
          hour: '2-digit',
          minute: '2-digit'
        });
      }
      
      // 本周
      if (date > new Date(now - 7 * 86400000)) {
        const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
        return days[date.getDay()] + ' ' + date.toLocaleTimeString('zh-CN', {
          hour: '2-digit',
          minute: '2-digit'
        });
      }
      
      // 更早
      return date.toLocaleString('zh-CN', {
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
      });
    },
    
    /**
     * 格式化时间（消息状态用）
     */
    formatTime(time) {
      const date = new Date(time);
      const now = new Date();
      const diff = now - date;
      
      if (diff < 60000) {
        return '刚刚';
      } else if (diff < 3600000) {
        return Math.floor(diff / 60000) + '分钟前';
      } else if (diff < 86400000) {
        return Math.floor(diff / 3600000) + '小时前';
      } else {
        return date.toLocaleString('zh-CN', {
          month: '2-digit',
          day: '2-digit',
          hour: '2-digit',
          minute: '2-digit'
        });
      }
    },
    
    /**
     * 预览图片
     */
    previewImage(url) {
      uni.previewImage({
        urls: [url],
        current: url
      });
    },
    
    /**
     * 返回
     */
    goBack() {
      uni.navigateBack({
        success: () => {
          // 通知消息列表页面刷新
          uni.$emit('refreshConversations');
        }
      });
    },
    
    /**
     * 跳转到用户详情页面
     */
    goToUserDetail(userId) {
      // 检查是否为红娘ID（以m_开头）
      if (typeof userId === 'string' && userId.startsWith('m_')) {
        console.log('点击的是红娘头像，不跳转');
        return;
      }
      
      // 将字符串类型的userId转换为数字
      let numericUserId = userId;
      if (typeof userId === 'string') {
        numericUserId = parseInt(userId);
      }
      
      // 验证userId是否有效
      if (!numericUserId || isNaN(numericUserId)) {
        uni.showToast({
          title: '用户信息无效',
          icon: 'none'
        });
        return;
      }
      
      console.log('跳转到用户详情页面，userId:', numericUserId);
      
      uni.navigateTo({
        url: `/pages/recommend/user-detail?userId=${numericUserId}`,
        fail: (err) => {
          console.error('跳转用户详情页失败:', err);
          uni.showToast({
            title: '跳转失败',
            icon: 'none'
          });
        }
      });
    },
    
    /**
     * 显示消息操作菜单
     */
    showMessageMenu(msg, index) {
      this.selectedMessage = msg;
      this.selectedMessageIndex = index;
      this.showMessageAction = true;
      
      // 计算菜单位置
      uni.createSelectorQuery().select('.message-item').boundingClientRect(rect => {
        if (rect) {
          this.menuTop = rect.top + rect.height;
        }
      }).exec();
    },
    
    /**
     * 隐藏消息操作菜单
     */
    hideMessageMenu() {
      this.showMessageAction = false;
      this.selectedMessage = null;
      this.selectedMessageIndex = -1;
    },
    
    /**
     * 复制消息
     */
    copyMessage() {
      if (!this.selectedMessage || this.selectedMessage.messageType !== 1) {
        return;
      }
      
      uni.setClipboardData({
        data: this.selectedMessage.content,
        success: () => {
          uni.showToast({
            title: '已复制',
            icon: 'success'
          });
        }
      });
      
      this.hideMessageMenu();
    },
    
    /**
     * 判断是否可以撤回
     */
    canRecall(msg) {
      const diff = Date.now() - new Date(msg.sendTime).getTime();
      return diff < 2 * 60 * 1000; // 2分钟内可撤回
    },
    
    /**
     * 撤回消息
     */
    async recallMessage() {
      if (!this.selectedMessage) {
        return;
      }
      
      try {
        // 查找TIM消息对象
        const timMessage = await timManager.tim.findMessage(this.selectedMessage.messageId);
        
        if (timMessage) {
          await timManager.revokeMessage(timMessage);
          
          // 更新本地消息状态
          this.selectedMessage.isRecalled = true;
          this.selectedMessage.content = '你撤回了一条消息';
          
          uni.showToast({
            title: '已撤回',
            icon: 'success'
          });
        }
      } catch (error) {
        console.error('撤回失败:', error);
        uni.showToast({
          title: '撤回失败',
          icon: 'none'
        });
      }
      
      this.hideMessageMenu();
    },
    
    /**
     * 删除消息
     */
    deleteMessage() {
      if (!this.selectedMessage) {
        return;
      }
      
      uni.showModal({
        title: '确认删除',
        content: '确定要删除这条消息吗？',
        success: (res) => {
          if (res.confirm) {
            // 从列表中删除
            this.messages.splice(this.selectedMessageIndex, 1);
            uni.showToast({
              title: '已删除',
              icon: 'success'
            });
          }
        }
      });
      
      this.hideMessageMenu();
    },
    
    /**
     * 处理消息点击
     */
    handleMessageClick(msg) {
      // 如果是发送失败的消息，提示重试
      if (msg.sendStatus === 4) {
        // 检查失败原因
        if (msg.failReason === 'audit_failed') {
          // 审核失败的消息不允许重试
          uni.showModal({
            title: '无法重试',
            content: '该消息包含敏感信息，无法发送',
            showCancel: false,
            confirmText: '知道了'
          });
          return;
        }
        
        // 其他原因失败的消息可以重试
        uni.showModal({
          title: '发送失败',
          content: '消息发送失败，是否重试？',
          success: (res) => {
            if (res.confirm) {
              this.retryMessage(msg);
            }
          }
        });
      }
    },
    
    /**
     * 重试发送消息
     */
    async retryMessage(msg) {
      if (msg.messageType !== 1) {
        uni.showToast({ title: '暂不支持重发该类型消息', icon: 'none' });
        return;
      }
      
      // 双重保护:检查是否是审核失败的消息
      if (msg.failReason === 'audit_failed') {
        uni.showToast({
          title: '该消息包含敏感信息，无法重试',
          icon: 'none',
          duration: 2000
        });
        return;
      }
      
      const isBlocked = await this.checkIsBlockedByTarget();
      if (isBlocked) {
        const index = this.messages.findIndex(m => m.messageId === msg.messageId);
        if (index > -1) {
          this.$set(this.messages[index], 'sendStatus', 4);
        }
        uni.showToast({ title: '对方已拉黑你，无法发送', icon: 'none' });
        return;
      }
      
      try {
        const index = this.messages.findIndex(m => m.messageId === msg.messageId);
        if (index > -1) {
          this.$set(this.messages[index], 'sendStatus', 1); // 发送中
        }
        
        const message = await timManager.sendTextMessage(this.targetUserId, msg.content);
        
        // 更新消息状态为已送达
        if (index > -1) {
          const convertedMsg = this.convertMessage(message);
          convertedMsg.sendStatus = 2; // 强制已送达
          convertedMsg.messageId = msg.messageId; // 保持原ID
          this.$set(this.messages, index, convertedMsg);
        }
        
        console.log('✅ 消息重发成功');
        this.syncMessageToMySQL(message);
        
      } catch (error) {
        console.error('❌ 消息重发失败:', error);
        const index = this.messages.findIndex(m => m.messageId === msg.messageId);
        if (index > -1) {
          this.$set(this.messages[index], 'sendStatus', 4);
        }
        uni.showToast({ title: '发送失败', icon: 'none' });
      }
    },
    
    // 其他功能方法
    switchInputType() {
      this.inputType = this.inputType === 'text' ? 'voice' : 'text';
    },
    
    /**
     * 开始录音
     */
    startVoiceRecord(e) {
      console.log('🎤 [按住说话] startVoiceRecord 方法被调用');
      
      // 记录触摸起始位置
      this.voiceTouchStartY = e.touches[0].clientY;
      this.voiceCanceling = false;
      
      // 检查是否被拉黑
      if (this.isBlockedByTarget) {
        uni.showToast({
          title: '对方已将你拉黑',
          icon: 'none'
        });
        return;
      }
      
      // 🔥 每次都重新获取录音管理器（确保状态干净）
      console.log('📱 获取录音管理器');
      this.recorderManager = uni.getRecorderManager();
      
      // 🔥 每次录音前都重新注册回调（确保回调有效）
      console.log('📝 注册录音回调');
      
      // 录音开始回调（可能延迟或不触发，所以状态已在 start() 后立即设置）
      this.recorderManager.onStart(() => {
        console.log('✅ 录音开始回调触发（延迟触发）');
      });
      
      // 录音结束回调
      this.recorderManager.onStop((res) => {
        console.log('🎤 录音结束:', res, ', voiceCanceling:', this.voiceCanceling);
        this.isRecording = false;
        this.showVoiceRecording = false;
        
        // 清除计时器
        if (this.voiceRecordingTimer) {
          clearInterval(this.voiceRecordingTimer);
          this.voiceRecordingTimer = null;
        }
        
        // 如果是取消状态，不发送
        if (this.voiceCanceling) {
          console.log('❌ 录音已取消，不发送');
          this.voiceCanceling = false;
          return;
        }
        
        this.voiceTempPath = res.tempFilePath;
        this.voiceDuration = Math.floor(res.duration / 1000); // 转换为秒
        
        console.log('   - 文件路径:', this.voiceTempPath);
        console.log('   - 时长:', this.voiceDuration, '秒');
        
        // 时长验证
        if (this.voiceDuration < 1) {
          uni.showToast({
            title: '录音时间太短',
            icon: 'none'
          });
          return;
        }
        
        if (this.voiceDuration > 60) {
          uni.showToast({
            title: '录音时间不能超过60秒',
            icon: 'none'
          });
          return;
        }
        
        // 发送语音消息
        this.sendVoiceMessage();
      });
      
      // 录音错误回调
      this.recorderManager.onError((err) => {
        console.error('❌ 录音错误:', err);
        
        // 立即清理录音状态和界面
        this.isRecording = false;
        this.showVoiceRecording = false;
        this.voiceCanceling = true;
        
        // 清除计时器
        if (this.voiceRecordingTimer) {
          clearInterval(this.voiceRecordingTimer);
          this.voiceRecordingTimer = null;
        }
        
        // 如果是权限错误，不显示任何提示（用户会看到系统权限弹窗）
        // 其他错误才显示提示
        if (err.errCode !== 'authorize' && err.errMsg && !err.errMsg.includes('authorize')) {
          uni.showToast({
            title: '录音失败',
            icon: 'none'
          });
        }
        
        console.log('✅ 已清理录音状态，隐藏录音界面');
      });
      
      // 🔥 先检查录音权限
      console.log('🔐 检查录音权限...');
      uni.getSetting({
        success: (res) => {
          console.log('📋 权限设置:', res.authSetting);
          if (res.authSetting['scope.record'] === false) {
            console.warn('⚠️ 录音权限被拒绝');
            uni.showModal({
              title: '需要录音权限',
              content: '请在设置中开启录音权限',
              success: (modalRes) => {
                if (modalRes.confirm) {
                  uni.openSetting();
                }
              }
            });
            return;
          }
        }
      });
      
      // 开始录音
      console.log('🎙️ 调用 recorderManager.start()');
      try {
        this.recorderManager.start({
          format: 'mp3',
          sampleRate: 16000,
          numberOfChannels: 1,
          encodeBitRate: 48000
        });
        console.log('✅ recorderManager.start() 调用成功');
        
        // 🔥 立即显示录音界面（不等待 onStart 回调）
        // 因为微信小程序的 onStart 可能延迟或不触发
        this.isRecording = true;
        this.showVoiceRecording = true;
        this.voiceStartTime = Date.now();
        this.voiceRecordingTime = 0;
        this.voiceVolume = 0.3;
        console.log('🎬 立即显示录音界面');
        console.log('   - isRecording:', this.isRecording);
        console.log('   - showVoiceRecording:', this.showVoiceRecording);
        
        // 启动计时器
        let volumeDirection = 1;
        let currentVolume = 0.3;
        this.voiceRecordingTimer = setInterval(() => {
          this.voiceRecordingTime = Math.floor((Date.now() - this.voiceStartTime) / 1000);
          
          // 检查是否达到60秒，自动停止录音
          if (this.voiceRecordingTime >= 60) {
            console.log('⏰ 录音时长达到60秒，自动停止');
            clearInterval(this.voiceRecordingTimer);
            this.voiceRecordingTimer = null;
            this.voiceCanceling = false;
            if (this.recorderManager) {
              this.recorderManager.stop();
            }
            return;
          }
          
          // 模拟音量波动
          if (Math.random() > 0.2) {
            currentVolume += volumeDirection * (0.1 + Math.random() * 0.2);
            if (currentVolume > 1.0) {
              currentVolume = 1.0;
              volumeDirection = -1;
            } else if (currentVolume < 0.4) {
              currentVolume = 0.4;
              volumeDirection = 1;
            }
            this.voiceVolume = currentVolume;
          } else {
            this.voiceVolume = Math.max(0.2, this.voiceVolume * 0.8);
          }
        }, 100);
        
      } catch (err) {
        console.error('❌ recorderManager.start() 调用失败:', err);
        this.isRecording = false;
        this.showVoiceRecording = false;
      }
    },
    
    /**
     * 停止录音
     */
    stopVoiceRecord() {
      console.log('🎤 [松开] stopVoiceRecord 方法被调用, isRecording:', this.isRecording, ', voiceCanceling:', this.voiceCanceling);
      
      // 清除计时器
      if (this.voiceRecordingTimer) {
        clearInterval(this.voiceRecordingTimer);
        this.voiceRecordingTimer = null;
      }
      
      // 如果正在取消，则取消录音
      if (this.voiceCanceling) {
        console.log('🚫 检测到取消状态，调用 cancelVoiceRecord');
        this.cancelVoiceRecord();
        return;
      }
      
      if (this.isRecording && this.recorderManager) {
        const duration = Date.now() - this.voiceStartTime;
        
        // 录音时间太短
        if (duration < 1000) {
          this.recorderManager.stop();
          this.isRecording = false;
          this.showVoiceRecording = false;
          uni.showToast({
            title: '录音时间太短',
            icon: 'none'
          });
          return;
        }
        
        this.recorderManager.stop();
      }
    },
    
    /**
     * 触摸移动 - 检测上滑取消
     */
    onVoiceTouchMove(e) {
      if (!this.isRecording) return;
      
      const currentY = e.touches[0].clientY;
      const deltaY = this.voiceTouchStartY - currentY;
      
      // 上滑超过100px，显示取消提示
      if (deltaY > 100) {
        this.voiceCanceling = true;
        console.log('⬆️ 上滑取消录音');
      } else {
        this.voiceCanceling = false;
      }
    },
    
    /**
     * 取消录音
     */
    cancelVoiceRecord() {
      console.log('❌ 取消录音, voiceCanceling:', this.voiceCanceling);
      
      // 清除计时器
      if (this.voiceRecordingTimer) {
        clearInterval(this.voiceRecordingTimer);
        this.voiceRecordingTimer = null;
      }
      
      // 先设置取消状态，再停止录音
      // 这样onStop回调中能正确判断
      if (!this.voiceCanceling) {
        this.voiceCanceling = true;
      }
      
      if (this.recorderManager && this.isRecording) {
        this.recorderManager.stop();  // 这会触发onStop回调
      } else {
        // 如果没有在录音，直接重置状态
        this.isRecording = false;
        this.showVoiceRecording = false;
        this.voiceCanceling = false;
      }
      
      uni.showToast({
        title: '已取消录音',
        icon: 'none'
      });
    },
    
    /**
     * 发送语音消息
     */
    async sendVoiceMessage() {
      // 检查是否被拉黑
      const isBlocked = await this.checkIsBlockedByTarget();
      if (isBlocked) {
        uni.showToast({
          title: '你已被对方拉黑，无法发送消息',
          icon: 'none'
        });
        return;
      }
      
      try {
        uni.showLoading({ title: '上传中...' });
        
        // 第一步：上传语音文件到MinIO
        const uploadResult = await this.uploadVoiceToMinIO();
        if (!uploadResult.success) {
          throw new Error(uploadResult.message || '上传失败');
        }
        
        console.log('✅ 语音文件上传成功:', uploadResult.fileUrl);
        uni.showLoading({ title: '发送中...' });
        
        // 第二步：通过腾讯IM发送语音消息（携带MinIO URL）
        const message = await timManager.sendVoiceMessage(
          this.targetUserId,
          uploadResult.fileUrl,
          this.voiceDuration,
          uploadResult.fileSize
        );
        
        // 添加到消息列表
        this.messages.push(this.convertMessage(message));
        this.scrollToBottom();
        
        uni.hideLoading();
        console.log('✅ 语音消息发送成功');
        
        // 同步到MySQL
        this.syncMessageToMySQL(message);
        
        // 更新消息计数
        if (!this.isVip) {
          await this.updateMessageCount();
        }
        
      } catch (error) {
        uni.hideLoading();
        console.error('❌ 语音消息发送失败:', error);
        uni.showToast({
          title: '发送失败: ' + error.message,
          icon: 'none'
        });
      }
    },
    
    /**
     * 上传语音文件到MinIO
     */
    async uploadVoiceToMinIO() {
      try {
        console.log('📤 开始上传语音文件到MinIO...');
        console.log('   - 文件路径:', this.voiceTempPath);
        console.log('   - 时长:', this.voiceDuration, '秒');
        
        // 使用uni.uploadFile上传到后端MinIO接口
        const [err, res] = await uni.uploadFile({
          url: 'https://api.zhongruanke.cn/api/voice/upload',
          filePath: this.voiceTempPath,
          name: 'file',
          header: {
            'Content-Type': 'multipart/form-data'
          }
        });
        
        if (err) {
          console.error('❌ 上传请求失败:', err);
          return {
            success: false,
            message: '网络请求失败'
          };
        }
        
        // 解析响应
        const result = JSON.parse(res.data);
        console.log('📥 MinIO上传响应:', result);
        
        if (result.success) {
          return {
            success: true,
            fileUrl: result.fileUrl,
            fileSize: result.fileSize
          };
        } else {
          return {
            success: false,
            message: result.message || '上传失败'
          };
        }
        
      } catch (error) {
        console.error('❌ 上传语音文件失败:', error);
        return {
          success: false,
          message: error.message || '上传异常'
        };
      }
    },
    insertEmoji(emoji) {
      this.inputText += emoji;
      this.showEmojiPanel = false;
    },
    chooseVideo() {
      uni.showToast({
        title: '视频功能开发中',
        icon: 'none'
      });
    },
    chooseFile() {
      uni.showToast({
        title: '文件功能开发中',
        icon: 'none'
      });
    },
    /**
     * 切换语音播放/暂停
     */
    toggleVoicePlay(msg) {
      // 如果正在播放这条语音，则暂停
      if (this.playingVoiceId === msg.messageId) {
        this.pauseVoice(msg);
      } else {
        // 否则开始播放
        this.playVoice(msg);
      }
    },
    
    /**
     * 播放语音
     */
    playVoice(msg) {
      console.log('📢 [播放语音] 开始 - messageId:', msg.messageId);
      
      if (!msg.mediaUrl) {
        // 如果是TIM消息，从payload中获取URL
        const audioUrl = msg.payload?.url || msg.payload?.remoteAudioUrl;
        if (!audioUrl) {
          uni.showToast({
            title: '语音文件不存在',
            icon: 'none'
          });
          return;
        }
        msg.mediaUrl = audioUrl;
      }
      
      // 如果有其他语音正在播放，先停止
      if (this.currentAudioContext) {
        console.log('⏹️ 停止之前的语音');
        this.currentAudioContext.stop();
        this.currentAudioContext.destroy();
        this.currentAudioContext = null;
      }
      
      // 清除暂停状态
      this.pausedVoiceId = null;
      
      // 设置当前播放的语音ID，触发动画
      this.playingVoiceId = msg.messageId;
      console.log('🎬 [动画开始] playingVoiceId =', this.playingVoiceId);
      
      // 创建音频上下文
      const innerAudioContext = uni.createInnerAudioContext();
      innerAudioContext.src = msg.mediaUrl;
      innerAudioContext.loop = false; // 不循环播放
      this.currentAudioContext = innerAudioContext;
      
      innerAudioContext.onPlay(() => {
        console.log('🔊 开始播放语音');
      });
      
      innerAudioContext.onEnded(() => {
        console.log('✅ 语音播放完成');
        this.playingVoiceId = null; // 停止动画
        this.pausedVoiceId = null;
        this.currentAudioContext = null;
        console.log('🛑 [动画停止] playingVoiceId =', this.playingVoiceId);
        innerAudioContext.destroy();
      });
      
      innerAudioContext.onError((err) => {
        console.error('❌ 语音播放失败:', err);
        this.playingVoiceId = null; // 停止动画
        this.pausedVoiceId = null;
        this.currentAudioContext = null;
        console.log('🛑 [动画停止-错误] playingVoiceId =', this.playingVoiceId);
        uni.showToast({
          title: '播放失败',
          icon: 'none'
        });
        innerAudioContext.destroy();
      });
      
      innerAudioContext.play();
    },
    
    /**
     * 暂停语音
     */
    pauseVoice(msg) {
      if (this.currentAudioContext) {
        this.currentAudioContext.pause();
        this.playingVoiceId = null; // 停止动画
        this.pausedVoiceId = msg.messageId; // 设置暂停状态
        console.log('⏸️ [暂停] playingVoiceId =', this.playingVoiceId, ', pausedVoiceId =', this.pausedVoiceId);
      }
    },
    
    /**
     * 继续播放语音
     */
    resumeVoice() {
      if (this.currentAudioContext && this.pausedVoiceId) {
        this.currentAudioContext.play();
        this.playingVoiceId = this.pausedVoiceId; // 恢复动画
        const resumedId = this.pausedVoiceId;
        this.pausedVoiceId = null; // 清除暂停状态
        console.log('▶️ [继续播放] playingVoiceId =', this.playingVoiceId, ', pausedVoiceId =', this.pausedVoiceId);
      }
    },
	showMoreOptions() {
	    this.showMoreOptionsModal = true;
	  },
	  closeMoreOptions() {
	      this.showMoreOptionsModal = false;
	    },
		/**
		   * 查看用户资料（跳转到原有more页面）
		   */
		  goToUserProfile() {
		    this.closeMoreOptions();
		    uni.navigateTo({
		      url: `/pages/message/more?userid=${this.targetUserId}`,
		      fail: (err) => {
		        console.error('跳转失败:', err);
		        uni.showToast({
		          title: '页面不存在',
		          icon: 'none'
		        });
		      }
		    });
		  },
		  /**
		     * 显示拉黑确认弹窗
		     */
		    blockFriend() {
		      this.closeMoreOptions();
		      this.showBlockConfirmModal = true;
		    },
		    
		    /**
		     * 关闭拉黑确认弹窗
		     */
		    closeBlockConfirm() {
		      this.showBlockConfirmModal = false;
		    },
		    /**
		     * 从后端获取VIP状态和今日剩余发送次数
		     */
		    async getUserMessageLimit() {
		      // 只要一方是红娘（ID 以 m_ 开头），就不做每日5条限制，直接视为无限制
		      const isMatchmakerChat = String(this.userId).startsWith('m_') || String(this.targetUserId).startsWith('m_');
		      if (isMatchmakerChat || this.fromMatchmaker) {
		        this.hasMessageLimit = false;
		        this.isVip = true;
		        this.remainingCount = 999;
		        console.log('✅ 红娘聊天模式：无消息限制（跳过 getUserMessageLimit 接口）');
		        return;
		      }
		      
		      try {
		        const [err, res] = await uni.request({
		          url: 'http://localhost:1004/api/chat/getUserMessageLimit',
		          method: 'GET',
		          data: {
		            userId: this.userId ,// 已在onLoad中初始化的当前用户ID
					targetUserId: this.targetUserId
		          },
		          header: {
		            'Content-Type': 'application/json'
		          }
		        });
		    
		        if (err) throw new Error('网络请求失败');
		        if (res.data.code !== 200) throw new Error(res.data.message || '获取限制信息失败');
		    
		        const { isVip, remainingCount, hasMessageLimit } = res.data.data;
		        this.isVip = isVip;
		        this.remainingCount = remainingCount;
		        this.hasMessageLimit = hasMessageLimit;
		    
		        console.log('✅ 用户消息限制信息：', { isVip, remainingCount, hasMessageLimit });
		      } catch (error) {
		        console.error('❌ 获取消息限制失败：', error);
		        // 异常降级：默认非VIP，剩余5次
		        this.isVip = false;
		        this.remainingCount = 5;
		        this.hasMessageLimit = true;
		      }
		    },
			/**
			 * 发送成功后，更新后端计数并同步前端剩余次数
			 */
			async updateMessageCount() {
			  try {
			    const [err, res] = await uni.request({
			      url: 'https://api.zhongruanke.cn/api/chat/updateMessageCount',
			      method: 'get',
			      data: {
			        userId: this.userId ,// 已在onLoad中初始化的当前用户ID
			        targetUserId: this.targetUserId
			      },
			      header: {
			        'Content-Type': 'application/json'
			      }
			    });
			
			    if (err) throw new Error('更新计数失败');
			    if (res.data.code === 200) {
			      this.remainingCount = res.data.data.remainingCount; // 同步后端返回的剩余次数
			    }
			  } catch (error) {
			    console.error('❌ 更新发送次数失败：', error);
			    // 前端本地降级：避免影响用户体验，本地暂减1（刷新页面后同步真实数据）
			    if (this.remainingCount > 0) {
			      this.remainingCount--;
			    }
			  }
			},
		    /**
		     * 确认拉黑好友
		     */
		    async confirmBlockFriend() {
		      try {
		        uni.showLoading({
		          title: '处理中...'
		        });
		        
		        // 调用后端拉黑接口（根据实际接口调整）
		        const [err, res] = await uni.request({
		          url: 'https://api.zhongruanke.cn/api/chatfriend/block',
		          method: 'POST',
		          data: {
		            userId: this.userId,
		            targetUserId: this.targetUserId,
		            targetUserName: this.targetUserName,
		            targetUserAvatar: this.targetUserAvatar
		          },
		          header: {
		            'Content-Type': 'application/json',
		            // 'Authorization': 'Bearer ' + uni.getStorageSync('token')
		          }
		        });
		        
		        uni.hideLoading();
		        
		        if (err) throw new Error('网络请求失败');
		        
		        if (res.data && res.data.code === 200) {
		          uni.showToast({ title: '拉黑成功', icon: 'success' });
		          this.closeBlockConfirm();
		          
		          // 触发拉黑列表更新事件，通知消息页面实时刷新
		          uni.$emit('blacklistUpdated');
		          
		          // 拉黑成功后立即返回消息列表页面（优化体验）
		          setTimeout(() => {
		            uni.navigateBack({
		              delta: 1,
		              success: () => {
		                // 返回成功后再次触发一次刷新，确保万无一失
		                uni.$emit('blacklistUpdated');
		              }
		            });
		          }, 1500);
		        } else {
		          throw new Error(res.data?.message || '拉黑失败');
		        }
		      } catch (error) {
		        console.error('拉黑失败:', error);
		        uni.showToast({ title: error.message || '拉黑失败', icon: 'none' });
		      }
		    },
		    
		    /**
		     * 初始化在线状态监听（WebSocket 实时推送 + HTTP 轮询）
		     */
		    async initOnlineStatusPolling() {
		      console.log('🔄 初始化在线状态监听（WebSocket + HTTP）');
		      
		      const timPresenceManager = require('@/utils/tim-presence-manager.js').default;
		      
		      // 1. 立即查询一次
		      await this.checkOnlineStatus();
		      
		      // 2. 监听 WebSocket 实时推送（实时性强）
		      this.onlineStatusCallback = (status) => {
		        console.log(`⚡ 实时收到用户 ${this.targetUserId} 状态变更: ${status}`);
		        this.isTargetOnline = (status === 'online');
		      };
		      
		      timPresenceManager.onStatusChange(this.targetUserId, this.onlineStatusCallback);
		      
		      // 3. 启动 HTTP 轮询作为补充（30秒间隔）
		      this.onlineStatusTimer = setInterval(() => {
		        this.checkOnlineStatus();
		      }, 30000);
		      
		      console.log('✅ 在线状态监听已启动（WebSocket 实时 + HTTP 轮询）');
		    },
		    
		    /**
		     * 查询在线状态
		     */
		    async checkOnlineStatus() {
		      try {
		        const [err, res] = await uni.request({
		          url: 'https://api.zhongruanke.cn/api/online/checkStatus',
		          method: 'GET',
		          data: {
		            userId: this.targetUserId
		          }
		        });
		        
		        if (!err && res.data && res.data.code === 200) {
		          this.isTargetOnline = res.data.data.online || false;
		          console.log(`� 用户 ${this.targetUserId} 在线状态:`, this.isTargetOnline);
		        }
		      } catch (error) {
		        console.error('❌ 查询在线状态失败:', error);
		      }
		    }
  },
  
  /**
   * 页面卸载时清理
   */
  onUnload() {
    console.log('=== 聊天页面卸载 ===');
    
    // 清理在线状态轮询
    if (this.onlineStatusTimer) {
      clearInterval(this.onlineStatusTimer);
      this.onlineStatusTimer = null;
      console.log('✅ 已停止在线状态轮询');
    }
    
    // 清理 WebSocket 监听
    if (this.onlineStatusCallback) {
      const timPresenceManager = require('@/utils/tim-presence-manager.js').default;
      timPresenceManager.offStatusChange(this.targetUserId, this.onlineStatusCallback);
      console.log('✅ 已清理 WebSocket 监听');
    }
    
    // 清理已读回执监听
    if (this.handleMessageReadByPeer) {
      timManager.offMessageRead(this.handleMessageReadByPeer);
      console.log('✅ 已通过 timManager 清理已读回执监听');
    }
    
    // 清理新消息监听
    if (this.handleNewMessage) {
      timManager.offMessage(this.handleNewMessage);
      console.log('✅ 已清理新消息监听');
    }
  }
};
</script>

<style scoped>
	/* 弹窗遮罩 */
	.modal-mask {
	  position: fixed;
	  top: 0;
	  left: 0;
	  right: 0;
	  bottom: 0;
	  background-color: rgba(0, 0, 0, 0.5);
	  z-index: 10000;
	  display: flex;
	  align-items: center;
	  justify-content: center;
	}
	
	/* 更多选项弹窗内容 */
	.modal-content {
	  width: 70%;
	  background-color: #fff;
	  border-radius: 20rpx;
	  overflow: hidden;
	}
	
	.modal-header {
	  padding: 30rpx;
	  text-align: center;
	  border-bottom: 1px solid #eee;
	}
	
	.modal-title {
	  font-size: 32rpx;
	  font-weight: bold;
	  display: block;
	}
	
	.modal-subtitle {
	  font-size: 24rpx;
	  color: #999;
	  display: block;
	  margin-top: 10rpx;
	}
	
	.modal-body {
	  padding: 20rpx 0;
	}
	
	.modal-item {
	  display: flex;
	  align-items: center;
	  padding: 25rpx 40rpx;
	  font-size: 30rpx;
	}
	
	.modal-item.danger {
	  color: #fa5151;
	}
	
	.item-icon {
	  font-size: 32rpx;
	  margin-right: 20rpx;
	}
	
	.modal-footer {
	  padding: 20rpx;
	  border-top: 1px solid #eee;
	}
	
	.modal-close-btn {
	  width: 94%;
	  background-color: #f5f5f5;
	  border: none;
	  border-radius: 10rpx;
	  padding: 20rpx;
	  font-size: 30rpx;
	}
	
	/* 确认弹窗样式 */
	.confirm-modal {
	  width: 60%;
	  background-color: #fff;
	  border-radius: 20rpx;
	  padding: 40rpx;
	  text-align: center;
	}
	
	.confirm-title {
	  font-size: 32rpx;
	  font-weight: bold;
	  margin-bottom: 30rpx;
	}
	
	.confirm-content {
	  font-size: 28rpx;
	  color: #666;
	  margin-bottom: 40rpx;
	  line-height: 1.5;
	}
	
	.confirm-buttons {
	  display: flex;
	  justify-content: space-between;
	}
	
	.confirm-btn {
	  flex: 1;
	  margin: 0 10rpx;
	  padding: 20rpx;
	  border-radius: 10rpx;
	  border: none;
	  font-size: 28rpx;
	}
	
	.confirm-btn.cancel {
	  background-color: #f5f5f5;
	}
	
	.confirm-btn.confirm {
	  background-color: #fa5151;
	  color: #fff;
	}
.chat-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f5f5f5;
}

/* 顶部导航 */
.chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20rpx 30rpx;
  /* paddingTop 通过动态样式设置，适配刘海屏 */
  background-color: #fff;
  border-bottom: 1px solid #e5e5e5;
}

.header-left, .header-right {
  width: 80rpx;
}

.icon-back {
  font-size: 40rpx;
}

.header-center {
  flex: 1;
  text-align: center;
  position: relative;
}

.title-wrapper {
  display: inline-flex;
  align-items: center;
  gap: 6rpx;
  position: relative;
}

.chat-title {
  font-size: 36rpx;
  font-weight: bold;
}

.title-arrow {
  font-size: 39rpx;
  color: #999;
}


.online-status {
  display: block;
  font-size: 24rpx;
  color: #999;
  margin-top: 5rpx;
}

.online-status.online {
  color: #07c160;
}

/* 消息列表 */
.message-list {
  flex: 1;
  padding: 20rpx;
  overflow-y: scroll;
}

.loading-tip {
  text-align: center;
  padding: 20rpx;
  color: #999;
  font-size: 28rpx;
}

.message-item {
  display: flex;
  margin-bottom: 30rpx;
}

.message-item.message-self {
  flex-direction: row-reverse;
}

.avatar {
  width: 80rpx;
  height: 80rpx;
  border-radius: 8rpx;
  margin: 0 20rpx;
}

.message-content-wrapper {
  max-width: 70%;
  display: inline-block;
}
.message-item.message-self .message-content-wrapper {
  text-align: right; /* 关键：让气泡和状态提示整体右对齐 */
}
.message-name {
  display: block;
  font-size: 24rpx;
  color: #999;
  margin-bottom: 10rpx;
}

.message-bubble {
  padding: 20rpx;
  border-radius: 8rpx;
  background-color: #fff;
  word-wrap: break-word;
  display: inline-block; /* 关键：气泡宽度由内容决定 */
    max-width: 100%; /* 防止内容过长超出容器 */
    position: relative;
}

.message-self .message-bubble {
  background-color: #95ec69;
  border-top-right-radius: 4rpx;
}

.message-bubble.bubble-self {
  background-color: #95ec69;
}
.message-text {
  font-size: 30rpx;
  line-height: 1.5;
}

.message-image {
  max-width: 400rpx;
  border-radius: 8rpx;
}

.message-voice {
  display: flex;
  align-items: center;
  gap: 12rpx;
  padding: 0rpx 0;
  min-width: 30rpx;
  max-width: 400rpx;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  outline: none;
  border: none;
  position: relative;
}

.voice-duration {
  font-size: 27rpx;
  color: #333;
  flex-shrink: 0;
  line-height: 1;
}

.voice-icon-wrapper {
  display: flex;
  flex-shrink: 0;
  line-height: 0;
  position: relative;
  top: 1rpx;
}

.voice-icon {
  width: 22rpx;
  height: 22rpx;
  display: block;
  transform: none;
  animation: none;
}

.voice-icon-wrapper.playing .voice-icon {
  animation: voice-bounce 0.6s ease-in-out infinite;
}

.voice-resume-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 32rpx;
  height: 32rpx;
  background: #07c160;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2rpx 8rpx rgba(7, 193, 96, 0.3);
}

.voice-resume-btn.resume-btn-left {
  left: -40rpx;
}

.voice-resume-btn.resume-btn-right {
  right: -40rpx;
}

.resume-icon {
  color: #fff;
  font-size: 16rpx;
  margin-left: 2rpx;
}

@keyframes voice-bounce {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.2);
  }
}

.message-video {
  width: 400rpx;
  height: 300rpx;
}

.message-recalled {
  color: #999;
  font-size: 28rpx;
}

.message-status {
  text-align: right;
  font-size: 22rpx;
  color: #999;
  margin-top: 8rpx;
}

.message-status .status-unread {
  color: #999;
}

.message-status .status-read {
  color: #07c160;
}

.message-status .status-failed {
  color: #fa5151;
}

.message-time {
  display: block;
  text-align: right;
  font-size: 22rpx;
  color: #ccc;
  margin-top: 5rpx;
}

/* 输入框 */
.input-bar {
  display: flex;
  align-items: center;
  padding: 20rpx;
  background-color: #fff;
  border-top: 1px solid #e5e5e5;
}

.input-icon {
  width: 80rpx;
  height: 80rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 50rpx;
}

.input-icon .icon-image {
  width: 50rpx;
  height: 50rpx;
}

.send-button {
  padding: 0 30rpx;
  height: 70rpx;
  line-height: 70rpx;
  background-color: #07c160;
  color: #fff;
  border-radius: 8rpx;
  text-align: center;
  font-size: 28rpx;
  margin-left: 10rpx;
  transition: opacity 0.3s;
}

.send-button.disabled {
  opacity: 0.5;
  background-color: #95ec69;
}

.input-field {
  flex: 1;
  height: 70rpx;
  padding: 0 20rpx;
  background-color: #f5f5f5;
  border-radius: 8rpx;
  font-size: 30rpx;
}

.voice-button {
  flex: 1;
  height: 70rpx;
  line-height: 70rpx;
  background-color: #f5f5f5;
  border-radius: 8rpx;
  text-align: center;
  font-size: 30rpx;
  border: none;
}

/* 表情面板 */
.emoji-panel {
  display: flex;
  flex-wrap: wrap;
  padding: 20rpx;
  background-color: #fff;
  border-top: 1px solid #e5e5e5;
}

.emoji-item {
  width: 80rpx;
  height: 80rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 60rpx;
}

/* 更多功能面板 */
.more-panel {
  display: flex;
  padding: 40rpx;
  background-color: #fff;
  border-top: 1px solid #e5e5e5;
}

.more-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0 40rpx;
}

.more-icon {
  width: 100rpx;
  height: 100rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 60rpx;
  background-color: #f5f5f5;
  border-radius: 16rpx;
  margin-bottom: 10rpx;
}

.more-text {
  font-size: 24rpx;
  color: #666;
}

/* 时间分隔线 */
.time-divider {
  text-align: center;
  padding: 20rpx 0;
}

.time-text {
  display: inline-block;
  padding: 8rpx 20rpx;
  background-color: rgba(0, 0, 0, 0.1);
  border-radius: 8rpx;
  font-size: 22rpx;
  color: #999;
}

/* 消息气泡失败状态 */
.bubble-failed {
	background-color: #95ec69;
  opacity: 0.6;
  border: 2rpx solid #fa5151;
}

/* 消息状态优化 */
.message-status .sending {
  color: #576b95;
}

.message-status .failed-group {
  display: flex;
  align-items: center;
  gap: 10rpx;
}

.message-status .retry-btn {
  color: #576b95;
  text-decoration: underline;
  cursor: pointer;
}

/* 消息操作菜单遮罩 */
.message-action-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.4);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 消息操作菜单 */
.message-action-menu {
  width: 600rpx;
  background-color: #fff;
  border-radius: 20rpx;
  overflow: hidden;
}

.message-action-menu .menu-item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 15rpx;
  padding: 30rpx;
  font-size: 32rpx;
  color: #333;
  border-bottom: 1rpx solid #f0f0f0;
  transition: background-color 0.2s;
}

.message-action-menu .menu-item:active {
  background-color: #f5f5f5;
}

.message-action-menu .menu-item.cancel {
  color: #999;
  border-bottom: none;
  margin-top: 20rpx;
  border-top: 10rpx solid #f5f5f5;
}

.message-action-menu .menu-icon {
  font-size: 36rpx;
}

/* 消息发送限制提示 */
.message-limit-tip {
  padding: 10rpx 20rpx;
  font-size: 24rpx;
  text-align: center;
  background-color: #fff;
  border-bottom: 1px solid #f5f5f5;
}
.vip-tip {
  color: #ff9500; /* VIP橙色提示 */
}
.limit-tip {
  color: #666; /* 普通灰色提示 */
}

.vip-link {
  color: #2c9fff; /* 蓝色文字 */
  text-decoration: underline; /* 下划线 */
  cursor: pointer; /* 鼠标悬浮时显示手型 */
  margin-left: 5rpx;
}

/* 点击时添加轻微反馈 */
.vip-link:active {
  opacity: 0.7; /* 点击时透明度降低 */
}

/* 录音中提示遮罩 */
.voice-recording-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.6);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 录音提示框 */
.voice-recording-box {
  width: 300rpx;
  height: 300rpx;
  background-color: rgba(0, 0, 0, 0.8);
  border-radius: 20rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
  transition: background-color 0.3s;
}

.voice-recording-box.canceling {
  background-color: rgba(220, 38, 38, 0.9);
}


.voice-wave-container {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  height: 100rpx;
  margin-bottom: 20rpx;
}

.voice-wave-bar {
  width: 6rpx;
  background: #fff;
  border-radius: 3rpx;
  transition: transform 0.1s ease-out;
  transform-origin: center;
}

.voice-wave-bar.bar1 {
  height: 30rpx;
}

.voice-wave-bar.bar2 {
  height: 45rpx;
}

.voice-wave-bar.bar3 {
  height: 60rpx;
}

.voice-wave-bar.bar4 {
  height: 50rpx;
}

.voice-wave-bar.bar5 {
  height: 35rpx;
}

.voice-text {
  font-size: 32rpx;
  margin-bottom: 10rpx;
}

.voice-time {
  font-size: 48rpx;
  font-weight: bold;
  color: #07c160;
  margin: 10rpx 0;
}

.voice-tip {
  font-size: 24rpx;
  color: #ccc;
}
</style>



