<template>
  <div class="dialog-page">
    <ZPaging
      use-chat-record-mode
      use-virtual-list
      :inside-more="true"
      :hide-no-more-inside="true"
      cell-height-mode="fixed"
      :refresher-enabled="true"
      :show-scrollbar="false"
      :loading-more-enabled="true"
      :hide-empty-view="true"
      height="100%"
      ref="zpagingRef"
      v-model="virtualList"
      :loading-more-custom-style="{ display: 'none', height: '0' }"
      @scrolltolower="onScrollToLower"
      @scrolltoupper="onScrollToUpper"
    >
      <template #top>
        <customNavbar
          :title="talkParams.username"
          id="navBarArea"
          :hideBack="dialogueStore.isOpenMultiSelect"
        >
          <template #left v-if="dialogueStore.isOpenMultiSelect">
            <text
              class="ml-[36rpx]"
              @click="dialogueStore.isOpenMultiSelect = false"
            >
              取消
            </text>
          </template>
          <template
            #subTitle
            v-if="talkStore?.findItem(talkParams.index_name)?.group_type === 4"
          >
            <div class="text-[24rpx] text-[#999999]">公司群</div>
          </template>
          <template #right>
            <div
              class="mr-[36rpx] toChatSetting_btn"
              v-if="!talkParams.isDismiss && !talkParams.isQuit"
            >
              <tm-icon
                color="rgb(51, 51, 51)"
                :font-size="36"
                name="tmicon-gengduo"
                @click="toChatSettingsPage"
              ></tm-icon>
            </div>
          </template>
        </customNavbar>
      </template>
      <!-- <template #top>
            <div class="load-toolbar pointer">
              <span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
              <span v-else-if="loadConfig.status == 1" @click="onScrollToLower"> 查看更多消息 ... </span>
              <span v-else class="no-more"> 没有更多消息了 </span>
            </div>
          </template> -->

      <!-- 数据加载状态栏 -->
      <div class="dialog-list" @touchstart="handleHidePanel">
        <div
          class="message-item"
          v-for="item in virtualList"
          :id="`zp-id-${item.msg_id}`"
          :key="item.zp_index"
          :data-msgid="item.msg_id"
          :data-msgtype="item.msg_type"
          :data-userid="item.user_id"
          :data-talktype="talkParams.type"
          :data-receiverid="talkParams.receiver_id"
          style="transform: scaleY(-1);"
          :ref="
            (el) => {
              if (el) {
                if (item.zp_index !== undefined) {
                  messageRecordElementRefs[item.zp_index] = el
                }
              }
            }
          "
        >
          <!-- 系统消息 -->
          <div v-if="item.msg_type >= 1000" class="message-box">
            <component
              :is="MessageComponents[item.msg_type] || 'unknown-message'"
              :extra="item.extra"
              :data="item"
            />
          </div>
          <!-- 撤回消息 -->
          <div v-else-if="item.is_revoke == 1" class="message-box">
            <revoke-message
              :login_uid="userStore.uid"
              :user_id="item.user_id"
              :nickname="item.nickname"
              :talk_type="item.talk_type"
              :datetime="item.created_at"
              :msg_id="item.msg_id"
              :revokeInfo="item.revokeInfo"
              :extra="item.extra"
            >
              <template
                v-if="
                  canEditRevokedMessage(item) && item.user_id === userStore.uid
                "
              >
                <span
                  class="edit-revoked-message"
                  @click="restoreRevokedMessage(item)"
                >
                  重新编辑
                </span>
              </template>
            </revoke-message>
          </div>

          <div
            v-else
            class="message-box record-box"
            :class="{
              'direction-rt': item.user_id === talkParams.uid,
              'multi-select': dialogueStore.isOpenMultiSelect,
              'multi-select-check': item.isCheck,
            }"
          >
            <!-- 多选按钮 -->
            <aside
              v-if="dialogueStore.isOpenMultiSelect"
              class="checkbox-column"
            >
              <!-- <n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" /> -->
              <tm-checkbox
                :round="10"
                :defaultChecked="item.isCheck"
                @update:modelValue="item.isCheck = !item.isCheck"
                :size="42"
                color="#46299D"
              ></tm-checkbox>
            </aside>

            <!-- 头像信息 -->
            <aside
              class="avatar-column"
              @click="toUserDetailPage(item)"
              @touchstart="() => handleAvatarTouchStart(item)"
              @touchend="handleAvatarTouchEnd"
            >
              <!-- <im-avatar
                class="pointer"
                :src="item.avatar"
                :size="80"
                :username="item.nickname"
                @click="showUserInfoModal(item.user_id)"
              /> -->
              <avatarModule
                :mode="1"
                :avatar="item.avatar"
                :groupType="0"
                :userName="item.nickname"
                :customStyle="{ width: '80rpx', height: '80rpx' }"
                :customTextStyle="{
                  fontSize: '32rpx',
                  fontWeight: 'bold',
                  color: '#fff',
                  lineHeight: '44rpx',
                }"
              ></avatarModule>
            </aside>

            <!-- 主体信息 -->
            <main class="main-column">
              <div class="talk-title">
                <span
                  class="nickname pointer"
                  v-show="
                    talkParams.type == 2 && item.user_id !== talkParams.uid
                  "
                >
                  <!-- <span class="at">@</span> -->
                  {{ item.nickname }}
                </span>
                <span>
                  {{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}
                </span>
              </div>

              <div
                class="talk-content"
                :class="{ pointer: dialogueStore.isOpenMultiSelect }"
              >
                <deepBubble
                  @clickMenu="(menuType) => onContextMenu(menuType, item)"
                  :isShowCopy="isShowCopy(item)"
                  :isShowWithdraw="isRevoke(talkParams.uid, item) || isLeader"
                >
                  <component
                    class="component-content"
                    :key="item.zp_index"
                    :is="MessageComponents[item.msg_type] || 'unknown-message'"
                    :extra="item.extra"
                    :data="item"
                    :max-width="true"
                    :source="'panel'"
                  />
                </deepBubble>
                <!-- <div class="talk-tools">
                    <template v-if="talkParams.type == 1 && item.float == 'right'">
                      <loading theme="outline" size="19" fill="#000" :sxtrokeWidth="1" class="icon-rotate"
                        v-show="item.send_status == 1" />

                      <span v-show="item.send_status == 1"> 正在发送... </span>
                      <span v-show="item.send_status != 1"> 已送达 </span>
                    </template>

                  </div> -->
              </div>

              <div
                class="talk-tools have_read_num"
                v-if="item.user_id === talkParams.uid"
                @click="toShowMessageReadDetail(item)"
              >
                <span v-if="talkParams.type === 1">未读</span>
                <span v-if="talkParams.type === 2">
                  已读 (0/{{ (Number(talkParams.num)-1) > 0 ? Number(talkParams.num)-1 : 0 }})
                </span>
              </div>

              <div
                v-if="item.extra.reply"
                class="talk-reply pointer"
                @click="onJumpMessage(item.extra?.reply?.msg_id)"
              >
                <!-- <n-icon :component="ToTop" size="14" class="icon-top" /> -->
                <span class="ellipsis">
                  回复 {{ item.extra?.reply?.nickname }}:
                  {{ item.extra?.reply?.content }}
                </span>
              </div>
            </main>
          </div>
        </div>
        <div class="load-toolbar pointer" style="transform: scaleY(-1);">
          <span v-if="loadConfig.status == 0">正在加载数据中 ...</span>
          <span
            v-if="
              loadConfig.status == 1 ||
              (loadConfig.status == 2 && !state.localPageLoadDone)
            "
            @click="onScrollToLower"
          >
            查看更多消息 ...
          </span>
          <span
            v-if="loadConfig.status == 2 && state.localPageLoadDone"
            class="no-more"
          >
            没有更多消息了
          </span>
        </div>
      </div>
      <template #bottom>
        <div class="footBox" id="footBoxArea">
          <span
            class="flex items-center justify-center text-[24rpx] text-[#999999]"
            style="background-color: #e5e5e5; padding: 12rpx 24rpx;"
            v-if="uploadsParams.isUploading"
          >
            {{
              '正在发送中，剩余' +
              uploadsParams.uploadingNum +
              '个...请不要离开哦~'
            }}
          </span>
          <div v-if="!dialogueStore.isOpenMultiSelect">
            <div
              class="pt-[16rpx] ml-[32rpx] mr-[32rpx] flex items-start justify-between"
            >
              <tm-image
                :width="52"
                :height="52"
                :src="state.isUseSpeech ? keyboardIcon : microphoneIcon"
                @click="changeEditorMode"
                style="align-self: center;"
              ></tm-image>
              <div class="flex-1 quillBox" style="">
                <QuillEditor
                  ref="editor"
                  id="editor"
                  :options="editorOption"
                  @editorChange="onEditorChange"
                  style="width: 100%; flex: 1; height: 100%;"
                  @click="onEditorClick"
                  v-if="state.canUseQuillEditor && !state.isUseSpeech"
                />
                <tm-input
                  type="textarea"
                  autoHeight
                  focusColor="#F9F9F9"
                  color="#F9F9F9"
                  :inputPadding="[12]"
                  placeholder=""
                  v-if="!state.canUseQuillEditor && !state.isUseSpeech"
                  @update:modelValue="onTextAreaChange"
                  v-model="state.textAreaValue"
                  @input="onTextAreaInput"
                ></tm-input>
                <allSpeech
                  @startRecord="startRecord"
                  @endRecord="endRecord"
                  @cancelRecord="cancelRecord"
                  popupTitle=""
                  popupDefaultTips=""
                  :btnDefaultText="$t('hold_to') + '  ' + $t('speak')"
                  lineStartColor="#fff"
                  lineEndColor="#fff"
                  :chatInputHeight="chatInputHeight"
                  v-if="state.isUseSpeech"
                ></allSpeech>
                <div class="quote-area" v-if="state?.quoteInfo">
                  <span
                    v-if="state?.quoteInfo?.msg_type === 1"
                    class="text-[28rpx] text-[#999]"
                  >
                    {{
                      state?.quoteInfo?.nickname +
                      '：' +
                      state?.quoteInfo?.extra?.content
                    }}
                  </span>
                  <span
                    v-if="state?.quoteInfo?.msg_type !== 1"
                    class="text-[28rpx] text-[#999]"
                  >
                    {{
                      state?.quoteInfo?.nickname +
                      '：' +
                      ChatMsgTypeMapping[state?.quoteInfo?.msg_type]
                    }}
                  </span>
                  <img
                    @click="clearQuoteInfo"
                    style="width: 30rpx; height: 30rpx;"
                    src="@/static/image/login/check-circle-filled@3x.png"
                  />
                </div>
              </div>
              <div class="flex items-center justify-end h-[72rpx]">
                <tm-image
                  :margin="[10, 0]"
                  @click="handleEmojiPanel"
                  :width="52"
                  :height="52"
                  :round="12"
                  :src="state.isOpenEmojiPanel ? keyboard : smile"
                ></tm-image>
                <tm-image
                  @click="handleFilePanel"
                  :margin="[10, 0]"
                  :width="52"
                  :height="52"
                  :round="12"
                  :src="addCircleGray"
                ></tm-image>
                <tm-button
                  @click="onSendMessageClick"
                  :margin="[0, 0]"
                  :padding="[0, 30]"
                  color="#46299D"
                  :fontSize="28"
                  size="mini"
                  :shadow="0"
                  label="发送"
                  :loading="state.isLoading"
                  :width="120"
                  v-if="!state.isUseSpeech"
                ></tm-button>
              </div>
            </div>
            <div v-if="state.isOpenEmojiPanel" class="mt-[50rpx]">
              <emojiPanel
                @on-select="
                  (data) => {
                    if (!state.canUseQuillEditor) {
                      onTextAreaEmoticon(data)
                    } else {
                      onEmoticonEvent(data)
                    }
                  }
                "
              />
            </div>
            <div v-if="state.isOpenFilePanel" class="mt-[16rpx]">
              <filePanel
                @selectImg="handleSelectImg"
                :talkParams="talkParams"
              />
            </div>
          </div>
          <div v-else class="h-[232rpx]">
            <div
              class="flex items-center justify-center mt-[12rpx] text-[24rpx] text-[#747474] leading-[44rpx]"
            >
              <div class="mr-[8rpx]">已选中:</div>
              <div>{{ selectedMessage.length }}条消息</div>
            </div>
            <div
              class="flex items-center justify-around pl-[128rpx] pr-[128rpx] mt-[18rpx] text-[20rpx] text-[#737373]"
            >
              <div
                @click="handleMergeForward"
                class="flex flex-col items-center justify-center"
              >
                <tm-image :width="68" :height="68" :src="zu6050"></tm-image>
                <div class="mt-[6rpx]">合并转发</div>
              </div>
              <div
                @click="handleSingleForward"
                class="flex flex-col items-center justify-center"
              >
                <tm-image :width="68" :height="68" :src="zu6051"></tm-image>
                <div class="mt-[6rpx]">逐条转发</div>
              </div>
              <!-- <div
                @click="handleWechatForward"
                class="flex flex-col items-center justify-center"
              >
                <tm-image :width="68" :height="68" :src="zu6052"></tm-image>
                <div class="mt-[6rpx]">微信</div>
              </div> -->
              <div
                @click="handleDelete"
                class="flex flex-col items-center justify-center"
              >
                <tm-image :width="68" :height="68" :src="zu6053"></tm-image>
                <div class="mt-[6rpx]">删除</div>
              </div>
            </div>
          </div>

          <!--底部安全区-->
          <div class="content-placeholder"></div>
          <tm-drawer
            placement="bottom"
            v-model:show="state.showWin"
            :hideHeader="true"
            :height="416"
            :round="6"
          >
            <div class="w-full h-full flex flex-col items-center">
              <div
                class="mt-[46rpx] mb-[44rpx] leading-[48rpx] text-[#747474] text-[24rpx]"
              >
                撤回该条消息？
              </div>
              <div class="divider"></div>
              <div
                @click="withdrawerConfirm"
                class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#CF3050] leading-[48rpx] w-full text-center"
              >
                撤回
              </div>
              <div class="divider"></div>
              <div
                @click="state.showWin = false"
                class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#000000] leading-[48rpx] w-full text-center"
              >
                取消
              </div>
            </div>
          </tm-drawer>
        </div>
      </template>
    </ZPaging>
    <tm-drawer
      placement="bottom"
      v-model:show="state.isShowMentionSelect"
      :hideHeader="true"
      :round="5"
      :height="state.mentionSelectHeight"
    >
      <div
        class="mention-select-drawer flex flex-row flex-1 flex-row flex-row-center-between"
      >
        <div
          class="cancel-btns flex-row flex flex-row-center-start"
          style="width: 210rpx;"
        >
          <div
            class="hide-btn"
            v-if="!state.mentionIsMulSelect"
            @click="hideMentionSelect"
          >
            <img
              style="width: 40rpx; height: 40rpx;"
              src="@/static/image/chatList/mention_select_hide_bg.png"
            />
            <img
              style="
                position: absolute;
                top: 50%;
                left: 50%;
                margin-left: -9rpx;
                margin-top: -5rpx;
              "
              src="@/static/image/chatList/mention_select_hide_icon.png"
            />
          </div>
          <span
            style="flex-shrink: 0; display: block;"
            class="text-[32rpx] font-regular text-[#191919]"
            v-if="state.mentionIsMulSelect"
            @click="changeMentionSelectMul(false)"
          >
            {{ $t('cancel') }}
          </span>
        </div>
        <div
          class="flex flex-row-center-center flex-col"
          style="padding: 6rpx 0;"
        >
          <text>{{ $t('chat.mention.select') }}</text>
        </div>
        <div class="flex-row flex flex-row-center-end" style="width: 210rpx;">
          <div
            class="mention-edit-btn"
            v-if="!state.mentionIsMulSelect"
            @click="changeMentionSelectMul(true)"
          >
            <span class="text-[32rpx] font-regular text-[#191919]">
              {{ $t('button.multiple.choice') }}
            </span>
          </div>
          <div
            class="mention-done-btn"
            :class="
              state?.selectedMembersNum > 0 ? 'mention-done-btn-can-do' : ''
            "
            v-if="state.mentionIsMulSelect"
            @click="confirmMentionSelect"
          >
            <span class="text-[32rpx] font-regular text-[#191919]">
              {{ $t('button.text.done') }}
            </span>
            <span
              class="text-[32rpx] font-regular text-[#191919]"
              v-if="state?.selectedMembersNum > 0"
            >
              {{ '(' + state?.selectedMembersNum + ')' }}
            </span>
          </div>
        </div>
      </div>
      <selectMemberByAlphabet
        :manageType="'mention'"
        ref="selectMemberByAlphabetRef"
        :selectAreaHeight="state.selectAreaHeight"
        @updateSelectedMembersNum="updateSelectedMembersNum"
        :isMulSelect="state.mentionIsMulSelect"
        @getSelectResult="getSelectResult"
        @getMentionSelectLists="getMentionSelectLists"
      ></selectMemberByAlphabet>
    </tm-drawer>
    <tm-drawer
      placement="bottom"
      v-model:show="state.isShowMessageReadDetail"
      :hideHeader="true"
      :round="5"
      :height="state.mentionSelectHeight"
      :inContent="true"
    >
      <div
        class="mention-select-drawer flex flex-row flex-1 flex-row flex-row-center-between"
      >
        <div
          class="cancel-btns flex-row flex flex-row-center-start"
          style="width: 210rpx;"
          @click="hideMessageReadDetail"
        >
          <span
            style="flex-shrink: 0; display: block;"
            class="text-[32rpx] font-regular text-[#191919]"
          >
            {{ $t('cancel') }}
          </span>
        </div>
        <div
          class="flex flex-row-center-center flex-col"
          style="padding: 6rpx 0;"
        >
          <text>{{ $t('chat.msgRead.list') }}</text>
        </div>
        <div
          class="flex-row flex flex-row-center-end"
          style="width: 210rpx;"
        ></div>
      </div>
      <div class="msg-read-detail-tabs">
        <tm-sheet>
          <tm-tabs
            :list="state.msgReadDetailTabs"
            showTabsLineAni
            activeFontColor="#7A58DE"
            tabsLineAniColor="#7A58DE"
            :item-width="375"
            :width="750"
            @change="msgReadDetailTabsChange"
            :default-name="state.msgReadDetailTabs[0].key"
          ></tm-tabs>
          <div class="msg-read-detail">
            <ZPaging
              ref="zPagingReadDetails"
              :show-scrollbar="false"
              :fixed="false"
              :height="state.readDetailHeight"
              :safe-area-inset-bottom="true"
              :inside-more="true"
              :hide-no-more-inside="true"
              @scrolltolower="loadMoreReadDetails"
            >
              <div
                class="msg-read-detail-each"
                v-for="(item, index) in state.msgReadOrNotDetail"
                :key="index"
              >
                <div class="msg-read-detail-each-avatar">
                  <avatarModule
                    :mode="2"
                    :groupType="item?.group_type"
                    :avatar="item?.avatar"
                    :userName="item?.nickName"
                    :customStyle="{ width: '72rpx', height: '72rpx' }"
                    :customTextStyle="{
                      fontSize: '24rpx',
                      fontWeight: 'bold',
                      color: '#fff',
                      lineHeight: '34rpx',
                    }"
                  ></avatarModule>
                </div>
                <div class="msg-read-detail-each-info">
                  <span>{{ item.nickName }}</span>
                  <span
                    style="
                      font-size: 20rpx;
                      color: #747474;
                      font-weight: 400;
                      line-height: 28rpx;
                    "
                  >
                    {{ item.jobNum }}
                  </span>
                </div>
              </div>
            </ZPaging>
          </div>
        </tm-sheet>
      </div>
    </tm-drawer>
  </div>
