
<template>
  <div class="cs-chat-container">

     <!-- 添加网络状态提示 v-if="networkStatus === 'offline'" -->
     <div v-if="networkStatus === 'offline'" class="network-status">
      <i class="el-icon-warning"></i>
      <span>{{ $t("chat.networkError") || "网络连接已断开" }}</span>
    </div>
    <!-- 添加连接状态提示  -->
    <div
      v-if="connectionStatus !== 'connected'"
      class="connection-status"
      :class="connectionStatus"
    >
      <i
        :class="
          connectionStatus === 'error' ? 'el-icon-warning' : 'el-icon-loading'
        "
      ></i>
      <span
        >{{
          connectionStatus === "error"
            ? $t("chat.Disconnected") || "连接已断开"
            : $t("chat.reconnecting") || "正在连接..."
        }}
      </span>
    </div>
    <!-- 聊天窗口主体 -->
    <div class="cs-chat-wrapper">
      <!-- 左侧联系人列表 -->
      <div class="cs-contact-list">
        <div class="cs-header">
          <i class="el-icon-s-custom"></i>
          {{ $t("chat.contactList") || "联系列表" }}
        </div>
        <div class="cs-search">
          <el-input
            prefix-icon="el-icon-search"
            v-model="searchText"
            :placeholder="$t(`chat.search`) || '搜索最近联系人'"
            clearable
          ></el-input>
        </div>

        <!-- 联系人列表 -->
        <div class="cs-contacts">
          <div
            v-for="(contact, index) in filteredContacts"
            :key="index"
            class="cs-contact-item"
            :class="{ active: currentContactId === contact.roomId }"
            @click="selectContact(contact.roomId)"
            :title="contact.name"
          >
            <div class="cs-avatar">
              <i class="iconfont icon-icon28" style="font-size: 1.5vw"></i>
              <span v-if="contact.unread" class="unread-badge">{{
                contact.unread
              }}</span>

              <!-- 添加游客标识 -->
              <span v-if="contact.isGuest" class="guest-badge">{{
                $t("chat.tourist") || "游客"
              }}</span>
            </div>
            <div class="cs-contact-info">
              <div class="cs-contact-name">
                {{ contact.name }}
              </div>
              <div class="cs-contact-msg">
                <span v-if="contact.important" class="important-tag"
                  >[{{ $t("chat.important") || "重要" }}]
                </span>
                <!-- {{ contact.lastMessage }} -->
              </div>

              <div>
                <span
                  class="cs-contact-time"
                  :title="contact.lastTime"
                  >{{ formatLastTime(contact.lastTime) }}</span
                >
              </div>
            </div>
            <!-- 添加重要标记图标 -->
            <div
              class="important-star"
              :class="{ 'is-important': contact.important }"
              @click.stop="toggleImportant(contact.roomId, !contact.important)"
              :title="$t(`chat.markAsImportant`) || '标记为重要聊天'"
            >
              <i class="el-icon-star-on"></i>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧聊天区域 -->
      <div class="cs-chat-area">
        <!-- 顶部信息栏 -->
        <div class="cs-chat-header">
          <div class="cs-chat-title">
            {{
              currentContact
                ? currentContact.name
                : $t("chat.chooseFirst") || "请选择联系人"
            }}
            <el-tag
              v-if="currentContact && currentContact.important"
              size="small"
              type="danger"
              @click="
                toggleImportant(
                  currentContact.roomId,
                  !currentContact.important
                )
              "
            >
              {{ $t("chat.important") || "重要" }}
            </el-tag>
            <el-tag
              v-else-if="currentContact"
              size="small"
              type="info"
              style="cursor: pointer;"
              @click="
                toggleImportant(
                  currentContact.roomId,
                  !currentContact.important
                )
              "
            >
              {{ $t("chat.markAsImportant") || "标记为重要" }}
            </el-tag>
          </div>
          <div class="cs-header-actions">
            <!-- loadHistory -->
            <i
              class="el-icon-time"
              :title="$t(`chat.history`) || '历史记录'"
              @click="loadMoreHistory"
            ></i>
            <!-- <i
              class="el-icon-refresh"
              title="刷新"
              @click="refreshMessages"
            ></i> -->
            <!-- <i class="el-icon-more" title="更多选项"></i> -->
          </div>
        </div>

        <!-- 聊天内容区域 -->
        <div
          class="cs-chat-messages"
          ref="messageContainer"
          @scroll="handleScroll"
        >
          <div v-if="!currentContact" class="cs-empty-chat">
            <i class="el-icon-chat-dot-round"></i>
            <p>{{ $t("chat.notSelected") || "您尚未选择联系人" }}</p>
          </div>
          <template v-else>
            <!-- 历史消息加载区域 -->
            <div v-if="currentMessages.length > 0" class="history-section">
              <!-- 加载更多历史消息按钮 -->
              <div
                v-if="hasMoreHistory"
                class="history-indicator"
                @click="loadMoreHistory"
                style="
                  cursor: pointer;
                  text-align: center;
                  color: #409eff;
                  margin-bottom: 10px;
                  font-size: 0.7vw;
                "
              >
                <i class="el-icon-arrow-up"></i>
                <span>{{ $t("chat.loadMore") || "加载更多历史消息" }}</span>
              </div>

              <!-- 没有更多历史消息提示 -->
              <div
                v-else
                class="no-more-history"
                style="
                  text-align: center;
                  color: #909399;
                  margin-bottom: 10px;
                  font-size: 0.7vw;
                  padding: 8px 0;
                "
              >
                <i class="el-icon-info"></i>
                <span>{{
                  noMoreHistoryMessage ||
                  $t("chat.noMoreHistory") ||
                  "没有更多历史消息"
                }}</span>
              </div>
            </div>
            <div v-if="messagesLoading" class="cs-loading">
              <i class="el-icon-loading"></i>
              <p>{{ $t("chat.loading") || "加载消息中..." }}</p>
            </div>
            <div v-else-if="currentMessages.length === 0" class="cs-empty-chat">
              <i class="el-icon-chat-line-round"></i>
              <p>{{ $t("chat.None") || "暂无消息记录" }}</p>
            </div>
            <div v-else class="cs-message-list">
              <div
                v-for="(message, idx) in currentMessages"
                :key="idx"
                class="cs-message"
                :class="{ 'cs-message-self': message.isSelf }"
              >
                <div class="cs-message-time" v-if="showMessageTime(idx)">
                  {{ formatTime(message.time) }}
                </div>
                <div class="cs-message-content">
                  <div class="cs-avatar">
                    <i class="iconfont icon-icon28" style="font-size: 2vw"></i>

                    <!-- <el-avatar
                      :size="36"
                      :src="
                        message.isSelf
                          ? getDefaultAvatar('我')
                          : getDefaultAvatar(message.sender)
                      "
                    >
                      {{ message.sender ? message.sender.charAt(0) : "?" }}
                    </el-avatar> -->
                  </div>
                  <div class="cs-bubble">
                    <div class="cs-sender">{{ message.sender }}</div>
                    <div
                      v-if="!message.isImage"
                      class="cs-text"
                      v-html="formatMessageContent(message.content)"
                    ></div>
                    <div v-else class="cs-image">
                      <img
                        :src="message.content"
                        @click="previewImage(message.content)"
                      />
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </template>
        </div>

        <!-- 输入区域 -->
        <div class="cs-chat-input">
          <div class="cs-toolbar">
            <i
              class="el-icon-picture-outline"
              :title="$t(`chat.sendPicture`) || '发送图片'"
              @click="openImageUpload"
            ></i>
            <input
              type="file"
              ref="imageInput"
              accept="image/*"
              style="display: none"
              @change="handleImageUpload"
            />
            <!-- <i class="el-icon-folder-opened" title="发送文件"></i> -->
            <!-- <i class="el-icon-s-opportunity" title="发送表情"></i> -->
            <!-- <i class="el-icon-scissors" title="截图"></i> -->
          </div>
          <!--  @keydown.enter.native="handleKeyDown" -->
          <div class="cs-input-area">
            <el-input
              type="textarea"
              v-model="inputMessage"
              :rows="3"
              :maxlength="400"
              :disabled="!currentContact"
              resize="none"
              :placeholder="
                $t(`chat.inputMessage`) ||
                `请输入消息，按Enter键发送，按Ctrl+Enter键换行`
              "
              @keydown.native="handleKeyDown"
            ></el-input>
          </div>

          <div class="cs-send-area">
            <span class="cs-counter">{{ inputMessage.length }}/400</span>
            <el-button
              type="primary"
              :disabled="!currentContact || !inputMessage.trim() || sending"
              @click="sendMessage"
            >
              <i v-if="sending" class="el-icon-loading"></i>
              <span v-else>{{ $t("chat.send") || "发送" }}</span>
            </el-button>
          </div>
        </div>
      </div>
    </div>

    <div
      v-if="showScrollButton"
      class="scroll-to-bottom"
      @click="scrollToBottom(true)"
    >
      {{ $t("chat.bottom") || "回到底部" }} <i class="el-icon-arrow-down"></i>
    </div>

    <!-- 图片预览 -->
    <el-dialog
      :visible.sync="previewVisible"
      append-to-body
      class="image-preview-dialog"
    >
      <img
        :src="previewImageUrl"
        class="preview-image"
        :alt="$t(`chat.Preview`) || '预览图片'"
      />
    </el-dialog>
  </div>
</template>
  
  <script>
import {
  getRoomList,
  getHistory,
  getHistory7,
  getReadMessage,
  getUpdateRoom,
  getFileUpdate,
} from "../../api/customerService";
// 正确导入 Client
import { Client, Stomp } from "@stomp/stompjs";

