<template>
  <view class="chat-container">
    <!-- 聊天头部 -->
    <view :style="{ paddingTop: top + 'px', height: localHeight + 'px' }" class="chat-header">
      <view class="back-btn" @tap="goBack">
        <uni-icons color="#333" size="28" type="left"></uni-icons>
      </view>
      <view class="chat-title">{{ chatTarget.title || '客服' }}</view>
      <view class="change-service-btn" @tap="goToChangeService">
        <uni-icons color="#333" size="22" type="switch"></uni-icons>
      </view>
    </view>

    <!-- 连接状态提示 -->
    <view v-if="connectingStatus" class="connecting-status">{{ connectingStatus }}</view>

    <!-- 聊天消息区域 -->
    <scroll-view class="chat-messages" scroll-y="true"
      upper-threshold="50" @scrolltoupper="loadMoreHistory" @scroll="onScroll">
      <!-- 加载历史消息提示 -->
      <view v-if="isLoadingHistory" class="message-time">加载历史消息...</view>

      <!-- 消息列表 -->
      <block v-for="(message, index) in messages" :key="index">
        <!-- 时间分割线 -->
        <view v-if="needShowTime(index)" class="message-time">{{ message.times }}</view>

        <!-- 消息项 -->
        <view :id="'msg-' + index" :class="{
          'self': message.isSelf,
          'other': !message.isSelf,
          'loading': message.isLoading
        }" class="message-item">
          <image :src="message.isSelf ? userAvatar : getAvatarUrl(message)" class="message-avatar" mode="aspectFill">
          </image>
          <!-- 文字 -->
          <view v-if="!message.type || message.type === 1" class="message-content">
            {{ message.content }}
          </view>
          <!-- 图片 -->
          <view v-else-if="message.type === 2" class="message-media">
            <image v-if="message.mediaUrl" :src="message.mediaUrl" class="chat-img" mode="aspectFit"
              @tap="previewImage(message.mediaUrl)" />
            <view v-else class="media-loading">图片加载中…</view>
          </view>
          <!-- 视频 -->
          <view v-else-if="message.type === 3" class="message-media">
            <video v-if="message.mediaUrl" :src="message.mediaUrl" class="chat-video" controls></video>
            <view v-else class="media-loading">视频加载中…</view>
          </view>
          <!-- 商品/购物车卡片 -->
          <view v-else-if="message.type === 4" class="message-card" @tap="openCardLink(message.card)">
            <image v-if="message.card.pic && !message.card._picErr" :src="message.card.pic" class="card-pic"
              mode="aspectFill" @error="onCardPicError(message)" />
            <view v-else class="card-pic card-pic--ph">商品</view>
            <view class="card-info">
              <view class="card-name">{{ message.card.name }}</view>
              <view class="card-price">¥{{ message.card.price }}</view>
              <view class="card-tag">商品</view>
            </view>
          </view>
          <!-- 订单卡片 -->
          <view v-else-if="message.type === 5" class="message-card" @tap="openCardLink(message.card)">
            <image v-if="message.card.pic && !message.card._picErr" :src="message.card.pic" class="card-pic"
              mode="aspectFill" @error="onCardPicError(message)" />
            <view v-else class="card-pic card-pic--ph">订单</view>
            <view class="card-info">
              <view class="card-name">订单 {{ message.card.order_no }}</view>
              <view class="card-price">¥{{ message.card.amount }}</view>
              <view class="card-tag">订单 · 共{{ message.card.count }}件</view>
            </view>
          </view>
          <view v-else class="message-content">{{ message.content }}</view>
        </view>
      </block>
    </scroll-view>

    <!-- 输入区域 -->
    <view class="chat-input-area">
      <view class="input-container">
        <textarea v-model="inputMessage" :adjust-position="true" auto-height class="message-input" cursor-spacing="10"
          enable-keyboard-accessory-view="true" hold-keyboard="true" maxlength="500" placeholder="请输入消息..."
          @blur="onInputBlur" @confirm="sendMessage" @focus="onInputFocus" @input="handleInput"></textarea>
        <view class="plus-btn" @tap="togglePanel">
          <uni-icons color="#666" size="30" type="plusempty"></uni-icons>
        </view>
        <button :disabled="inputMessage.trim() === ''" class="send-btn" @tap="sendMessage">
          发送
        </button>
      </view>
      <!-- 更多功能面板 -->
      <view v-if="showPanel" class="more-panel">
        <view class="panel-item" @tap="chooseMedia('image')">
          <view class="panel-icon">🖼️</view>
          <text>相册图片</text>
        </view>
        <view class="panel-item" @tap="chooseMedia('camera')">
          <view class="panel-icon">📷</view>
          <text>拍摄</text>
        </view>
        <view class="panel-item" @tap="chooseMedia('video')">
          <view class="panel-icon">🎬</view>
          <text>视频</text>
        </view>
        <view class="panel-item" @tap="openGoodsPicker">
          <view class="panel-icon">🛒</view>
          <text>商品/购物车</text>
        </view>
        <view class="panel-item" @tap="openOrderPicker">
          <view class="panel-icon">📦</view>
          <text>订单</text>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import { menuButtonInfo, picUrl, request, NavgateTo } from '@/utils'