</template>
<script setup>
import microphoneIcon from '@/static/image/record/voiceIcon.png'
import keyboardIcon from '@/static/image/record/keyboardIcon.png'
import allSpeech from '@/uni_modules/all-speech/components/all-speech/all-speech.vue'
import selectMemberByAlphabet from '../chatSettings/components/selectMemberByAlphabet.vue'
import {
  ref,
  reactive,
  watch,
  computed,
  onMounted,
  onUnmounted,
  nextTick,
} from 'vue'
import { QuillEditor, Quill } from '@vueup/vue-quill'
import EmojiBlot from './formats/emoji'
import { useChatList } from '@/store/chatList/index.js'
import { useAuth } from '@/store/auth'
import {
  useUserStore,
  useDialogueStore,
  useUploadsStore,
  useEditorDraftStore,
  useTalkStore,
  useSettingsStore,
  useDialogueListStore,
} from '@/store'
import addCircleGray from '@/static/image/chatList/addCircleGray.png'
import {
  MessageComponents,
  ForwardableMessageType,
  ChatMsgTypeMapping,
} from '@/constant/message'
import { formatTime, parseTime } from '@/utils/datetime'
import { deltaToMessage, deltaToString, isEmptyDelta } from './util'
import smile from '@/static/image/chatList/smile@2x.png'
import keyboard from '@/static/image/chatList/keyboard@2x.png'
import { useInject, useTalkRecord } from '@/hooks'
import { emitCall } from '@/utils/common'
import ZPaging from '@/uni_modules/z-paging/components/z-paging/z-paging.vue'
import useZPaging from '@/uni_modules/z-paging/components/z-paging/js/hooks/useZPaging.js'
import emojiPanel from './components/emojiPanel.vue'
import filePanel from './components/filePanel.vue'
import lodash from 'lodash'
import {
  ServePublishMessage,
  detailGetRecordsContext,
  ServeClearTalkUnreadNum,
  ServeTalkRecords,
  ServeReadConditionList,
  ServeMessageReadDetail,
} from '@/api/chat'
import copy07 from '@/static/image/chatList/copy07@2x.png'
import multipleChoices from '@/static/image/chatList/multipleChoices@2x.png'
import cite from '@/static/image/chatList/cite@2x.png'
import withdraw from '@/static/image/chatList/withdraw@2x.png'
import delete07 from '@/static/image/chatList/delete@2x.png'
import zu6050 from '@/static/image/chatList/zu6050@2x.png'
import zu6051 from '@/static/image/chatList/zu6051@2x.png'
import zu6052 from '@/static/image/chatList/zu6052@2x.png'
import zu6053 from '@/static/image/chatList/zu6053@2x.png'
import deepBubble from '@/components/deep-bubble/deep-bubble.vue'
import { isRevoke } from './menu'
import useConfirm from '@/components/x-confirm/useConfirm.js'
import {
  onLoad as uniOnload,
  onUnload as uniOnUnload,
  onShow,
  onHide,
} from '@dcloudio/uni-app'
import ws from '@/connect'