export default {
  name: "CustomerServiceChat",
  data() {
    return {
      searchText: "",
      inputMessage: "",
      currentContactId: null,
      previewVisible: false,
      previewImageUrl: "",
      contacts: [],
      messages: {},
      messagesLoading: false,
      sending: false,
      loadingRooms: true,
      stompClient: null,
      wsConnected: false,
      userEmail: "", // 当前客服邮箱
      userType: 1, // 0或者1  游客或者登录用户

      loadingHistory: false, // 是否正在加载历史消息
      userViewHistory: false, // 用户是否在浏览历史
      userScrolled: false, // 新增：用户是否手动滚动过
      history7Params: {
        //7天历史消息参数
        id: "", //最后一条消息id
        roomId: "", //聊天室id
        userType: 2, //用户类型
        email: "", //客服邮箱
      },
      historyAllParams: {
        //7天以前的历史消息
        id: "", //最后一条消息id
        roomId: "", //聊天室id
        userType: 2, //用户类型
      },
      receiveUserType: "", //接收者类型
      manualCreatedRooms: [], //手动创建的聊天室
      chatRooms: [], // 初始化聊天室列表数组
      isWebSocketConnected: false,
      connectionStatus: "disconnected",
      isLoadingMoreContacts: false, // 是否正在加载更多联系人
      lastContactTime: null, // 最后一个联系人的时间
      showScrollButton: false,
      visibilityHandler: null, // 页面可见性处理器
      reconnectTimer: null, // 重连定时器
      maxReconnectAttempts: 5, // 最大重连次数
      reconnectInterval: 5000, // 重连间隔(ms)
      reconnectAttempts: 0, // 当前重连次数
      isHandlingError: false, // 防止重复处理错误
      lastErrorTime: 0, // 最后一次错误时间
      lastActivityTime: Date.now(), // 最后活动时间
      activityCheckInterval: null, // 活动检测定时器
      activityEvents: null, // 活动监听事件列表
      activityHandler: null, // 活动监听处理函数
      connectionVerifyTimer: null, // 连接验证定时器
      connectionVerifyTimeout: 60000, // 连接验证超时时间(60秒)
      isConnectionVerified: false, // 连接是否已验证

      // === 新增：心跳检测相关 ===
      heartbeatInterval: null, // 心跳定时器
      heartbeatTimeout: 30000, // 心跳间隔（30秒）
      lastHeartbeatTime: 0, // 最后一次心跳时间
      connectionCheckInterval: null, // 连接检查定时器
      connectionCheckTimeout: 60000, // 连接检查间隔（60秒）

      // 历史消息加载状态控制
      hasMoreHistory: true, // 是否还有更多历史消息
      noMoreHistoryMessage: "", // 无更多历史消息时的提示文字
      networkStatus: "online",

    };
  },
  computed: {
    filteredContacts() {
      //搜索联系人
      if (!this.searchText) {
        return this.contacts;
      }
      return this.contacts.filter((contact) =>
        contact.name.toLowerCase().includes(this.searchText.toLowerCase())
      );
    },
    currentContact() {
      //选中联系人对象
      return this.contacts.find(
        (contact) => contact.roomId === this.currentContactId
      );
    },
    currentMessages() {
      //当前聊天室消息
      return this.messages[this.currentContactId] || [];
    },
  },

  async created() {
    try {
      let userEmail = localStorage.getItem("userEmail");
      this.userEmail = JSON.parse(userEmail);
      window.addEventListener("setItem", () => {
        let userEmail = localStorage.getItem("userEmail");
        this.userEmail = JSON.parse(userEmail);
      });

      // 获取聊天室列表
      await this.fetchRoomList();
      // 在组件创建时加载手动创建的聊天室
      this.loadManualCreatedRooms();

      console.log(this.userEmail, "初始化的时候");
      // 初始化 WebSocket 连接
      this.initWebSocket();
    } catch (error) {
      console.error("初始化失败:", error);
    }
  },
  async mounted() {
    // 获取聊天室列表
    await this.fetchRoomList();

    let userEmail = localStorage.getItem("userEmail");
    this.userEmail = JSON.parse(userEmail);
    window.addEventListener("setItem", () => {
      let userEmail = localStorage.getItem("userEmail");
      this.userEmail = JSON.parse(userEmail);
    });

   // 添加网络状态变化监听
   window.addEventListener("online", this.handleNetworkChange);
    window.addEventListener("offline", this.handleNetworkChange);
    // 注释：不再自动滚动，等用户选择聊天室后再滚动
    // this.$nextTick(() => {
    //   this.scrollToBottom();
    // });
    // 添加滚动事件监听
    this.$nextTick(() => {
      if (this.$refs.messageContainer) {
        this.$refs.messageContainer.addEventListener(
          "scroll",
          this.handleScroll
        );
      }
    });
    // 添加联系人列表滚动事件监听
    this.$nextTick(() => {
      const contactList = document.querySelector(".cs-contacts");
      if (contactList) {
        contactList.addEventListener("scroll", this.handleContactListScroll);
      }
    });

    // 添加页面可见性监听
    this.visibilityHandler = () => {
      if (document.visibilityState === "visible") {
        // === 优化：页面变为可见时，更新活动时间并智能检查连接状态 ===
        console.log("🔍 客服页面重新可见，执行连接状态检查");
        this.updateLastActivityTime();

        // 立即执行一次连接状态检查
        this.performConnectionCheck();

        // 如果连接状态不正常，则重连
        if (
          this.connectionStatus !== "connected" ||
          !this.isWebSocketConnected
        ) {
          console.log("🔄 客服页面可见，检测到连接异常，开始重连");
          this.checkAndReconnect();
        } else {
          console.log("✅ 客服页面可见，连接状态正常");
          // 重新启动心跳检测（可能在页面隐藏时被暂停）
          if (!this.heartbeatInterval) {
            this.startHeartbeat();
          }
          if (!this.connectionCheckInterval) {
            this.startConnectionCheck();
          }
        }
      } else {
        console.log("📱 客服页面变为隐藏状态");
        // 页面隐藏时不停止心跳检测，继续保持连接
      }
    };
    document.addEventListener("visibilitychange", this.visibilityHandler);

    // 添加用户活动检测
    this.startActivityCheck();

    // === 新增：添加用户活动监听器 ===
    this.activityEvents = [
      "mousedown",
      "mousemove",
      "keypress",
      "scroll",
      "touchstart",
      "click",
    ];
    this.activityHandler = () => {
      this.updateLastActivityTime();
    };

    // 添加活动监听器
    this.activityEvents.forEach((event) => {
      document.addEventListener(event, this.activityHandler, true);
    });

    window.addEventListener("storage", this.handleStorageChange);
  },
  methods: {
    handleKeyDown(e) {
      if (e.key === "Enter") {
        if (e.ctrlKey) {
          // 插入换行
          const textarea = e.target;
          const value = textarea.value;
          const start = textarea.selectionStart;
          const end = textarea.selectionEnd;
          // 在光标处插入\n
          textarea.value =
            value.substring(0, start) + "\n" + value.substring(end);
          // 移动光标到新行
          textarea.selectionStart = textarea.selectionEnd = start + 1;
          // 阻止默认行为（防止触发发送）
          e.preventDefault();
        } else {
          // 阻止默认行为并发送消息
          e.preventDefault();
          this.sendMessage();
        }
      }
    },

    // 初始化 WebSocket 连接
    initWebSocket() {
      if (this.isWebSocketConnected) {
        console.log("WebSocket已连接，跳过初始化");
        return;
      }

      // 防止重复初始化
      if (this.stompClient && this.stompClient.state !== "DISCONNECTED") {
        console.log("WebSocket正在连接中，跳过初始化");
        return;
      }

      try {
        // 确保之前的连接已经清理
        if (this.stompClient) {
          this.forceDisconnectAll();
        }

        console.log("开始初始化WebSocket连接...");
        const baseUrl = process.env.VUE_APP_BASE_API.replace("https", "wss");
        const wsUrl = `${baseUrl}chat/ws`;
        this.stompClient = Stomp.client(wsUrl);

        // 配置 STOMP 客户端参数
        this.stompClient.splitLargeFrames = true; // 启用大型消息帧分割
        this.stompClient.maxWebSocketFrameSize = 16 * 1024 * 1024; // 设置最大帧大小为16MB
        this.stompClient.maxWebSocketMessageSize = 16 * 1024 * 1024; // 设置最大消息大小为16MB
        this.stompClient.webSocketFactory = () => {
          const ws = new WebSocket(wsUrl);
          ws.binaryType = "arraybuffer"; // 设置二进制类型为 arraybuffer
          return ws;
        };

        // 修改调试日志的方式
        this.stompClient.debug = (str) => {
          // 只打印与客服相关的日志
          if (
            str.includes("CONNECTED") ||
            str.includes("DISCONNECTED") ||
            str.includes("ERROR")
          ) {
            console.log("[客服系统]", str);
          }
        };
        this.userType = 2; //客服
        const headers = {
          email: this.userEmail,
          type: this.userType,
        };

        // 添加STOMP错误处理
        this.stompClient.onStompError = (frame) => {
          console.error("[客服系统] STOMP 错误:", frame);
          // 处理STOMP帧错误
          this.handleSocketError(frame.headers?.message || frame.body);
        };

        // 添加重连逻辑
        this.stompClient.connect(
          headers,
          (frame) => {
            console.log("🎉 [客服系统] WebSocket 连接成功", frame);
            this.isWebSocketConnected = true;
            this.connectionStatus = "connected";
            this.reconnectAttempts = 0;
            this.isConnectionVerified = false; // 重置验证状态
            this.lastHeartbeatTime = Date.now(); // 记录连接时间作为心跳时间

            console.log("🔗 开始订阅客服消息...");
            // 订阅消息
            this.subscribeToMessages();
            this.updateLastActivityTime();

            // === 启动心跳检测 ===
            this.startHeartbeat();

            // === 启动连接状态检查 ===
            this.startConnectionCheck();

            // === 注意：不在这里启动验证，而是在订阅成功后 ===
            console.log("⚡ 客服连接成功，等待订阅完成后验证");
          },
          (error) => {
            console.error("[客服系统] WebSocket 错误:", error);
            // 处理特定的Socket错误
            this.handleSocketError(error);
          }
        );

        // 配置心跳
        this.stompClient.heartbeat.outgoing = 20000;
        this.stompClient.heartbeat.incoming = 20000;
      } catch (error) {
        console.error("初始化 CustomerService WebSocket 失败:", error);
        this.handleDisconnect();
      }
    },

    // // 订阅消息
    subscribeToMessages() {
      if (!this.stompClient || !this.isWebSocketConnected) {
        console.log("STOMP客户端未连接，无法订阅消息");
        return;
      }

      try {
        console.log(
          "开始订阅客服消息频道:",
          `/sub/queue/customer/${this.userEmail}`
        );

        // 修改订阅路径，使用客服特定的订阅路径
        const subscription1 = this.stompClient.subscribe(
          `/sub/queue/customer/${this.userEmail}`,
          this.handleIncomingMessage
        );

        // 订阅聊天室关闭消息
        const subscription2 = this.stompClient.subscribe(
          `/sub/queue/close/room/${this.userEmail}`,
          this.handleRoomClose
        );

        if (subscription1 && subscription2) {
          console.log(
            "✅ CustomerService 成功订阅消息频道:",
            `/sub/queue/customer/${this.userEmail}`
          );

          console.log(
            "✅ CustomerService 成功订阅关闭消息频道:",
            `/sub/queue/close/room/${this.userEmail}`
          );

          // === 订阅成功立即标记连接验证 ===
          console.log("📢 客服订阅成功，立即标记连接已验证");
          this.markConnectionVerified();

          // 确保连接状态正确
          if (this.connectionStatus !== "connected") {
            console.log("📡 修正客服连接状态为connected");
            this.connectionStatus = "connected";
          }
        } else {
          console.error("❌ 客服订阅失败，返回空subscription");
          // 如果订阅失败，启动验证机制等待超时重连
          this.startConnectionVerification();
        }
      } catch (error) {
        console.error("❌ CustomerService 订阅消息异常:", error);
        // 如果订阅异常，启动验证机制等待超时重连
        this.startConnectionVerification();
      }
    },

    // 处理聊天室关闭的方法 删除游客
    handleRoomClose(message) {
      try {
        // 获取需要关闭的游客邮箱
        const closedUserEmail = message.body;

        // 标准化处理 返回的格式 "\"guest_1748242041830_jmz4c9qx5\""
        const normalize = (str) => {
          if (!str) return "";
          if (typeof str === "object" && "value" in str) str = str.value;
          str = String(str).trim().toLowerCase();
          // 去除所有首尾引号
          str = str.replace(/^['"]+|['"]+$/g, "");
          return str;
        };

        const targetEmail = normalize(closedUserEmail);
        // 在联系人列表中查找对应的聊天室

        const contactIndex = this.contacts.findIndex((contact) => {
          const contactEmail = normalize(contact.name);
          return contactEmail === targetEmail;
        });

        // console.log("标准化比较结果:", {
        //   targetEmail,
        //   contacts: this.contacts.map(c => normalize(c.name)),
        //   contactIndex
        // });

        if (contactIndex !== -1) {
          // 如果当前选中的就是被关闭的聊天室，需要清除选中状态
          if (this.currentContactId === this.contacts[contactIndex].roomId) {
            this.currentContactId = null;
          }

          // 从联系人列表中移除
          this.contacts.splice(contactIndex, 1);

          // 从消息列表中移除
          this.$delete(this.messages, this.contacts[contactIndex].roomId);

          // 从手动创建的聊天室列表中移除
          const manualRoomIndex = this.manualCreatedRooms.findIndex(
            (room) => room.name === closedUserEmail
          );
          if (manualRoomIndex !== -1) {
            this.manualCreatedRooms.splice(manualRoomIndex, 1);
            this.saveManualCreatedRooms();
          }

          // === 减少提示：聊天室关闭只在控制台记录 ===
          console.log(`聊天室 ${closedUserEmail} 已关闭`);
        }
      } catch (error) {
        console.error("处理聊天室关闭消息失败:", error);
      }
    },

    // 断开连接
    disconnectWebSocket() {
      if (this.stompClient) {
        try {
          // 取消所有订阅
          if (this.stompClient.subscriptions) {
            Object.keys(this.stompClient.subscriptions).forEach((id) => {
              this.stompClient.unsubscribe(id);
            });
          }

          // 断开连接
          this.stompClient.deactivate();
          this.isWebSocketConnected = false;
          this.connectionStatus = "disconnected";
        } catch (error) {
          console.error("断开 CustomerService WebSocket 连接失败:", error);
        }
      }
    },

    /**
     * 解析Socket错误信息，提取错误码和错误消息
     * @param {string|Object} errorInfo - 原始错误信息
     * @returns {Object} { code: string, message: string }
     */
    parseSocketError(errorInfo) {
      let errorMessage = "";

      // 处理不同类型的错误信息
      if (typeof errorInfo === "string") {
        errorMessage = errorInfo;
      } else if (errorInfo && typeof errorInfo === "object") {
        // 从错误对象中提取消息
        errorMessage =
          errorInfo.message ||
          errorInfo.body ||
          errorInfo.headers?.message ||
          String(errorInfo);
      } else {
        errorMessage = String(errorInfo || "");
      }

      // 处理格式："1020,本机连接数已达上限,请先关闭已有链接"
      if (errorMessage.includes(",")) {
        const parts = errorMessage.split(",");
        const code = parts[0].trim();
        const message = parts.slice(1).join(",").trim();
        return { code, message };
      }

      // 处理其他格式，尝试从消息中提取错误码
      const codeMatch = errorMessage.match(/(\d{4})/);
      if (codeMatch) {
        return { code: codeMatch[1], message: errorMessage };
      }

      return { code: "", message: errorMessage };
    },

    /**
     * 处理Socket连接错误
     * @param {Object|string} error - 错误信息
     */
    async handleSocketError(error) {
      // 防止重复处理错误（5秒内的重复错误忽略）
      const now = Date.now();
      if (this.isHandlingError || now - this.lastErrorTime < 5000) {
        console.log("正在处理错误或错误处理间隔太短，跳过此次错误处理");
        return;
      }

      this.isHandlingError = true;
      this.lastErrorTime = now;

      try {
        const { code, message } = this.parseSocketError(error);

        console.log("解析的错误信息:", { code, message });

        switch (code) {
          case "1020": // IP_LIMIT_CONNECT - 本机连接数已达上限
            await this.handleConnectionLimitError();
            break;

          case "1021": // MAX_LIMIT_CONNECT - 服务器连接数已达上限
            this.handleServerLimitError(message);
            break;

          case "1022": // SET_PRINCIPAL_FAIL - 用户身份设置失败
            this.handlePrincipalError(message);
            break;

          case "1023": // GET_PRINCIPAL_FAIL - 用户信息获取失败
            this.handlePrincipalError(message);
            break;

          default:
            // 其他错误，检查是否包含连接数上限关键词
            if (
              message.includes("连接数已达上限") ||
              message.includes("本机连接数已达上限")
            ) {
              await this.handleConnectionLimitError();
            } else {
              // 使用原有的断开重连逻辑
              this.handleDisconnect();
            }
            break;
        }
      } catch (handleError) {
        console.error("处理Socket错误时发生异常:", handleError);
        this.handleDisconnect();
      } finally {
        // 延迟重置处理标志，防止快速重复
        setTimeout(() => {
          this.isHandlingError = false;
        }, 2000);
      }
    },

    /**
     * 处理连接数上限错误 (1020)
     */
    async handleConnectionLimitError() {
      console.log("检测到连接数上限错误，开始强制断开并重连...");

      // 清除现有的重连定时器，避免冲突
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
        this.reconnectTimer = null;
      }

      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      // === 移除用户提示：这种错误会自动处理，不需要打扰用户 ===
      console.log("💡 检测到连接数上限，后台自动重连中...");

      try {
        // 1. 强制断开现有连接
        this.forceDisconnectAll();

        // 2. 等待一段时间让服务器释放连接
        await new Promise((resolve) => setTimeout(resolve, 3000));

        // 3. 只重连一次，避免无限循环
        console.log("尝试重新连接...");
        await this.initWebSocket();

        if (this.isWebSocketConnected) {
          console.log("✅ 客服连接已自动恢复正常");
          // === 移除成功提示：自动恢复不需要告知用户 ===
        } else {
          // 如果重连失败，只在控制台记录，避免满屏提示
          console.error("❌ 客服连接重连失败");
        }
      } catch (error) {
        console.error("处理连接数上限错误失败:", error);
        // === 减少错误提示：只在控制台记录 ===
      }
    },

    /**
     * 处理服务器连接数上限错误 (1021)
     */
    handleServerLimitError(message) {
      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      console.log("服务器连接数已达上限");

      // === 减少错误提示：只在控制台记录 ===
      console.error("服务器繁忙，连接数已达上限");

      // 不进行自动重连，让用户手动刷新
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
      }
    },

    /**
     * 处理用户身份相关错误 (1022, 1023)
     */
    handlePrincipalError(message) {
      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      console.log("用户身份验证失败:", message);

      // === 减少错误提示：只在控制台记录 ===
      console.error("身份验证失败:", message);

      // 不进行自动重连，可能需要重新登录
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
      }
    },

    /**
     * 开始连接验证机制
     * 在连接建立后的1分钟内验证连接是否真正可用
     * 通过订阅成功和接收任何消息来验证，不主动发送ping消息
     */
    startConnectionVerification() {
      console.log("🔍 启动客服连接验证机制（被动验证）...");
      console.log("当前连接状态:", this.connectionStatus);
      console.log("当前WebSocket连接状态:", this.isWebSocketConnected);
      console.log("当前STOMP连接状态:", this.stompClient?.connected);

      this.isConnectionVerified = false;

      // 清除之前的验证定时器
      this.clearConnectionVerifyTimer();

      // 如果已经是connected状态且STOMP也连接成功，检查是否可以立即验证
      if (
        this.connectionStatus === "connected" &&
        this.isWebSocketConnected &&
        this.stompClient?.connected
      ) {
        console.log("✅ 客服连接状态良好，立即标记为已验证");
        this.markConnectionVerified();
        return;
      }

      // 设置1分钟验证超时
      this.connectionVerifyTimer = setTimeout(() => {
        if (!this.isConnectionVerified) {
          console.log(
            "⏰ 客服连接验证超时（1分钟），当前状态:",
            this.connectionStatus
          );
          console.log("WebSocket连接状态:", this.isWebSocketConnected);
          console.log("STOMP连接状态:", this.stompClient?.connected);
          console.log("连接可能不可用");
          this.handleConnectionVerificationFailure();
        }
      }, this.connectionVerifyTimeout); // 60秒超时

      console.log("⏲️ 已设置客服1分钟验证超时定时器");
      // 注意：采用被动验证方式，不发送ping消息，避免在对话框中显示验证消息
    },

    /**
     * 标记连接已验证
     */
    markConnectionVerified() {
      if (!this.isConnectionVerified) {
        console.log("🎉 客服连接验证成功！清除验证定时器");
        this.isConnectionVerified = true;
        this.clearConnectionVerifyTimer();

        // 确保连接状态是正确的
        if (this.connectionStatus !== "connected") {
          console.log("📡 修正客服连接状态为connected");
          this.connectionStatus = "connected";
        }
      } else {
        console.log("🔄 客服连接已经验证过了，跳过重复验证");
      }
    },

    /**
     * 处理连接验证失败
     */
    handleConnectionVerificationFailure() {
      console.log("连接验证失败，连接可能无法正常收发消息");

      // 防止重复处理
      const now = Date.now();
      if (this.isHandlingError && now - this.lastErrorTime < 5000) {
        console.log("正在处理错误中，跳过重复处理");
        return;
      }

      this.isHandlingError = true;
      this.lastErrorTime = now;

      // 清除验证定时器
      this.clearConnectionVerifyTimer();

      // 重置连接状态
      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      // 2秒后重新连接
      setTimeout(() => {
        console.log("连接验证失败，开始重新连接...");
        this.isHandlingError = false;

        // 断开当前连接
        if (this.stompClient) {
          try {
            this.stompClient.disconnect();
          } catch (error) {
            console.warn("断开连接时出错:", error);
          }
        }

        // 重新连接
        this.initWebSocket().catch((error) => {
          console.error("重新连接失败:", error);
          this.isHandlingError = false;
        });
      }, 2000);
    },

    /**
     * 检查并确保连接状态
     * @returns {Promise<boolean>} 连接是否可用
     */
    async checkAndEnsureConnection() {
      console.log("🔍 检查客服连接状态...");

      // 更新最后活动时间
      this.updateLastActivityTime();

      // 检查基本连接状态
      if (!this.stompClient) {
        console.log("❌ STOMP客户端不存在，需要重新连接");
        return await this.reconnectForSend();
      }

      // 检查STOMP连接状态
      if (!this.stompClient.connected) {
        console.log("❌ STOMP连接已断开，需要重新连接");
        return await this.reconnectForSend();
      }

      // 检查WebSocket底层连接
      if (
        this.stompClient.ws &&
        this.stompClient.ws.readyState !== WebSocket.OPEN
      ) {
        console.log("❌ WebSocket底层连接异常，需要重新连接");
        return await this.reconnectForSend();
      }

      // 检查应用层连接状态
      if (!this.isWebSocketConnected || this.connectionStatus !== "connected") {
        console.log("❌ 应用层连接状态异常，需要重新连接");
        return await this.reconnectForSend();
      }

      console.log("✅ 客服连接状态良好");
      return true;
    },

    /**
     * 为发送消息重新连接
     * @returns {Promise<boolean>} 重连是否成功
     */
    async reconnectForSend() {
      try {
        console.log("🔄 开始为发送消息重新连接...");
        this.connectionStatus = "connecting";

        // 强制断开现有连接
        this.forceDisconnectAll();

        // 等待一段时间
        await new Promise((resolve) => setTimeout(resolve, 1000));

        // 重新初始化连接
        await this.initWebSocket();

        // 检查连接是否成功
        if (
          this.isWebSocketConnected &&
          this.connectionStatus === "connected"
        ) {
          console.log("✅ 重连成功");
          return true;
        } else {
          console.log("❌ 重连失败");
          console.error("❌ 重连失败");
          return false;
        }
      } catch (error) {
        console.error("重连过程异常:", error);
        console.error("❌ 连接异常");
        return false;
      }
    },

    /**
     * 检查是否是连接错误
     * @param {Error} error - 错误对象
     * @returns {boolean} 是否是连接错误
     */
    isConnectionError(error) {
      if (!error) return false;

      const errorMessage = error.message || error.toString();

      return (
        errorMessage.includes("ExecutorSubscribableChannel") ||
        errorMessage.includes("NullPointerException") ||
        errorMessage.includes("Failed to send message") ||
        errorMessage.includes("connection") ||
        errorMessage.includes("disconnect") ||
        errorMessage.includes("websocket") ||
        errorMessage.includes("STOMP")
      );
    },

    /**
     * 处理发送消息时的连接错误
     * @param {Error} error - 错误对象
     */
    async handleConnectionErrorInSend(error) {
      console.log("🚨 发送消息时检测到连接错误:", error.message);

      // 显示用户友好的错误信息
      console.log("🔄 连接已断开，正在重新连接...");

      // 重置连接状态
      this.isWebSocketConnected = false;
      this.connectionStatus = "connecting";

      try {
        // 尝试重新连接
        const reconnected = await this.reconnectForSend();
        if (reconnected) {
          console.log("✅ 发送消息时自动重连成功");
          // === 移除成功提示：自动恢复不需要告知用户 ===
        }
      } catch (reconnectError) {
        console.error("🔄 客服自动重连失败:", reconnectError);
        this.connectionStatus = "error";
        // === 移除重连失败提示：会继续自动重试，不需要打扰用户 ===
      }
    },

    /**
     * 清除连接验证定时器
     */
    clearConnectionVerifyTimer() {
      if (this.connectionVerifyTimer) {
        console.log("🧹 清除客服连接验证定时器");
        clearTimeout(this.connectionVerifyTimer);
        this.connectionVerifyTimer = null;
      } else {
        console.log("🔍 没有需要清除的客服验证定时器");
      }
    },

    /**
     * 启动心跳检测
     */
    startHeartbeat() {
      console.log("💓 启动客服心跳检测...");

      // 清除之前的心跳定时器
      this.stopHeartbeat();

      this.heartbeatInterval = setInterval(() => {
        if (this.isWebSocketConnected && this.stompClient?.connected) {
          this.sendHeartbeat();
        } else {
          console.warn("💔 客服心跳检测发现连接异常");
          this.handleHeartbeatFailure();
        }
      }, this.heartbeatTimeout);

      console.log(
        `💓 客服心跳检测已启动，间隔: ${this.heartbeatTimeout / 1000}秒`
      );
    },

    /**
     * 停止心跳检测
     */
    stopHeartbeat() {
      if (this.heartbeatInterval) {
        console.log("💔 停止客服心跳检测");
        clearInterval(this.heartbeatInterval);
        this.heartbeatInterval = null;
      }
    },

    /**
     * 发送心跳包
     */
    sendHeartbeat() {
      try {
        if (!this.stompClient?.connected) {
          console.warn("💔 STOMP未连接，无法发送心跳");
          this.handleHeartbeatFailure();
          return;
        }

        // 使用STOMP的内置心跳，不发送实际消息避免干扰聊天
        // 检查WebSocket底层连接状态
        if (
          this.stompClient.ws &&
          this.stompClient.ws.readyState === WebSocket.OPEN
        ) {
          this.lastHeartbeatTime = Date.now();
          // === 减少心跳日志：只在异常时输出，正常时静默运行 ===

          // 更新活动时间
          this.updateLastActivityTime();
        } else {
          console.warn("💔 WebSocket底层连接异常");
          this.handleHeartbeatFailure();
        }
      } catch (error) {
        console.error("💔 客服心跳检测异常:", error);
        this.handleHeartbeatFailure();
      }
    },

    /**
     * 处理心跳失败
     */
    handleHeartbeatFailure() {
      console.warn("💔 客服心跳失败，开始重连...");

      // 停止心跳
      this.stopHeartbeat();

      // 标记连接断开
      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      // 触发重连
      this.handleDisconnect();
    },

    /**
     * 启动连接状态检查
     */
    startConnectionCheck() {
      console.log("🔍 启动客服连接状态检查...");

      // 清除之前的检查定时器
      this.stopConnectionCheck();

      this.connectionCheckInterval = setInterval(() => {
        this.performConnectionCheck();
      }, this.connectionCheckTimeout);

      console.log(
        `🔍 客服连接状态检查已启动，间隔: ${
          this.connectionCheckTimeout / 1000
        }秒`
      );
    },

    /**
     * 停止连接状态检查
     */
    stopConnectionCheck() {
      if (this.connectionCheckInterval) {
        console.log("🔍 停止客服连接状态检查");
        clearInterval(this.connectionCheckInterval);
        this.connectionCheckInterval = null;
      }
    },

    /**
     * 执行连接状态检查
     */
    performConnectionCheck() {
      // === 减少日志频率：只在检测到问题时输出详细信息 ===

      const now = Date.now();
      const timeSinceLastHeartbeat = now - this.lastHeartbeatTime;

      // 检查基本连接状态
      if (
        !this.stompClient ||
        !this.stompClient.connected ||
        !this.isWebSocketConnected
      ) {
        console.warn("🚨 客服连接状态检查：基本连接异常");
        this.handleConnectionFailure("基本连接状态异常");
        return;
      }

      // 检查心跳超时（3分钟内没有心跳认为连接异常）
      if (timeSinceLastHeartbeat > 3 * 60 * 1000) {
        console.warn("🚨 客服连接状态检查：心跳超时");
        this.handleConnectionFailure("心跳超时");
        return;
      }

      // 检查WebSocket底层状态
      if (
        this.stompClient.ws &&
        this.stompClient.ws.readyState !== WebSocket.OPEN
      ) {
        console.warn("🚨 客服连接状态检查：WebSocket底层连接异常");
        this.handleConnectionFailure("WebSocket底层连接异常");
        return;
      }

      // === 减少正常状态日志：只在异常时输出 ===
    },

    /**
     * 处理连接检查失败
     */
    handleConnectionFailure(reason) {
      console.warn(`🚨 客服连接失败: ${reason}`);

      // 防止重复处理
      const now = Date.now();
      if (this.isHandlingError && now - this.lastErrorTime < 10000) {
        console.log("正在处理连接失败，跳过重复处理");
        return;
      }

      this.isHandlingError = true;
      this.lastErrorTime = now;

      // 停止所有定时器
      this.stopHeartbeat();
      this.stopConnectionCheck();

      // 标记连接断开
      this.isWebSocketConnected = false;
      this.connectionStatus = "error";

      // === 移除用户提示：后台自动处理，不打扰用户 ===
      // 只在控制台记录，不显示toast消息

      // 触发重连
      setTimeout(() => {
        this.isHandlingError = false;
        this.handleDisconnect();
      }, 1000);
    },

    /**
     * 强制断开所有现有连接
     */
    forceDisconnectAll() {
      try {
        console.log("开始强制断开所有连接...");

        // 清除重连定时器
        if (this.reconnectTimer) {
          clearTimeout(this.reconnectTimer);
          this.reconnectTimer = null;
        }

        // === 新增：清除连接验证定时器 ===
        this.clearConnectionVerifyTimer();

        // === 新增：停止心跳和连接检查 ===
        this.stopHeartbeat();
        this.stopConnectionCheck();

        if (this.stompClient) {
          // 取消所有订阅
          if (this.stompClient.subscriptions) {
            Object.keys(this.stompClient.subscriptions).forEach((id) => {
              try {
                this.stompClient.unsubscribe(id);
              } catch (error) {
                console.log("取消订阅失败:", error);
              }
            });
          }

          // 强制断开连接
          try {
            this.stompClient.deactivate();
          } catch (error) {
            console.log("断开连接失败:", error);
          }

          // 等待一小段时间确保连接完全断开
          setTimeout(() => {
            this.stompClient = null;
          }, 100);
        }

        // 重置连接状态
        this.isWebSocketConnected = false;
        this.connectionStatus = "disconnected";

        console.log("已强制断开所有连接");
      } catch (error) {
        console.error("强制断开连接失败:", error);
        this.stompClient = null;
      }
    },

    // 处理断开连接
    handleDisconnect() {
      // 如果正在处理特殊错误，不执行普通重连逻辑
      if (this.isHandlingError) {
        console.log("正在处理特殊错误，跳过普通断开处理");
        return;
      }

      // === 新增：清除连接验证定时器 ===
      this.clearConnectionVerifyTimer();

      // === 新增：停止心跳和连接检查 ===
      this.stopHeartbeat();
      this.stopConnectionCheck();

      this.isWebSocketConnected = false;
      this.connectionStatus = "error";
      this.isConnectionVerified = false; // 重置验证状态

      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.reconnectAttempts++;
        console.log(
          `🔄 客服自动重连中 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`
        );

        this.reconnectTimer = setTimeout(() => {
          if (!this.isWebSocketConnected && !this.isHandlingError) {
            this.initWebSocket();
          }
        }, this.reconnectInterval);
      } else {
        console.log("❌ 达到最大重连次数，停止自动重连");
        // === 减少错误提示：只在控制台记录 ===
        console.error("❌ 达到最大重连次数，连接失败");
      }
    },

    // 检查并重连
    async checkAndReconnect() {
      if (!this.isWebSocketConnected) {
        console.log("页面恢复可见，尝试重新连接...");
        await this.initWebSocket();
      }
    },

    // 开始活动检测
    startActivityCheck() {
      this.activityCheckInterval = setInterval(() => {
        const now = Date.now();
        const inactiveTime = now - this.lastActivityTime;

        // === 修改：客服系统不应该因为无操作而主动断开连接 ===
        // 客服可能需要长时间待机等待用户消息，所以移除自动断开逻辑
        // 只在极端情况下（超过4小时无任何活动）才考虑断开，避免僵尸连接
        if (inactiveTime > 4 * 60 * 60 * 1000) {
          // 4小时
          console.log("客服系统：4小时无活动，断开连接防止僵尸连接");
          this.disconnectWebSocket();
        }

        // 每30分钟记录一次状态，便于调试
        if (
          inactiveTime > 30 * 60 * 1000 &&
          inactiveTime % (30 * 60 * 1000) < 60000
        ) {
          console.log(
            `客服系统：已无活动 ${Math.floor(
              inactiveTime / (60 * 1000)
            )} 分钟，连接状态：${this.connectionStatus}`
          );
        }
      }, 60000); // 每分钟检查一次
    },

    // 更新最后活动时间
    updateLastActivityTime() {
      this.lastActivityTime = Date.now();
      // console.log("客服活动时间已更新"); // 取消注释可用于调试
    },

    // 获取当前的 UTC 时间
    getUTCTime() {
      const now = new Date();
      return new Date(now.getTime() + now.getTimezoneOffset() * 60000);
    },

    // 发送消息
    async sendMessage() {
       // 网络断开时阻止发送消息并提示
       if (this.networkStatus !== 'online') {
        this.$message({
          message: this.$t("chat.networkError") || "网络连接已断开，无法发送消息",
          type: "error",
          showClose: true
        });
        return;
      }


      if (!this.inputMessage.trim() || !this.currentContact || this.sending)
        return;

      const messageContent = this.inputMessage.trim();
      this.inputMessage = "";
      this.sending = true;

      try {
        // === 新增：增强连接状态检查 ===
        const connectionCheck = await this.checkAndEnsureConnection();
        if (!connectionCheck) {
          console.log("客服连接检查失败，无法发送消息");
          this.sending = false;
          // === 修复：连接失败时恢复输入内容 ===
          this.inputMessage = messageContent;
          return;
        }

        // 正确设置接收者类型
        const receiveUserType =
          this.currentContact.sendUserType !== undefined
            ? this.currentContact.sendUserType
            : 1; // 默认登录用户

        const message = {
          content: messageContent,
          type: 1, // 1 表示文字消息
          email: this.currentContact.name,
          receiveUserType: receiveUserType,
          roomId: this.currentContactId,
        };

        // 发送消息到服务器
        this.stompClient.send(
          "/point/send/message/to/user",
          {},
          JSON.stringify(message)
        );

        // === 修复：立即添加消息到本地聊天记录，避免快速发送时消息不显示 ===
        const currentTime = new Date().toISOString();
        const localMessageId = `local_${Date.now()}_${Math.random()
          .toString(36)
          .substr(2, 9)}`;

        console.log("📤 发送消息 - 立即添加到本地:", {
          currentContactId: this.currentContactId,
          currentContactName: this.currentContact?.name,
          messageContent: messageContent,
          currentTime: currentTime,
          localMessageId: localMessageId,
        });

        // 立即添加消息到本地聊天记录
        this.addMessageToChat(
          {
            id: localMessageId, // 使用临时ID，服务器回传时会更新
            sender: this.$t("chat.my") || "我",
            avatar: "iconfont icon-icon28",
            content: messageContent,
            time: currentTime,
            isSelf: true,
            isImage: false,
            type: 1,
            roomId: this.currentContactId,
            isLocalMessage: true, // 标记为本地消息
          },
          true
        ); // 标记为用户主动发送的消息

        // 发送消息后立即更新联系人时间
        this.updateContactLastMessage({
          roomId: this.currentContactId,
          content: messageContent,
          isImage: false,
          time: currentTime,
        });

        // 重置当前聊天室的未读消息数
        const contact = this.contacts.find(
          (c) => c.roomId === this.currentContactId
        );
        if (contact) {
          contact.unread = 0;
        }

        this.sending = false;

        this.$nextTick(() => {
          this.scrollToBottom();
        });
      } catch (error) {
        console.error("客服发送消息失败:", error);
        this.sending = false;

        // === 新增：处理特定错误类型 ===
        if (this.isConnectionError(error)) {
          console.log("检测到客服连接错误，开始重连...");
          this.handleConnectionErrorInSend(error);
        } else {
          // 检查是否是Socket特定错误
          const { code } = this.parseSocketError(error);
          if (["1020", "1021", "1022", "1023"].includes(code)) {
            // 如果是Socket特定错误，不重复处理，因为连接错误处理器会处理
            return;
          }

          // === 优化错误提示：只显示用户需要知道的错误 ===
          console.error("💬 客服发送消息错误详情:", error);

          // 仅在明确需要用户操作时才显示提示
          if (
            error.message &&
            (error.message.includes("connection") ||
              error.message.includes("WebSocket") ||
              error.message.includes("STOMP"))
          ) {
            console.log("🔄 发送失败，触发自动重连机制");
            // 连接错误会被自动处理，不需要用户提示
          } else {
            // 其他错误可能需要用户重试，但减少提示频率
            console.error("💬 发送消息失败，需要用户重试");
            // 只在非连接错误时才提示用户
            this.$message.error(this.$t("chat.failInSend") || "发送失败，请重试");
          }
        }
      }
    },
    //换行消息显示处理
    formatMessageContent(content) {
      if (!content) return "";
      // 防止XSS，建议先做转义（如有需要）
      return content.replace(/\n/g, "<br>");
    },

    // 订阅个人消息队列
    subscribeToPersonalMessages() {
      if (!this.stompClient || !this.wsConnected) return;
      this.stompClient.subscribe(
        `/user/queue/${this.userEmail}`,
        this.handleIncomingMessage
      );
    },

    // 处理接收到的消息
    async handleIncomingMessage(message) {
      try {
        // === 收到消息说明连接正常工作，标记为已验证并更新活动时间 ===
        console.log("🎉 客服收到消息，标记连接已验证");
        this.markConnectionVerified();
        this.updateLastActivityTime(); // 收到消息也是一种活动
        this.lastHeartbeatTime = Date.now(); // 更新心跳时间

        const msg = JSON.parse(message.body);
        console.log("客服收到的消息", msg);

        // === 修复：处理后端返回的时间格式 ===
        const serverTime = msg.createTime || msg.sendTime;
        let formattedTime;

        if (serverTime) {
          if (typeof serverTime === "string" && serverTime.includes("T")) {
            // 后端返回的标准格式 "2025-06-12T02:22:39"，直接使用
            formattedTime = serverTime;
          } else if (
            typeof serverTime === "number" ||
            /^\d+$/.test(serverTime)
          ) {
            // 如果是时间戳，转换为ISO字符串
            formattedTime = new Date(parseInt(serverTime)).toISOString();
          } else {
            // 其他情况尝试解析
            formattedTime = new Date(serverTime).toISOString();
          }
        } else {
          // 如果没有服务器时间，使用本地时间的ISO格式
          formattedTime = new Date().toISOString();
        }

        const messageData = {
          id: msg.id,
          sender:
            msg.sendUserType === this.userType &&
            msg.sendEmail === this.userEmail
              ? this.$t("chat.my") || "我"
              : msg.sendEmail || this.$t("chat.unknownSender") || "未知发送者",
          avatar:
            msg.sendUserType === 2
              ? "iconfont icon-icon28"
              : "iconfont icon-user",
          content: msg.content,
          time: formattedTime,
          isSelf:
            msg.sendUserType === this.userType &&
            msg.sendEmail === this.userEmail,
          isImage: msg.type === 2,
          type: msg.type,
          roomId: msg.roomId,
          sendUserType: msg.sendUserType,
          isCreate: msg.isCreate,
          clientReadNum: msg.clientReadNum,
        };

        // === 处理回环消息：如果是自己发送的消息，检查是否为本地消息的服务器确认 ===
        if (messageData.isSelf) {
          const roomMessages = this.messages[messageData.roomId] || [];

          // 查找是否有对应的本地消息（相同内容且时间接近）
          const localMessageIndex = roomMessages.findIndex((msg) => {
            if (!msg.isLocalMessage || msg.content !== messageData.content)
              return false;

            const localTime = new Date(msg.time).getTime();
            const serverTime = new Date(messageData.time).getTime();
            const timeDiff = Math.abs(serverTime - localTime);

            // 如果时间差在30秒内，认为是同一条消息
            return timeDiff < 30000;
          });

          if (localMessageIndex !== -1) {
            // 找到对应的本地消息，更新为服务器消息
            // 更新消息ID和移除本地标记
            this.$set(roomMessages, localMessageIndex, {
              ...roomMessages[localMessageIndex],
              id: messageData.id,
              time: messageData.time, // 使用服务器时间
              isLocalMessage: false, // 移除本地标记
            });

            return; // 不需要添加新消息
          }

          // 如果没找到对应的本地消息，检查是否重复
          const isDuplicate = this.checkDuplicateMessage(messageData);
          if (isDuplicate) {
            return;
          }
        }

        // 更新或创建聊天室
        const existingContact = this.contacts.find(
          (c) => c.roomId === messageData.roomId
        );

        if (!existingContact) {
          // 如果聊天室不存在，创建新的聊天室
          const newContact = {
            roomId: messageData.roomId,
            name: messageData.sender,
            lastMessage: messageData.isImage
              ? this.$t(`chat.picture2`) || "[图片]"
              : messageData.content,
            lastTime: messageData.time, // 直接使用 createTime
            unread: messageData.isSelf ? 0 : 1, // 如果是自己发送的，不增加未读数
            important: false,
            isGuest: msg.sendUserType === 0,
            sendUserType: messageData.sendUserType,
            isManualCreated: true,
          };

          // 不使用unshift，而是添加到数组中，让排序决定位置
          this.contacts.push(newContact);
          this.$set(this.messages, messageData.roomId, []);
        } else {
          // 如果聊天室已存在，更新最后一条消息和时间
          existingContact.lastMessage = messageData.isImage
            ? this.$t(`chat.picture2`) || "[图片]"
            : messageData.content;
          existingContact.lastTime = messageData.time; // 直接使用 createTime
        }

        // 添加消息到聊天记录
        if (!this.messages[messageData.roomId]) {
          this.$set(this.messages, messageData.roomId, []);
        }

        this.messages[messageData.roomId].push({
          id: messageData.id,
          sender: messageData.sender,
          avatar: messageData.avatar,
          content: messageData.content,
          time: messageData.time,
          isSelf: messageData.isSelf,
          isImage: messageData.isImage,
          type: messageData.type,
          roomId: messageData.roomId,
        });

        // 智能排序：只在检测到顺序混乱时才排序
        if (this.needsResort(this.messages[messageData.roomId])) {
          this.messages[messageData.roomId] = this.sortMessages(
            this.messages[messageData.roomId]
          );
        }

        // === 优化未读数逻辑 ===
        if (messageData.roomId === this.currentContactId) {
          if (this.userViewHistory) {
            // 正在查看历史，不清零未读数，显示clientReadNum
            const contact = this.contacts.find(
              (c) => c.roomId === messageData.roomId
            );
            if (contact) {
              contact.unread =
                messageData.clientReadNum || contact.unread + 1 || 1;
              this.setUnreadCount(messageData.roomId, contact.unread);
            }
          } else {
            // 在底部，自动已读
            await this.markMessagesAsRead(messageData.roomId);
          }
        } else {
          // 非当前会话，未读数递增
          if (!messageData.isSelf) {
            const contact = this.contacts.find(
              (c) => c.roomId === messageData.roomId
            );
            if (contact) {
              contact.unread =
                messageData.clientReadNum || contact.unread + 1 || 1;
              this.setUnreadCount(messageData.roomId, contact.unread);
            }
          }
        }

        // 重新排序联系人列表
        this.sortContacts();
      } catch (error) {
        console.error("处理新消息失败:", error);
      }
    },
    // 处理联系人列表滚动
    handleContactListScroll(e) {
      const container = e.target;
      // 判断是否滚动到底部（允许2px的误差）
      if (
        container.scrollHeight - container.scrollTop - container.clientHeight <
        2
      ) {
        this.loadMoreContacts();
      }
    },

    // 加载更多联系人
    async loadMoreContacts() {
      if (this.isLoadingMoreContacts) return;

      const lastContact = this.contacts[this.contacts.length - 1];
      if (!lastContact) return;

      this.isLoadingMoreContacts = true;

      try {
        const formatDateTime = (date) => {
          if (!date) return null;
          const d = new Date(date);
          const year = d.getFullYear();
          const month = String(d.getMonth() + 1).padStart(2, "0");
          const day = String(d.getDate()).padStart(2, "0");
          const hours = String(d.getHours()).padStart(2, "0");
          const minutes = String(d.getMinutes()).padStart(2, "0");
          const seconds = String(d.getSeconds()).padStart(2, "0");
          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
        };

        const requestData = {
          sendDateTime: formatDateTime(lastContact.lastTime),
          userType: 2,
          email: this.userEmail,
        };

        const response = await getRoomList(requestData);

        if (response?.code === 200) {
          const newContacts = response.rows.map((room) => {
            const existingContact = this.contacts.find(
              (c) => c.roomId === room.id
            );
            const manualRoom = this.manualCreatedRooms.find(
              (c) => c.roomId === room.id
            );

            const isImportant =
              room.flag === 1
                ? true
                : room.flag === 0
                ? false
                : room.important === 1
                ? true
                : existingContact
                ? existingContact.important
                : false;

            // === 修复：处理服务器返回的时间格式 ===
            const serverTime = room.lastUserSendTime;
            let lastTime;

            if (serverTime) {
              if (typeof serverTime === "string" && serverTime.includes("T")) {
                // 后端返回的标准格式，直接使用
                lastTime = serverTime;
              } else if (
                typeof serverTime === "number" ||
                /^\d+$/.test(serverTime)
              ) {
                // 时间戳格式，转换为ISO字符串
                lastTime = new Date(parseInt(serverTime)).toISOString();
              } else {
                // 其他格式，尝试解析
                lastTime = new Date(serverTime).toISOString();
              }
            } else {
              // 如果没有服务器时间，使用本地时间
              lastTime = new Date().toISOString();
            }

            return {
              roomId: room.id,
              name: room.userEmail || this.$t(`chat.Unnamed`) || "未命名聊天室",
              avatar: this.getDefaultAvatar(
                room.roomName || this.$t(`chat.Unnamed`) || "未命名聊天室"
              ),
              lastMessage:
                room.lastMessage ||
                (existingContact
                  ? existingContact.lastMessage
                  : this.$t(`chat.noNewsAtTheMoment`) || "暂无消息"),
              lastTime: lastTime,
              unread: existingContact?.unread ?? room.clientReadNum ?? 0,
              important: isImportant,
              isManualCreated: manualRoom ? true : false,
              sendUserType: room.sendUserType,
              isGuest: room.sendUserType === 0,
            };
          });

          const uniqueNewContacts = newContacts.filter(
            (newContact) =>
              !this.contacts.some(
                (existingContact) =>
                  existingContact.roomId === newContact.roomId
              )
          );

          if (uniqueNewContacts.length > 0) {
            this.contacts = [...this.contacts, ...uniqueNewContacts];
            this.sortContacts();
          }
        } else {
          this.$message({
            message: this.$t("chat.contactFailed") || "加载更多联系人失败",
            type: "error",
            duration: 3000,
            showClose: true,
          });
        }
      } catch (error) {
        console.error("5858", error);
      } finally {
        this.isLoadingMoreContacts = false;
      }
    },
    // 处理新聊天室创建
    handleNewChatRoom(messageData) {
      // 检查是否已存在该聊天室
      const existingContact = this.contacts.find(
        (c) => c.roomId === messageData.roomId
      );

      if (!existingContact) {
        // 创建新的聊天室对象
        const newContact = {
          roomId: messageData.roomId,
          name: messageData.sender,
          // 修改这里：使用实际收到的消息内容作为最后一条消息
          lastMessage: messageData.isImage
            ? this.$t(`chat.picture2`) || "[图片]"
            : messageData.content,
          lastTime: messageData.time,
          unread: 1,
          important: false,
          isGuest: messageData.sendUserType === 0,
          sendUserType: messageData.sendUserType,
          isManualCreated: true,
          clientReadNum: messageData.clientReadNum,
        };

        // 添加到聊天列表
        this.contacts.push(newContact);

        // 初始化该聊天室的消息数组
        this.$set(this.messages, messageData.roomId, []);

        // 将当前消息添加到聊天记录中
        this.messages[messageData.roomId].push({
          id: messageData.id,
          sender: messageData.sender,
          avatar:
            messageData.sendUserType === 2
              ? "iconfont icon-icon28"
              : "iconfont icon-user",
          content: messageData.content,
          time: messageData.time,
          isSelf: false,
          isImage: messageData.type === 2,
          type: messageData.type,
          roomId: messageData.roomId,
        });

        // 新聊天室的首条消息通常不需要排序，但保险起见检查一下
        if (this.needsResort(this.messages[messageData.roomId])) {
          this.messages[messageData.roomId] = this.sortMessages(
            this.messages[messageData.roomId]
          );
        }

        // 保存到手动创建的聊天室列表
        this.manualCreatedRooms.push(newContact);
        this.saveManualCreatedRooms();

        // 重新排序联系人列表
        this.sortContacts();
      }
    },

    saveManualCreatedRooms() {
      localStorage.setItem(
        "manualCreatedRooms",
        JSON.stringify(this.manualCreatedRooms)
      );
    },

    // 从 localStorage 加载手动创建的聊天室
    async loadManualCreatedRooms() {
      try {
        const savedRooms = localStorage.getItem("manualCreatedRooms");
        if (savedRooms) {
          this.manualCreatedRooms = JSON.parse(savedRooms);

          // 将手动创建的聊天室添加到当前联系人列表
          for (const room of this.manualCreatedRooms) {
            const exists = this.contacts.find((c) => c.roomId === room.roomId);
            if (!exists) {
              this.contacts.push({
                ...room,
                lastTime: room.lastTime || new Date().toISOString(),
              });

              // 初始化消息数组
              if (!this.messages[room.roomId]) {
                this.$set(this.messages, room.roomId, []);
                // 如果需要,可以在这里加载该聊天室的历史消息
                await this.loadMessages(room.roomId);
              }
            }
          }
          this.sortContacts();
        }
      } catch (error) {
        console.error("加载手动创建的聊天室失败:", error);
      }
    },

    // 添加新方法：创建新聊天室
    async createNewChatRoom(messageData) {
      try {
        // 调用后端 API 创建新的聊天室
        const response = await createChatRoom({
          userEmail: messageData.sender,
          userType: messageData.sendUserType,
        });

        if (response && response.code === 200) {
          const newRoom = {
            userEmail: messageData.sender,
            roomId: response.data.roomId,
            lastMessage: messageData.content,
            lastMessageTime: messageData.time,
            unreadCount: messageData.clientReadNum || 0,
            userType: messageData.sendUserType,
          };

          this.chatRooms.unshift(newRoom);
          return newRoom;
        }
      } catch (error) {
        console.error("创建新聊天室失败:", error);
        throw error;
      }
    },
    // 更新聊天室列表
    updateChatRoomList(messageData) {
      const roomIndex = this.chatRooms.findIndex(
        (room) => room.roomId === messageData.roomId
      );

      if (roomIndex !== -1) {
        // 更新现有聊天室信息
        this.chatRooms[roomIndex] = {
          ...this.chatRooms[roomIndex],
          lastMessage: messageData.content,
          lastMessageTime: messageData.time,
          unreadCount:
            messageData.clientReadNum || this.chatRooms[roomIndex].unreadCount,
        };

        // 将更新的聊天室移到列表顶部
        const updatedRoom = this.chatRooms.splice(roomIndex, 1)[0];
        this.chatRooms.unshift(updatedRoom);
      }
    },
    // 修改标记为已读方法，添加参数支持
    async markMessagesAsRead(roomId = this.currentContactId) {
      if (!roomId) return;

      try {
        const data = {
          roomId: roomId,
          userType: 2,
        };

        const response = await getReadMessage(data);

        if (response && response.code === 200) {
          console.log("消息已标记为已读");

          // 更新联系人列表中的未读计数
          const contact = this.contacts.find((c) => c.roomId === roomId);
          if (contact) {
            contact.unread = 0;
            this.setUnreadCount(roomId, 0);
          }
        } else {
          console.warn("标记消息已读失败", response);
        }
      } catch (error) {
        console.error("标记消息已读出错:", error);
      }
    },

    // 解析 UTC 时间字符串
    parseUTCTime(timeStr) {
      if (!timeStr) return new Date(); // 如果没有时间，返回当前时间
      try {
        return new Date(timeStr); // 直接解析 UTC 时间
      } catch (error) {
        console.error("解析时间错误:", error);
        return new Date();
      }
    },

    // 获取聊天室列表
    async fetchRoomList() {
      try {
        this.loadingRooms = true;
        const requestData = {
          lastTime: null,
          userType: 2,
          email: this.userEmail,
        };

        const response = await getRoomList(requestData);
        if (response?.code === 200) {
          const newContacts = response.rows.map((room) => {
            const existingContact = this.contacts.find(
              (c) => c.roomId === room.id
            );

            const manualRoom = this.manualCreatedRooms.find(
              (c) => c.roomId === room.id
            );

            const isImportant =
              room.flag === 1
                ? true
                : room.flag === 0
                ? false
                : room.important === 1
                ? true
                : existingContact
                ? existingContact.important
                : false;

            // === 修复：处理服务器返回的时间格式 ===
            const serverTime = room.lastUserSendTime || room.createTime;
            let lastTime;

            if (serverTime) {
              if (typeof serverTime === "string" && serverTime.includes("T")) {
                // 后端返回的标准格式，直接使用
                lastTime = serverTime;
              } else if (
                typeof serverTime === "number" ||
                /^\d+$/.test(serverTime)
              ) {
                // 时间戳格式，转换为ISO字符串
                lastTime = new Date(parseInt(serverTime)).toISOString();
              } else {
                // 其他格式，尝试解析
                lastTime = new Date(serverTime).toISOString();
              }
            } else {
              // 如果没有服务器时间，使用本地时间
              lastTime = new Date().toISOString();
            }

            return {
              roomId: room.id,
              name: room.userEmail || this.$t(`chat.Unnamed`) || "未命名聊天室",
              avatar: this.getDefaultAvatar(
                room.roomName || this.$t(`chat.Unnamed`) || "未命名聊天室"
              ),
              lastMessage:
                room.lastMessage ||
                (existingContact
                  ? existingContact.lastMessage
                  : this.$t(`chat.noNewsAtTheMoment`) || "暂无消息"),
              lastTime: lastTime, // 已经确保不为空
              unread: existingContact?.unread ?? room.clientReadNum ?? 0,
              important: isImportant,
              isManualCreated: manualRoom ? true : false,
              sendUserType: room.sendUserType,
              isGuest: room.sendUserType === 0,
            };
          });

          this.contacts = newContacts;
          this.sortContacts();
        }
      } catch (error) {
        // 判断是否为主动取消
        if (
          error &&
          (error.message === "canceled" ||
            error.message === "Cancel" ||
            error.message?.includes("canceled"))
        ) {
          // 主动取消的请求，不提示
          return;
        }
        console.error("获取聊天室列表异常:", error);
        this.$message({
          message: this.$t("chat.listException") || "获取聊天室列表异常",
          type: "error",
          duration: 3000,
          showClose: true,
        });
      } finally {
        this.loadingRooms = false;
      }
    },

    // 加载更多历史消息 - 简化版本
    async loadMoreHistory() {
      if (!this.currentContactId) return;

      // 获取当前已加载的消息列表
      const currentMsgs = this.messages[this.currentContactId] || [];

      // 检查是否有历史消息记录
      if (currentMsgs.length === 0) {
        this.hasMoreHistory = false;
        this.noMoreHistoryMessage =
          this.$t("chat.noMoreHistory") || "没有更多历史消息";
        return;
      }

      // 获取ID最小的消息（最早的消息）作为查询参数
      const earliestMessage = this.getEarliestMessage(currentMsgs);
      if (!earliestMessage || !earliestMessage.id) {
        this.hasMoreHistory = false;
        this.noMoreHistoryMessage =
          this.$t("chat.noMoreHistory") || "没有更多历史消息";
        return;
      }

      // 使用最早消息的id作为查询参数
      this.history7Params.id = earliestMessage.id;
      this.history7Params.roomId = this.currentContactId;
      this.history7Params.email = this.userEmail;

      try {
        this.messagesLoading = true;
        const response = await getHistory7(this.history7Params);

        // 简化：如果接口返回数据为空，就显示没有更多历史消息
        if (
          !response ||
          response.code !== 200 ||
          !response.data ||
          response.data.length === 0
        ) {
          this.hasMoreHistory = false;
          this.noMoreHistoryMessage =
            this.$t("chat.noMoreHistory") || "没有更多历史消息";
          return;
        }

        // 过滤当前聊天室的消息
        const filteredMessages = response.data.filter((msg) => {
          return (
            msg.roomId == this.currentContactId ||
            String(msg.roomId) === String(this.currentContactId)
          );
        });

        // 如果过滤后没有消息，显示没有更多历史消息
        if (filteredMessages.length === 0) {
          this.hasMoreHistory = false;
          this.noMoreHistoryMessage =
            this.$t("chat.noMoreHistory") || "没有更多历史消息";
          return;
        }

        let moreMessages = filteredMessages.map((msg) => ({
          id: msg.id,
          sender:
            msg.isSelf === 1
              ? this.$t("chat.my") || "我"
              : msg.sendEmail || this.$t("chat.unknownSender") || "未知发送者",
          avatar: "iconfont icon-icon28",
          content: msg.content,
          time: msg.createTime,
          isSelf: msg.isSelf === 1,
          isImage: msg.type === 2,
          isRead: msg.isRead === 1,
          type: msg.type,
          roomId: msg.roomId,
        }));

        // 过滤掉重复的消息
        const currentMessageIds = (
          this.messages[this.currentContactId] || []
        ).map((m) => m.id);
        const uniqueMessages = moreMessages.filter(
          (msg) => !currentMessageIds.includes(msg.id)
        );

        // 如果去重后没有新消息，显示没有更多历史消息
        if (uniqueMessages.length === 0) {
          this.hasMoreHistory = false;
          this.noMoreHistoryMessage =
            this.$t("chat.noMoreHistory") || "没有更多历史消息";
          return;
        }

        // 使用去重后的消息
        moreMessages = this.sortMessages(uniqueMessages);

        // 追加到当前消息列表前面
        const oldMessages = this.messages[this.currentContactId] || [];
        this.$set(this.messages, this.currentContactId, [
          ...moreMessages,
          ...oldMessages,
        ]);
      } catch (error) {
        console.error("加载更多历史消息失败:", error);
        this.$message.error(
          this.$t("chat.historicalFailure") || "加载更多历史消息失败"
        );
      } finally {
        this.messagesLoading = false;
      }
    },

    // 选择联系人
    async selectContact(roomId) {
      if (this.currentContactId === roomId) return;

      // === 新增：更新活动时间 ===
      this.updateLastActivityTime();

      try {
        this.messagesLoading = true; // 显示加载状态
        this.currentContactId = roomId;
        this.userViewHistory = false;

        // 简化：切换聊天室时重置历史消息状态，显示加载按钮
        this.hasMoreHistory = true;
        this.noMoreHistoryMessage = "";

        // 重置分页参数
        this.history7Params = {
          id: "", // 首次加载为空
          // pageNum: 1, // 首次页码为1
          roomId: roomId,
          userType: 2,
        };

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

        // 标记消息为已读
        await this.markMessagesAsRead(roomId);
      } catch (error) {
        console.error("选择联系人失败:", error);
        this.$message({
          message: this.$t("chat.loadFailed") || "加载失败",
          type: "error",
          duration: 3000,
          showClose: true,
        });
      } finally {
        this.messagesLoading = false;
        // 滚动到底部
        this.$nextTick(() => {
          this.scrollToBottom();
        });
      }
    },
    //判断是否在聊天框底部
    isAtBottom() {
      const container = this.$refs.messageContainer;
      if (!container) return true;
      // 允许2px误差
      return (
        container.scrollHeight - container.scrollTop - container.clientHeight <
        2
      );
    },

    // 加载聊天消息
    async loadMessages(roomId) {
      if (!roomId) return;

      try {
        console.log(this.userEmail, "加载聊天消息");
        this.history7Params.email = this.userEmail;
        this.history7Params.roomId = roomId;
        const response = await getHistory7(this.history7Params);

        if (response?.code === 200 && response.data) {
          // 处理消息数据
          let roomMessages = response.data
            .filter((msg) => msg.roomId == roomId)
            .map((msg) => ({
              id: msg.id,
              sender:
                msg.isSelf === 1
                  ? this.$t("chat.my") || "我"
                  : msg.sendEmail ||
                    this.$t("chat.unknownSender") ||
                    "未知发送者",
              avatar:
                msg.sendUserType == 2
                  ? "iconfont icon-icon28"
                  : "iconfont icon-user",
              content: msg.content,
              time: msg.createTime,
              isSelf: msg.isSelf === 1,
              isImage: msg.type === 2,
              isRead: msg.isRead === 1,
              type: msg.type,
              roomId: msg.roomId,
              sendUserType: msg.sendUserType,
            }));

          // 使用智能排序（ID为主，时间为辅）
          roomMessages = this.sortMessages(roomMessages);

          // 更新消息列表
          this.$set(this.messages, roomId, roomMessages);

          // 更新联系人的最后消息时间（使用最新消息的时间）
          const contact = this.contacts.find((c) => c.roomId === roomId);
          if (contact && roomMessages.length > 0) {
            const latestMessageTime =
              roomMessages[roomMessages.length - 1].time;
            contact.lastTime = latestMessageTime;
          }

          // 更新联系人的未读状态
          if (contact) {
            contact.unread = 0;
          }

          // 简化：初始加载时不需要特殊处理，保持默认状态
        } else {
          // 如果没有消息数据，初始化为空数组
          this.$set(this.messages, roomId, []);

          if (response?.code !== 200) {
            this.$message({
              message: this.$t("chat.recordFailed") || "加载聊天记录失败",
              type: "error",
              duration: 3000,
              showClose: true,
            });
          }
        }
      } catch (error) {
        console.error("加载消息异常:", error);
        // this.$message({
        //   message: this.$t("chat.messageException") || "加载消息异常",
        //   type: "error",
        //   duration: 3000,
        //   showClose: true,
        // });
        this.$set(this.messages, roomId, []);
      }
    },

    /**
     * 检查是否为重复消息（用于处理回环消息）
     * @param {Object} messageData - 消息数据
     * @returns {boolean} 是否为重复消息
     */
    checkDuplicateMessage(messageData) {
      const roomMessages = this.messages[messageData.roomId];
      if (!roomMessages) return false;

      // 检查是否已存在相同ID的消息
      if (
        messageData.id &&
        roomMessages.some((msg) => msg.id === messageData.id)
      ) {
        console.log("🔍 发现相同ID的消息，判定为重复:", messageData.id);
        return true;
      }

      // 检查最近30秒内是否有相同内容的消息（缩短时间窗口，提高准确性）
      const thirtySecondsAgo = Date.now() - 30 * 1000;
      const serverMsgTime = new Date(messageData.time).getTime();

      return roomMessages.some((msg) => {
        // 跳过本地消息的检查，因为本地消息会被服务器消息替换
        if (msg.isLocalMessage) return false;

        if (!msg.isSelf || msg.content !== messageData.content) return false;

        const msgTime = new Date(msg.time).getTime();

        // 检查时间差是否在合理范围内（30秒内且内容完全匹配）
        const timeDiff = Math.abs(msgTime - serverMsgTime);
        const isRecent = msgTime > thirtySecondsAgo;
        const isTimeClose = timeDiff < 30000; // 30秒内

        if (isRecent && isTimeClose) {
          console.log("🔍 发现重复消息:", {
            existingTime: msg.time,
            newTime: messageData.time,
            timeDiff: timeDiff,
            content: messageData.content.substring(0, 50),
          });
          return true;
        }

        return false;
      });
    },

    /**
     * 添加消息到聊天记录
     * @param {Object} messageData - 消息数据
     * @param {boolean} isSentByUser - 是否为用户主动发送的消息，影响滚动行为
     */
    addMessageToChat(messageData, isSentByUser = false) {
      const roomId = messageData.roomId || this.currentContactId;
      if (!this.messages[roomId]) {
        this.$set(this.messages, roomId, []);
      }
      // === ChatWidget式push，不做本地排序 ===
      const message = {
        id: messageData.id || Date.now(),
        sender: messageData.sender,
        avatar:
          messageData.avatar ||
          (messageData.isSelf ? "iconfont icon-icon28" : "iconfont icon-user"),
        content: messageData.content,
        time: messageData.time || new Date(),
        isSelf: messageData.isSelf,
        isImage: messageData.isImage || false,
        type: messageData.type || 1,
        roomId: roomId,
        isRead: messageData.isRead || false,
        isLocalMessage: messageData.isLocalMessage || false,
      };
      this.messages[roomId].push(message);
      // 更新最后一条消息
      this.updateContactLastMessage({
        roomId: roomId,
        content: message.isImage
          ? this.$t("chat.picture2") || "[图片]"
          : message.content,
        isImage: message.isImage,
        time: message.time,
      });
      // 滚动逻辑同原实现
      if (roomId === this.currentContactId) {
        if (isSentByUser) {
          this.$nextTick(() => {
            this.scrollToBottom(true);
            this.userViewHistory = false;
          });
        } else if (!this.userViewHistory) {
          this.$nextTick(() => {
            this.scrollToBottom();
          });
        }
      }
    },
    // 处理图片上传
    async handleImageUpload(event) {
      // 检查是否有选中的联系人和 WebSocket 连接
      if (!this.currentContact) {
        this.$message({
          message: this.$t("chat.chooseFirst") || "请先选择联系人",
          type: "error",
          duration: 3000,
          showClose: true,
        });
        return;
      }

      if (!this.stompClient || !this.isWebSocketConnected) {
        this.$message({
          message:
            this.$t("chat.chatDisconnected") ||
            "聊天连接已断开，请刷新页面重试",
          type: "error",
          duration: 3000,
          showClose: true,
        });
        return;
      }

      const file = event.target.files[0];
      if (!file) return;

      // 检查是否为图片
      if (!file.type.startsWith("image/")) {
        this.$message({
          message: this.$t("chat.onlyImages") || "只能上传图片文件!",
          type: "error",
          duration: 3000,
          showClose: true,
        });
        return;
      }

      // 检查文件大小 (限制为5MB)
      const maxSize = 5 * 1024 * 1024;
      if (file.size > maxSize) {
        this.$message({
          message: this.$t("chat.imageTooLarge") || "图片大小不能超过5MB!",
          type: "error",
          duration: 3000,
          showClose: true,
        });
        return;
      }

      this.sending = true;

      try {
        // === 移除上传提示：上传通常很快，不需要提示 ===
        console.log("📤 正在上传图片...");
        // 创建 FormData
        const formData = new FormData();
        formData.append("file", file);

        // 上传图片
        const response = await this.$axios({
          method: "post",
          url: `${process.env.VUE_APP_BASE_API}pool/ticket/uploadFile`,
          data: formData,
          headers: {
            "Content-Type": "multipart/form-data",
          },
        });

        if (response.data.code === 200) {
          const imageUrl = response.data.data.url;

          // 直接发送图片消息到服务器
          this.sendImageMessage(imageUrl);

          console.log("✅ 图片发送成功");
          // === 移除发送成功提示：图片已在聊天中显示，不需要额外提示 ===
        } else {
          throw new Error(response.data.msg || "上传失败");
        }
      } catch (error) {
        console.error("上传图片异常:", error);
        this.$message({
          message: this.$t("chat.pictureFailed") || "图片发送失败，请重试",
          type: "error",
          duration: 3000,
          showClose: true,
        });
      } finally {
        this.sending = false;
        // 清空文件选择器
        this.$refs.imageInput.value = "";
      }
    },

    // 发送图片消息
    async sendImageMessage(imageUrl) {
      try {
        // === 新增：检查连接状态 ===
        const connectionCheck = await this.checkAndEnsureConnection();
        if (!connectionCheck) {
          console.log("客服图片发送连接检查失败");
          // === 减少错误提示：连接错误会自动重连 ===
          console.error("❌ 连接异常，图片发送失败");
          return;
        }

        const message = {
          type: 2, // 2 表示图片消息
          email: this.currentContact.name,
          receiveUserType: this.currentContact.sendUserType || 1,
          roomId: this.currentContactId,
          content: imageUrl, // 使用接口返回的url
        };

        this.stompClient.send(
          "/point/send/message/to/user",
          {},
          JSON.stringify(message)
        );

        // === 修复：立即添加图片消息到本地聊天记录 ===
        const currentTime = new Date().toISOString();
        const localImageId = `local_img_${Date.now()}_${Math.random()
          .toString(36)
          .substr(2, 9)}`;

        console.log("📤 发送图片 - 立即添加到本地:", {
          currentContactId: this.currentContactId,
          imageUrl: imageUrl,
          currentTime: currentTime,
          localImageId: localImageId,
        });

        // 立即添加图片消息到本地聊天记录
        this.addMessageToChat(
          {
            id: localImageId, // 使用临时ID
            sender: this.$t("chat.my") || "我",
            avatar: "iconfont icon-icon28",
            content: imageUrl,
            time: currentTime,
            isSelf: true,
            isImage: true,
            type: 2,
            roomId: this.currentContactId,
            isLocalMessage: true, // 标记为本地消息
          },
          true
        ); // 标记为用户主动发送的消息

        this.updateContactLastMessage({
          roomId: this.currentContactId,
          content: imageUrl,
          isImage: true,
          time: currentTime,
        });
      } catch (error) {
        console.error("发送图片消息失败:", error);

        // === 新增：处理连接错误 ===
        if (this.isConnectionError(error)) {
          console.log("图片发送时检测到连接错误，开始重连...");
          this.handleConnectionErrorInSend(error);
        } else {
          // === 减少错误提示：只在非连接错误时提示 ===
          console.error("💬 图片发送失败，需要用户重试");
          this.$message.error(this.$t("chat.pictureFailed") || "发送图片消息失败，请重试");
        }
      }
    },

    // 更新联系人最后一条消息
    updateContactLastMessage(message) {
      // 增强查找逻辑：同时支持精确匹配和部分匹配
      let contact = this.contacts.find((c) => c.roomId === message.roomId);

      // 如果找不到，尝试通过名称查找（兼容旧数据）
      if (!contact && typeof message.roomId === "string") {
        contact = this.contacts.find(
          (c) =>
            (c.name && c.name.includes(message.roomId)) ||
            (c.roomId && c.roomId.includes(message.roomId))
        );
      }

      if (contact) {
        const oldTime = contact.lastTime;
        const newTime = message.time || new Date().toISOString();

        // 更新联系人信息
        contact.lastMessage = message.isImage
          ? this.$t("chat.picture2") || "[图片]"
          : message.content;
        contact.lastTime = newTime;

        console.log("⚡ updateContactLastMessage - 执行时间更新:", {
          contactName: contact.name,
          roomId: message.roomId,
          oldTime: oldTime,
          newTime: newTime,
          messageTime: message.time,
          isImage: message.isImage,
          contactsTotal: this.contacts.length,
        });

        // 强制触发Vue响应式更新
        this.$set(contact, "lastTime", newTime);
        this.$set(contact, "lastMessage", contact.lastMessage);

        // 重新排序联系人列表
        this.sortContacts();

        // 强制触发DOM更新
        this.$nextTick(() => {
          this.$forceUpdate();
        });
      } else {
        console.error("❌ updateContactLastMessage - 未找到联系人:", {
          searchRoomId: message.roomId,
          messageContent: message.content,
          allContacts: this.contacts.map((c) => ({
            roomId: c.roomId,
            name: c.name,
            lastTime: c.lastTime,
          })),
        });
      }
    },

    // 增加未读消息计数
    incrementUnreadCount(roomId, readNum = 1) {
      const contact = this.contacts.find((c) => c.roomId === roomId);
      if (contact) {
        // 如果有指定未读数，直接设置，否则增加1
        if (readNum > 1) {
          contact.unread = readNum;
        } else {
          contact.unread = (contact.unread || 0) + 1;
        }
      }
    },

    // 预览图片
    previewImage(imageUrl) {
      this.previewImageUrl = imageUrl;
      this.previewVisible = true;
    },

    // 标记聊天为重要/非重要
    async toggleImportant(roomId, important) {
      if (!roomId) return;

      try {
        // 发送请求，使用 id 和 flag 参数
        const response = await getUpdateRoom({
          id: roomId,
          flag: important ? 1 : 0, // 1代表重要，0代表不重要
        });

        if (response && response.code === 200) {
          // 更新本地数据
          const contact = this.contacts.find((c) => c.roomId === roomId);
          if (contact) {
            contact.important = important;
          }

          // 重新排序联系人列表，使重要的排在前面
          this.sortContacts();

          console.log(important ? "✅ 已标记为重要聊天" : "✅ 已取消重要标记");
          // === 移除标记提示：状态变化在页面上已可见 ===
        } else {
          this.$message({
            message:
              response?.msg || this.$t("chat.markingFailed") || "标记操作失败",
            type: "error",
            duration: 3000,
            showClose: true,
          });
        }
      } catch (error) {
        console.error("标记聊天状态异常:", error);
        // this.$message({
        //   message: this.$t("chat.markingFailed") || "标记操作失败,请重试",
        //   type: "error",
        //   duration: 3000,
        //   showClose: true,
        // });
      }
    },

    /**
     * 解析和标准化时间，确保正确处理UTC时间
     * @param {string|Date|null} timeValue - 时间值
     * @returns {number} - 时间戳，如果无效则返回当前时间
     */
    parseTimeForSort(timeValue) {
      if (!timeValue) {
        // 如果没有时间，使用当前时间（确保新聊天室排在前面）
        return Date.now();
      }

      let timestamp;

      if (typeof timeValue === "string") {
        // 处理UTC时间字符串
        let timeStr = timeValue;

        // 如果时间字符串不包含时区信息，假设它是UTC时间
        if (
          !timeStr.includes("Z") &&
          !timeStr.includes("+") &&
          !timeStr.includes("-")
        ) {
          timeStr += "Z";
        }

        timestamp = new Date(timeStr).getTime();
      } else if (timeValue instanceof Date) {
        timestamp = timeValue.getTime();
      } else {
        // 其他情况使用当前时间
        timestamp = Date.now();
      }

      // 如果解析失败（NaN），使用当前时间
      if (isNaN(timestamp)) {
        timestamp = Date.now();
      }

      return timestamp;
    },

    // 修复所有联系人的时间问题
    fixContactTimes() {
      this.contacts.forEach((contact) => {
        if (!contact.lastTime) {
          const currentTime = new Date().toISOString();
          console.warn("🔧 修复联系人空时间:", {
            contactName: contact.name,
            roomId: contact.roomId,
            fixedTime: currentTime,
          });
          this.$set(contact, "lastTime", currentTime);
        }
      });
    },

    // 根据重要性对联系人列表排序
    sortContacts() {
      // 先修复空时间问题
      this.fixContactTimes();

      // 使用新的智能排序
      this.contacts = this.sortContactsByTime(this.contacts);
    },

    // 滚动到底部
    scrollToBottom(force = false) {
      const container = this.$refs.messageContainer;
      if (!container) return;

      // 使用 nextTick 确保 DOM 更新后再滚动
      this.$nextTick(() => {
        // 添加一个小延时确保内容完全渲染
        setTimeout(() => {
          const scrollOptions = {
            top: container.scrollHeight,
            behavior: force ? "auto" : "smooth",
          };

          try {
            container.scrollTo(scrollOptions);
          } catch (error) {
            // 如果平滑滚动不支持，则直接设置
            container.scrollTop = container.scrollHeight;
          }

          // 滚动完成后隐藏按钮
          if (force) {
            this.showScrollButton = false;
          }
        }, 100);
      });
    },

    // 判断是否显示时间
    showMessageTime(index) {
      // 显示时间的逻辑：第一条消息或距离上一条消息超过5分钟
      if (index === 0) return true;

      const currentMsg = this.currentMessages[index];
      const prevMsg = this.currentMessages[index - 1];

      if (!currentMsg.time || !prevMsg.time) return false;

      const currentTime = new Date(currentMsg.time).getTime();
      const prevTime = new Date(prevMsg.time).getTime();

      const diffMinutes = (currentTime - prevTime) / (1000 * 60);
      return diffMinutes > 5;
    },

    // 格式化消息时间（只做格式化，不做多余转换）
    formatTime(date) {
      if (!date) return "";

      // === 严格遵守用户要求：后端时间直接去掉T，本地时间用toISOString() ===
      let str = "";

      if (typeof date === "string" && date.includes("T")) {
        // 后端返回的时间格式 "2025-06-12T02:22:39"
        // 直接使用，不做转换
        str = date;
      } else if (date instanceof Date) {
        // 本地时间：使用toISOString()方法
        str = date.toISOString();
      } else if (typeof date === "number" || /^\d+$/.test(date)) {
        // 时间戳格式：转换为Date后使用toISOString()
        try {
          const dateObj = new Date(parseInt(date));
          if (!isNaN(dateObj.getTime())) {
            str = dateObj.toISOString();
          } else {
            return String(date);
          }
        } catch (error) {
          return String(date);
        }
      } else {
        // 其他格式：尝试转换为Date对象后使用toISOString()
        try {
          const dateObj = new Date(date);
          if (isNaN(dateObj.getTime())) {
            return String(date);
          }
          str = dateObj.toISOString();
        } catch (error) {
          return String(date);
        }
      }

      const [d, t] = str.split("T");
      if (!t) return str;
      const [hour, minute] = t.split(":");

      // 取当前UTC日期
      const now = new Date();
      const nowUTC = now.toISOString().split("T")[0];
      const msgUTC = d;

      if (nowUTC === msgUTC) {
        return `UTC ${this.$t("chat.today")} ${hour}:${minute}`;
      }

      // 判断昨天
      const yesterdayUTC = new Date(Date.now() - 24 * 60 * 60 * 1000)
        .toISOString()
        .split("T")[0];
      if (yesterdayUTC === msgUTC) {
        return `UTC ${this.$t("chat.yesterday")} ${hour}:${minute}`;
      }

      return `UTC ${d} ${hour}:${minute}`;
    },

    // 格式化最后消息时间（显示年月日和时分）
    formatLastTime(date) {
      if (!date) {
        return ""; // 返回友好的默认值
      }

      try {
        // === 严格遵守用户要求：后端时间直接去掉T，本地时间用toISOString() ===

        if (typeof date === "string" && date.includes("T")) {
          // 后端返回的时间格式 "2025-06-12T02:22:39"
          // 直接去掉T，提取年月日时分，不做任何转换
          const [datePart, timePart] = date.split("T");
          if (datePart && timePart) {
            // 提取时分（去掉秒和毫秒）
            const timeOnly = timePart.split(":").slice(0, 2).join(":");
            // 返回格式：YYYY-MM-DD HH:mm UTC
            return `UTC ${datePart} ${timeOnly}`;
          }
        } else if (date instanceof Date) {
          // 本地时间：使用toISOString()方法
          const timeStr = date.toISOString();
          const [datePart, timePart] = timeStr.split("T");
          if (datePart && timePart) {
            const timeOnly = timePart.split(":").slice(0, 2).join(":");
            return `UTC ${datePart} ${timeOnly}`;
          }
        } else if (typeof date === "number" || /^\d+$/.test(date)) {
          // 时间戳格式：转换为Date后使用toISOString()
          const dateObj = new Date(parseInt(date));
          if (!isNaN(dateObj.getTime())) {
            const timeStr = dateObj.toISOString();
            const [datePart, timePart] = timeStr.split("T");
            if (datePart && timePart) {
              const timeOnly = timePart.split(":").slice(0, 2).join(":");
              return `UTC ${datePart} ${timeOnly}`;
            }
          }
        }

        // 兜底处理：尝试解析为Date对象
        const dateObj = new Date(date);
        if (!isNaN(dateObj.getTime())) {
          const timeStr = dateObj.toISOString();
          const [datePart, timePart] = timeStr.split("T");
          if (datePart && timePart) {
            const timeOnly = timePart.split(":").slice(0, 2).join(":");
            return `UTC ${datePart} ${timeOnly}`;
          }
        }

        return String(date); // 如果都解析失败，返回原始值
      } catch (error) {
        console.error("格式化时间失败:", error);
        return String(date);
      }
    },

    // 获取默认头像
    getDefaultAvatar(name) {
      if (!name) return "";

      // 根据名称生成颜色
      const colors = [
        "#4CAF50",
        "#9C27B0",
        "#FF5722",
        "#2196F3",
        "#FFC107",
        "#607D8B",
        "#E91E63",
      ];
      const index = Math.abs(name.charCodeAt(0)) % colors.length;
      const color = colors[index];

      // 获取名称首字母
      const initial = name.charAt(0).toUpperCase();
      return initial;
      // 生成占位头像URL
    },
    // 处理滚动事件
    handleScroll() {
      const container = this.$refs.messageContainer;
      if (!container) return;
      this.updateLastActivityTime();
      this.showScrollButton = !this.isAtBottom();
      if (this.isAtBottom()) {
        this.userViewHistory = false;
        // 到底部时自动已读
        this.markMessagesAsRead(this.currentContactId);
      } else {
        this.userViewHistory = true;
      }
    },

    // 小时钟加载历史消息(7天前)
    async loadHistory() {
      this.loadingHistory = true;
      this.userViewHistory = true; // 用户主动查看历史
      if (!this.currentContactId) return;

      try {
        this.messagesLoading = true;
        // 获取当前已加载的消息列表
        const currentMsgs = this.messages[this.currentContactId] || [];

        // 检查是否有历史消息记录
        if (currentMsgs.length === 0) {
          this.$message({
            message: this.$t("chat.noMoreHistory") || "没有更多历史消息",
            type: "warning",
            duration: 3000,
            showClose: true,
          });
          return;
        }

        // 获取ID最小的消息（最早的消息）作为查询参数
        const earliestMessage = this.getEarliestMessage(currentMsgs);
        if (!earliestMessage || !earliestMessage.id) {
          this.$message({
            message: this.$t("chat.noMoreHistory") || "没有更多历史消息",
            type: "warning",
            duration: 3000,
            showClose: true,
          });
          return;
        }

        // 使用最早消息的id作为查询参数
        this.history7Params.id = earliestMessage.id;

        console.log("🕐 小时钟加载历史消息 - 使用最早消息ID:", {
          totalMessages: currentMsgs.length,
          earliestMessageId: earliestMessage.id,
          earliestMessageTime: earliestMessage.time,
        });
        this.history7Params.roomId = this.currentContactId;
        this.history7Params.email = this.userEmail;
        const response = await getHistory7(this.history7Params);

        console.log("📡 loadHistory - 小时钟接口响应详情:", {
          responseCode: response?.code,
          hasData: !!response?.data,
          dataLength: response?.data?.length || 0,
          currentContactId: this.currentContactId,
          requestParams: this.history7Params,
        });

        if (response && response.code === 200 && response.data) {
          console.log("📦 loadHistory - 小时钟原始数据:", response.data);

          // 过滤当前聊天室的消息（处理数据类型不匹配问题）
          const filteredHistoryMessages = response.data.filter((msg) => {
            // 支持字符串和数字类型的roomId比较
            return (
              msg.roomId == this.currentContactId ||
              String(msg.roomId) === String(this.currentContactId)
            );
          });

          console.log("🔍 loadHistory - 小时钟过滤后数据:", {
            originalCount: response.data.length,
            filteredCount: filteredHistoryMessages.length,
            targetRoomId: this.currentContactId,
            messageRoomIds: response.data.map((m) => m.roomId).slice(0, 5),
          });

          let historyMessages = filteredHistoryMessages.map((msg) => ({
            id: msg.id,
            sender: msg.sendEmail,
            avatar: "iconfont icon-icon28",
            content: msg.content,
            time: msg.createTime, // 直接用字符串
            isSelf: msg.isSelf === 1,
            isImage: msg.type === 2,
            isRead: msg.isRead === 1,
            type: msg.type,
            roomId: msg.roomId,
          }));

          console.log("🔄 loadHistory - 小时钟处理后消息:", {
            processedCount: historyMessages.length,
            messageIds: historyMessages.map((m) => m.id),
            messageTimes: historyMessages.map((m) => m.time).slice(0, 3),
          });

          // 检查重复消息
          const currentMessageIds = (
            this.messages[this.currentContactId] || []
          ).map((m) => m.id);
          const newHistoryIds = historyMessages.map((m) => m.id);
          const duplicateHistoryIds = newHistoryIds.filter((id) =>
            currentMessageIds.includes(id)
          );

          console.log("🔍 loadHistory - 小时钟重复消息检查:", {
            currentMessageCount: currentMessageIds.length,
            newHistoryCount: newHistoryIds.length,
            duplicateCount: duplicateHistoryIds.length,
            duplicateIds: duplicateHistoryIds,
          });

          // 如果没有获取到新的历史消息
          if (historyMessages.length === 0) {
            console.warn(
              "⚠️ loadHistory - 小时钟过滤后无消息，设置无更多历史状态"
            );
            this.hasMoreHistory = false;
            this.noMoreHistoryMessage =
              this.$t("chat.noMoreHistory") || "没有更多历史消息";
            return;
          }

          // 过滤掉重复的历史消息
          const uniqueHistoryMessages = historyMessages.filter(
            (msg) => !currentMessageIds.includes(msg.id)
          );

          console.log("✂️ loadHistory - 小时钟去重后消息:", {
            originalCount: historyMessages.length,
            uniqueCount: uniqueHistoryMessages.length,
            removedDuplicates:
              historyMessages.length - uniqueHistoryMessages.length,
          });

          // 如果去重后没有新的历史消息
          if (uniqueHistoryMessages.length === 0) {
            console.warn(
              "⚠️ loadHistory - 小时钟去重后无新消息，设置无更多历史状态"
            );
            this.hasMoreHistory = false;
            this.noMoreHistoryMessage =
              this.$t("chat.noMoreHistory") || "没有更多历史消息";
            return;
          }

          // 使用去重后的历史消息
          historyMessages = uniqueHistoryMessages;

          historyMessages = this.sortMessages(historyMessages);
          const currentMessages = this.messages[this.currentContactId] || [];

          this.$set(this.messages, this.currentContactId, [
            ...historyMessages,
            ...currentMessages,
          ]);

          console.log("✅ loadHistory - 小时钟历史消息加载完成:", {
            loadedCount: historyMessages.length,
            totalCount: this.messages[this.currentContactId].length,
          });
          // === 移除加载成功提示：消息已显示在聊天中 ===
        } else {
          console.warn(
            "⚠️ loadHistory - 小时钟接口返回无数据，设置无更多历史状态"
          );
          this.hasMoreHistory = false;
          this.noMoreHistoryMessage =
            this.$t("chat.noMoreHistory") || "没有更多历史消息";
        }
      } catch (error) {
        console.error("加载历史消息异常:", error);
        this.$message({
          message:
            this.$t("chat.historicalFailure") || "加载历史消息失败,请重试",
          type: "error",
          duration: 3000,
          showClose: true,
        });
      } finally {
        this.messagesLoading = false;
        this.loadingHistory = false;
      }
    },

    // 刷新当前聊天消息
    async refreshMessages() {
      if (!this.currentContactId) return;
      await this.loadMessages(this.currentContactId);
    },

    // 打开图片上传控件
    openImageUpload() {
      if (!this.currentContact) return;
      this.$refs.imageInput.click();
    },
    // 将本地时间转换为 UTC 时间
    convertToUTC(date) {
      if (!date) return null;
      const d = new Date(date);
      return new Date(d.getTime() - d.getTimezoneOffset() * 60000);
    },

    // 将 UTC 时间转换为本地时间
    convertToLocal(utcDate) {
      if (!utcDate) return null;
      const d = new Date(utcDate);
      return new Date(d.getTime() + d.getTimezoneOffset() * 60000);
    },

    // 修正后端返回不带Z的UTC时间字符串
    fixToUTC(str) {
      if (typeof str !== "string") return str;
      if (str.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(str)) return str;
      return str + "Z";
    },

    /**
     * 智能消息排序：ID为主，时间为辅
     * 解决快速发送消息时排序混乱的问题
     * @param {Array} messages - 消息数组
     * @returns {Array} - 排序后的消息数组
     */
    sortMessages(messages) {
      if (!messages || messages.length <= 1) return messages;

      return messages.sort((a, b) => {
        // 策略1: 如果两条消息都有ID，优先使用ID排序（更可靠）
        if (a.id && b.id) {
          const idA = parseInt(a.id);
          const idB = parseInt(b.id);
          if (!isNaN(idA) && !isNaN(idB)) {
            const idDiff = idA - idB;
            if (idDiff !== 0) {
              return idDiff; // ID不同时，直接按ID排序
            }
          }
        }

        // 策略2: ID相同或无ID时，使用时间排序
        const timeA = a.time ? new Date(a.time).getTime() : 0;
        const timeB = b.time ? new Date(b.time).getTime() : 0;

        return timeA - timeB;
      });
    },

    /**
     * 检查消息数组是否需要重新排序
     * @param {Array} messages - 消息数组
     * @returns {boolean} - 是否需要排序
     */
    needsResort(messages) {
      if (!messages || messages.length <= 1) return false;

      // 检查最后几条消息是否按顺序排列
      const checkCount = Math.min(5, messages.length);
      const recentMessages = messages.slice(-checkCount);

      for (let i = 1; i < recentMessages.length; i++) {
        const prev = recentMessages[i - 1];
        const curr = recentMessages[i];

        // 如果有ID且ID乱序，需要重排
        if (prev.id && curr.id) {
          if (parseInt(prev.id) > parseInt(curr.id)) {
            return true;
          }
        } else {
          // 使用时间比较
          const prevTime = new Date(prev.time).getTime();
          const currTime = new Date(curr.time).getTime();
          if (prevTime > currTime) {
            return true;
          }
        }
      }

      return false;
    },

    /**
     * 获取消息数组中ID最小的消息（用于历史消息分页）
     * 策略：优先使用ID最小的消息，如果没有有效ID则使用时间最早的消息
     * @param {Array} messages - 消息数组
     * @returns {Object|null} - ID最小或时间最早的消息对象
     */
    getEarliestMessage(messages) {
      if (!messages || messages.length === 0) {
        console.warn("⚠️ getEarliestMessage: 消息数组为空");
        return null;
      }

      console.log("🔍 查找最早消息:", {
        totalCount: messages.length,
        messageIds: messages.map((m) => m.id).slice(0, 5), // 显示前5个ID
        messageTimes: messages.map((m) => m.time).slice(0, 3), // 显示前3个时间
      });

      // 策略1: 优先使用有有效ID的消息进行比较
      const messagesWithValidId = messages.filter((msg) => {
        const id = parseInt(msg.id);
        return msg.id && !isNaN(id) && id > 0;
      });

      if (messagesWithValidId.length > 0) {
        // 找到ID最小的消息
        const earliestById = messagesWithValidId.reduce((earliest, current) => {
          const earliestId = parseInt(earliest.id);
          const currentId = parseInt(current.id);
          return currentId < earliestId ? current : earliest;
        });

        console.log("✅ 使用ID最小的消息:", {
          messageId: earliestById.id,
          messageTime: earliestById.time,
          content: earliestById.content?.substring(0, 30) + "...",
        });

        return earliestById;
      }

      // 策略2: 如果没有有效ID，使用时间最早的消息
      console.log("⚠️ 没有有效ID，降级使用时间最早的消息");

      const earliestByTime = messages.reduce((earliest, current) => {
        const earliestTime = new Date(earliest.time || 0).getTime();
        const currentTime = new Date(current.time || 0).getTime();
        return currentTime < earliestTime ? current : earliest;
      });

      console.log("✅ 使用时间最早的消息:", {
        messageTime: earliestByTime.time,
        content: earliestByTime.content?.substring(0, 30) + "...",
        hasId: !!earliestByTime.id,
      });

      return earliestByTime;
    },

    /**
     * 智能联系人排序：时间为主，确保精确度
     * @param {Array} contacts - 联系人数组
     * @returns {Array} - 排序后的联系人数组
     */
    sortContactsByTime(contacts) {
      return contacts.sort((a, b) => {
        // 1. 首先按重要性排序（重要的在前）
        if (a.important && !b.important) return -1;
        if (!a.important && b.important) return 1;

        // 2. 然后按时间倒序（最新在前）
        const aTime = this.parseTimeForSort(a.lastTime);
        const bTime = this.parseTimeForSort(b.lastTime);

        // 降序排序：最新的在前面
        return bTime - aTime;
      });
    },

    /**
     * 调试工具：分析历史消息加载问题
     * 在浏览器控制台调用：this.$refs.customerService.debugHistoryLoading()
     */
    debugHistoryLoading() {
      console.log("🔍 历史消息加载调试信息:");
      console.log(
        "当前联系人ID:",
        this.currentContactId,
        typeof this.currentContactId
      );
      console.log(
        "当前消息数量:",
        this.messages[this.currentContactId]?.length || 0
      );
      console.log("历史消息状态:", {
        hasMoreHistory: this.hasMoreHistory,
        noMoreHistoryMessage: this.noMoreHistoryMessage,
      });
      console.log("请求参数:", this.history7Params);

      const currentMsgs = this.messages[this.currentContactId] || [];
      if (currentMsgs.length > 0) {
        const earliestMessage = this.getEarliestMessage(currentMsgs);
        console.log("最早消息:", earliestMessage);
        console.log(
          "消息ID分布:",
          currentMsgs.map((m) => ({ id: m.id, time: m.time })).slice(0, 10)
        );
      }

      return {
        currentContactId: this.currentContactId,
        messageCount: currentMsgs.length,
        hasMoreHistory: this.hasMoreHistory,
        noMoreHistoryMessage: this.noMoreHistoryMessage,
        requestParams: this.history7Params,
        earliestMessage: this.getEarliestMessage(currentMsgs),
      };
    },

    /**
     * 获取未读消息的localStorage键名
     */
    getUnreadStorageKey(roomId) {
      return `cs_unread_${roomId}`;
    },
    /**
     * 读取未读数
     */
    getUnreadCount(roomId) {
      const key = this.getUnreadStorageKey(roomId);
      return parseInt(localStorage.getItem(key), 10) || 0;
    },
    /**
     * 更新未读数
     */
    setUnreadCount(roomId, count) {
      const key = this.getUnreadStorageKey(roomId);
      localStorage.setItem(key, String(count));
    },
    /**
     * 监听storage事件，实现多窗口未读同步
     */
    handleStorageChange(e) {
      if (e.key && e.key.startsWith("cs_unread_")) {
        const roomId = e.key.replace("cs_unread_", "");
        const count = parseInt(e.newValue, 10) || 0;
        const contact = this.contacts.find((c) => c.roomId == roomId);
        if (contact) contact.unread = count;
      }
    },

    // 处理网络状态变化
    handleNetworkChange() {
      this.networkStatus = navigator.onLine ? "online" : "offline";

      if (navigator.onLine) {
        //网络恢复重新刷新页面
        location.reload(); // 重新加载当前页面
      }
    },
  },

  beforeDestroy() {
    if (this.stompClient) {
      if (this.stompClient.connected) {
        this.stompClient.disconnect(() => {
          console.log("WebSocket 已断开连接");
        });
      }
    }

    // 组件销毁前断开连接
    this.disconnectWebSocket();

    // 移除滚动事件监听
    if (this.$refs.messageContainer) {
      this.$refs.messageContainer.removeEventListener(
        "scroll",
        this.handleScroll
      );
    }

    // 清理新增的资源
    if (this.visibilityHandler) {
      document.removeEventListener("visibilitychange", this.visibilityHandler);
    }

    if (this.activityCheckInterval) {
      clearInterval(this.activityCheckInterval);
    }

    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
    }

    // === 新增：清理活动监听器 ===
    if (this.activityEvents && this.activityHandler) {
      this.activityEvents.forEach((event) => {
        document.removeEventListener(event, this.activityHandler, true);
      });
    }

    // === 新增：清除连接验证定时器 ===
    this.clearConnectionVerifyTimer();

    // === 新增：清除心跳和连接检查定时器 ===
    this.stopHeartbeat();
    this.stopConnectionCheck();

    window.removeEventListener("storage", this.handleStorageChange);

    // 移除新添加的事件监听
    window.removeEventListener("online", this.handleNetworkChange);
    window.removeEventListener("offline", this.handleNetworkChange);
  },
};
</script>
  <style scoped>