import mqttTool from '@/utils/mqtt'
import { apiArr } from '../../../api/customerService'
import { uploadOSS, signPrivateView } from '@/utils/uploadOSS'

export default {
  data() {
    return {
      localHeight: '',
      top: '',
      // 聊天目标信息
      chatTarget: {
        mchId: '',
        bindId: 0,
        title: '',
        avatar: '',
        openId: '' // 接收方的open_id
      },
      // 用户头像
      userAvatar: '',
      // 消息列表
      messages: [],

      // 输入的消息
      inputMessage: '',
      // 更多功能面板
      showPanel: false,
      // 是否可以发送消息
      canSend: false,
      // 连接状态
      isConnected: false,
      // 连接状态文本
      connectingStatus: '',
      // 滚动到指定视图
      scrollToView: '',
      // 是否加载历史消息
      isLoadingHistory: false,
      // 心跳包定时器
      keepaliveTimer: null,
      selfClientId: uni.getStorageSync('openId'),
      // MQTT工具实例
      client: null,
      // 重连失败提示定时器
      reconnectFailedTimer: null,
      // 分页参数
      pageNum: 1,
      pageSize: 10,
      // 是否还有更多历史消息
      hasMoreHistory: true,
      // 滚动到底部的标记
      scrollToBottomFlag: false
    }
  },
  onLoad(options) {
    console.log('客服聊天页面onLoad触发')
    const meun = menuButtonInfo()
    this.top = meun.top
    this.localHeight = meun.height
    console.log('导航栏信息：top:', this.top, 'height:', this.localHeight)
    // 获取聊天对象信息
    if (options.item) {
      const item = JSON.parse(options.item)
      console.log('参数接收:', item)
      if (Number(item.type) === 1) {
        // 客户选择客服跳转进来
        this.chatTarget = item
        console.log('客户找客服跳转:', this.chatTarget)
        this.chatTarget.title = this.chatTarget.employee_name
        this.getMqttConfig().then(() => {
          // 获取配置后再初始化聊天
          console.log('获取MQTT配置成功，开始初始化聊天')
          this.initChat()
        }).catch(error => {
          console.error('获取MQTT配置失败:', error)
        })
      } else {
        // 客服选择聊天列表进来
        this.chatTarget = item
        console.log('客服找客户进来:', this.chatTarget)
        this.chatTarget.title = this.chatTarget.server_name
        this.chatTarget.bindId = this.chatTarget.id
        if (this.chatTarget.client_id_one === this.selfClientId) {
          this.chatTarget.openId = this.chatTarget.client_id_two
        } else {
          this.chatTarget.openId = this.chatTarget.client_id_one
        }
        // 初始化MQTT连接
        console.log('开始初始化聊天')
        this.initChat()
      }
    } else {
      console.log('没有接收到参数item')
    }
    // 初始化用户头像
    this.userAvatar = picUrl + uni.getStorageSync('headPhoto')
    console.log('用户头像:', this.userAvatar)
  },
  onShow() {
    // 监听 picker 页回传的商品/订单卡片（只注册一次）
    if (!this._onPickCard) {
      this._onPickCard = ({ type, card }) => {
        this.publishMsg(type, JSON.stringify(card))
      }
      uni.$on('chat:pickCard', this._onPickCard)
    }
  },
  methods: {
    getAvatarUrl(record) {
      return this.chatTarget.employee_image ? this.chatTarget.employee_image : 'https://static.hshuishang.com/defaultTx.png'
    },
    async connect() {
      this.client = null
      const options = {
        clientId: this.selfClientId
      }
	  console.log('clientId:', options.clientId)

      // 添加连接状态回调
      const callbacks = {
        onConnect: () => {
          console.log('客服连接成功')
          this.isConnected = true
          this.connectingStatus = ''
        },
        onDisconnect: this.onDisconnect.bind(this),
        onError: (error) => {
          console.error('客服连接错误:', error)
          this.isConnected = false
          this.connectingStatus = '连接错误，请重试'
        },
        onReconnect: () => {
          console.log('客服正在重连...')
          this.isConnected = false
          this.connectingStatus = '连接已断开，正在重连...'
        }
      }

      this.client = mqttTool.connect(options, callbacks)
      this.isConnected = !!this.client

      await this.subscribe()
      this.client.on('message', (topic, message) => {
        const msgStr = Buffer.from(message).toString('utf8') // 二进制转UTF-8字符串
        const msg = JSON.parse(msgStr) // 后续解析逻辑不变

        let jsMsg = msg // 直接使用已解析的对象，无需再次解析
        console.log('收到消息', topic, msg)
        if (jsMsg.send_client === this.selfClientId || jsMsg.receive_client === this.selfClientId) {
          if (jsMsg.send_client === this.chatTarget.openId || jsMsg.receive_client === this.chatTarget.openId) {
            this.appendMessage(jsMsg, jsMsg.send_client === this.selfClientId)
          }
        }
      })
    },

    // 把一条原始消息（含 type/content）转成可渲染的消息对象并追加；图片/视频异步签名 URL
    async appendMessage(raw, isSelf) {
      const type = Number(raw.type) || 1
      const item = {
        type,
        content: raw.content,
        time: Date.now(),
        isSelf,
        isLoading: false,
        mediaUrl: '',
        card: null
      }
      if (type === 4 || type === 5) {
        try { item.card = typeof raw.content === 'string' ? JSON.parse(raw.content) : raw.content } catch (e) { item.card = {} }
      }
      const idx = this.messages.push(item) - 1
      this.scrollToView = 'msg-' + idx
      // 图片/视频：content 是私密 object_key，需签名后显示
      if (type === 2 || type === 3) {
        try {
          const r = await signPrivateView(raw.content)
          this.$set(this.messages[idx], 'mediaUrl', r.url)
        } catch (e) {
          console.error('签发聊天媒体URL失败', e)
        }
      }
    },
    async subscribe() {
      if (this.isConnected && this.client) {
        const topic = 'contact/message/send_msg/' + this.chatTarget.bindId // 按会话精确订阅，天然隔离（沿用 contact/message 授权前缀）
        this.client.subscribe(topic, { qos: 0 }, (err) => {
          if (!err) {
            console.log('订阅成功', topic, { qos: 0 })
            this.connectingStatus = ''
          } else {
            console.log('订阅失败:', err)
            this.connectingStatus = '订阅失败，请重试'
          }
        })
      } else {
        console.log('连接失败', this.isConnected, this.client)
        this.connectingStatus = '连接失败，请重试'
      }
    },
    // 初始化聊天
    async initChat() {
      try {
        // 显示连接状态
        this.connectingStatus = '正在连接客服...'
        await this.connect()
        // 连接成功后启动心跳包
        this.startKeepalive()
        // 连接成功后立即加载历史消息
        console.log('连接成功，开始加载历史消息')
        await this.loadHistoryMessages()
        console.log('历史消息加载完成，消息数量：', this.messages.length)
        

      } catch (error) {
        console.error('初始化聊天失败', error)
        this.connectingStatus = '连接失败，请检查网络'

        // 失败后尝试重新连接
        this.reconnectFailedTimer = setTimeout(() => {
          this.initChat()
        }, 3000)
      }
    },

    // 获取MQTT连接配置
    async getMqttConfig() {
      console.log('🚀 ~ onLoad ~ this.chatTarget.open_id:', this.chatTarget.open_id)
      try {
        // 如果没有已创建的实例或clientId，则通过API获取
        return new Promise((resolve, reject) => {
          const params = {
            worker_id: this.chatTarget.id || '',
            open_id: this.selfClientId || ''
          }
          request(apiArr.csGetToClientId, 'POST', params).then((res) => {
            console.log('聊天列表:', res)
            // 检查响应数据格式是否正确
            if (res && res.client_bind && res.client_bind.client_id_one && res.client_bind.client_id_two) {
              if (res.client_bind.client_id_one === this.selfClientId) {
                this.chatTarget.openId = res.client_bind.client_id_two
              } else {
                this.chatTarget.openId = res.client_bind.client_id_one
              }
              this.chatTarget.bindId = res.client_bind.id
              resolve()
            } else {
              console.error('MQTT配置响应格式不正确:', res)
              reject(new Error('未获取到有效的MQTT配置'))
            }
          }).catch(error => {
            console.error('获取MQTT配置失败', error)
            reject(error)
          })
        })
      } catch (error) {
        console.error('获取MQTT配置失败', error)
        throw error
      }
    },

    // MQTT断开连接回调
    onDisconnect(packet) {
      console.log('MQTT连接断开', packet)
      this.isConnected = false
      this.client = null

      // 根据断开原因设置不同的连接状态文本
      if (packet && packet.error) {
        // 连接失败的情况
        this.connectingStatus = '连接失败，请检查网络'
      } else {
        // 其他断开连接的情况
        this.connectingStatus = '连接已断开，正在重连...'
      }

      // 停止心跳包
      this.stopKeepalive()
    },

    // 加载历史消息
    async loadHistoryMessages() {
      console.log('loadHistoryMessages方法调用')
      console.log('加载条件检查：hasMoreHistory:', this.hasMoreHistory, 'isLoadingHistory:', this.isLoadingHistory)
      
      if (!this.hasMoreHistory || this.isLoadingHistory) {
        console.log('不满足加载条件：hasMoreHistory:', this.hasMoreHistory, 'isLoadingHistory:', this.isLoadingHistory)
        return
      }

      try {
        this.isLoadingHistory = true
        console.log('开始加载历史消息，当前页码：', this.pageNum)

        // 确保已经获取了mqttConfig.bindId
        if (!this.chatTarget.bindId) {
          console.log('没有bindId，开始获取MQTT配置')
          await this.getMqttConfig()
          console.log('获取MQTT配置成功，bindId：', this.chatTarget.bindId)
        }

        const params = {
          bindId: this.chatTarget.bindId,
          order: 'desc', // 按时间降序排列
          page_num: this.pageNum,
          page_size: this.pageSize
        }

        console.log('请求历史消息参数:', params)
        const res = await request(apiArr.csGetMsgRecord, 'POST', params)

        console.log('历史消息返回结果:', res)
        if (res && res.msg_record) {
          const historyMessages = res.msg_record

          console.log('原始历史消息数量：', historyMessages.length)
          // 如果没有更多历史消息了
          if (historyMessages.length === 0) {
            console.log('没有更多历史消息了')
            this.hasMoreHistory = false
            return
          }

          // 处理历史消息，转换为需要的格式
          const formattedMessages = historyMessages.map(msg => {
            const type = Number(msg.type) || 1
            const item = {
              type,
              content: msg.content,
              time: new Date(msg.create_time).getTime(),
              times: msg.update_time,
              isSelf: msg.send_client === this.selfClientId,
              isLoading: false,
              mediaUrl: '',
              card: null
            }
            if (type === 4 || type === 5) {
              try { item.card = typeof msg.content === 'string' ? JSON.parse(msg.content) : msg.content } catch (e) { item.card = {} }
            }
            return item
          }).reverse(); // 反转消息顺序，确保最早的消息在最前面

          // 图片/视频历史消息：异步签发私密 URL
          formattedMessages.forEach(item => {
            if (item.type === 2 || item.type === 3) {
              signPrivateView(item.content).then(r => {
                this.$set(item, 'mediaUrl', r.url)
              }).catch(e => console.error('历史媒体签名失败', e))
            }
          })

          console.log('格式化后的历史消息：', formattedMessages)
          // 将格式化后的历史消息添加到消息列表开头
          const previousMessageCount = this.messages.length;
          console.log('添加前消息数量：', previousMessageCount)
          this.messages = [...formattedMessages, ...this.messages];
          console.log('添加后消息数量：', this.messages.length)

          // 增加页码
          this.pageNum++;
          console.log('下一页页码：', this.pageNum)
          
          // 如果是首次加载，滚动到底部显示最新消息
          if (previousMessageCount === 0) {
            setTimeout(() => {
              console.log('首次加载，滚动到底部，消息数量：', this.messages.length)
              // 使用更可靠的滚动方式
              uni.pageScrollTo({
                scrollTop: 999999,
                duration: 300
              });
            }, 100);
          } else {
            // 不是首次加载时，保持当前滚动位置，不自动滚动到底部
            // 确保新加载的历史消息在顶部可见
            console.log('非首次加载，新增消息数量：', formattedMessages.length)
          }
        } else {
          console.log('接口返回数据格式不正确或无消息记录')
          // 仅当不是第一页时才设置hasMoreHistory为false
          if (this.pageNum > 1) {
            this.hasMoreHistory = false
          }
        }
      } catch (error) {
        console.error('加载历史消息失败', error)
      } finally {
        this.isLoadingHistory = false
        console.log('加载历史消息结束')
      }
    },

    // 滚动事件监听
    onScroll(e) {
      console.log('滚动事件触发，scrollTop：', e.detail.scrollTop)
    },
    
    // 加载更多历史消息
    loadMoreHistory() {
      console.log('滚动到顶部事件触发')
      // 滚动到顶部时加载更多历史消息
      console.log('当前条件：isLoadingHistory:', this.isLoadingHistory, 'hasMoreHistory:', this.hasMoreHistory, 'pageNum:', this.pageNum)
      
      // 重置hasMoreHistory为true，确保可以继续加载
      if (!this.hasMoreHistory && this.pageNum === 1) {
        console.log('重置hasMoreHistory为true')
        this.hasMoreHistory = true
      }
      
      if (!this.isLoadingHistory && this.hasMoreHistory) {
        console.log('开始加载更多历史消息')
        this.loadHistoryMessages()
      } else {
        console.log('不满足加载更多条件：isLoadingHistory:', this.isLoadingHistory, 'hasMoreHistory:', this.hasMoreHistory)
      }
    },

    // 发送消息
    sendMessage() {
      const content = this.inputMessage.trim()
      console.log('发送消息', content)
      if (!content || !this.client || !this.isConnected) return
      // 滚动到底部
      this.scrollToBottom()
      console.log('需要发送的对象', this.chatTarget)
      // 按照用户提供的格式构建发送消息
      const msgData = {
        bind_id: this.chatTarget.bindId, // 聊天列表的ID
        send_client: this.selfClientId, // 消息发送方open_id 
        receive_client: this.chatTarget.openId, // 消息接收方open_id
        type: 1, // 消息类型，1表示文字消息
        content: content, // 消息内容
        receive_read_status: 2 // 接收方阅读状态
      }
      console.log('发送消息', msgData)
      this.client.publish(
        'contact/message/send_msg/' + this.chatTarget.bindId, // 按会话精确主题，双方订阅同一主题
        JSON.stringify(msgData),
        { Qos: 0 },
        (err) => {
          if (err) {
            console.error('发送消息失败', err)
            // 可以在这里添加消息发送失败的处理逻辑
          } else {
            console.log('发送消息成功')
          }
        }
      )

      // 清空输入框
      this.inputMessage = ''
    },

    // 切换"+"功能面板
    togglePanel() {
      this.showPanel = !this.showPanel
    },

    // 统一发布消息（type: 1文字 2图片 3视频 4商品 5订单；content 为文本/object_key/JSON字符串）
    publishMsg(type, content) {
      if (!this.client || !this.isConnected) {
        uni.showToast({ title: '连接断开，请重试', icon: 'none' })
        return
      }
      const msgData = {
        bind_id: this.chatTarget.bindId,
        send_client: this.selfClientId,
        receive_client: this.chatTarget.openId,
        type,
        content,
        receive_read_status: 2
      }
      this.client.publish('contact/message/send_msg/' + this.chatTarget.bindId, JSON.stringify(msgData), { Qos: 0 }, (err) => {
        if (err) console.error('发送消息失败', err)
      })
    },

    // 选择图片/拍摄/视频并上传（私密，按会话授权）
    chooseMedia(source) {
      this.showPanel = false
      if (source === 'video') {
        uni.chooseVideo({
          sourceType: ['album', 'camera'],
          maxDuration: 60,
          success: (res) => this.uploadAndSend(res.tempFilePath, 'chat_video', 3)
        })
      } else {
        uni.chooseImage({
          count: 1,
          sizeType: ['compressed'],
          sourceType: source === 'camera' ? ['camera'] : ['album'],
          success: (res) => {
            const fp = res.tempFilePaths && res.tempFilePaths[0]
            if (fp) this.uploadAndSend(fp, 'chat_image', 2)
          }
        })
      }
    },

    // 上传到私密 bucket 后，把 object_key 作为消息内容发布
    async uploadAndSend(filePath, scene, type) {
      try {
        const { objectKey } = await uploadOSS({ filePath, scene, bindId: this.chatTarget.bindId })
        this.publishMsg(type, objectKey)
      } catch (e) {
        console.error('上传失败', e)
        uni.showToast({ title: '上传失败，请重试', icon: 'none' })
      }
    },

    // 预览图片
    previewImage(url) {
      if (url) uni.previewImage({ urls: [url], current: url })
    },

    // 点击商品/订单卡片跳转
    openCardLink(card) {
      if (!card) return
      // 兼容老消息：仍带 path 的直接跳
      if (!card.page && card.path) {
        NavgateTo(card.path, { isLogin: false })
        return
      }
      if (!card.page) return
      // 完整 item 经本地存储中转，避免 URL 过长被截断（详情页优先读 storage）
      const item = card.item || {}
      try {
        uni.setStorageSync('chatCardItem', item)
      } catch (e) {
        console.error('暂存卡片数据失败', e)
      }
      NavgateTo(card.page + '?item=' + encodeURIComponent(JSON.stringify(item)) + '&fromChat=1', { isLogin: false })
    },

    // 卡片图片加载失败 -> 显示占位（用 $set 保证响应式）
    onCardPicError(message) {
      if (message && message.card) {
        this.$set(message.card, '_picErr', true)
      }
    },

    // 选择商品/购物车发送
    openGoodsPicker() {
      this.showPanel = false
      // 跳转到选择页（复用购物车/商品列表），选完回传后 publishMsg(4, JSON)
      NavgateTo('/packages/customerService/picker/index?type=goods&bindId=' + this.chatTarget.bindId, { isLogin: false })
    },

    // 选择订单发送
    openOrderPicker() {
      this.showPanel = false
      NavgateTo('/packages/customerService/picker/index?type=order&bindId=' + this.chatTarget.bindId, { isLogin: false })
    },

    // 处理输入事件
    handleInput() {
      this.canSend = this.inputMessage.trim().length > 0
    },

    onInputFocus() {
      // 输入框获取焦点时，设置滚动到底部的标记
      this.scrollToBottomFlag = true
      setTimeout(() => {
        if (this.scrollToBottomFlag) {
          this.scrollToBottom()
        }
      }, 300)
    },

    onInputBlur() {
      // 输入框失去焦点时，重置滚动标记
      this.scrollToBottomFlag = false
    },

    // 是否需要显示时间分割线
    needShowTime(index) {
      if (index === 0) return true

      const currentMsg = this.messages[index]
      const prevMsg = this.messages[index - 1]

      // 如果两条消息间隔超过5分钟，则显示时间分割线
      return (currentMsg.time - prevMsg.time) > 5 * 60 * 1000
    },

    // 格式化时间
    formatTime(time) {
      const date = new Date(time)
      const hours = date.getHours().toString().padStart(2, '0')
      const minutes = date.getMinutes().toString().padStart(2, '0')

      return `${hours}:${minutes}`
    },

    // 滚动到底部
    scrollToBottom() {
      setTimeout(() => {
        console.log('手动滚动到底部')
        uni.pageScrollTo({
          scrollTop: 999999,
          duration: 300
        });
      }, 100)
    },

    // 返回上一页
    goBack() {
      uni.navigateBack()
    },

    // 启动心跳包 - 增强版：添加错误处理和状态检查
    startKeepalive() {
      // 停止之前的定时器
      this.stopKeepalive()

      // 每30秒发送一次心跳包
      this.keepaliveTimer = setInterval(() => {
        if (this.client && this.isConnected) {
          const keepaliveData = {
            client_id: this.selfClientId // 自己的client_id
          }

          this.client.publish(
            'contact/message/keep_time',
            JSON.stringify(keepaliveData),
            {},
            (err) => {
              if (err) {
                console.error('发送心跳包失败', err)
                // 心跳包发送失败可能表示连接有问题，可以考虑触发重连
                if (!this.isConnected) {
                  return
                }
                console.log('心跳包发送失败，尝试检查连接状态')
                // 这里可以添加额外的连接检查逻辑
              }
            }
          )
        } else {
          console.warn('MQTT未连接，停止心跳包')
          this.stopKeepalive()
        }
      }, 30000)
    },

    // 停止心跳包
    stopKeepalive() {
      if (this.keepaliveTimer) {
        clearInterval(this.keepaliveTimer)
        this.keepaliveTimer = null
      }
    },

    // 跳转到切换客服页面
    goToChangeService() {
      uni.navigateTo({
        url: '/packages/customerService/changeService/index?currentMchId=' + this.chatTarget.mchId
      })
    }
  },

  // 页面卸载时停止心跳包
  onUnload() {
    // 断开MQTT连接
    if (this.client) {
      this.client.end()
    }

    // 停止心跳包
    this.stopKeepalive()

    // 清除重连失败提示定时器
    if (this.reconnectFailedTimer) {
      clearTimeout(this.reconnectFailedTimer)
      this.reconnectFailedTimer = null
    }

    // 移除卡片选择监听
    if (this._onPickCard) {
      uni.$off('chat:pickCard', this._onPickCard)
      this._onPickCard = null
    }
  }
}
</script>