Quill.register('formats/emoji', EmojiBlot)
import 'quill-mention'
const selectMemberByAlphabetRef = ref(null)

//观察者
let observer
//获取聊天消息记录元素
const messageRecordElementRefs = ref([])
const messageRecordElementRefsWithoutIndex = ref([])

const {
  getDialogueList,
  updateZpagingRef,
  virtualList,
} = useDialogueListStore()
const talkStore = useTalkStore()
const { showConfirm } = useConfirm()
const settingsStore = useSettingsStore()
const userStore = useUserStore()
const dialogueStore = useDialogueStore()
const editorDraftStore = useEditorDraftStore()
const uploadsStore = useUploadsStore()
const editor = ref()
const zpagingRef = ref()
useZPaging(zpagingRef)
const indexName = computed(() => dialogueStore.index_name)
const talkParams = reactive({
  uid: computed(() => userStore.uid),
  index_name: computed(() => dialogueStore.index_name),
  type: computed(() => dialogueStore.talk.talk_type),
  receiver_id: computed(() => dialogueStore.talk.receiver_id),
  username: computed(() => dialogueStore.talk.username),
  online: computed(() => dialogueStore.online),
  keyboard: computed(() => dialogueStore.keyboard),
  num: computed(() => dialogueStore.members.length),
  isDismiss: computed(() => dialogueStore.isDismiss),
  isQuit: computed(() => dialogueStore.isQuit),
  adminList: computed(() => dialogueStore.getAdminList),
  unReadNum: computed(() => dialogueStore.unreadNum),
})

const uploadsParams = reactive({
  isUploading: computed(() => uploadsStore.isUploading),
  uploadingNum: computed(() => uploadsStore.uploadingNum),
})

const state = ref({
  isOpenEmojiPanel: false,
  isOpenFilePanel: false,
  showWin: false,
  onfocusItem: null,
  sessionId: '', //会话Id
  localPageLoadDone: true, //分页加载缓存中的聊天记录是否完毕
  quoteInfo: null, //引用信息
  mentionIsMulSelect: false, //是否是多选提醒的人
  selectedMembersNum: 0, //选中的要提醒的人数
  mentionSelectHeight: 0, //选择要提醒人的区域高度
  selectAreaHeight: 0, //选择要提醒人的可选人员列表区域高度
  isShowMentionSelect: false, //是否显示要提醒人的选择区域
  useCustomLoadMore: false, //是否使用自定义加载更多事件（下拉刷新、上拉加载）
  recordDate: '', //按日期查询聊天记录的开始日期
  serveFindRecord: [], //调用接口查找到的聊天记录
  middleMsg: {}, //缓存中没有时，调用接口初次使用的依据记录
  keepDialogInfo: false, //是否保存会话信息
  lastCursorIndex: undefined, //在失焦前保存光标位置
  mentionUserIds: [], //存储所有被@的用户ID
  isInsertingMention: false, //是否正在插入mention
  showMentionSelectTimer: null, //显示提醒选择框的定时器
  lastMentionText: '', // 记录上一次触发@时的完整文本内容
  lastMentionTriggered: false, // 记录当前@是否已经触发过
  lastMentionPosition: -1, // 添加新的状态来记录上一次@的位置
  isLoading: false, //发送按钮loading
  lastSelection: 0,
  canUseQuillEditor: true, //是否可以使用quill编辑器，如果版本不支持，则使用普通输入框
  textAreaValue: '', //普通输入框的值
  isUseSpeech: true, //是否使用语音输入
  visibleElements: new Set(), //当前需要发送已读回执的可见元素
  lastUpdateTime: 0, // 用于节流
  setMessageReadInterval: null, // 设置别人发出的消息，我已读的定时器
  tempWaitDoRead: [], //当前需要发送已读回执的元素
  visibleOutElements: new Set(), //当前需要获取别人发送的已读回执列表的可见元素
  setOutMessageReadInterval: null, // 设置我发出的消息，别人已读的定时器
  tempWaitDoCheck: [], //当前获取别人发送已读回执的元素
  isShowMessageReadDetail: false, //是否显示消息已读未读详情
  msgReadDetailTabs: [
    {
      key: '1',
      title: '未读',
    },
    {
      key: '0',
      title: '已读',
    },
  ],
  msgReadOrNotDetail: [], //消息已读未读详情
  currentMsgReadOrNotDetail: null, //当前消息已读未读详情
  readNumPage: 1, //已读未读详情分页
  hasMoreReadDetail: true, //是否还有更多已读未读详情
  currentIsUnread: 1, //当前已读未读状态
  readDetailHeight: 400, //已读未读详情高度
  isFirstEnter: true, //是否是第一次进入
  isFromHide: false, //是否从hide后恢复
})

// 创建一个响应式的 Map 来维护已读数量
const recordReadsMap = ref(new Map())

// 监听 Map 的变化，更新 UI
watch(
  recordReadsMap,
  (newMap) => {
    requestAnimationFrame(() => {
      newMap.forEach((readNum, msgId) => {
        const element = document.getElementById(`zp-id-${msgId}`)
        if (element) {
          element.dataset.readNum = readNum
          const readNumElement = element.querySelector('.have_read_num')
          if (readNumElement) {
            if (talkParams.type === 1) {
              readNumElement.textContent = readNum > 0 ? '已读' : '未读'
            } else {
              readNumElement.textContent =
                '已读 (' + readNum + '/' + (Number(talkParams.num) - 1 > 0 ? Number(talkParams.num) - 1 : 0) + ')'
            }
          }
        }
      })
    })
  },
  {
    deep: true,
    immediate: true,
  },
)

uniOnload(async (options) => {
  console.log('onLoad' + JSON.stringify(options))
  if (options.sessionId) {
    state.value.sessionId = options.sessionId
  }
  if (options.keepDialogInfo) {
    state.value.keepDialogInfo = options.keepDialogInfo === '1' ? true : false
  }
  if (options.msgInfo) {
    const msgInfo = JSON.parse(decodeURIComponent(options.msgInfo))
    queryRecordsByMsgInfo(msgInfo)
    state.value.useCustomLoadMore = true
    return
  }
  if (options.recordDate) {
    state.value.recordDate = options.recordDate
    const msgInfo = await findTalkRecords(options.recordDate, true)
    queryRecordsByMsgInfo(msgInfo)
    state.value.useCustomLoadMore = true
    return
  }
  initData()
})
uniOnUnload(() => {
  console.log('onUnload')
  ServeClearTalkUnreadNum(
    {
      talk_type: Number(talkParams.type),
      receiver_id: Number(talkParams.receiver_id),
    },
    talkParams.unReadNum,
  ).then(() => {
    talkStore.updateItem({
      index_name: talkParams.index_name,
      unread_num: 0,
    })
    dialogueStore.clearUnreadNum()
  })
})
const handleEmojiPanel = () => {
  state.value.isOpenFilePanel = false
  state.value.isUseSpeech = false
  state.value.isOpenEmojiPanel = !state.value.isOpenEmojiPanel
}
const handleFilePanel = () => {
  state.value.isOpenEmojiPanel = false
  state.value.isUseSpeech = false
  state.value.isOpenFilePanel = !state.value.isOpenFilePanel
}

//点击隐藏表情/文件上传 面板
const handleHidePanel = () => {
  state.value.isOpenFilePanel = false
  state.value.isOpenEmojiPanel = false
}

//切换键盘输入/语音输入
const changeEditorMode = () => {
  state.value.isUseSpeech = !state.value.isUseSpeech
  handleHidePanel()
}

//点击编辑区聚焦输入框
const onEditorClick = () => {
  handleHidePanel()
  // const quill = getQuill();

  // if (quill.getText().endsWith('@\n')) {
  //   showMentionSelectDebounced(quill)
  // }
  // quill.focus()
}

const onSendMessage = (data = {}, callBack, showLoading = false) => {
  if (showLoading) {
    state.value.isLoading = true
  }
  let message = {
    ...data,
    receiver: {
      receiver_id: talkParams.receiver_id,
      talk_type: talkParams.type,
    },
  }

  ServePublishMessage(message)
    .then(({ code, message }) => {
      state.value.isLoading = false
      if (code == 200) {
        uploadsStore.updateUploadStatus(false)
        if (callBack) {
          callBack(true)
        }
      } else {
        uploadsStore.updateUploadStatus(false)
        message.warning(message)
      }
    })
    .catch(() => {
      state.value.isLoading = false
      uploadsStore.updateUploadStatus(false)
      message.warning('网络繁忙,请稍后重试!')
    })
}

const onTextAreaChange = (value) => {
  state.value.textAreaValue = value

  // 更新mentionUserIds数组，确保与输入框中的@内容一致
  const atPattern = /@([^@\s]+)(?:\s|$)/g
  const matches = Array.from(value.matchAll(atPattern))
  const mentionedUsers = matches.map((match) => match[1].trim().toLowerCase())

  // 获取当前对话中的所有成员信息
  const members = dialogueStore.members || []

  // 根据@的用户名找到对应的user_id
  const newMentionUserIds = mentionedUsers
    .map((username) => {
      if (username === '所有人') {
        return 0 // 如果是@所有人，返回0
      }
      const member = members.find(
        (m) => m.nickname.trim().toLowerCase() === username,
      )
      return member ? member.id : null
    })
    .filter((id) => id !== null)

  // 只有在输入框中有@内容时才更新mentionUserIds
  if (value.includes('@')) {
    state.value.mentionUserIds = newMentionUserIds
  } else {
    state.value.mentionUserIds = []
  }
}