.cs-chat-container {
  width: 65%;
  height: 600px;
  margin: 0 auto;
  background-color: #f5f6f7;
  border-radius: 10px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  overflow: hidden;
  margin-top: 50px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  position: relative;
}

.cs-chat-wrapper {
  display: flex;
  height: 100%;
}

/* 联系人列表样式 */
.cs-contact-list {
  width: 290px;
  min-width: 260px; /* 添加最小宽度 */
  border-right: 1px solid #e0e0e0;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden; /* 防止整体出现滚动条 */
}

.cs-header {
  padding: 15px;
  font-weight: bold;
  border-bottom: 1px solid #e0e0e0;
  color: #333;
  font-size: 16px;
  background-color: #f8f8f8;
}

.cs-search {
  padding: 10px;
  border-bottom: 1px solid #e0e0e0;
}

.cs-contacts {
  flex: 1;
  overflow-y: auto;
}

.cs-contact-item {
  display: flex;
  padding: 10px;
  cursor: pointer;
  border-bottom: 1px solid #f0f0f0;
  transition: background-color 0.2s;
}

.cs-contact-item:hover {
  background-color: #f5f5f5;
}

.cs-contact-item.active {
  background-color: #e6f7ff;
}

/* 修改头像区域样式 */
.cs-avatar {
  position: relative;
  margin-right: 10px;
  flex-shrink: 0; /* 防止头像被压缩 */
}