<style>
@import url("./index.css");
</style>
<style scoped>
:root {
  --header-height: 80px; /* 头部高度 */
  --input-height: 80px; /* 输入区域高度 */
}

/* 图片/视频消息 */
.message-media {
  max-width: 60%;
}
.chat-img {
  width: 320rpx;
  height: 320rpx;
  border-radius: 12rpx;
  background: #f0f0f0;
}
.chat-video {
  width: 400rpx;
  height: 300rpx;
  border-radius: 12rpx;
}
.media-loading {
  padding: 30rpx 40rpx;
  background: #fff;
  border-radius: 12rpx;
  color: #999;
  font-size: 24rpx;
}

/* 商品/订单卡片 */
.message-card {
  display: flex;
  width: 520rpx;
  background: #fff;
  border-radius: 14rpx;
  overflow: hidden;
  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
}
.card-pic {
  width: 180rpx;
  height: 180rpx;
  flex-shrink: 0;
  background: #f5f5f5;
}
.card-pic--ph {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #bbb;
  font-size: 28rpx;
}
.card-info {
  flex: 1;
  padding: 18rpx 20rpx;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
}
.card-name {
  font-size: 28rpx;
  color: #222;
  line-height: 38rpx;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-price {
  font-size: 32rpx;
  color: #FF370B;
  font-weight: 600;
}
.card-tag {
  align-self: flex-start;
  font-size: 20rpx;
  color: #999;
  border: 1rpx solid #eee;
  border-radius: 6rpx;
  padding: 0 10rpx;
}

/* "+" 按钮与更多面板 */
.plus-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60rpx;
  height: 60rpx;
}
.more-panel {
  display: flex;
  flex-wrap: wrap;
  padding: 24rpx 12rpx;
  background: #f7f7f7;
}
.panel-item {
  width: 20%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8rpx;
  font-size: 22rpx;
  color: #666;
  margin-bottom: 16rpx;
}
.panel-icon {
  width: 96rpx;
  height: 96rpx;
  background: #fff;
  border-radius: 16rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 44rpx;
}
</style>