// 处理输入框输入事件
const onTextAreaInput = (value) => {
  console.log(value, 'value')
  if (value.length > 0) {
    if (value[value.length - 1] === '@') {
      if (talkParams.type === 1) {
        return
      }
      state.value.isShowMentionSelect = true
    }
  }
}

const onSendMessageClick = () => {
  if (!state.value.canUseQuillEditor) {
    // 处理普通输入框的发送消息
    if (state.value.textAreaValue.trim() === '') {
      return
    }
    if (state.value.textAreaValue.length > 1024) {
      return message.warning('发送内容超长，请分条发送')
    }
    let message = {
      type: 'text',
      content: state.value.textAreaValue,
      quote_id: state.value.quoteInfo ? state.value.quoteInfo.msg_id : null, // 添加quote_id
      mentions: state.value.mentionUserIds, // 使用最终的用户ID数组
    }
    console.log(message)
    onSendMessage(
      message,
      (ok) => {
        if (!ok) return
        state.value.textAreaValue = ''
        state.value.quoteInfo = null // 发送后清除引用信息
      },
      true,
    )
    return
  }
  // 发送前确保 mentionUserIds 是最新的
  updateMentionUserIds()

  let delta = getQuill().getContents()
  if (state.value.quoteInfo) {
    delta.ops.unshift({
      insert: {
        quote: {
          id: state.value.quoteInfo.msg_id,
        },
      },
    })
  }
  let data = deltaToMessage(delta)

  if (data.items.length === 0) {
    return
  }

  switch (data.msgType) {
    case 1: // 文字消息
      if (data.items[0].content.trim() === '') {
        return
      }
      if (data.items[0].content.length > 1024) {
        return message.warning('发送内容超长，请分条发送')
      }
      onSendTextEvent({
        data,
        callBack: (ok) => {
          if (!ok) return
          getQuill().setContents([], Quill.sources.USER)
          if (state.value.quoteInfo) {
            state.value.quoteInfo = null
          }
        },
      })
      break
  }
}

// 发送文本消息
const onSendTextEvent = lodash.throttle((value) => {
  let { data, callBack } = value

  let message = {
    type: 'text',
    content: data.items[0].content,
    quote_id: data.quoteId,
    mentions: state.value.mentionUserIds, // 使用最终的用户ID数组
  }
  console.log(message)

  onSendMessage(message, callBack, true)
}, 1000)

// 编辑器输入事件
const onInputEvent = ({ data }) => {
  talkStore.updateItem({
    index_name: indexName.value,
    draft_text: data,
  })

  // 判断对方是否在线和是否需要推送
  // 3秒时间内推送一次
  if (settingsStore.isKeyboard && props.online) {
    onKeyboardPush()
  }
}

// 发送表情消息
const onSendEmoticonEvent = ({ data }) => {
  onSendMessage({ type: 'emoticon', emoticon_id: data })
}

// 注册事件
const evnets = {
  text_event: onSendTextEvent,
  input_event: onInputEvent,
  emoticon_event: onSendEmoticonEvent,
  history_event: () => {
    isShowHistory.value = true
  },
}

const {
  loadConfig,
  records,
  onLoad,
  onRefreshLoad,
  onJumpMessage,
} = useTalkRecord(talkParams.uid)

const getQuill = () => {
  return editor.value?.getQuill()
}

const isShowCopy = (item) => {
  switch (item.msg_type) {
    case 1:
      return true
    case 3:
      return true
    case 5:
      return true
    case 6:
      return true
    default:
      return false
  }
}

const selectedMessage = computed(() => {
  return virtualList.value.filter((item) => item.isCheck)
})

// 编辑器事件
const onEditorEvent = (msg) => {
  evnets[msg.event] && evnets[msg.event](msg)
}

const getQuillSelectionIndex = () => {
  let quill = getQuill()
  return (quill.getSelection() || {}).index
}

const onEmoticonEvent = (data) => {
  if (data.type == 1) {
    const quill = getQuill()
    let index = getQuillSelectionIndex()

    if (index == 1 && quill.getLength() == 1 && quill.getText(0, 1) == '\n') {
      quill.deleteText(0, 1)
      index = 0
    }
    if (data.img) {
      quill.insertEmbed(index, 'emoji', {
        alt: data.value,
        src: data.img,
      })
    } else {
      quill.insertText(index, data.value)
    }

    if (index) {
      quill.setSelection(index + 1, 0, 'user')
    }
  } else {
    let fn = emitCall('emoticon_event', data.value, () => {})
    emit('editor-event', fn)
  }
}
let calcDelta = false
const onEditorChange = () => {
  if (calcDelta) {
    calcDelta = false
    return
  }
  // 以下逻辑是 光标与@之间存在其他内容时 不触发选人弹窗
  const qtext = getQuill().getText()
  let selectIdx = getQuill()?.getSelection()?.index
  const textBeforeCursor = qtext.substring(0, selectIdx)
  if (textBeforeCursor[0]?.charCodeAt(0) === 10) {
    const delta = getQuill().getContents()
    const ops = delta.ops || []
    if (ops[0].insert === '\n') {
      ops.splice(0, 1)
      if (ops.length > 0) {
        nextTick(() => {
          getQuill().setContents(delta)
          getQuill().setSelection(getQuill().getText().length, 0)
        })
      }
    }
    // for (let i = 0; i < ops.length; i++) {
    //   if (ops[i].insert === '\n') {
    //     console.error('有空格')
    //     ops.splice(i, 1)
    //     calcDelta = true
    //   }
    // }
    // getQuill().setContents(delta)
    // getQuill().setSelection(getQuill().getText().length, 0)
  }
  let endWithAt = false
  if (
    textBeforeCursor[textBeforeCursor.length - 1] === '@' ||
    textBeforeCursor[textBeforeCursor.length - 2]?.charCodeAt(0) === 64
  ) {
    endWithAt = true
  }
  if (endWithAt) {
    state.value.cursorMention = true
  } else {
    state.value.cursorMention = false
  }
  if (getQuill().getText() !== state.value.lastMentionText) {
    state.value.lastMentionTriggered = false
  }
  let delta = getQuill().getContents()
  let text = deltaToString(delta)

  // 如果正在插入mention，不进行mention的检查和更新
  if (!state.value.isInsertingMention) {
    updateMentionUserIds()
  }

  if (!isEmptyDelta(delta)) {
    editorDraftStore.items[indexName.value || ''] = JSON.stringify({
      text: text,
      ops: delta.ops,
    })
  } else {
    // 删除 editorDraftStore.items 下的元素
    delete editorDraftStore.items[indexName.value || '']
  }
  onEditorEvent(emitCall('input_event', text))
  // emit('editor-event', emitCall('input_event', text))
  // 清理过期的撤回消息（超过5分钟）
  const now = new Date().getTime()
  Object.keys(state.value.revokedMessages || {}).forEach((msgId) => {
    if (now - state.value.revokedMessages[msgId].revokeTime > 5 * 60 * 1000) {
      delete state.value.revokedMessages[msgId]
    }
  })
}

const onClipboardMatcher = (node, Delta) => {
  const ops = []

  Delta.ops.forEach((op) => {
    // 如果粘贴了图片，这里会是一个对象，所以可以这样处理
    if (op.insert && typeof op.insert === 'string') {
      ops.push({
        insert: op.insert, // 文字内容
        attributes: {}, //文字样式（包括背景色和文字颜色等）
      })
    } else {
      ops.push(op)
    }
  })

  Delta.ops = ops
  return Delta
}

const editorOption = {
  debug: false,
  modules: {
    toolbar: false,
    clipboard: {
      // 粘贴版，处理粘贴时候的自带样式
      matchers: [[Node.ELEMENT_NODE, onClipboardMatcher]],
    },

    keyboard: {
      bindings: {
        enter: {
          key: 13,
          handler: onSendMessageClick,
        },
      },
    },

    // imageUploader: {
    //   upload: onEditorUpload
    // },

    mention: {
      allowedChars: /^[\u4e00-\u9fa5]*$/,
      mentionDenotationChars: ['@'],
      positioningStrategy: 'fixed',
      renderItem: (data) => {
        const el = document.createElement('div')
        el.className = 'ed-member-item'
        el.innerHTML += `<span class="nickname">${data.nickname}</span>`
        return el
      },
      source: function (searchTerm, renderList, mentionChar) {
        if (talkParams.type === 1) {
          return
        }
        // 在失焦前保存光标位置
        const quill = getQuill()
        const range = quill.getSelection()
        if (range) {
          state.value.lastCursorIndex = range.index
        }

        // 使用防抖函数
        showMentionSelectDebounced(quill)
      },
      mentionContainerClass: '',
    },
  },
  placeholder: '',
}

const handleSelectImg = (data, file_num) => {
  if (Array.isArray(data)) {
    // 批量发送图片
    data.forEach((item) => {
      onSendMessage({ ...item, file_num: item.file_num })
    })
  } else {
    // 单张图片发送
    onSendMessage({ ...data, file_num })
  }
}

const virtualListChange = (vList) => {
  virtualList.value = vList
}

const onContextMenu = (menuType, item) => {
  console.log(menuType, item, 'item')
  switch (menuType) {
    case 'actionCopy':
      actionCopy(item)
      break
    case 'multipleChoose':
      multipleChoose(item)
      break
    case 'actionCite':
      actionCite(item)
      break
    case 'actionWithdraw':
      actionWithdraw(item)
      break
    case 'actionDelete':
      actionDelete(item)
      break

    default:
      break
  }
}

const actionCopy = (item) => {
  console.log('复制')
  let content = ''
  switch (item.msg_type) {
    case 1:
      content = item.extra.content
      break
    case 3:
      content = item.extra.url
      break
    case 5:
      content = item.extra.url
      break

    default:
      break
  }
  uni.setClipboardData({
    data: content,
  })
}

const multipleChoose = (item) => {
  item.isCheck = true
  dialogueStore.setMultiSelect(true)
}

const actionCite = (item) => {
  console.log('引用')
  state.value.quoteInfo = item
}

//清除引用信息
const clearQuoteInfo = () => {
  state.value.quoteInfo = null
}

const actionWithdraw = (item) => {
  console.log('撤回')
  state.value.onfocusItem = item
  state.value.showWin = true
}

const withdrawerConfirm = () => {
  dialogueStore.ApiRevokeRecord(state.value.onfocusItem.msg_id)
  state.value.onfocusItem = null
  state.value.showWin = false
}