.unread-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  background-color: #f56c6c;
  color: white;
  font-size: 12px;
  min-width: 16px;
  height: 16px;
  text-align: center;
  line-height: 16px;
  border-radius: 8px;
  padding: 0 4px;
}

.cs-contact-info {
  flex: 1;
  min-width: 0; /* 允许内容收缩 */
  overflow: hidden; /* 防止内容溢出 */
}

.cs-contact-name {
  font-weight: 500;
  font-size: 14px;
  color: #333;
  display: flex;
  justify-content: space-between;
  margin-bottom: 4px;
  white-space: nowrap; /* 防止换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
}

.cs-contact-time {
  font-size: 12px;
  color: #999;
  font-weight: normal;
}

.cs-contact-msg {
  font-size: 12px;
  color: #666;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%; /* 限制最大宽度 */
}

.important-tag {
  color: #f56c6c;
  font-size: 12px;
  margin-right: 4px;
}

/* 聊天区域样式 */
.cs-chat-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  background-color: #f5f5f5;
}

.cs-chat-header {
  padding: 15px;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #fff;
}

.cs-chat-title {
  font-weight: bold;
  font-size: 16px;
  color: #333;
  display: flex;
  align-items: center;
  gap: 10px;
}

.cs-header-actions i {
  font-size: 18px;
  margin-left: 15px;
  color: #666;
  cursor: pointer;
}

.cs-header-actions i:hover {
  color: #409eff;
}

.cs-chat-messages {
  flex: 1;
  padding: 15px;
  overflow-y: auto;
  background-color: #f5f5f5;
  height: calc(100% - 180px); /* 减去头部和输入框的高度 */
  position: relative; /* 添加相对定位 */
}

.cs-loading,
.cs-empty-chat {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #909399;
}

.cs-loading i,
.cs-empty-chat i {
  font-size: 60px;
  margin-bottom: 20px;
  color: #dcdfe6;
}

/* 确保消息列表正确显示 */
.cs-message-list {
  display: flex;
  flex-direction: column;
  padding-bottom: 20px; /* 添加底部间距 */
}

.cs-message {
  margin-bottom: 15px;
}

.cs-message-time {
  text-align: center;
  margin: 10px 0;
  font-size: 12px;
  color: #909399;
}

.cs-message-content {
  display: flex;
  align-items: flex-start;
}

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

.cs-message-self .cs-avatar {
  margin-right: 0;
  margin-left: 10px;
}

/* 调整消息气泡样式 */
.cs-bubble {
  max-width: 70%;
  padding: 8px 12px;
  border-radius: 4px;
  background-color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
  position: relative;
  margin-bottom: 4px; /* 添加消息间距 */
}