// 添加检查是否可以重新编辑撤回消息的函数
const canEditRevokedMessage = (item) => {
  // console.log(item)
  if (item.is_revoke === 1 && item.msg_type === 1) {
    const now = new Date().getTime()
    const revokeTime = new Date(item.created_at).getTime()
    // console.log(now)
    // 检查是否在5分钟内
    return now - revokeTime <= 5 * 60 * 1000
  }
  return false
}

// 添加恢复撤回消息到输入框的函数
const restoreRevokedMessage = async (item) => {
  // 接口拿数据，之后把查询的内容给输入框
  const res = await detailGetRecordsContext({
    msgId: item.msg_id,
  })
  console.log(res)
  if (res.code == 200) {
    const content = res.data.item?.extra?.content
    const quill = getQuill()
    quill.setText(content)
    // 将光标设置到文本末尾
    quill.setSelection(content.length, 0)
    quill.focus()
  }
  /* const revokedMsg = state.value.revokedMessages[msgId]

  // 根据消息类型处理
  if (revokedMsg.msgType === 1) { // 文本消息
    const quill = getQuill()
    quill.setText(revokedMsg.content)
    quill.focus()
  } */
  // 可以根据需要添加其他类型消息的处理
}

const actionDelete = (item) => {
  console.log('删除')
  item.isCheck = true
  handleDelete()
}

const handleMergeForward = () => {
  if (selectedMessage.value.length == 0) {
    return message.warning('未选择消息')
  }
  console.log('合并转发')
  dialogueStore.setForwardType(2)
  dialogueStore.setForwardMessages(selectedMessage.value)
  uni.navigateTo({
    url: '/pages/chooseChat/index',
    success: function (res) {
      clearMultiSelect()
    },
  })
}

const handleSingleForward = () => {
  if (selectedMessage.value.length == 0) {
    return message.warning('未选择消息')
  }
  console.log('逐条转发')
  dialogueStore.setForwardType(1)
  dialogueStore.setForwardMessages(selectedMessage.value)
  uni.navigateTo({
    url: '/pages/chooseChat/index',
    success: function (res) {
      clearMultiSelect()
    },
  })
}

const handleWechatForward = () => {
  if (selectedMessage.value.length == 0) {
    return message.warning('未选择消息')
  }
  console.log('微信转发')
}

const handleDelete = () => {
  if (selectedMessage.value.length == 0) {
    return message.warning('未选择消息')
  }
  console.log('删除')
  showConfirm({
    content: '确定删除聊天记录',
    confirmText: '删除',
    confirmColor: '#CF3050',
    onConfirm: async () => {
      const msgIds = selectedMessage.value.map((item) => item.msg_id)
      virtualList.value = virtualList.value.filter(
        (item) => !msgIds.includes(item.msg_id),
      )
      dialogueStore.ApiDeleteRecord(msgIds)
      clearMultiSelect()
    },
    onCancel: () => {},
  })
}

//更新选中的要提醒的人数
const updateSelectedMembersNum = (numChange) => {
  state.value.selectedMembersNum = state.value.selectedMembersNum + numChange
}

watch(
  () => zpagingRef.value,
  (newValue, oldValue) => {
    if (newValue) {
      updateZpagingRef(newValue)
    }
  },
)

watch(
  () => virtualList.value,
  (newValue, oldValue) => {
    if (newValue) {
      const dialogueList = getDialogueList(talkParams.index_name)
      // console.log(newValue[newValue.length - 1]?.sequence, dialogueList?.records?.[0]?.sequence)
      if (!dialogueList || dialogueList?.length === 0) {
        state.value.localPageLoadDone = true
        return
      }
      // 只在正常加载模式下检查是否加载完缓存数据
      if (!state.value.useCustomLoadMore) {
        if (
          newValue[newValue.length - 1]?.sequence ===
          dialogueList?.records?.[0]?.sequence
        ) {
          if (
            dialogueList?.records?.[0]?.sequence !== 1 &&
            !state.value.localPageLoadDone
          ) {
            loadConfig.status = 1
          }
          //相同意味着分页加载缓存中的聊天记录完毕
          state.value.localPageLoadDone = true
        } else {
          state.value.localPageLoadDone = false
        }
      }

      // 处理新消息
      if (oldValue && oldValue.length > 0) {
        const lastOldMsgId = oldValue[0].msg_id
        const lastIndex = newValue.findIndex(
          (msg) => msg.msg_id === lastOldMsgId,
        )
        console.error(lastIndex, 'lastIndex')

        if (lastIndex === -1) {
          // 没找到lastOldMsgId，说明都是新消息
          newValue.forEach((msg) => {
            nextTick(() => {
              const element = document.getElementById(`zp-id-${msg.msg_id}`)
              if (element) {
                messageRecordElementRefs.value.unshift(element)
              }
            })
          })
        } else if (lastIndex > 0) {
          // 找到了lastOldMsgId，它前面的都是新消息
          for (let i = 0; i < lastIndex; i++) {
            const msg = newValue[i]
            console.error(msg, '新消息msg')
            nextTick(() => {
              const element = document.getElementById(`zp-id-${msg.msg_id}`)
              if (element) {
                messageRecordElementRefs.value.unshift(element)
              }
            })
          }
        } else if (lastIndex === 0) {
          messageRecordElementRefsWithoutIndex.value = []
          // 新消息和旧消息的id相同，说明没有比它更新的消息需要处理。但是资源文件是预创建的，需要处理
          for (let i = 0; i < newValue.length; i++) {
            if (!newValue[i].zp_index && newValue[i].zp_index !== 0) {
              if (newValue[i]?.file_num === newValue[i].msg_id) {
                return
              }
              nextTick(() => {
                const element = document.getElementById(
                  `zp-id-${newValue[i].msg_id}`,
                )
                if (element) {
                  messageRecordElementRefsWithoutIndex.value.unshift(element)
                }
              })
            }
          }
        }
      }
    }
  },
  {
    deep: true,
  },
)

const onScrollToLower = async () => {
  if (state.value.useCustomLoadMore) {
    const tempVirtualList = lodash.cloneDeep(virtualList.value).reverse()
    const dialogueList = getDialogueList(talkParams.index_name)
    const recordIndex = dialogueList?.records?.findIndex(
      (record) => record.msg_id === tempVirtualList[0].msg_id,
    )
    if (!recordIndex || recordIndex === -1) {
      const moreRecords = await findTalkRecords(
        '',
        false,
        tempVirtualList[0].sequence,
        {
          direction: 'up',
          sort_sequence: '',
        },
      )
      console.log(moreRecords)

      // 格式化新加载的消息
      const formattedMoreRecords = moreRecords.map((item) => ({
        ...item,
        float: item.user_id === talkParams.uid ? 'right' : 'left',
      }))

      virtualList.value = formattedMoreRecords.concat(tempVirtualList).reverse()
      loadConfig.status =
        dialogueList?.records?.[0]?.sequence > 1 && moreRecords.length > 0
          ? 1
          : 2
    } else {
      if (tempVirtualList[0].sequence > dialogueList.records[0].sequence) {
        virtualList.value = dialogueList.records
          .slice(Math.max(0, recordIndex - 10), recordIndex)
          .concat(tempVirtualList)
          .reverse()
        // zpagingRef.value.setLocalPaging(
        //   dialogueList.records
        //     .slice(0, recordIndex)
        //     .concat(tempVirtualList)
        //     .reverse(),
        //   // zpagingRef.value.scrollIntoViewById('zp-id-' + virtualList.value[virtualList.value.length - 1].msg_id)
        // )

        console.log(virtualList.value)
      }
    }
    return
  }
  if (state.value.localPageLoadDone) {
    //本地缓存的聊天记录分页加载完之后，才可以请求接口
    onRefreshLoad()
  }
}

//本来的下拉刷新——列表倒置后为上拉加载
const onScrollToUpper = async () => {
  if (state.value.useCustomLoadMore) {
    const tempVirtualList = lodash.cloneDeep(virtualList.value).reverse()
    const dialogueList = getDialogueList(talkParams.index_name)
    const recordIndex = dialogueList?.records?.findIndex(
      (record) =>
        record.msg_id === tempVirtualList[tempVirtualList.length - 1].msg_id,
    )
    console.log(recordIndex)
    if (!recordIndex || recordIndex === -1) {
      // 记住加载更多前消息的ID
      const currentMsgId = tempVirtualList[tempVirtualList.length - 1].msg_id
      const moreRecords = await findTalkRecords(
        '',
        false,
        tempVirtualList[tempVirtualList.length - 1].sequence,
      )
      console.log(moreRecords)

      // 格式化新加载的消息
      const formattedMoreRecords = moreRecords.map((item) => ({
        ...item,
        float: item.user_id === talkParams.uid ? 'right' : 'left',
      }))

      virtualList.value = tempVirtualList
        .concat(formattedMoreRecords.reverse())
        .reverse()

      console.log(virtualList.value)

      // 数据更新后，滚动到之前的位置
      nextTick(() => {
        zpagingRef.value?.scrollIntoViewById('zp-id-' + currentMsgId)
      })
    } else {
      if (
        tempVirtualList[tempVirtualList.length - 1].sequence <
        dialogueList.records[dialogueList.records.length - 1].sequence
      ) {
        // 记住加载更多前消息的ID
        const currentMsgId = tempVirtualList[tempVirtualList.length - 1].msg_id

        virtualList.value = tempVirtualList
          .concat(
            dialogueList.records.slice(
              recordIndex + 1,
              Math.min(recordIndex + 11, dialogueList.records.length),
            ),
          )
          .reverse()

        // 数据更新后，滚动到之前的位置
        nextTick(() => {
          zpagingRef.value?.scrollIntoViewById('zp-id-' + currentMsgId)
        })
      }
    }
  }
}

const clearMultiSelect = () => {
  dialogueStore.setMultiSelect(false)
  virtualList.value.forEach((item) => {
    item.isCheck = false
  })
}

const initData = async () => {
  const dialogueList = getDialogueList(talkParams.index_name)
  let doLocalPaging = false
  if (dialogueList?.records?.length > 0) {
    doLocalPaging = true
  }
  console.error('dialogueList', dialogueList)

  let objT = {
    uid: talkParams.uid,
    talk_type: talkParams.type,
    receiver_id: talkParams.receiver_id,
    index_name: talkParams.index_name,
    direction: dialogueList ? 'down' : 'up',
    no_limit: dialogueList ? 1 : 0,
  }
  await onLoad({ ...objT })
  if (doLocalPaging) {
    zpagingRef.value?.setLocalPaging(records.value)
  }
}

//点击跳转到聊天设置页面
const toChatSettingsPage = () => {
  uni.navigateTo({
    url:
      '/pages/chatSettings/index?groupId=' +
      talkParams?.receiver_id +
      '&sessionId=' +
      state.value.sessionId,
  })
}