.cs-message-self .cs-bubble {
  background-color: #d8f4fe;
}

.cs-sender {
  font-size: 12px;
  color: #909399;
  margin-bottom: 4px;
}

.cs-text {
  font-size: 14px;
  line-height: 1.5;
  word-break: break-word;
}

/* 确保图片消息正确显示 */
.cs-image img {
  max-width: 200px;
  max-height: 200px;
  border-radius: 4px;
  cursor: pointer;
  display: block; /* 确保图片正确显示 */
}

/* 输入区域样式 */
.cs-chat-input {
  padding: 10px;
  background-color: #fff;
  border-top: 1px solid #e0e0e0;
}

.cs-toolbar {
  padding: 5px 0;
  margin-bottom: 5px;
}

.cs-toolbar i {
  font-size: 18px;
  margin-right: 15px;
  color: #606266;
  cursor: pointer;
}

.cs-toolbar i:hover {
  color: #409eff;
}

.cs-input-area {
  margin-bottom: 10px;
}

.cs-send-area {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.cs-counter {
  margin-right: 10px;
  font-size: 12px;
  color: #909399;
}

.shop-type {
  font-size: 12px;
  color: #909399;
  font-weight: normal;
  margin-left: 5px;
}

/* 图片预览 */
.image-preview-dialog {
  display: flex;
  justify-content: center;
  align-items: center;
}

.preview-image {
  max-width: 100%;
  max-height: 80vh;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .cs-contact-list {
    width: 200px;
  }

  .cs-image img {
    max-width: 150px;
    max-height: 150px;
  }
}

/* 重要标记图标样式 */
.important-star {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  cursor: pointer;
  margin-left: 5px;
  color: #c0c4cc;
  transition: color 0.3s;
  flex-shrink: 0; /* 防止图标被压缩 */
}

.important-star:hover {
  color: #ac85e0; /* 鼠标悬停时的颜色 */
}

.important-star.is-important {
  color: #ac85e0; /* 重要标记时的紫色 */
}

.important-star i {
  font-size: 16px;
}

/* 调整联系人项目布局 */
.cs-contact-item {
  display: flex;
  padding: 10px;
  cursor: pointer;
  border-bottom: 1px solid #f0f0f0;
  transition: background-color 0.2s;
  align-items: center;
  width: 100%;
  box-sizing: border-box; /* 确保padding不会导致溢出 */
}

/* 重要标签的样式调整 */
.important-tag {
  color: #ac85e0; /* 紫色标签 */
  font-size: 12px;
  margin-right: 4px;
  font-weight: bold;
}

/* 游客标记样式 */
.guest-badge {
  position: absolute;
  bottom: -5px;
  right: -5px;
  background-color: #67c23a;
  color: white;
  font-size: 10px;
  width: 16px;
  height: 16px;
  text-align: center;
  line-height: 16px;
  border-radius: 8px;
}

/* 游客聊天室项的背景稍微区分 */
.cs-contact-item.is-guest {
  background-color: #f9f9f9;
}

/* 滚动按钮样式 */
.scroll-to-bottom {
  position: absolute; /* 改为 fixed 定位 */
  right: 4px; /* 根据容器宽度调整位置 */
  bottom: 184px;
  background-color: #fff;
  border-radius: 5px 0px 0px 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;

  transition: all 0.3s;
  z-index: 1000; /* 确保按钮在最上层 */
  padding: 5px 1vw;
  font-size: 0.7vw;
  color: #7638ff;
}

.scroll-to-bottom:hover {
  background-color: #f0f0f0;
  transform: translateY(-2px);
}

.scroll-to-bottom i {
  font-size: 0.8vw;
  color: #7638ff;
  margin-left: 5px;
}

/* 添加连接状态样式 */
.connection-status {
  position: fixed;
  top: 8%;
  right: 41%;
  padding: 8px 16px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 1000;
  color: #7638ff;

  /* box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); */
}

.connection-status.error {
  background-color: #fef0f0;
  color: #f56c6c;
}

.connection-status.connecting {
  background-color: #f0f9eb;
  color: #67c23a;
}

/* 历史消息区域样式 */
.history-section {
  margin-bottom: 10px;
}

.history-indicator {
  transition: all 0.3s ease;
  border-radius: 4px;
  padding: 8px 12px;
}

/* .history-indicator:hover {
  background-color: #f0f9ff;
  color: #1890ff;
  transform: translateY(-1px);
} */

.no-more-history {
  /* background-color: #fafafa; */
  border-radius: 4px;
  /* border: 1px dashed #d9d9d9; */
  transition: all 0.3s ease;
}

.no-more-history i {
  margin-right: 6px;
  font-size: 0.8em;
}

.network-status {
  position: fixed;
  top: 80px;
  right: 20px;
  padding: 8px 16px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 1000;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  background-color: #fef0f0;
  color: #f56c6c;
}

/* .no-more-history:hover {
  border-color: #b7b7b7;
  background-color: #f5f5f5;
} */
</style>