//点击跳转到用户详情页面
const toUserDetailPage = (userItem) => {
  uni.navigateTo({
    url:
      '/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
  })
}

//切换提醒的人选择弹窗多选状态
const changeMentionSelectMul = (status) => {
  state.value.mentionIsMulSelect = status
}

//隐藏要提醒人的选择
const hideMentionSelect = () => {
  state.value.isShowMentionSelect = false
  // 清除保存的光标位置
  state.value.lastCursorIndex = undefined
  // 获得焦点
  const quill = getQuill()
  // quill.focus()
}

//确认要提醒人的选择
const confirmMentionSelect = () => {
  if (state?.value.selectedMembersNum > 0) {
    if (selectMemberByAlphabetRef.value) {
      selectMemberByAlphabetRef.value.confirmSelectMembers()
    }
    hideMentionSelect()

    // 重置选中人数和多选状态
    state.value.selectedMembersNum = 0
    state.value.mentionIsMulSelect = false
  }
}

//获取选择的结果
const getSelectResult = (mentionSelect) => {
  console.log(mentionSelect)
  getMentionSelectLists(mentionSelect)
}

//处理要提醒人的消息样式
const getMentionSelectLists = (mentionSelectList) => {
  if (!state.value.canUseQuillEditor) {
    if (mentionSelectList.length > 0) {
      mentionSelectList.forEach((item) => {
        onTextAreaMention(item)
      })
    }
    return
  }
  const quill = getQuill()
  const mention = quill.getModule('mention')

  // 使用之前保存的光标位置
  if (state.value.lastCursorIndex !== undefined) {
    // 删除光标前的 @ 符号
    quill.deleteText(state.value.lastCursorIndex - 1, 1)
  }

  // 设置正在插入mention的标记
  state.value.isInsertingMention = true

  // 逐个插入mention
  mentionSelectList.forEach((mentionSelectItem) => {
    // 如果是@所有人，确保 id 为 0
    const id =
      mentionSelectItem?.nickname === '所有人' ? 0 : mentionSelectItem?.id
    mention.insertItem(
      {
        id: id,
        denotationChar: '@',
        value: mentionSelectItem?.nickname + ' ',
      },
      true,
    )
  })

  // 清除保存的光标位置
  state.value.lastCursorIndex = undefined

  // 延迟清除插入mention的标记并手动触发一次内容更新
  setTimeout(() => {
    state.value.isInsertingMention = false
    // 手动触发一次内容更新，确保 mentionUserIds 是最新的
    updateMentionUserIds()
  }, 100)

  hideMentionSelect()
}

// 新增一个更新 mentionUserIds 的函数
const updateMentionUserIds = () => {
  const delta = getQuill().getContents()
  const ops = delta.ops || []
  const currentMentions = new Set()

  // 收集当前所有@的用户ID，并转换为number类型
  ops.forEach((op) => {
    if (op.insert && op.insert.mention) {
      const id = Number(op.insert.mention.id)
      // 过滤掉 null 值
      if (!isNaN(id)) {
        currentMentions.add(id)
      }
    }
  })

  // 如果当前有@所有人，则添加0
  if (currentMentions.has(0)) {
    state.value.mentionUserIds = [0]
  } else {
    // 如果没有@任何人，保持空数组
    state.value.mentionUserIds = Array.from(currentMentions)
  }
}

//根据msg信息找到对应的聊天记录，并根据sequence等查看上下文
const queryRecordsByMsgInfo = async (msgInfo) => {
  console.log(msgInfo)
  state.value.middleMsg = msgInfo
  const dialogueList = getDialogueList(talkParams.index_name)
  const recordIndex = dialogueList?.records?.findIndex(
    (record) => record.msg_id === msgInfo.msg_id,
  )
  let recordsList = []
  console.log(recordIndex)
  if (!recordIndex || recordIndex === -1) {
    recordsList = await findTalkRecords('', true, msgInfo.sequence - 1)
  } else {
    // console.log(recordIndex)
    const startRecordIndex = Math.max(0, recordIndex - 10)
    const endRecordIndex = Math.max(0, recordIndex + 10)
    // console.log(dialogueList.records.slice(startRecordIndex, endRecordIndex))
    // console.log(recordIndex-startRecordIndex)
    recordsList = dialogueList.records.slice(startRecordIndex, endRecordIndex)
  }

  // 格式化消息，确保每条消息都有正确的 float
  recordsList = recordsList.map((item) => {
    return {
      ...item,
      float: item.user_id === talkParams.uid ? 'right' : 'left',
    }
  })

  nextTick(() => {
    zpagingRef.value.complete(recordsList.reverse())
    loadConfig.status =
      dialogueList?.records?.[0]?.sequence > 1 && recordsList.length > 0 ? 1 : 2
    nextTick(() => {
      let offset = uni.getSystemInfoSync().windowHeight
      const navBarAreaQuery = uni.createSelectorQuery()
      navBarAreaQuery
        .select('#navBarArea')
        .boundingClientRect((res) => {
          if (res) {
            // console.log('元素高度:', res.height)
            offset = offset - res.height
          }
        })
        .exec()
      const footBoxAreaQuery = uni.createSelectorQuery()
      footBoxAreaQuery
        .select('#footBoxArea')
        .boundingClientRect((res) => {
          if (res) {
            // console.log('元素高度:', res.height)
            offset = offset - res.height
          }
        })
        .exec()
      setTimeout(() => {
        zpagingRef.value.scrollIntoViewById(
          'zp-id-' + msgInfo.msg_id,
          offset - 60,
        )
      }, 1000)
    })
  })
}

//查找聊天记录
const findTalkRecords = (record, isMiddle, sequence, appointParams) => {
  return new Promise((resolve, reject) => {
    let params = {
      talk_type: talkParams.type, //1私聊；2群聊
      receiver_id: talkParams.receiver_id, //目标用户id或群聊id
      no_limit: '', //1不限制
      file_name: '',
      msg_type: 0, //消息类型：0:全部;2:代码;3:图片;4:音频;5:视频;6:文件;7:位置;9:会话;11群投票;12图文混合
      cursor: sequence || 0, //上次查询的游标
      limit: 10, //数据行数
      direction: 'down', //down向下查最新，up向上查老数据
      start_time: '',
      end_time: '',
      group_member_user_id: 0, //群成员id，当查询群历史消息的时候，需要指定群成员的时候送
      sort_sequence: 'asc',
      create_time: state.value.middleMsg.created_at,
    }
    if (record) {
      params = Object.assign({}, params, {
        start_time: record,
        end_time: record,
        limit: 1,
        direction: '',
      })
    }
    if (appointParams) {
      params = Object.assign({}, params, appointParams)
    }
    console.log(params)
    const resp = ServeTalkRecords(params)
    console.log(resp)
    resp.then(({ code, data }) => {
      console.log(data)
      if (code == 200) {
        if (data?.items.length > 0) {
          if (record) {
            resolve(data?.items[0])
            return
          }
          if (isMiddle) {
            state.value.serveFindRecord = JSON.parse(
              JSON.stringify(data?.items),
            )
            return findTalkRecords('', false, sequence + 1, {
              direction: 'up',
              sort_sequence: '',
            }).then((upResult) => {
              const finalResult = [...upResult, ...state.value.serveFindRecord]
              console.log(finalResult)
              resolve(finalResult)
            })
          } else {
            state.value.serveFindRecord = data?.items
              .reverse()
              .concat(state.value.serveFindRecord)
            resolve(JSON.parse(JSON.stringify(state.value.serveFindRecord)))
            state.value.serveFindRecord = []
          }
        } else {
          resolve([])
        }
      } else {
        resolve([])
      }
    })
    resp.catch(() => {})
  })
}

//是否是管理员
const isLeader = computed(() => {
  if (talkParams.adminList.length > 0) {
    return (
      talkParams.adminList.filter(
        (adminItem) => adminItem.erp_user_id === useAuth()?.userInfo?.value?.ID,
      ).length > 0
    )
  }
  return false
})

//长按头像@用户
const doMentionUser = (mentionSelect) => {
  console.log(mentionSelect)
  if (talkParams.type === 1) {
    return
  }
  // 构造正确的 mention 对象
  const mentionObj = {
    id: mentionSelect.user_id, // 使用 user_id 而不是 erp_user_id
    nickname: mentionSelect.nickname,
  }
  getMentionSelectLists([mentionObj])
}

let avatarPressTimer = null
let currentPressItem = null

const handleAvatarTouchStart = (item) => {
  currentPressItem = item
  avatarPressTimer = setTimeout(() => {
    if (!state.value.canUseQuillEditor) {
      onTextAreaMention(item)
    } else {
      doMentionUser(item)
    }
  }, 500)
}

const handleAvatarTouchEnd = () => {
  if (avatarPressTimer) {
    clearTimeout(avatarPressTimer)
    avatarPressTimer = null
  }
  currentPressItem = null
}

onMounted(async () => {
  if (uni.getSystemInfoSync().osName === 'ios') {
    let versions = uni.getSystemInfoSync().osVersion.split('.')
    if (Number(versions[0]) < 16) {
      console.error('ios版本低于16')
      state.value.canUseQuillEditor = false
    }
  }
  if (typeof plus !== 'undefined') {
    const webview = plus.webview.currentWebview()
    webview.setStyle({
      bottom: 0,
    })
  } else {
    document.addEventListener('plusready', () => {
      const webview = plus.webview.currentWebview()
      webview.setStyle({
        bottom: 0,
      })
    })
  }
  nextTick(() => {
    state.value.mentionSelectHeight = pxTorPx(
      uni.getSystemInfoSync().windowHeight * 0.86,
    )

    state.value.selectAreaHeight =
      rpxToPx(state.value.mentionSelectHeight) - rpxToPx(90) + 'px'

    state.value.readDetailHeight =
      rpxToPx(state.value.mentionSelectHeight) - rpxToPx(300) + 'px'
  })

  //设置观察者前设置定时器
  if (state.value.setMessageReadInterval) {
    clearInterval(state.value.setMessageReadInterval)
    state.value.setMessageReadInterval = null
  }
  state.value.setMessageReadInterval = setInterval(() => {
    checkVisibleElements()
  }, 2000)

  if (state.value.setOutMessageReadInterval) {
    clearInterval(state.value.setOutMessageReadInterval)
    state.value.setOutMessageReadInterval = null
  }
  state.value.setOutMessageReadInterval = setInterval(() => {
    checkVisibleOutElements()
  }, 2000)

  //初始化设置观察者
  const options = {
    root: null, // 使用浏览器窗口作为根容器
    threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], // 设置多个阈值点
    rootMargin: '50px 0px', // 增加观察范围
  }
  observer = new IntersectionObserver(handleIntersection, options)
  nextTick(() => {
    watch(
      messageRecordElementRefs,
      (newMessageRecordElementRefs) => {
        if (Array.isArray(newMessageRecordElementRefs)) {
          newMessageRecordElementRefs.forEach((el, index) => {
            observeElement(el, index)
          })
        }
      },
      {
        immediate: true,
        deep: true,
      },
    )
    watch(
      messageRecordElementRefsWithoutIndex,
      (newMessageRecordElementRefs) => {
        if (Array.isArray(newMessageRecordElementRefs)) {
          newMessageRecordElementRefs.forEach((el, index) => {
            observeElement(el, index)
          })
        }
      },
      {
        immediate: true,
        deep: true,
      },
    )
    if (messageRecordElementRefs.value.length > 0) {
      messageRecordElementRefs.value.forEach((el, index) =>
        observeElement(el, index),
      )
    }
  })
})

//检查需要发送已读回执的元素
const checkVisibleElements = () => {
  if (state.value.visibleElements.size > 0) {
    // console.error('当前待发送已读的消息元素:', state.value.visibleElements)
    let waitDoRead = []
    state.value.visibleElements.forEach((el) => {
      // console.log(el)
      const msgId = el.dataset.msgid
      const talkType = Number(el.dataset.talktype)
      const receiverId = Number(el.dataset.receiverid)
      // console.log(msgId, talkType, receiverId)
      if (waitDoRead.length === 0) {
        waitDoRead.push({
          msg_ids: [msgId],
          talk_type: talkType,
          receiver_id: receiverId,
        })
      } else {
        const existingItem = waitDoRead.find(
          (item) =>
            item.talk_type === talkType && item.receiver_id === receiverId,
        )
        if (existingItem) {
          existingItem.msg_ids.push(msgId)
        } else {
          waitDoRead.push({
            msg_ids: [msgId],
            talk_type: talkType,
            receiver_id: receiverId,
          })
        }
      }
    })
    // console.error(waitDoRead)
    if (waitDoRead.length > 0) {
      waitDoRead.forEach((doReadItem) => {
        // 查找上一次存储的对应项
        const prevItem = state.value.tempWaitDoRead.find(
          (prev) =>
            prev.talk_type === doReadItem.talk_type &&
            prev.receiver_id === doReadItem.receiver_id,
        )
        // 如果找不到上一次的项，或者msg_ids不一致，则发送
        if (
          !prevItem ||
          !doReadItem.msg_ids.every((id) => prevItem.msg_ids.includes(id))
        ) {
          console.error('====发送了已读回执=====', doReadItem)
          //发送已读回执
          ws.emit('im.message.read', doReadItem)
        }
      })
    }
    // 更新完成后再保存当前数据
    state.value.tempWaitDoRead = JSON.parse(JSON.stringify(waitDoRead))
  }
}

//检查需要获取别人发送的已读回执列表的元素
const checkVisibleOutElements = () => {
  if (state.value.visibleOutElements.size > 0) {
    // console.error('当前待获取已读回执列表的消息元素:', state.value.visibleOutElements)
    let waitDoCheck = []
    state.value.visibleOutElements.forEach((el) => {
      // console.log(el)
      const msgId = el.dataset.msgid
      const talkType = Number(el.dataset.talktype)
      const receiverId = Number(el.dataset.receiverid)
      if (waitDoCheck.length === 0) {
        waitDoCheck.push({
          msg_ids: [msgId],
          talk_type: talkType,
          receiver_id: receiverId,
        })
      } else {
        const existingItem = waitDoCheck.find(
          (item) =>
            item.talk_type === talkType && item.receiver_id === receiverId,
        )
        if (existingItem) {
          existingItem.msg_ids.push(msgId)
        } else {
          waitDoCheck.push({
            msg_ids: [msgId],
            talk_type: talkType,
            receiver_id: receiverId,
          })
        }
      }
    })
    // console.error(waitDoCheck)
    if (waitDoCheck.length > 0) {
      waitDoCheck.forEach((doCheckItem) => {
        // 查找上一次存储的对应项
        // const prevItem = state.value.tempWaitDoCheck.find(
        //   (prev) =>
        //     prev.talk_type === doCheckItem.talk_type &&
        //     prev.receiver_id === doCheckItem.receiver_id,
        // )
        // // 如果找不到上一次的项，或者msg_ids不一致，则发送
        // if (
        //   !prevItem ||
        //   !doCheckItem.msg_ids.every((id) => prevItem.msg_ids.includes(id))
        // ) {
        console.error('====调用了已读回执查询接口=====', doCheckItem)
        let params = Object.assign({}, doCheckItem, {
          talkType: doCheckItem.talk_type, //1私聊2群聊
          receiverId:
            doCheckItem.talk_type === 1
              ? talkParams.uid
              : talkParams.receiver_id, //私聊的时候是对方用户id，群聊的时候是对方群id
          msgIds: doCheckItem.msg_ids,
          type: 'list', //list是列表，detail是详情
        })

        const resp = ServeReadConditionList(params)
        // console.log(resp)
        resp
          .then(({ code, data }) => {
            // console.log(data)
            if (code == 200) {
              // 处理批量更新
              if (Array.isArray(data.data)) {
                console.error('处理批量更新', data.data)
                data.data.forEach((item) => {
                  if (item.msgId && item.readNum !== undefined) {
                    recordReadsMap.value.set(item.msgId, item.readNum)
                  }
                })
              } else if (data.data && data.data.readNum !== undefined) {
                console.error('处理单个更新', data.data)
                doCheckItem.msg_ids.forEach((msgId) => {
                  recordReadsMap.value.set(msgId, data.data.readNum)
                })
              }
            }
          })
          .catch(() => {})
        // }
      })
    }
    // 更新完成后再保存当前数据
    state.value.tempWaitDoCheck = JSON.parse(JSON.stringify(waitDoCheck))
  }
}

// 观察元素
const observeElement = (el, index) => {
  if (el && observer) {
    // 使用 requestAnimationFrame 优化 DOM 操作
    requestAnimationFrame(() => {
      observer.unobserve(el) // 先取消观察
      observer.observe(el) // 再重新观察
    })
  }
}

// 观察者函数
const handleIntersection = (entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
      // 确保元素有足够比例可见
      // 元素进入视口
      let elData = entry.target.dataset
      const msgType = elData.msgtype
      const userId = elData.userid
      if (Number(msgType) < 1000 && Number(userId) !== Number(talkParams.uid)) {
        //我读别人发的消息，需要发送已读回执
        state.value.visibleElements.add(entry.target)
      }
      if (Number(msgType) < 1000 && Number(userId) === Number(talkParams.uid)) {
        //我发的消息，需要获取别人发送的已读回执列表
        state.value.visibleOutElements.add(entry.target)
      }
    } else {
      // 元素离开视口，从集合中移除
      state.value.visibleElements.delete(entry.target)
      state.value.visibleOutElements.delete(entry.target)
    }
  })
  if (state.value.isFirstEnter) {
    state.value.isFirstEnter = false
    // 立即执行一次
    // checkVisibleElements()
    // checkVisibleOutElements()
  }
}

const pxTorPx = (px) => {
  const sysInfo = uni.getSystemInfoSync()
  const rpx = px / (sysInfo.screenWidth / 750)
  return rpx
}

const rpxToPx = (rpx) => {
  const sysInfo = uni.getSystemInfoSync()
  const px = (sysInfo.screenWidth / 750) * rpx
  return px
}

onUnmounted(() => {
  if (!state.value.keepDialogInfo) {
    dialogueStore.setDialogue({})
  }
  clearMultiSelect()
  if (avatarPressTimer) {
    clearTimeout(avatarPressTimer)
  }
  // 清理防抖定时器
  if (state.value.showMentionSelectTimer) {
    clearTimeout(state.value.showMentionSelectTimer)
  }
  if (uploadsStore.isUploading) {
    uploadsStore.clearUpload()
  }
  if (observer) {
    observer.disconnect()
  }
  if (state.value.setMessageReadInterval) {
    clearInterval(state.value.setMessageReadInterval)
    state.value.setMessageReadInterval = null
    checkVisibleElements()
  }
  if (state.value.setOutMessageReadInterval) {
    clearInterval(state.value.setOutMessageReadInterval)
    state.value.setOutMessageReadInterval = null
    checkVisibleOutElements()
  }
})

onShow(() => {
  if (state.value.isFromHide) {
    if (state.value.setMessageReadInterval) {
      clearInterval(state.value.setMessageReadInterval)
      state.value.setMessageReadInterval = null
    }
    state.value.setMessageReadInterval = setInterval(() => {
      checkVisibleElements()
    }, 2000)

    if (state.value.setOutMessageReadInterval) {
      clearInterval(state.value.setOutMessageReadInterval)
      state.value.setOutMessageReadInterval = null
    }
    state.value.setOutMessageReadInterval = setInterval(() => {
      checkVisibleOutElements()
    }, 2000)
    state.value.isFromHide = false
  }
})
onHide(() => {
  state.value.isFromHide = true
  if (state.value.setMessageReadInterval) {
    clearInterval(state.value.setMessageReadInterval)
    state.value.setMessageReadInterval = null
    checkVisibleElements()
  }
  if (state.value.setOutMessageReadInterval) {
    clearInterval(state.value.setOutMessageReadInterval)
    state.value.setOutMessageReadInterval = null
    checkVisibleOutElements()
  }
})

// 修改防抖函数的实现
const showMentionSelectDebounced = (quill) => {
  const text = quill.getText()
  // 光标不在@后第一位时，不触发选人弹窗
  if (!state.value.cursorMention) {
    return
  }
  // 以下逻辑是 记录触发@时，用户的输入框内容，下次一样内容得@不会再次触发
  if (text !== state.value.lastMentionText) {
    state.value.lastMentionTriggered = false
  }
  // 如果已经触发过，则不再触发
  if (state.value.lastMentionTriggered) {
    console.log('return')
    return
  }
  // 记录当前文本内容和触发状态
  state.value.lastMentionText = text
  state.value.lastMentionTriggered = true
  state.value.isShowMentionSelect = true
  // quill.blur()
}

// 处理普通输入框的表情插入
const onTextAreaEmoticon = (data) => {
  if (data.type == 1) {
    if (data.img) {
      // 如果是图片表情，插入对应的文本标记
      state.value.textAreaValue += `${data.value}`
    } else {
      // 如果是文本表情，直接插入
      state.value.textAreaValue += data.value
    }
  }
}

// 处理普通输入框的长按@功能
const onTextAreaMention = (user) => {
  if (talkParams.type === 1) {
    return
  }
  if (state.value.textAreaValue.length > 0) {
    if (
      state.value.textAreaValue[state.value.textAreaValue.length - 1] === '@'
    ) {
      state.value.textAreaValue = state.value.textAreaValue.slice(0, -1)
    }
  }
  state.value.textAreaValue += `@${user.nickname} `

  // 先创建新数组，再赋值
  const newMentionUserIds = state.value.mentionUserIds
    ? [...state.value.mentionUserIds]
    : []
  newMentionUserIds.push(user.nickname === '所有人' ? 0 : user.id)
  state.value.mentionUserIds = newMentionUserIds

  if (state.value.isShowMentionSelect) {
    state.value.isShowMentionSelect = false
  }
}

// 隐藏消息已读未读详情
const hideMessageReadDetail = () => {
  state.value.isShowMessageReadDetail = false
}

// 显示消息已读未读详情
const toShowMessageReadDetail = (item) => {
  console.log(item)
  if (talkParams.type === 1) {
    return
  }
  state.value.isShowMessageReadDetail = true
  state.value.currentMsgReadOrNotDetail = item
  getMessageReadDetail(1)
}
//切换消息已读/未读详情
const msgReadDetailTabsChange = (e) => {
  // console.log(e)
  if (Number(e) !== Number(state.value.currentIsUnread)) {
    state.value.readNumPage = 1
  }
  state.value.currentIsUnread = Number(e)
  getMessageReadDetail(e)
}
//获取消息已读未读详情
const getMessageReadDetail = (isUnread) => {
  let params = {
    page: state.value.readNumPage,
    pageSize: 10,
    type: 'detail', //list是列表，detail是详情
    talkType: state.value.currentMsgReadOrNotDetail.talk_type, //1私聊2群聊
    receiverId: state.value.currentMsgReadOrNotDetail.receiver_id, //私聊的时候是对方用户id，群聊的时候是对方群id
    msgId: state.value.currentMsgReadOrNotDetail.msg_id,
    isUnread: Number(isUnread), //不送或者送0代表看已读，送1看未读
  }
  const resp = ServeMessageReadDetail(params)
  // console.log(resp)
  resp
    .then(({ code, data }) => {
      console.log(data)
      if (code == 200) {
        if (Number(isUnread) === 0) {
          state.value.msgReadDetailTabs[0].title =
            '未读 （' + (Number(talkParams.num) - 1 - data.count > 0 ? Number(talkParams.num) - 1 - data.count : 0) + '）'
          state.value.msgReadDetailTabs[1].title = '已读 （' + data.count + '）'
        } else if (Number(isUnread) === 1) {
          state.value.msgReadDetailTabs[0].title = '未读 （' + data.count + '）'
          state.value.msgReadDetailTabs[1].title =
            '已读 （' + (Number(talkParams.num) - 1 - data.count > 0 ? Number(talkParams.num) - 1 - data.count : 0) + '）'
        }
        if (state.value.readNumPage === 1) {
          state.value.msgReadOrNotDetail = data.data
        } else {
          state.value.msgReadOrNotDetail = [
            ...state.value.msgReadOrNotDetail,
            ...data.data,
          ]
        }
        if (!data?.data || data?.data?.length < 10) {
          state.value.hasMoreReadDetail = false
        } else {
          state.value.hasMoreReadDetail = true
        }
      }
    })
    .catch(() => {})
}
//滚动到底部加载更多已读未读详情
const loadMoreReadDetails = () => {
  if (!state.value.hasMoreReadDetail) {
    return
  }
  state.value.readNumPage += 1
  getMessageReadDetail(state.value.currentIsUnread)
}
</script>
<style scoped lang="less">
.dialog-page {
  flex: 1;
  background-image: url('@/static/image/clockIn/z3280@3x.png');
  background-size: cover;
  background-position: bottom center;
  background-attachment: scroll;
  width: 100%;

  .dialog-list {
    padding: 20rpx 32rpx;
  }

  .toChatSetting_btn {
    ::v-deep .tmicon-gengduo {
      line-height: unset !important;
    }
  }
}

.edit-revoked-message {
  margin-left: 10rpx;
  color: #46299d;
  cursor: pointer;
  font-size: 24rpx;

  &:hover {
    text-decoration: underline;
  }
}

.searchRoot {
  background-color: #fff;
  padding: 22rpx 18rpx;
}

.contentRoot {
  margin-top: 20rpx;
  background-color: #fff;
}

.footBox {
  min-height: 162rpx;
  background-color: #fff;

  .quote-area {
    margin: 4rpx 0 0 0;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    overflow: hidden;
    width: 100%;

    span {
      display: -webkit-inline-box;
      text-overflow: ellipsis;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      width: 100%;
      word-break: break-all;
    }

    img {
      margin: 0 0 0 30rpx;
      flex-shrink: 0;
    }
  }
}

.load-toolbar {
  height: 50rpx;
  color: #409eff;
  text-align: center;
  line-height: 50rpx;
  font-size: 24rpx;

  .no-more {
    color: #b9b3b3;
  }
}

.message-item {
  &.border {
    border-radius: 16rpx;
  }
}

.message-box {
  width: 100%;
  min-height: 30rpx;
  margin-bottom: 5rpx;
}

.record-box {
  display: flex;
  flex-direction: row;
  align-items: flex-start;

  .checkbox-column {
    display: flex;
    justify-content: center;
    width: 42rpx;
    order: 1;
    user-select: none;
    margin-top: 20rpx;
    margin-right: 20rpx;
  }

  .avatar-column {
    width: 80rpx;
    display: flex;
    align-items: center;
    order: 2;
    user-select: none;
    margin-top: 16rpx;
    flex-direction: column;
  }

  .main-column {
    flex: 1 auto;
    order: 3;
    position: relative;
    box-sizing: border-box;
    padding: 16rpx 20rpx 14rpx 20rpx;
    // overflow: hidden;
    min-height: 30px;

    .talk-title {
      display: flex;
      align-items: center;
      margin-bottom: 6rpx;
      font-size: 24rpx;
      user-select: none;
      color: #bababa;
      opacity: 1;

      &.show {
        opacity: 1;
      }

      .nickname {
        color: var(--im-text-color);
        margin-right: 5rpx;

        .at {
          display: none;
        }

        &:hover {
          color: var(--im-primary-color);

          .at {
            display: inline-block;
          }
        }
      }

      span {
        transform: scale(0.88);
        transform-origin: left center;
      }
    }

    .talk-content {
      display: flex;
      justify-content: flex-start;
      align-items: flex-end;

      box-sizing: border-box;
      width: 100%;

      .talk-tools {
        display: flex;
        margin: 0 16rpx;
        color: #a79e9e;
        font-size: 24rpx;
        user-select: none;
        align-items: center;
        justify-content: space-around;

        .more-tools {
          visibility: hidden;
          margin-left: 5rpx;
        }
      }
    }

    .have_read_num {
      text-align: right;
      color: #7a58de;
      font-size: 22rpx;
      font-weight: 400;
      line-height: 34rpx;
      margin: 5rpx 0 0;
    }

    .talk-reply {
      display: flex;
      align-items: flex-start;
      align-items: center;
      width: fit-content;
      padding: 8rpx;
      margin-top: 6rpx;
      margin-right: auto;
      font-size: 24rpx;
      color: #8f8f8f;
      word-break: break-all;
      background-color: var(--im-message-left-bg-color);
      border-radius: 10rpx;
      max-width: 450rpx;
      overflow: hidden;
      user-select: none;

      .icon-top {
        margin-right: 6rpx;
      }

      .ellipsis {
        display: -webkit-inline-box;
        text-overflow: ellipsis;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;
        overflow: hidden;
      }
    }

    &:hover {
      .talk-title {
        opacity: 1;
      }

      .more-tools {
        visibility: visible !important;
      }
    }
  }

  &.direction-rt {
    .avatar-column {
      order: 3;
    }

    .main-column {
      order: 2;

      .talk-title {
        justify-content: flex-end;

        span {
          transform-origin: right center;
        }
      }

      .talk-content {
        flex-direction: row-reverse;
      }

      .talk-reply {
        margin-right: 0;
        margin-left: auto;
      }
    }
  }

  &.multi-select {
    border-radius: 5px;

    &:hover,
    &.multi-select-check {
      background-color: var(--im-active-bg-color);
    }
  }
}

.content-placeholder {
  height: 58rpx;
}

.quillBox {
  :deep(.ql-clipboard) {
    position: relative;
    opacity: 0;
    height: 0rpx;
    overflow: auto;
    display: none;
  }

  :deep(.ql-editor) {
    padding: 14rpx 22rpx;
    background-color: #f9f9f9;
    border-radius: 8rpx;
    outline: none !important;
    max-height: 294rpx;
    overflow: auto;
    line-height: 44rpx;
    font-size: 32rpx;

    .ed-emoji {
      width: 44rpx;
      height: 44rpx;
      display: inline-block;
    }
  }

  :deep(.round-3) {
    max-height: 320rpx;
    margin: 0 0 0 16rpx!important;
    overflow-y: scroll;
  }
}

:deep(.wd-action-sheet) {
  background-color: #8b8b8b !important;
}

:deep(.wd-action-sheet__panel-title) {
  color: #fff !important;
}

.component-content {
  position: relative;
  z-index: 1;
  /* 确保 z-index 低于 deepBubble */
}

.divider {
  width: 100%;
  height: 1rpx;
  background-color: #e7e7e7;
}

.mention-select-drawer {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  padding: 36rpx 32rpx 0;

  .cancel-btns {
    flex-shrink: 0;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;

    .hide-btn {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      position: relative;

      text {
      }

      img {
        width: 18rpx;
        height: 10rpx;
      }
    }
  }

  .mention-done-btn {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    padding: 6rpx 24rpx;
    background-color: #f3f3f3;
    border-radius: 8rpx;
    flex-shrink: 0;

    span {
      color: #bababa;
      line-height: 40rpx;
      flex-shrink: 0;
    }
  }

  .mention-done-btn-can-do {
    background-color: #46299d;

    span {
      color: #fff;
    }
  }

  .mention-edit-btn {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    flex-shrink: 0;

    span {
      flex-shrink: 0;
    }
  }
}

:deep(.mention) {
  color: #1890ff;
}

.msg-read-detail-tabs {
  padding: 32rpx 0 0;
  :deep(.noNvueBorder) {
    padding: 0 !important;
    margin: 0 !important;
  }
  .msg-read-detail {
    padding: 28rpx 32rpx;
    .msg-read-detail-each {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: flex-start;
      padding: 20rpx 32rpx;
      border-bottom: 1rpx solid #f8f8f8;
      .msg-read-detail-each-avatar {
        margin: 0 20rpx 0 0;
      }
      .msg-read-detail-each-info {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        justify-content: center;
        span {
          font-size: 28rpx;
          color: #191919;
          font-weight: 500;
          line-height: 40rpx;
        }
      }
    }
  }
}
</style>
