2024-11-22 01:06:37 +00:00
|
|
|
|
<template>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<div class="dialog-page">
|
|
|
|
|
<ZPaging
|
|
|
|
|
use-chat-record-mode
|
2025-03-07 07:02:53 +00:00
|
|
|
|
use-virtual-list
|
2025-04-10 08:15:44 +00:00
|
|
|
|
:inside-more="true"
|
|
|
|
|
:hide-no-more-inside="true"
|
2025-04-07 06:10:16 +00:00
|
|
|
|
cell-height-mode="fixed"
|
2025-03-07 07:02:53 +00:00
|
|
|
|
:refresher-enabled="true"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
:show-scrollbar="false"
|
2025-03-07 07:02:53 +00:00
|
|
|
|
:loading-more-enabled="true"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
:hide-empty-view="true"
|
|
|
|
|
height="100%"
|
|
|
|
|
ref="zpagingRef"
|
2025-03-06 10:50:11 +00:00
|
|
|
|
v-model="virtualList"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
:loading-more-custom-style="{ display: 'none', height: '0' }"
|
2025-03-07 07:02:53 +00:00
|
|
|
|
@scrolltolower="onScrollToLower"
|
2025-03-13 11:54:29 +00:00
|
|
|
|
@scrolltoupper="onScrollToUpper"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
|
|
|
|
<template #top>
|
2025-03-26 11:51:07 +00:00
|
|
|
|
<customNavbar
|
|
|
|
|
:title="talkParams.username"
|
|
|
|
|
id="navBarArea"
|
|
|
|
|
:hideBack="dialogueStore.isOpenMultiSelect"
|
|
|
|
|
>
|
|
|
|
|
<template #left v-if="dialogueStore.isOpenMultiSelect">
|
2025-03-28 08:13:45 +00:00
|
|
|
|
<text
|
|
|
|
|
class="ml-[36rpx]"
|
|
|
|
|
@click="dialogueStore.isOpenMultiSelect = false"
|
|
|
|
|
>
|
|
|
|
|
取消
|
|
|
|
|
</text>
|
2025-03-26 11:51:07 +00:00
|
|
|
|
</template>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<template
|
|
|
|
|
#subTitle
|
|
|
|
|
v-if="talkStore?.findItem(talkParams.index_name)?.group_type === 4"
|
|
|
|
|
>
|
|
|
|
|
<div class="text-[24rpx] text-[#999999]">公司群</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template #right>
|
2025-03-14 05:15:54 +00:00
|
|
|
|
<div
|
|
|
|
|
class="mr-[36rpx] toChatSetting_btn"
|
2025-03-24 08:37:29 +00:00
|
|
|
|
v-if="!talkParams.isDismiss && !talkParams.isQuit"
|
2025-03-14 05:15:54 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<tm-icon
|
|
|
|
|
color="rgb(51, 51, 51)"
|
|
|
|
|
:font-size="36"
|
|
|
|
|
name="tmicon-gengduo"
|
|
|
|
|
@click="toChatSettingsPage"
|
|
|
|
|
></tm-icon>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</customNavbar>
|
|
|
|
|
</template>
|
|
|
|
|
<!-- <template #top>
|
2024-12-06 08:55:15 +00:00
|
|
|
|
<div class="load-toolbar pointer">
|
|
|
|
|
<span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
|
2025-03-07 07:02:53 +00:00
|
|
|
|
<span v-else-if="loadConfig.status == 1" @click="onScrollToLower"> 查看更多消息 ... </span>
|
2024-12-06 08:55:15 +00:00
|
|
|
|
<span v-else class="no-more"> 没有更多消息了 </span>
|
|
|
|
|
</div>
|
|
|
|
|
</template> -->
|
|
|
|
|
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<!-- 数据加载状态栏 -->
|
2025-03-06 10:50:11 +00:00
|
|
|
|
<div class="dialog-list" @touchstart="handleHidePanel">
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<div
|
|
|
|
|
class="message-item"
|
|
|
|
|
v-for="item in virtualList"
|
2025-03-13 11:54:29 +00:00
|
|
|
|
:id="`zp-id-${item.msg_id}`"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
:key="item.zp_index"
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="transform: scaleY(-1);"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
|
|
|
|
<!-- 系统消息 -->
|
|
|
|
|
<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"
|
2025-03-13 05:08:58 +00:00
|
|
|
|
:msg_id="item.msg_id"
|
2025-03-17 08:32:29 +00:00
|
|
|
|
:revokeInfo="item.revokeInfo"
|
|
|
|
|
:extra="item.extra"
|
2025-03-13 05:08:58 +00:00
|
|
|
|
>
|
2025-03-14 05:15:54 +00:00
|
|
|
|
<template
|
|
|
|
|
v-if="
|
|
|
|
|
canEditRevokedMessage(item) && item.user_id === userStore.uid
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<span
|
|
|
|
|
class="edit-revoked-message"
|
|
|
|
|
@click="restoreRevokedMessage(item)"
|
|
|
|
|
>
|
|
|
|
|
重新编辑
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
2025-03-13 05:08:58 +00:00
|
|
|
|
</revoke-message>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
2025-02-05 08:22:32 +00:00
|
|
|
|
<div
|
2025-02-11 03:45:19 +00:00
|
|
|
|
v-else
|
|
|
|
|
class="message-box record-box"
|
|
|
|
|
:class="{
|
2025-03-21 09:01:34 +00:00
|
|
|
|
'direction-rt': item.user_id === talkParams.uid,
|
2025-02-11 03:45:19 +00:00
|
|
|
|
'multi-select': dialogueStore.isOpenMultiSelect,
|
|
|
|
|
'multi-select-check': item.isCheck,
|
|
|
|
|
}"
|
2025-02-05 08:22:32 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<!-- 多选按钮 -->
|
|
|
|
|
<aside
|
|
|
|
|
v-if="dialogueStore.isOpenMultiSelect"
|
|
|
|
|
class="checkbox-column"
|
2025-02-05 08:22:32 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<!-- <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>
|
|
|
|
|
|
|
|
|
|
<!-- 头像信息 -->
|
2025-03-22 06:22:09 +00:00
|
|
|
|
<aside
|
|
|
|
|
class="avatar-column"
|
|
|
|
|
@click="toUserDetailPage(item)"
|
|
|
|
|
@touchstart="() => handleAvatarTouchStart(item)"
|
|
|
|
|
@touchend="handleAvatarTouchEnd"
|
|
|
|
|
>
|
2025-04-03 07:45:12 +00:00
|
|
|
|
<!-- <im-avatar
|
2025-02-11 03:45:19 +00:00
|
|
|
|
class="pointer"
|
|
|
|
|
:src="item.avatar"
|
|
|
|
|
:size="80"
|
|
|
|
|
:username="item.nickname"
|
|
|
|
|
@click="showUserInfoModal(item.user_id)"
|
2025-04-03 07:45:12 +00:00
|
|
|
|
/> -->
|
|
|
|
|
<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>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</aside>
|
|
|
|
|
|
|
|
|
|
<!-- 主体信息 -->
|
|
|
|
|
<main class="main-column">
|
|
|
|
|
<div class="talk-title">
|
|
|
|
|
<span
|
|
|
|
|
class="nickname pointer"
|
2025-03-22 06:22:09 +00:00
|
|
|
|
v-show="
|
|
|
|
|
talkParams.type == 2 && item.user_id !== talkParams.uid
|
|
|
|
|
"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
2025-03-22 06:22:09 +00:00
|
|
|
|
<!-- <span class="at">@</span> -->
|
2025-02-11 03:45:19 +00:00
|
|
|
|
{{ item.nickname }}
|
|
|
|
|
</span>
|
|
|
|
|
<span>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
{{ parseTime(item.created_at, '{m}/{d} {h}:{i}') }}
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
class="talk-content"
|
|
|
|
|
:class="{ pointer: dialogueStore.isOpenMultiSelect }"
|
2025-02-05 08:22:32 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<deepBubble
|
|
|
|
|
@clickMenu="(menuType) => onContextMenu(menuType, item)"
|
|
|
|
|
:isShowCopy="isShowCopy(item)"
|
2025-03-14 05:15:54 +00:00
|
|
|
|
:isShowWithdraw="isRevoke(talkParams.uid, item) || isLeader"
|
2025-02-05 08:22:32 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<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">
|
2024-12-06 08:55:15 +00:00
|
|
|
|
<template v-if="talkParams.type == 1 && item.float == 'right'">
|
2024-12-19 03:02:47 +00:00
|
|
|
|
<loading theme="outline" size="19" fill="#000" :sxtrokeWidth="1" class="icon-rotate"
|
2024-11-26 08:51:36 +00:00
|
|
|
|
v-show="item.send_status == 1" />
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
2024-11-26 08:51:36 +00:00
|
|
|
|
<span v-show="item.send_status == 1"> 正在发送... </span>
|
2024-12-06 08:55:15 +00:00
|
|
|
|
<span v-show="item.send_status != 1"> 已送达 </span>
|
2024-11-26 08:51:36 +00:00
|
|
|
|
</template>
|
|
|
|
|
|
2024-12-06 08:55:15 +00:00
|
|
|
|
</div> -->
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</div>
|
2024-11-22 01:06:37 +00:00
|
|
|
|
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<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>
|
2024-12-19 03:02:47 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
<div class="load-toolbar pointer" style="transform: scaleY(-1);">
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<span v-if="loadConfig.status == 0">正在加载数据中 ...</span>
|
2025-04-09 07:08:54 +00:00
|
|
|
|
<span
|
|
|
|
|
v-if="
|
|
|
|
|
loadConfig.status == 1 ||
|
|
|
|
|
(loadConfig.status == 2 && !state.localPageLoadDone)
|
|
|
|
|
"
|
|
|
|
|
@click="onScrollToLower"
|
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
查看更多消息 ...
|
|
|
|
|
</span>
|
2025-04-09 07:08:54 +00:00
|
|
|
|
<span
|
|
|
|
|
v-if="loadConfig.status == 2 && state.localPageLoadDone"
|
|
|
|
|
class="no-more"
|
|
|
|
|
>
|
2025-03-07 07:02:53 +00:00
|
|
|
|
没有更多消息了
|
|
|
|
|
</span>
|
2024-11-22 01:06:37 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<template #bottom>
|
2025-03-13 11:54:29 +00:00
|
|
|
|
<div class="footBox" id="footBoxArea">
|
2025-03-30 08:22:29 +00:00
|
|
|
|
<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>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<div v-if="!dialogueStore.isOpenMultiSelect">
|
|
|
|
|
<div
|
2025-03-10 07:09:26 +00:00
|
|
|
|
class="pt-[16rpx] ml-[32rpx] mr-[32rpx] flex items-start justify-between"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
2025-03-28 08:13:45 +00:00
|
|
|
|
<div class="flex-1 quillBox" style="">
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<QuillEditor
|
|
|
|
|
ref="editor"
|
|
|
|
|
id="editor"
|
|
|
|
|
:options="editorOption"
|
|
|
|
|
@editorChange="onEditorChange"
|
2025-03-28 10:33:43 +00:00
|
|
|
|
style="width: 100%; flex: 1; height: 100%;"
|
2025-03-06 10:50:11 +00:00
|
|
|
|
@click="onEditorClick"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
/>
|
|
|
|
|
<!-- <tm-input type=textarea autoHeight focusColor="#F9F9F9" color="#F9F9F9" :inputPadding="[12]"
|
|
|
|
|
placeholder=""></tm-input> -->
|
2025-03-10 07:09:26 +00:00
|
|
|
|
<div class="quote-area" v-if="state?.quoteInfo">
|
|
|
|
|
<span
|
|
|
|
|
v-if="state?.quoteInfo?.msg_type === 1"
|
|
|
|
|
class="text-[28rpx] text-[#999]"
|
|
|
|
|
>
|
|
|
|
|
{{
|
|
|
|
|
state?.quoteInfo?.nickname +
|
2025-03-20 11:12:46 +00:00
|
|
|
|
':' +
|
2025-03-10 07:09:26 +00:00
|
|
|
|
state?.quoteInfo?.extra?.content
|
|
|
|
|
}}
|
|
|
|
|
</span>
|
|
|
|
|
<span
|
2025-03-28 08:13:45 +00:00
|
|
|
|
v-if="state?.quoteInfo?.msg_type !== 1"
|
2025-03-10 07:09:26 +00:00
|
|
|
|
class="text-[28rpx] text-[#999]"
|
|
|
|
|
>
|
|
|
|
|
{{
|
|
|
|
|
state?.quoteInfo?.nickname +
|
2025-03-20 11:12:46 +00:00
|
|
|
|
':' +
|
2025-03-11 11:56:43 +00:00
|
|
|
|
ChatMsgTypeMapping[state?.quoteInfo?.msg_type]
|
2025-03-10 07:09:26 +00:00
|
|
|
|
}}
|
|
|
|
|
</span>
|
|
|
|
|
<img
|
|
|
|
|
@click="clearQuoteInfo"
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="width: 30rpx; height: 30rpx;"
|
2025-03-27 09:25:12 +00:00
|
|
|
|
src="@/static/image/login/check-circle-filled@3x.png"
|
2025-03-10 07:09:26 +00:00
|
|
|
|
/>
|
|
|
|
|
</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="发送"
|
2025-04-08 08:58:28 +00:00
|
|
|
|
:loading="state.isLoading"
|
|
|
|
|
:width="120"
|
2025-03-10 07:09:26 +00:00
|
|
|
|
></tm-button>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="state.isOpenEmojiPanel" class="mt-[50rpx]">
|
|
|
|
|
<emojiPanel @on-select="onEmoticonEvent" />
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="state.isOpenFilePanel" class="mt-[16rpx]">
|
|
|
|
|
<filePanel
|
|
|
|
|
@selectImg="handleSelectImg"
|
|
|
|
|
:talkParams="talkParams"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2024-12-19 03:02:47 +00:00
|
|
|
|
</div>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<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>
|
2025-03-26 11:51:07 +00:00
|
|
|
|
<!-- <div
|
2025-02-11 03:45:19 +00:00
|
|
|
|
@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>
|
2025-03-26 11:51:07 +00:00
|
|
|
|
</div> -->
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<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>
|
2024-12-19 03:02:47 +00:00
|
|
|
|
</div>
|
2024-12-06 08:55:15 +00:00
|
|
|
|
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<!--底部安全区-->
|
|
|
|
|
<div class="content-placeholder"></div>
|
|
|
|
|
<tm-drawer
|
|
|
|
|
placement="bottom"
|
|
|
|
|
v-model:show="state.showWin"
|
|
|
|
|
:hideHeader="true"
|
|
|
|
|
:height="416"
|
|
|
|
|
:round="6"
|
2025-02-05 08:22:32 +00:00
|
|
|
|
>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
<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"
|
2025-04-08 08:58:28 +00:00
|
|
|
|
class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#CF3050] leading-[48rpx] w-full text-center"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
|
|
|
|
撤回
|
|
|
|
|
</div>
|
|
|
|
|
<div class="divider"></div>
|
|
|
|
|
<div
|
|
|
|
|
@click="state.showWin = false"
|
2025-04-08 08:58:28 +00:00
|
|
|
|
class="mt-[32rpx] mb-[32rpx] text-[32rpx] text-[#000000] leading-[48rpx] w-full text-center"
|
2025-02-11 03:45:19 +00:00
|
|
|
|
>
|
|
|
|
|
取消
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</tm-drawer>
|
2024-12-24 08:28:44 +00:00
|
|
|
|
</div>
|
2025-02-11 03:45:19 +00:00
|
|
|
|
</template>
|
|
|
|
|
</ZPaging>
|
2025-03-12 08:25:42 +00:00
|
|
|
|
<tm-drawer
|
|
|
|
|
placement="bottom"
|
2025-03-12 11:59:54 +00:00
|
|
|
|
v-model:show="state.isShowMentionSelect"
|
2025-03-12 08:25:42 +00:00
|
|
|
|
:hideHeader="true"
|
|
|
|
|
:round="5"
|
|
|
|
|
:height="state.mentionSelectHeight"
|
|
|
|
|
>
|
2025-03-11 11:56:43 +00:00
|
|
|
|
<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"
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="width: 210rpx;"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
>
|
2025-03-12 08:25:42 +00:00
|
|
|
|
<div
|
|
|
|
|
class="hide-btn"
|
|
|
|
|
v-if="!state.mentionIsMulSelect"
|
|
|
|
|
@click="hideMentionSelect"
|
|
|
|
|
>
|
2025-03-11 11:56:43 +00:00
|
|
|
|
<img
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="width: 40rpx; height: 40rpx;"
|
2025-03-27 09:25:12 +00:00
|
|
|
|
src="@/static/image/chatList/mention_select_hide_bg.png"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
/>
|
|
|
|
|
<img
|
|
|
|
|
style="
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 50%;
|
|
|
|
|
left: 50%;
|
|
|
|
|
margin-left: -9rpx;
|
|
|
|
|
margin-top: -5rpx;
|
|
|
|
|
"
|
2025-03-27 09:25:12 +00:00
|
|
|
|
src="@/static/image/chatList/mention_select_hide_icon.png"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<span
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="flex-shrink: 0; display: block;"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
class="text-[32rpx] font-regular text-[#191919]"
|
|
|
|
|
v-if="state.mentionIsMulSelect"
|
|
|
|
|
@click="changeMentionSelectMul(false)"
|
|
|
|
|
>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
{{ $t('cancel') }}
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
class="flex flex-row-center-center flex-col"
|
2025-03-20 11:12:46 +00:00
|
|
|
|
style="padding: 6rpx 0;"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
<text>{{ $t('chat.mention.select') }}</text>
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</div>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
<div class="flex-row flex flex-row-center-end" style="width: 210rpx;">
|
2025-03-11 11:56:43 +00:00
|
|
|
|
<div
|
|
|
|
|
class="mention-edit-btn"
|
|
|
|
|
v-if="!state.mentionIsMulSelect"
|
|
|
|
|
@click="changeMentionSelectMul(true)"
|
|
|
|
|
>
|
|
|
|
|
<span class="text-[32rpx] font-regular text-[#191919]">
|
2025-03-20 11:12:46 +00:00
|
|
|
|
{{ $t('button.multiple.choice') }}
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
class="mention-done-btn"
|
|
|
|
|
:class="
|
2025-03-12 08:25:42 +00:00
|
|
|
|
state?.selectedMembersNum > 0 ? 'mention-done-btn-can-do' : ''
|
2025-03-11 11:56:43 +00:00
|
|
|
|
"
|
|
|
|
|
v-if="state.mentionIsMulSelect"
|
2025-03-12 08:25:42 +00:00
|
|
|
|
@click="confirmMentionSelect"
|
2025-03-11 11:56:43 +00:00
|
|
|
|
>
|
|
|
|
|
<span class="text-[32rpx] font-regular text-[#191919]">
|
2025-03-20 11:12:46 +00:00
|
|
|
|
{{ $t('button.text.done') }}
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</span>
|
2025-03-12 08:25:42 +00:00
|
|
|
|
<span
|
|
|
|
|
class="text-[32rpx] font-regular text-[#191919]"
|
|
|
|
|
v-if="state?.selectedMembersNum > 0"
|
|
|
|
|
>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
{{ '(' + state?.selectedMembersNum + ')' }}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
</span>
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-03-12 08:25:42 +00:00
|
|
|
|
<selectMemberByAlphabet
|
|
|
|
|
:manageType="'mention'"
|
|
|
|
|
ref="selectMemberByAlphabetRef"
|
|
|
|
|
:selectAreaHeight="state.selectAreaHeight"
|
|
|
|
|
@updateSelectedMembersNum="updateSelectedMembersNum"
|
|
|
|
|
:isMulSelect="state.mentionIsMulSelect"
|
|
|
|
|
@getSelectResult="getSelectResult"
|
2025-03-12 11:59:54 +00:00
|
|
|
|
@getMentionSelectLists="getMentionSelectLists"
|
2025-03-12 08:25:42 +00:00
|
|
|
|
></selectMemberByAlphabet>
|
2025-03-11 11:56:43 +00:00
|
|
|
|
</tm-drawer>
|
2024-11-22 01:06:37 +00:00
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<script setup>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
import selectMemberByAlphabet from '../chatSettings/components/selectMemberByAlphabet.vue'
|
2025-02-05 08:22:32 +00:00
|
|
|
|
import {
|
|
|
|
|
ref,
|
|
|
|
|
reactive,
|
|
|
|
|
watch,
|
|
|
|
|
computed,
|
|
|
|
|
onMounted,
|
|
|
|
|
onUnmounted,
|
|
|
|
|
nextTick,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
} 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'
|
2024-12-20 08:59:58 +00:00
|
|
|
|
import {
|
|
|
|
|
useUserStore,
|
|
|
|
|
useDialogueStore,
|
|
|
|
|
useUploadsStore,
|
|
|
|
|
useEditorDraftStore,
|
|
|
|
|
useTalkStore,
|
|
|
|
|
useSettingsStore,
|
2025-02-05 08:22:32 +00:00
|
|
|
|
useDialogueListStore,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
} from '@/store'
|
|
|
|
|
import addCircleGray from '@/static/image/chatList/addCircleGray.png'
|
2025-03-11 11:56:43 +00:00
|
|
|
|
import {
|
|
|
|
|
MessageComponents,
|
|
|
|
|
ForwardableMessageType,
|
|
|
|
|
ChatMsgTypeMapping,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
} 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'
|
2025-03-18 12:00:41 +00:00
|
|
|
|
import {
|
|
|
|
|
ServePublishMessage,
|
|
|
|
|
detailGetRecordsContext,
|
|
|
|
|
ServeClearTalkUnreadNum,
|
|
|
|
|
ServeTalkRecords,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
} 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 } from '@dcloudio/uni-app'
|
|
|
|
|
|
|
|
|
|
Quill.register('formats/emoji', EmojiBlot)
|
|
|
|
|
import 'quill-mention'
|
|
|
|
|
const selectMemberByAlphabetRef = ref(null)
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
getDialogueList,
|
|
|
|
|
updateZpagingRef,
|
|
|
|
|
virtualList,
|
|
|
|
|
} = useDialogueListStore()
|
|
|
|
|
const talkStore = useTalkStore()
|
|
|
|
|
const { showConfirm } = useConfirm()
|
|
|
|
|
const settingsStore = useSettingsStore()
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
const dialogueStore = useDialogueStore()
|
|
|
|
|
const editorDraftStore = useEditorDraftStore()
|
2025-03-30 08:22:29 +00:00
|
|
|
|
const uploadsStore = useUploadsStore()
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const editor = ref()
|
|
|
|
|
const zpagingRef = ref()
|
|
|
|
|
useZPaging(zpagingRef)
|
|
|
|
|
const indexName = computed(() => dialogueStore.index_name)
|
2024-11-22 01:06:37 +00:00
|
|
|
|
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),
|
2025-02-05 08:22:32 +00:00
|
|
|
|
num: computed(() => dialogueStore.members.length),
|
2025-03-14 05:15:54 +00:00
|
|
|
|
isDismiss: computed(() => dialogueStore.isDismiss),
|
2025-03-24 08:37:29 +00:00
|
|
|
|
isQuit: computed(() => dialogueStore.isQuit),
|
2025-03-14 05:15:54 +00:00
|
|
|
|
adminList: computed(() => dialogueStore.getAdminList),
|
2025-03-24 12:03:52 +00:00
|
|
|
|
unReadNum: computed(() => dialogueStore.unreadNum),
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-22 01:06:37 +00:00
|
|
|
|
|
2025-03-30 08:22:29 +00:00
|
|
|
|
const uploadsParams = reactive({
|
|
|
|
|
isUploading: computed(() => uploadsStore.isUploading),
|
|
|
|
|
uploadingNum: computed(() => uploadsStore.uploadingNum),
|
|
|
|
|
})
|
|
|
|
|
|
2024-11-26 08:51:36 +00:00
|
|
|
|
const state = ref({
|
2024-12-06 08:55:15 +00:00
|
|
|
|
isOpenEmojiPanel: false,
|
2024-12-19 03:02:47 +00:00
|
|
|
|
isOpenFilePanel: false,
|
2024-12-24 08:28:44 +00:00
|
|
|
|
showWin: false,
|
|
|
|
|
onfocusItem: null,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
sessionId: '', //会话Id
|
2025-03-07 07:02:53 +00:00
|
|
|
|
localPageLoadDone: true, //分页加载缓存中的聊天记录是否完毕
|
2025-03-10 07:09:26 +00:00
|
|
|
|
quoteInfo: null, //引用信息
|
2025-03-11 11:56:43 +00:00
|
|
|
|
mentionIsMulSelect: false, //是否是多选提醒的人
|
2025-03-12 08:25:42 +00:00
|
|
|
|
selectedMembersNum: 0, //选中的要提醒的人数
|
|
|
|
|
mentionSelectHeight: 0, //选择要提醒人的区域高度
|
|
|
|
|
selectAreaHeight: 0, //选择要提醒人的可选人员列表区域高度
|
2025-03-12 11:59:54 +00:00
|
|
|
|
isShowMentionSelect: false, //是否显示要提醒人的选择区域
|
2025-03-13 11:54:29 +00:00
|
|
|
|
useCustomLoadMore: false, //是否使用自定义加载更多事件(下拉刷新、上拉加载)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
recordDate: '', //按日期查询聊天记录的开始日期
|
2025-03-18 12:00:41 +00:00
|
|
|
|
serveFindRecord: [], //调用接口查找到的聊天记录
|
2025-03-19 11:58:23 +00:00
|
|
|
|
middleMsg: {}, //缓存中没有时,调用接口初次使用的依据记录
|
|
|
|
|
keepDialogInfo: false, //是否保存会话信息
|
2025-03-20 11:12:46 +00:00
|
|
|
|
lastCursorIndex: undefined, //在失焦前保存光标位置
|
|
|
|
|
mentionUserIds: [], //存储所有被@的用户ID
|
|
|
|
|
isInsertingMention: false, //是否正在插入mention
|
2025-03-26 06:30:20 +00:00
|
|
|
|
showMentionSelectTimer: null, //显示提醒选择框的定时器
|
|
|
|
|
lastMentionText: '', // 记录上一次触发@时的完整文本内容
|
|
|
|
|
lastMentionTriggered: false, // 记录当前@是否已经触发过
|
|
|
|
|
lastMentionPosition: -1, // 添加新的状态来记录上一次@的位置
|
2025-04-09 07:08:54 +00:00
|
|
|
|
isLoading: false, //发送按钮loading
|
|
|
|
|
lastSelection: 0,
|
2025-01-06 10:55:00 +00:00
|
|
|
|
})
|
|
|
|
|
|
2025-03-18 12:00:41 +00:00
|
|
|
|
uniOnload(async (options) => {
|
2025-03-19 11:58:23 +00:00
|
|
|
|
console.log('onLoad' + JSON.stringify(options))
|
2025-01-06 10:55:00 +00:00
|
|
|
|
if (options.sessionId) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.sessionId = options.sessionId
|
2025-01-06 10:55:00 +00:00
|
|
|
|
}
|
2025-03-19 11:58:23 +00:00
|
|
|
|
if (options.keepDialogInfo) {
|
|
|
|
|
state.value.keepDialogInfo = options.keepDialogInfo === '1' ? true : false
|
|
|
|
|
}
|
2025-03-13 11:54:29 +00:00
|
|
|
|
if (options.msgInfo) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const msgInfo = JSON.parse(decodeURIComponent(options.msgInfo))
|
|
|
|
|
queryRecordsByMsgInfo(msgInfo)
|
|
|
|
|
state.value.useCustomLoadMore = true
|
|
|
|
|
return
|
2025-03-13 11:54:29 +00:00
|
|
|
|
}
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (options.recordDate) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.recordDate = options.recordDate
|
|
|
|
|
const msgInfo = await findTalkRecords(options.recordDate, true)
|
|
|
|
|
queryRecordsByMsgInfo(msgInfo)
|
|
|
|
|
state.value.useCustomLoadMore = true
|
|
|
|
|
return
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
initData()
|
|
|
|
|
})
|
2025-03-17 03:21:23 +00:00
|
|
|
|
uniOnUnload(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('onUnload')
|
2025-03-26 06:30:20 +00:00
|
|
|
|
ServeClearTalkUnreadNum(
|
|
|
|
|
{
|
|
|
|
|
talk_type: Number(talkParams.type),
|
|
|
|
|
receiver_id: Number(talkParams.receiver_id),
|
|
|
|
|
},
|
|
|
|
|
talkParams.unReadNum,
|
|
|
|
|
).then(() => {
|
2025-03-17 03:21:23 +00:00
|
|
|
|
talkStore.updateItem({
|
2025-03-18 12:00:41 +00:00
|
|
|
|
index_name: talkParams.index_name,
|
2025-03-17 03:21:23 +00:00
|
|
|
|
unread_num: 0,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2025-03-25 02:33:30 +00:00
|
|
|
|
dialogueStore.clearUnreadNum()
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
})
|
2024-12-06 08:55:15 +00:00
|
|
|
|
const handleEmojiPanel = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.isOpenFilePanel = false
|
|
|
|
|
state.value.isOpenEmojiPanel = !state.value.isOpenEmojiPanel
|
|
|
|
|
}
|
2024-12-06 08:55:15 +00:00
|
|
|
|
const handleFilePanel = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.isOpenEmojiPanel = false
|
|
|
|
|
state.value.isOpenFilePanel = !state.value.isOpenFilePanel
|
|
|
|
|
}
|
2024-12-06 08:55:15 +00:00
|
|
|
|
|
2025-03-06 10:50:11 +00:00
|
|
|
|
//点击隐藏表情/文件上传 面板
|
|
|
|
|
const handleHidePanel = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.isOpenFilePanel = false
|
|
|
|
|
state.value.isOpenEmojiPanel = false
|
|
|
|
|
}
|
2025-03-06 10:50:11 +00:00
|
|
|
|
|
|
|
|
|
//点击编辑区聚焦输入框
|
|
|
|
|
const onEditorClick = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
handleHidePanel()
|
2025-04-09 07:08:54 +00:00
|
|
|
|
// const quill = getQuill();
|
|
|
|
|
|
2025-03-28 08:13:45 +00:00
|
|
|
|
// if (quill.getText().endsWith('@\n')) {
|
|
|
|
|
// showMentionSelectDebounced(quill)
|
|
|
|
|
// }
|
2025-04-09 02:02:58 +00:00
|
|
|
|
// quill.focus()
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-06 10:50:11 +00:00
|
|
|
|
|
2025-04-08 08:58:28 +00:00
|
|
|
|
const onSendMessage = (data = {}, callBack, showLoading = false) => {
|
|
|
|
|
if (showLoading) {
|
|
|
|
|
state.value.isLoading = true
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
let message = {
|
|
|
|
|
...data,
|
|
|
|
|
receiver: {
|
|
|
|
|
receiver_id: talkParams.receiver_id,
|
2025-02-05 08:22:32 +00:00
|
|
|
|
talk_type: talkParams.type,
|
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
ServePublishMessage(message)
|
|
|
|
|
.then(({ code, message }) => {
|
2025-04-08 08:58:28 +00:00
|
|
|
|
state.value.isLoading = false
|
2024-11-28 08:55:45 +00:00
|
|
|
|
if (code == 200) {
|
2025-03-30 08:22:29 +00:00
|
|
|
|
uploadsStore.updateUploadStatus(false)
|
2025-03-06 10:50:11 +00:00
|
|
|
|
if (callBack) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
callBack(true)
|
2025-03-06 10:50:11 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
} else {
|
2025-03-30 08:22:29 +00:00
|
|
|
|
uploadsStore.updateUploadStatus(false)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
message.warning(message)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
2025-04-08 08:58:28 +00:00
|
|
|
|
state.value.isLoading = false
|
2025-03-30 08:22:29 +00:00
|
|
|
|
uploadsStore.updateUploadStatus(false)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
message.warning('网络繁忙,请稍后重试!')
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
const onSendMessageClick = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
// 发送前确保 mentionUserIds 是最新的
|
|
|
|
|
updateMentionUserIds()
|
|
|
|
|
|
|
|
|
|
let delta = getQuill().getContents()
|
2025-03-11 11:56:43 +00:00
|
|
|
|
if (state.value.quoteInfo) {
|
|
|
|
|
delta.ops.unshift({
|
|
|
|
|
insert: {
|
|
|
|
|
quote: {
|
|
|
|
|
id: state.value.quoteInfo.msg_id,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2025-03-11 11:56:43 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let data = deltaToMessage(delta)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
if (data.items.length === 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (data.msgType) {
|
|
|
|
|
case 1: // 文字消息
|
2025-03-30 08:22:29 +00:00
|
|
|
|
if (data.items[0].content.trim() === '') {
|
|
|
|
|
return
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
if (data.items[0].content.length > 1024) {
|
2025-03-30 08:22:29 +00:00
|
|
|
|
return message.warning('发送内容超长,请分条发送')
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
onSendTextEvent({
|
2025-02-05 08:22:32 +00:00
|
|
|
|
data,
|
|
|
|
|
callBack: (ok) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
if (!ok) return
|
|
|
|
|
getQuill().setContents([], Quill.sources.USER)
|
2025-03-11 11:56:43 +00:00
|
|
|
|
if (state.value.quoteInfo) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.quoteInfo = null
|
2025-03-11 11:56:43 +00:00
|
|
|
|
}
|
2025-02-05 08:22:32 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
break
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
// 发送文本消息
|
|
|
|
|
const onSendTextEvent = lodash.throttle((value) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let { data, callBack } = value
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
let message = {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
type: 'text',
|
2024-11-28 08:55:45 +00:00
|
|
|
|
content: data.items[0].content,
|
|
|
|
|
quote_id: data.quoteId,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
mentions: state.value.mentionUserIds, // 使用最终的用户ID数组
|
|
|
|
|
}
|
|
|
|
|
console.log(message)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
2025-04-08 08:58:28 +00:00
|
|
|
|
onSendMessage(message, callBack, true)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}, 1000)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
// 编辑器输入事件
|
|
|
|
|
const onInputEvent = ({ data }) => {
|
|
|
|
|
talkStore.updateItem({
|
|
|
|
|
index_name: indexName.value,
|
2025-02-05 08:22:32 +00:00
|
|
|
|
draft_text: data,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
// 判断对方是否在线和是否需要推送
|
|
|
|
|
// 3秒时间内推送一次
|
|
|
|
|
if (settingsStore.isKeyboard && props.online) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
onKeyboardPush()
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
// 发送表情消息
|
2024-12-13 05:09:38 +00:00
|
|
|
|
const onSendEmoticonEvent = ({ data }) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
onSendMessage({ type: 'emoticon', emoticon_id: data })
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
// 注册事件
|
|
|
|
|
const evnets = {
|
|
|
|
|
text_event: onSendTextEvent,
|
|
|
|
|
input_event: onInputEvent,
|
|
|
|
|
emoticon_event: onSendEmoticonEvent,
|
|
|
|
|
history_event: () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
isShowHistory.value = true
|
2024-11-28 08:55:45 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const {
|
|
|
|
|
loadConfig,
|
|
|
|
|
records,
|
|
|
|
|
onLoad,
|
|
|
|
|
onRefreshLoad,
|
|
|
|
|
onJumpMessage,
|
|
|
|
|
} = useTalkRecord(talkParams.uid)
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
|
|
|
|
const getQuill = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return editor.value?.getQuill()
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2024-12-20 08:59:58 +00:00
|
|
|
|
const isShowCopy = (item) => {
|
|
|
|
|
switch (item.msg_type) {
|
|
|
|
|
case 1:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return true
|
2024-12-20 08:59:58 +00:00
|
|
|
|
case 3:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return true
|
2024-12-20 08:59:58 +00:00
|
|
|
|
case 5:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return true
|
2024-12-20 08:59:58 +00:00
|
|
|
|
case 6:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return true
|
2024-12-20 08:59:58 +00:00
|
|
|
|
default:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return false
|
2024-12-20 08:59:58 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-12-20 08:59:58 +00:00
|
|
|
|
|
2024-12-19 03:02:47 +00:00
|
|
|
|
const selectedMessage = computed(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return virtualList.value.filter((item) => item.isCheck)
|
|
|
|
|
})
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2024-11-28 08:55:45 +00:00
|
|
|
|
// 编辑器事件
|
|
|
|
|
const onEditorEvent = (msg) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
evnets[msg.event] && evnets[msg.event](msg)
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
const getQuillSelectionIndex = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let quill = getQuill()
|
|
|
|
|
return (quill.getSelection() || {}).index
|
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
const onEmoticonEvent = (data) => {
|
|
|
|
|
if (data.type == 1) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const quill = getQuill()
|
|
|
|
|
let index = getQuillSelectionIndex()
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
if (index == 1 && quill.getLength() == 1 && quill.getText(0, 1) == '\n') {
|
|
|
|
|
quill.deleteText(0, 1)
|
|
|
|
|
index = 0
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
|
|
|
|
if (data.img) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
quill.insertEmbed(index, 'emoji', {
|
2024-11-28 08:55:45 +00:00
|
|
|
|
alt: data.value,
|
|
|
|
|
src: data.img,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-28 08:55:45 +00:00
|
|
|
|
} else {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
quill.insertText(index, data.value)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
quill.setSelection(index + 1, 0, 'user')
|
2024-11-28 08:55:45 +00:00
|
|
|
|
} else {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let fn = emitCall('emoticon_event', data.value, () => {})
|
|
|
|
|
emit('editor-event', fn)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
2024-11-26 08:51:36 +00:00
|
|
|
|
const onEditorChange = () => {
|
2025-03-28 08:13:45 +00:00
|
|
|
|
if (getQuill().getText() !== state.value.lastMentionText) {
|
|
|
|
|
state.value.lastMentionTriggered = false
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let delta = getQuill().getContents()
|
|
|
|
|
let text = deltaToString(delta)
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
// 如果正在插入mention,不进行mention的检查和更新
|
|
|
|
|
if (!state.value.isInsertingMention) {
|
|
|
|
|
updateMentionUserIds()
|
|
|
|
|
}
|
2025-03-12 11:59:54 +00:00
|
|
|
|
|
2024-11-26 08:51:36 +00:00
|
|
|
|
if (!isEmptyDelta(delta)) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
editorDraftStore.items[indexName.value || ''] = JSON.stringify({
|
2024-11-26 08:51:36 +00:00
|
|
|
|
text: text,
|
2025-02-05 08:22:32 +00:00
|
|
|
|
ops: delta.ops,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-26 08:51:36 +00:00
|
|
|
|
} else {
|
|
|
|
|
// 删除 editorDraftStore.items 下的元素
|
2025-03-20 11:12:46 +00:00
|
|
|
|
delete editorDraftStore.items[indexName.value || '']
|
2024-11-26 08:51:36 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
onEditorEvent(emitCall('input_event', text))
|
2024-11-26 08:51:36 +00:00
|
|
|
|
// emit('editor-event', emitCall('input_event', text))
|
2025-03-13 05:08:58 +00:00
|
|
|
|
// 清理过期的撤回消息(超过5分钟)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const now = new Date().getTime()
|
2025-03-17 11:54:43 +00:00
|
|
|
|
Object.keys(state.value.revokedMessages || {}).forEach((msgId) => {
|
2025-03-14 05:15:54 +00:00
|
|
|
|
if (now - state.value.revokedMessages[msgId].revokeTime > 5 * 60 * 1000) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
delete state.value.revokedMessages[msgId]
|
2025-03-13 05:08:58 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2024-11-28 08:55:45 +00:00
|
|
|
|
const onClipboardMatcher = (node, Delta) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const ops = []
|
2024-11-28 08:55:45 +00:00
|
|
|
|
|
|
|
|
|
Delta.ops.forEach((op) => {
|
|
|
|
|
// 如果粘贴了图片,这里会是一个对象,所以可以这样处理
|
2025-03-20 11:12:46 +00:00
|
|
|
|
if (op.insert && typeof op.insert === 'string') {
|
2024-11-28 08:55:45 +00:00
|
|
|
|
ops.push({
|
|
|
|
|
insert: op.insert, // 文字内容
|
2025-02-05 08:22:32 +00:00
|
|
|
|
attributes: {}, //文字样式(包括背景色和文字颜色等)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-28 08:55:45 +00:00
|
|
|
|
} else {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
ops.push(op)
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
Delta.ops = ops
|
|
|
|
|
return Delta
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
|
|
|
|
const editorOption = {
|
|
|
|
|
debug: false,
|
|
|
|
|
modules: {
|
|
|
|
|
toolbar: false,
|
2024-11-28 08:55:45 +00:00
|
|
|
|
clipboard: {
|
|
|
|
|
// 粘贴版,处理粘贴时候的自带样式
|
2025-02-05 08:22:32 +00:00
|
|
|
|
matchers: [[Node.ELEMENT_NODE, onClipboardMatcher]],
|
2024-11-28 08:55:45 +00:00
|
|
|
|
},
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
|
|
|
|
keyboard: {
|
|
|
|
|
bindings: {
|
|
|
|
|
enter: {
|
|
|
|
|
key: 13,
|
2025-02-05 08:22:32 +00:00
|
|
|
|
handler: onSendMessageClick,
|
|
|
|
|
},
|
|
|
|
|
},
|
2024-11-26 08:51:36 +00:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// imageUploader: {
|
|
|
|
|
// upload: onEditorUpload
|
|
|
|
|
// },
|
|
|
|
|
|
2025-03-20 03:02:29 +00:00
|
|
|
|
mention: {
|
|
|
|
|
allowedChars: /^[\u4e00-\u9fa5]*$/,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
mentionDenotationChars: ['@'],
|
|
|
|
|
positioningStrategy: 'fixed',
|
2025-03-20 03:02:29 +00:00
|
|
|
|
renderItem: (data) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const el = document.createElement('div')
|
|
|
|
|
el.className = 'ed-member-item'
|
|
|
|
|
el.innerHTML += `<span class="nickname">${data.nickname}</span>`
|
|
|
|
|
return el
|
2025-03-20 03:02:29 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
source: function (searchTerm, renderList, mentionChar) {
|
2025-03-24 08:37:29 +00:00
|
|
|
|
if (talkParams.type === 1) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
// 在失焦前保存光标位置
|
|
|
|
|
const quill = getQuill()
|
|
|
|
|
const range = quill.getSelection()
|
|
|
|
|
if (range) {
|
|
|
|
|
state.value.lastCursorIndex = range.index
|
|
|
|
|
}
|
2025-03-26 06:30:20 +00:00
|
|
|
|
|
|
|
|
|
// 使用防抖函数
|
|
|
|
|
showMentionSelectDebounced(quill)
|
2025-03-20 03:02:29 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
mentionContainerClass: '',
|
2025-03-20 03:02:29 +00:00
|
|
|
|
},
|
2024-11-26 08:51:36 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
placeholder: '',
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2025-03-15 08:44:40 +00:00
|
|
|
|
const handleSelectImg = (data, file_num) => {
|
2025-03-31 06:29:58 +00:00
|
|
|
|
if (Array.isArray(data)) {
|
|
|
|
|
// 批量发送图片
|
2025-04-03 07:45:12 +00:00
|
|
|
|
data.forEach((item) => {
|
2025-03-31 06:29:58 +00:00
|
|
|
|
onSendMessage({ ...item, file_num: item.file_num })
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
// 单张图片发送
|
|
|
|
|
onSendMessage({ ...data, file_num })
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2024-12-06 08:55:15 +00:00
|
|
|
|
const virtualListChange = (vList) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
virtualList.value = vList
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2024-12-20 08:59:58 +00:00
|
|
|
|
const onContextMenu = (menuType, item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(menuType, item, 'item')
|
2024-12-20 08:59:58 +00:00
|
|
|
|
switch (menuType) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
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
|
2024-12-20 08:59:58 +00:00
|
|
|
|
|
|
|
|
|
default:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
break
|
2024-12-20 08:59:58 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const actionCopy = (item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('复制')
|
|
|
|
|
let content = ''
|
2024-12-19 03:02:47 +00:00
|
|
|
|
switch (item.msg_type) {
|
|
|
|
|
case 1:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
content = item.extra.content
|
|
|
|
|
break
|
2024-12-19 03:02:47 +00:00
|
|
|
|
case 3:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
content = item.extra.url
|
|
|
|
|
break
|
2024-12-19 03:02:47 +00:00
|
|
|
|
case 5:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
content = item.extra.url
|
|
|
|
|
break
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
default:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
break
|
2024-12-19 03:02:47 +00:00
|
|
|
|
}
|
|
|
|
|
uni.setClipboardData({
|
|
|
|
|
data: content,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const multipleChoose = (item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
item.isCheck = true
|
|
|
|
|
dialogueStore.setMultiSelect(true)
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2024-12-20 08:59:58 +00:00
|
|
|
|
const actionCite = (item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('引用')
|
|
|
|
|
state.value.quoteInfo = item
|
|
|
|
|
}
|
2025-03-10 07:09:26 +00:00
|
|
|
|
|
|
|
|
|
//清除引用信息
|
|
|
|
|
const clearQuoteInfo = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.quoteInfo = null
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2024-12-20 08:59:58 +00:00
|
|
|
|
const actionWithdraw = (item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('撤回')
|
|
|
|
|
state.value.onfocusItem = item
|
|
|
|
|
state.value.showWin = true
|
|
|
|
|
}
|
2024-12-24 08:28:44 +00:00
|
|
|
|
|
|
|
|
|
const withdrawerConfirm = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
dialogueStore.ApiRevokeRecord(state.value.onfocusItem.msg_id)
|
|
|
|
|
state.value.onfocusItem = null
|
|
|
|
|
state.value.showWin = false
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2025-03-13 05:08:58 +00:00
|
|
|
|
// 添加检查是否可以重新编辑撤回消息的函数
|
2025-03-14 01:46:03 +00:00
|
|
|
|
const canEditRevokedMessage = (item) => {
|
2025-03-19 11:58:23 +00:00
|
|
|
|
// console.log(item)
|
2025-03-14 05:15:54 +00:00
|
|
|
|
if (item.is_revoke === 1 && item.msg_type === 1) {
|
|
|
|
|
const now = new Date().getTime()
|
|
|
|
|
const revokeTime = new Date(item.created_at).getTime()
|
2025-03-19 11:58:23 +00:00
|
|
|
|
// console.log(now)
|
2025-03-14 01:46:03 +00:00
|
|
|
|
// 检查是否在5分钟内
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return now - revokeTime <= 5 * 60 * 1000
|
2025-03-14 01:46:03 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return false
|
|
|
|
|
}
|
2025-03-13 05:08:58 +00:00
|
|
|
|
|
|
|
|
|
// 添加恢复撤回消息到输入框的函数
|
2025-03-14 01:46:03 +00:00
|
|
|
|
const restoreRevokedMessage = async (item) => {
|
|
|
|
|
// 接口拿数据,之后把查询的内容给输入框
|
|
|
|
|
const res = await detailGetRecordsContext({
|
2025-03-14 05:15:54 +00:00
|
|
|
|
msgId: item.msg_id,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
console.log(res)
|
2025-03-14 05:15:54 +00:00
|
|
|
|
if (res.code == 200) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const content = res.data.item?.extra?.content
|
|
|
|
|
const quill = getQuill()
|
|
|
|
|
quill.setText(content)
|
2025-03-14 01:46:03 +00:00
|
|
|
|
// 将光标设置到文本末尾
|
2025-03-20 11:12:46 +00:00
|
|
|
|
quill.setSelection(content.length, 0)
|
|
|
|
|
quill.focus()
|
2025-03-14 01:46:03 +00:00
|
|
|
|
}
|
|
|
|
|
/* const revokedMsg = state.value.revokedMessages[msgId]
|
2025-03-13 05:08:58 +00:00
|
|
|
|
|
|
|
|
|
// 根据消息类型处理
|
|
|
|
|
if (revokedMsg.msgType === 1) { // 文本消息
|
|
|
|
|
const quill = getQuill()
|
|
|
|
|
quill.setText(revokedMsg.content)
|
|
|
|
|
quill.focus()
|
2025-03-14 01:46:03 +00:00
|
|
|
|
} */
|
2025-03-13 05:08:58 +00:00
|
|
|
|
// 可以根据需要添加其他类型消息的处理
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-13 05:08:58 +00:00
|
|
|
|
|
2024-12-20 08:59:58 +00:00
|
|
|
|
const actionDelete = (item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('删除')
|
|
|
|
|
item.isCheck = true
|
|
|
|
|
handleDelete()
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const handleMergeForward = () => {
|
|
|
|
|
if (selectedMessage.value.length == 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return message.warning('未选择消息')
|
2024-12-19 03:02:47 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('合并转发')
|
|
|
|
|
dialogueStore.setForwardType(2)
|
|
|
|
|
dialogueStore.setForwardMessages(selectedMessage.value)
|
2024-12-19 03:02:47 +00:00
|
|
|
|
uni.navigateTo({
|
2025-03-20 11:12:46 +00:00
|
|
|
|
url: '/pages/chooseChat/index',
|
2024-12-19 03:02:47 +00:00
|
|
|
|
success: function (res) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
clearMultiSelect()
|
2025-02-05 08:22:32 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const handleSingleForward = () => {
|
|
|
|
|
if (selectedMessage.value.length == 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return message.warning('未选择消息')
|
2024-12-19 03:02:47 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('逐条转发')
|
|
|
|
|
dialogueStore.setForwardType(1)
|
|
|
|
|
dialogueStore.setForwardMessages(selectedMessage.value)
|
2024-12-20 08:59:58 +00:00
|
|
|
|
uni.navigateTo({
|
2025-03-20 11:12:46 +00:00
|
|
|
|
url: '/pages/chooseChat/index',
|
2024-12-20 08:59:58 +00:00
|
|
|
|
success: function (res) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
clearMultiSelect()
|
2025-02-05 08:22:32 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const handleWechatForward = () => {
|
|
|
|
|
if (selectedMessage.value.length == 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return message.warning('未选择消息')
|
2024-12-19 03:02:47 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('微信转发')
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const handleDelete = () => {
|
|
|
|
|
if (selectedMessage.value.length == 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return message.warning('未选择消息')
|
2024-12-19 03:02:47 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log('删除')
|
2024-12-24 08:28:44 +00:00
|
|
|
|
showConfirm({
|
2025-03-20 11:12:46 +00:00
|
|
|
|
content: '确定删除聊天记录',
|
|
|
|
|
confirmText: '删除',
|
|
|
|
|
confirmColor: '#CF3050',
|
2024-12-24 08:28:44 +00:00
|
|
|
|
onConfirm: async () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const msgIds = selectedMessage.value.map((item) => item.msg_id)
|
2025-02-05 08:22:32 +00:00
|
|
|
|
virtualList.value = virtualList.value.filter(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
(item) => !msgIds.includes(item.msg_id),
|
|
|
|
|
)
|
|
|
|
|
dialogueStore.ApiDeleteRecord(msgIds)
|
|
|
|
|
clearMultiSelect()
|
2024-12-24 08:28:44 +00:00
|
|
|
|
},
|
2025-02-05 08:22:32 +00:00
|
|
|
|
onCancel: () => {},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2025-03-12 08:25:42 +00:00
|
|
|
|
//更新选中的要提醒的人数
|
|
|
|
|
const updateSelectedMembersNum = (numChange) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.selectedMembersNum = state.value.selectedMembersNum + numChange
|
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
2025-02-05 08:22:32 +00:00
|
|
|
|
watch(
|
|
|
|
|
() => zpagingRef.value,
|
|
|
|
|
(newValue, oldValue) => {
|
|
|
|
|
if (newValue) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
updateZpagingRef(newValue)
|
2025-02-05 08:22:32 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
},
|
|
|
|
|
)
|
2024-11-22 01:06:37 +00:00
|
|
|
|
|
2025-03-07 07:02:53 +00:00
|
|
|
|
watch(
|
|
|
|
|
() => virtualList.value,
|
|
|
|
|
(newValue, oldValue) => {
|
|
|
|
|
if (newValue) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const dialogueList = getDialogueList(talkParams.index_name)
|
2025-03-07 08:14:25 +00:00
|
|
|
|
// console.log(newValue[newValue.length - 1]?.sequence, dialogueList?.records?.[0]?.sequence)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (!dialogueList || dialogueList?.length === 0) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.localPageLoadDone = true
|
|
|
|
|
return
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-19 11:58:23 +00:00
|
|
|
|
// 只在正常加载模式下检查是否加载完缓存数据
|
|
|
|
|
if (!state.value.useCustomLoadMore) {
|
|
|
|
|
if (
|
|
|
|
|
newValue[newValue.length - 1]?.sequence ===
|
|
|
|
|
dialogueList?.records?.[0]?.sequence
|
|
|
|
|
) {
|
2025-03-24 08:37:29 +00:00
|
|
|
|
if (
|
|
|
|
|
dialogueList?.records?.[0]?.sequence !== 1 &&
|
|
|
|
|
!state.value.localPageLoadDone
|
|
|
|
|
) {
|
2025-03-24 01:50:57 +00:00
|
|
|
|
loadConfig.status = 1
|
|
|
|
|
}
|
2025-03-24 08:37:29 +00:00
|
|
|
|
//相同意味着分页加载缓存中的聊天记录完毕
|
|
|
|
|
state.value.localPageLoadDone = true
|
2025-03-19 11:58:23 +00:00
|
|
|
|
} else {
|
|
|
|
|
state.value.localPageLoadDone = false
|
|
|
|
|
}
|
2025-03-07 07:02:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
deep: true,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
},
|
|
|
|
|
)
|
2025-03-07 07:02:53 +00:00
|
|
|
|
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const onScrollToLower = async () => {
|
2025-03-13 11:54:29 +00:00
|
|
|
|
if (state.value.useCustomLoadMore) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const tempVirtualList = lodash.cloneDeep(virtualList.value).reverse()
|
|
|
|
|
const dialogueList = getDialogueList(talkParams.index_name)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const recordIndex = dialogueList?.records?.findIndex(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
(record) => record.msg_id === tempVirtualList[0].msg_id,
|
|
|
|
|
)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (!recordIndex || recordIndex === -1) {
|
|
|
|
|
const moreRecords = await findTalkRecords(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'',
|
2025-03-18 12:00:41 +00:00
|
|
|
|
false,
|
|
|
|
|
tempVirtualList[0].sequence,
|
|
|
|
|
{
|
2025-03-20 11:12:46 +00:00
|
|
|
|
direction: 'up',
|
|
|
|
|
sort_sequence: '',
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
console.log(moreRecords)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
|
2025-03-19 11:58:23 +00:00
|
|
|
|
// 格式化新加载的消息
|
|
|
|
|
const formattedMoreRecords = moreRecords.map((item) => ({
|
|
|
|
|
...item,
|
|
|
|
|
float: item.user_id === talkParams.uid ? 'right' : 'left',
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
virtualList.value = formattedMoreRecords.concat(tempVirtualList).reverse()
|
2025-03-24 08:37:29 +00:00
|
|
|
|
loadConfig.status =
|
|
|
|
|
dialogueList?.records?.[0]?.sequence > 1 && moreRecords.length > 0
|
|
|
|
|
? 1
|
|
|
|
|
: 2
|
2025-03-13 11:54:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (tempVirtualList[0].sequence > dialogueList.records[0].sequence) {
|
|
|
|
|
virtualList.value = dialogueList.records
|
2025-03-15 08:44:40 +00:00
|
|
|
|
.slice(Math.max(0, recordIndex - 10), recordIndex)
|
2025-03-13 11:54:29 +00:00
|
|
|
|
.concat(tempVirtualList)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.reverse()
|
2025-03-13 11:54:29 +00:00
|
|
|
|
// zpagingRef.value.setLocalPaging(
|
|
|
|
|
// dialogueList.records
|
|
|
|
|
// .slice(0, recordIndex)
|
|
|
|
|
// .concat(tempVirtualList)
|
|
|
|
|
// .reverse(),
|
|
|
|
|
// // zpagingRef.value.scrollIntoViewById('zp-id-' + virtualList.value[virtualList.value.length - 1].msg_id)
|
|
|
|
|
// )
|
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(virtualList.value)
|
2025-03-13 11:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return
|
2025-03-13 11:54:29 +00:00
|
|
|
|
}
|
2025-03-07 07:02:53 +00:00
|
|
|
|
if (state.value.localPageLoadDone) {
|
|
|
|
|
//本地缓存的聊天记录分页加载完之后,才可以请求接口
|
2025-03-20 11:12:46 +00:00
|
|
|
|
onRefreshLoad()
|
2025-03-07 07:02:53 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-07 07:02:53 +00:00
|
|
|
|
|
2025-03-13 11:54:29 +00:00
|
|
|
|
//本来的下拉刷新——列表倒置后为上拉加载
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const onScrollToUpper = async () => {
|
2025-03-13 11:54:29 +00:00
|
|
|
|
if (state.value.useCustomLoadMore) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const tempVirtualList = lodash.cloneDeep(virtualList.value).reverse()
|
|
|
|
|
const dialogueList = getDialogueList(talkParams.index_name)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const recordIndex = dialogueList?.records?.findIndex(
|
2025-03-13 11:54:29 +00:00
|
|
|
|
(record) =>
|
2025-03-20 11:12:46 +00:00
|
|
|
|
record.msg_id === tempVirtualList[tempVirtualList.length - 1].msg_id,
|
|
|
|
|
)
|
|
|
|
|
console.log(recordIndex)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (!recordIndex || recordIndex === -1) {
|
|
|
|
|
// 记住加载更多前消息的ID
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const currentMsgId = tempVirtualList[tempVirtualList.length - 1].msg_id
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const moreRecords = await findTalkRecords(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'',
|
2025-03-18 12:00:41 +00:00
|
|
|
|
false,
|
|
|
|
|
tempVirtualList[tempVirtualList.length - 1].sequence,
|
|
|
|
|
)
|
|
|
|
|
console.log(moreRecords)
|
2025-03-19 11:58:23 +00:00
|
|
|
|
|
|
|
|
|
// 格式化新加载的消息
|
|
|
|
|
const formattedMoreRecords = moreRecords.map((item) => ({
|
|
|
|
|
...item,
|
|
|
|
|
float: item.user_id === talkParams.uid ? 'right' : 'left',
|
|
|
|
|
}))
|
|
|
|
|
|
2025-03-20 03:02:29 +00:00
|
|
|
|
virtualList.value = tempVirtualList
|
2025-03-19 11:58:23 +00:00
|
|
|
|
.concat(formattedMoreRecords.reverse())
|
|
|
|
|
.reverse()
|
2025-03-18 12:00:41 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(virtualList.value)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
|
|
|
|
|
// 数据更新后,滚动到之前的位置
|
|
|
|
|
nextTick(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
zpagingRef.value?.scrollIntoViewById('zp-id-' + currentMsgId)
|
|
|
|
|
})
|
2025-03-13 11:54:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (
|
|
|
|
|
tempVirtualList[tempVirtualList.length - 1].sequence <
|
|
|
|
|
dialogueList.records[dialogueList.records.length - 1].sequence
|
|
|
|
|
) {
|
2025-03-15 08:44:40 +00:00
|
|
|
|
// 记住加载更多前消息的ID
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const currentMsgId = tempVirtualList[tempVirtualList.length - 1].msg_id
|
2025-03-15 08:44:40 +00:00
|
|
|
|
|
2025-03-13 11:54:29 +00:00
|
|
|
|
virtualList.value = tempVirtualList
|
|
|
|
|
.concat(
|
|
|
|
|
dialogueList.records.slice(
|
2025-03-24 01:50:57 +00:00
|
|
|
|
recordIndex + 1,
|
2025-03-24 08:37:29 +00:00
|
|
|
|
Math.min(recordIndex + 11, dialogueList.records.length),
|
|
|
|
|
),
|
2025-03-13 11:54:29 +00:00
|
|
|
|
)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.reverse()
|
2025-03-13 11:54:29 +00:00
|
|
|
|
|
2025-03-15 08:44:40 +00:00
|
|
|
|
// 数据更新后,滚动到之前的位置
|
|
|
|
|
nextTick(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
zpagingRef.value?.scrollIntoViewById('zp-id-' + currentMsgId)
|
|
|
|
|
})
|
2025-03-13 11:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-13 11:54:29 +00:00
|
|
|
|
|
2024-12-19 03:02:47 +00:00
|
|
|
|
const clearMultiSelect = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
dialogueStore.setMultiSelect(false)
|
2025-02-05 08:22:32 +00:00
|
|
|
|
virtualList.value.forEach((item) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
item.isCheck = false
|
|
|
|
|
})
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
const initData = async () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const dialogueList = getDialogueList(talkParams.index_name)
|
2024-11-22 01:06:37 +00:00
|
|
|
|
|
|
|
|
|
let objT = {
|
|
|
|
|
uid: talkParams.uid,
|
|
|
|
|
talk_type: talkParams.type,
|
|
|
|
|
receiver_id: talkParams.receiver_id,
|
2024-12-06 08:55:15 +00:00
|
|
|
|
index_name: talkParams.index_name,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
direction: dialogueList ? 'down' : 'up',
|
2024-12-19 03:02:47 +00:00
|
|
|
|
no_limit: dialogueList ? 1 : 0,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
|
|
|
|
await onLoad({ ...objT })
|
|
|
|
|
zpagingRef.value?.setLocalPaging(records.value)
|
|
|
|
|
}
|
2024-12-10 03:31:36 +00:00
|
|
|
|
|
2025-01-02 08:01:36 +00:00
|
|
|
|
//点击跳转到聊天设置页面
|
|
|
|
|
const toChatSettingsPage = () => {
|
|
|
|
|
uni.navigateTo({
|
2025-02-05 08:22:32 +00:00
|
|
|
|
url:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'/pages/chatSettings/index?groupId=' +
|
2025-02-05 08:22:32 +00:00
|
|
|
|
talkParams?.receiver_id +
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'&sessionId=' +
|
2025-03-07 07:02:53 +00:00
|
|
|
|
state.value.sessionId,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
2025-01-02 08:01:36 +00:00
|
|
|
|
|
2025-01-16 10:25:21 +00:00
|
|
|
|
//点击跳转到用户详情页面
|
|
|
|
|
const toUserDetailPage = (userItem) => {
|
|
|
|
|
uni.navigateTo({
|
2025-02-05 08:22:32 +00:00
|
|
|
|
url:
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'/pages/dialog/dialogDetail/userDetail?erpUserId=' + userItem.erp_user_id,
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-01-16 10:25:21 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
//切换提醒的人选择弹窗多选状态
|
|
|
|
|
const changeMentionSelectMul = (status) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.mentionIsMulSelect = status
|
|
|
|
|
}
|
2025-03-11 11:56:43 +00:00
|
|
|
|
|
2025-03-12 08:25:42 +00:00
|
|
|
|
//隐藏要提醒人的选择
|
|
|
|
|
const hideMentionSelect = () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
state.value.isShowMentionSelect = false
|
|
|
|
|
// 清除保存的光标位置
|
|
|
|
|
state.value.lastCursorIndex = undefined
|
|
|
|
|
// 获得焦点
|
|
|
|
|
const quill = getQuill()
|
2025-04-08 08:58:28 +00:00
|
|
|
|
// quill.focus()
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
|
|
|
|
//确认要提醒人的选择
|
|
|
|
|
const confirmMentionSelect = () => {
|
|
|
|
|
if (state?.value.selectedMembersNum > 0) {
|
|
|
|
|
if (selectMemberByAlphabetRef.value) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
selectMemberByAlphabetRef.value.confirmSelectMembers()
|
2025-03-12 08:25:42 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
hideMentionSelect()
|
2025-03-12 08:25:42 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
|
|
|
|
//获取选择的结果
|
|
|
|
|
const getSelectResult = (mentionSelect) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(mentionSelect)
|
|
|
|
|
getMentionSelectLists(mentionSelect)
|
|
|
|
|
}
|
2025-03-12 11:59:54 +00:00
|
|
|
|
|
|
|
|
|
//处理要提醒人的消息样式
|
|
|
|
|
const getMentionSelectLists = (mentionSelectList) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
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
|
2025-03-12 11:59:54 +00:00
|
|
|
|
mentionSelectList.forEach((mentionSelectItem) => {
|
2025-03-26 11:51:07 +00:00
|
|
|
|
// 如果是@所有人,确保 id 为 0
|
|
|
|
|
const id =
|
|
|
|
|
mentionSelectItem?.nickname === '所有人' ? 0 : mentionSelectItem?.id
|
2025-03-20 11:12:46 +00:00
|
|
|
|
mention.insertItem(
|
|
|
|
|
{
|
2025-03-26 11:51:07 +00:00
|
|
|
|
id: id,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
denotationChar: '@',
|
2025-03-24 08:37:29 +00:00
|
|
|
|
value: mentionSelectItem?.nickname + ' ',
|
2025-03-12 11:59:54 +00:00
|
|
|
|
},
|
2025-03-20 11:12:46 +00:00
|
|
|
|
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类型
|
2025-03-22 06:22:09 +00:00
|
|
|
|
ops.forEach((op) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
if (op.insert && op.insert.mention) {
|
2025-03-26 11:51:07 +00:00
|
|
|
|
const id = Number(op.insert.mention.id)
|
|
|
|
|
// 过滤掉 null 值
|
|
|
|
|
if (!isNaN(id)) {
|
|
|
|
|
currentMentions.add(id)
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2025-03-27 09:25:12 +00:00
|
|
|
|
// 如果当前有@所有人,则添加0
|
|
|
|
|
if (currentMentions.has(0)) {
|
|
|
|
|
state.value.mentionUserIds = [0]
|
|
|
|
|
} else {
|
|
|
|
|
// 如果没有@任何人,保持空数组
|
|
|
|
|
state.value.mentionUserIds = Array.from(currentMentions)
|
2025-03-26 11:51:07 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
2025-03-13 11:54:29 +00:00
|
|
|
|
//根据msg信息找到对应的聊天记录,并根据sequence等查看上下文
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const queryRecordsByMsgInfo = async (msgInfo) => {
|
2025-03-13 11:54:29 +00:00
|
|
|
|
console.log(msgInfo)
|
2025-03-19 11:58:23 +00:00
|
|
|
|
state.value.middleMsg = msgInfo
|
2025-03-13 11:54:29 +00:00
|
|
|
|
const dialogueList = getDialogueList(talkParams.index_name)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
const recordIndex = dialogueList?.records?.findIndex(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
(record) => record.msg_id === msgInfo.msg_id,
|
|
|
|
|
)
|
|
|
|
|
let recordsList = []
|
|
|
|
|
console.log(recordIndex)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (!recordIndex || recordIndex === -1) {
|
2025-04-08 08:58:28 +00:00
|
|
|
|
recordsList = await findTalkRecords('', true, msgInfo.sequence - 1)
|
2025-03-13 11:54:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
// console.log(recordIndex)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const startRecordIndex = Math.max(0, recordIndex - 10)
|
|
|
|
|
const endRecordIndex = Math.max(0, recordIndex + 10)
|
2025-03-13 11:54:29 +00:00
|
|
|
|
// console.log(dialogueList.records.slice(startRecordIndex, endRecordIndex))
|
|
|
|
|
// console.log(recordIndex-startRecordIndex)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
recordsList = dialogueList.records.slice(startRecordIndex, endRecordIndex)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-19 11:58:23 +00:00
|
|
|
|
|
|
|
|
|
// 格式化消息,确保每条消息都有正确的 float
|
|
|
|
|
recordsList = recordsList.map((item) => {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
float: item.user_id === talkParams.uid ? 'right' : 'left',
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2025-03-18 12:00:41 +00:00
|
|
|
|
nextTick(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
zpagingRef.value.complete(recordsList.reverse())
|
2025-03-24 08:37:29 +00:00
|
|
|
|
loadConfig.status =
|
|
|
|
|
dialogueList?.records?.[0]?.sequence > 1 && recordsList.length > 0 ? 1 : 2
|
2025-03-13 11:54:29 +00:00
|
|
|
|
nextTick(() => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
let offset = uni.getSystemInfoSync().windowHeight
|
|
|
|
|
const navBarAreaQuery = uni.createSelectorQuery()
|
2025-03-18 12:00:41 +00:00
|
|
|
|
navBarAreaQuery
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.select('#navBarArea')
|
2025-03-18 12:00:41 +00:00
|
|
|
|
.boundingClientRect((res) => {
|
|
|
|
|
if (res) {
|
|
|
|
|
// console.log('元素高度:', res.height)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
offset = offset - res.height
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.exec()
|
|
|
|
|
const footBoxAreaQuery = uni.createSelectorQuery()
|
2025-03-18 12:00:41 +00:00
|
|
|
|
footBoxAreaQuery
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.select('#footBoxArea')
|
2025-03-18 12:00:41 +00:00
|
|
|
|
.boundingClientRect((res) => {
|
|
|
|
|
if (res) {
|
|
|
|
|
// console.log('元素高度:', res.height)
|
2025-03-20 11:12:46 +00:00
|
|
|
|
offset = offset - res.height
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.exec()
|
2025-03-18 12:00:41 +00:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
zpagingRef.value.scrollIntoViewById(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
'zp-id-' + msgInfo.msg_id,
|
|
|
|
|
offset - 60,
|
|
|
|
|
)
|
|
|
|
|
}, 1000)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-03-18 12:00:41 +00:00
|
|
|
|
|
|
|
|
|
//查找聊天记录
|
|
|
|
|
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
|
2025-03-20 11:12:46 +00:00
|
|
|
|
no_limit: '', //1不限制
|
|
|
|
|
file_name: '',
|
2025-03-18 12:00:41 +00:00
|
|
|
|
msg_type: 0, //消息类型:0:全部;2:代码;3:图片;4:音频;5:视频;6:文件;7:位置;9:会话;11群投票;12图文混合
|
|
|
|
|
cursor: sequence || 0, //上次查询的游标
|
|
|
|
|
limit: 10, //数据行数
|
2025-03-20 11:12:46 +00:00
|
|
|
|
direction: 'down', //down向下查最新,up向上查老数据
|
|
|
|
|
start_time: '',
|
|
|
|
|
end_time: '',
|
2025-03-18 12:00:41 +00:00
|
|
|
|
group_member_user_id: 0, //群成员id,当查询群历史消息的时候,需要指定群成员的时候送
|
|
|
|
|
sort_sequence: 'asc',
|
2025-03-19 11:58:23 +00:00
|
|
|
|
create_time: state.value.middleMsg.created_at,
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
if (record) {
|
|
|
|
|
params = Object.assign({}, params, {
|
|
|
|
|
start_time: record,
|
|
|
|
|
end_time: record,
|
|
|
|
|
limit: 1,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
direction: '',
|
|
|
|
|
})
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
if (appointParams) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
params = Object.assign({}, params, appointParams)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(params)
|
|
|
|
|
const resp = ServeTalkRecords(params)
|
|
|
|
|
console.log(resp)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
resp.then(({ code, data }) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(data)
|
2025-03-18 12:00:41 +00:00
|
|
|
|
if (code == 200) {
|
|
|
|
|
if (data?.items.length > 0) {
|
|
|
|
|
if (record) {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
resolve(data?.items[0])
|
|
|
|
|
return
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
if (isMiddle) {
|
|
|
|
|
state.value.serveFindRecord = JSON.parse(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
JSON.stringify(data?.items),
|
|
|
|
|
)
|
|
|
|
|
return findTalkRecords('', false, sequence + 1, {
|
|
|
|
|
direction: 'up',
|
|
|
|
|
sort_sequence: '',
|
2025-04-08 08:58:28 +00:00
|
|
|
|
}).then((upResult) => {
|
|
|
|
|
const finalResult = [...upResult, ...state.value.serveFindRecord]
|
2025-03-20 11:12:46 +00:00
|
|
|
|
console.log(finalResult)
|
|
|
|
|
resolve(finalResult)
|
|
|
|
|
})
|
2025-03-18 12:00:41 +00:00
|
|
|
|
} else {
|
|
|
|
|
state.value.serveFindRecord = data?.items
|
|
|
|
|
.reverse()
|
2025-03-20 11:12:46 +00:00
|
|
|
|
.concat(state.value.serveFindRecord)
|
|
|
|
|
resolve(JSON.parse(JSON.stringify(state.value.serveFindRecord)))
|
|
|
|
|
state.value.serveFindRecord = []
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-24 08:37:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
resolve([])
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-03-24 08:37:29 +00:00
|
|
|
|
resolve([])
|
2025-03-18 12:00:41 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
resp.catch(() => {})
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-03-13 11:54:29 +00:00
|
|
|
|
|
2025-03-14 05:15:54 +00:00
|
|
|
|
//是否是管理员
|
|
|
|
|
const isLeader = computed(() => {
|
|
|
|
|
if (talkParams.adminList.length > 0) {
|
|
|
|
|
return (
|
|
|
|
|
talkParams.adminList.filter(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
(adminItem) => adminItem.erp_user_id === useAuth()?.userInfo?.value?.ID,
|
2025-03-14 05:15:54 +00:00
|
|
|
|
).length > 0
|
2025-03-20 11:12:46 +00:00
|
|
|
|
)
|
2025-03-14 05:15:54 +00:00
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
return false
|
|
|
|
|
})
|
2025-03-14 05:15:54 +00:00
|
|
|
|
|
2025-03-22 06:22:09 +00:00
|
|
|
|
//长按头像@用户
|
|
|
|
|
const doMentionUser = (mentionSelect) => {
|
|
|
|
|
console.log(mentionSelect)
|
2025-03-28 10:33:43 +00:00
|
|
|
|
if (talkParams.type === 1) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-03-22 06:22:09 +00:00
|
|
|
|
// 构造正确的 mention 对象
|
|
|
|
|
const mentionObj = {
|
|
|
|
|
id: mentionSelect.user_id, // 使用 user_id 而不是 erp_user_id
|
2025-03-24 01:50:57 +00:00
|
|
|
|
nickname: mentionSelect.nickname,
|
2025-03-22 06:22:09 +00:00
|
|
|
|
}
|
|
|
|
|
getMentionSelectLists([mentionObj])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let avatarPressTimer = null
|
|
|
|
|
let currentPressItem = null
|
|
|
|
|
|
|
|
|
|
const handleAvatarTouchStart = (item) => {
|
|
|
|
|
currentPressItem = item
|
|
|
|
|
avatarPressTimer = setTimeout(() => {
|
|
|
|
|
doMentionUser(item)
|
|
|
|
|
}, 500)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleAvatarTouchEnd = () => {
|
|
|
|
|
if (avatarPressTimer) {
|
|
|
|
|
clearTimeout(avatarPressTimer)
|
|
|
|
|
avatarPressTimer = null
|
|
|
|
|
}
|
|
|
|
|
currentPressItem = null
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 03:02:47 +00:00
|
|
|
|
onMounted(async () => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
if (typeof plus !== 'undefined') {
|
|
|
|
|
const webview = plus.webview.currentWebview()
|
2025-03-14 09:05:05 +00:00
|
|
|
|
webview.setStyle({
|
|
|
|
|
bottom: 0,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2025-03-14 09:05:05 +00:00
|
|
|
|
} else {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
document.addEventListener('plusready', () => {
|
|
|
|
|
const webview = plus.webview.currentWebview()
|
2025-03-14 09:05:05 +00:00
|
|
|
|
webview.setStyle({
|
|
|
|
|
bottom: 0,
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
|
|
|
|
})
|
2025-03-14 09:05:05 +00:00
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
nextTick(() => {
|
|
|
|
|
state.value.mentionSelectHeight = pxTorPx(
|
2025-03-20 11:12:46 +00:00
|
|
|
|
uni.getSystemInfoSync().windowHeight * 0.86,
|
|
|
|
|
)
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
|
|
|
|
state.value.selectAreaHeight =
|
2025-03-20 11:12:46 +00:00
|
|
|
|
rpxToPx(state.value.mentionSelectHeight) - rpxToPx(90) + 'px'
|
|
|
|
|
})
|
|
|
|
|
})
|
2024-11-22 01:06:37 +00:00
|
|
|
|
|
2025-03-12 08:25:42 +00:00
|
|
|
|
const pxTorPx = (px) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const sysInfo = uni.getSystemInfoSync()
|
|
|
|
|
const rpx = px / (sysInfo.screenWidth / 750)
|
|
|
|
|
return rpx
|
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
|
|
|
|
const rpxToPx = (rpx) => {
|
2025-03-20 11:12:46 +00:00
|
|
|
|
const sysInfo = uni.getSystemInfoSync()
|
|
|
|
|
const px = (sysInfo.screenWidth / 750) * rpx
|
|
|
|
|
return px
|
|
|
|
|
}
|
2025-03-12 08:25:42 +00:00
|
|
|
|
|
2024-12-06 08:55:15 +00:00
|
|
|
|
onUnmounted(() => {
|
2025-03-19 11:58:23 +00:00
|
|
|
|
if (!state.value.keepDialogInfo) {
|
2025-03-18 12:00:41 +00:00
|
|
|
|
dialogueStore.setDialogue({})
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
clearMultiSelect()
|
2025-03-22 06:22:09 +00:00
|
|
|
|
if (avatarPressTimer) {
|
|
|
|
|
clearTimeout(avatarPressTimer)
|
|
|
|
|
}
|
2025-03-26 06:30:20 +00:00
|
|
|
|
// 清理防抖定时器
|
|
|
|
|
if (state.value.showMentionSelectTimer) {
|
|
|
|
|
clearTimeout(state.value.showMentionSelectTimer)
|
|
|
|
|
}
|
2025-03-30 08:22:29 +00:00
|
|
|
|
if (uploadsStore.isUploading) {
|
|
|
|
|
uploadsStore.clearUpload()
|
|
|
|
|
}
|
2025-03-20 11:12:46 +00:00
|
|
|
|
})
|
2025-03-26 06:30:20 +00:00
|
|
|
|
|
|
|
|
|
// 修改防抖函数的实现
|
|
|
|
|
const showMentionSelectDebounced = (quill) => {
|
|
|
|
|
const text = quill.getText()
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-04-09 07:08:54 +00:00
|
|
|
|
// 以下逻辑是 光标与@之间存在其他内容时 不触发选人弹窗
|
|
|
|
|
const selection = quill.getSelection()
|
|
|
|
|
if (selection) {
|
|
|
|
|
state.lastSelection = selection.index
|
|
|
|
|
if (
|
|
|
|
|
text[selection.index - 1].charCodeAt(0) !== 64 &&
|
|
|
|
|
text[selection.index - 1].charCodeAt(0) !== 32 &&
|
|
|
|
|
text[selection.index - 1].charCodeAt(0) !== 10
|
|
|
|
|
) {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: text[selection.index - 1],
|
|
|
|
|
icon: 'none',
|
|
|
|
|
})
|
|
|
|
|
state.value.lastMentionTriggered = false
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 以下逻辑是 记录触发@时,用户的输入框内容,下次一样内容得@不会再次触发
|
2025-03-26 06:30:20 +00:00
|
|
|
|
if (text !== state.value.lastMentionText) {
|
|
|
|
|
state.value.lastMentionTriggered = false
|
|
|
|
|
}
|
|
|
|
|
// 如果已经触发过,则不再触发
|
|
|
|
|
if (state.value.lastMentionTriggered) {
|
2025-03-28 08:13:45 +00:00
|
|
|
|
console.log('return')
|
2025-03-26 06:30:20 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// 记录当前文本内容和触发状态
|
|
|
|
|
state.value.lastMentionText = text
|
|
|
|
|
state.value.lastMentionTriggered = true
|
|
|
|
|
state.value.isShowMentionSelect = true
|
2025-04-08 08:58:28 +00:00
|
|
|
|
// quill.blur()
|
2025-03-26 06:30:20 +00:00
|
|
|
|
}
|
2024-11-22 01:06:37 +00:00
|
|
|
|
</script>
|
2024-11-22 09:00:03 +00:00
|
|
|
|
<style scoped lang="less">
|
2025-02-11 03:45:19 +00:00
|
|
|
|
.dialog-page {
|
2024-11-22 01:06:37 +00:00
|
|
|
|
flex: 1;
|
2025-03-20 11:12:46 +00:00
|
|
|
|
background-image: url('@/static/image/clockIn/z3280@3x.png');
|
2024-11-22 01:06:37 +00:00
|
|
|
|
background-size: cover;
|
2025-02-11 03:45:19 +00:00
|
|
|
|
background-position: bottom center;
|
2025-03-20 11:12:46 +00:00
|
|
|
|
background-attachment: scroll;
|
2025-02-11 03:45:19 +00:00
|
|
|
|
width: 100%;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
2025-02-11 03:45:19 +00:00
|
|
|
|
.dialog-list {
|
|
|
|
|
padding: 20rpx 32rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.toChatSetting_btn {
|
|
|
|
|
::v-deep .tmicon-gengduo {
|
|
|
|
|
line-height: unset !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-22 01:06:37 +00:00
|
|
|
|
}
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
2025-03-13 05:08:58 +00:00
|
|
|
|
.edit-revoked-message {
|
|
|
|
|
margin-left: 10rpx;
|
2025-03-14 05:15:54 +00:00
|
|
|
|
color: #46299d;
|
2025-03-13 05:08:58 +00:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-22 01:06:37 +00:00
|
|
|
|
.searchRoot {
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
padding: 22rpx 18rpx;
|
|
|
|
|
}
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
2024-11-22 01:06:37 +00:00
|
|
|
|
.contentRoot {
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
}
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
2024-11-22 01:06:37 +00:00
|
|
|
|
.footBox {
|
2024-11-26 08:51:36 +00:00
|
|
|
|
min-height: 162rpx;
|
2024-11-22 01:06:37 +00:00
|
|
|
|
background-color: #fff;
|
2025-03-10 07:09:26 +00:00
|
|
|
|
|
|
|
|
|
.quote-area {
|
|
|
|
|
margin: 4rpx 0 0 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
width: 100%;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-10 07:09:26 +00:00
|
|
|
|
span {
|
|
|
|
|
display: -webkit-inline-box;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
-webkit-line-clamp: 2;
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
width: 100%;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
word-break: break-all;
|
2025-03-10 07:09:26 +00:00
|
|
|
|
}
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-10 07:09:26 +00:00
|
|
|
|
img {
|
|
|
|
|
margin: 0 0 0 30rpx;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-22 01:06:37 +00:00
|
|
|
|
}
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
|
|
|
|
.load-toolbar {
|
2024-11-26 08:51:36 +00:00
|
|
|
|
height: 50rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
color: #409eff;
|
|
|
|
|
text-align: center;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
line-height: 50rpx;
|
|
|
|
|
font-size: 24rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
|
|
|
|
.no-more {
|
|
|
|
|
color: #b9b3b3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message-item {
|
|
|
|
|
&.border {
|
2024-11-26 08:51:36 +00:00
|
|
|
|
border-radius: 16rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.message-box {
|
|
|
|
|
width: 100%;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
min-height: 30rpx;
|
|
|
|
|
margin-bottom: 5rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.record-box {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: flex-start;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
2024-11-22 09:00:03 +00:00
|
|
|
|
.checkbox-column {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
2024-12-19 03:02:47 +00:00
|
|
|
|
width: 42rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
order: 1;
|
|
|
|
|
user-select: none;
|
2024-12-19 03:02:47 +00:00
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
margin-right: 20rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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;
|
2024-12-19 03:02:47 +00:00
|
|
|
|
// overflow: hidden;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
min-height: 30px;
|
|
|
|
|
|
|
|
|
|
.talk-title {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 6rpx;
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
user-select: none;
|
2025-02-05 08:22:32 +00:00
|
|
|
|
color: #bababa;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
opacity: 1;
|
|
|
|
|
|
|
|
|
|
&.show {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nickname {
|
|
|
|
|
color: var(--im-text-color);
|
2024-11-26 08:51:36 +00:00
|
|
|
|
margin-right: 5rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
|
|
|
|
|
.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;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
margin: 0 16rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
color: #a79e9e;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
font-size: 24rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
user-select: none;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-around;
|
|
|
|
|
|
|
|
|
|
.more-tools {
|
|
|
|
|
visibility: hidden;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
margin-left: 5rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.talk-reply {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
align-items: center;
|
|
|
|
|
width: fit-content;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
padding: 8rpx;
|
|
|
|
|
margin-top: 6rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
margin-right: auto;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
font-size: 24rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
color: #8f8f8f;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
background-color: var(--im-message-left-bg-color);
|
2024-11-26 08:51:36 +00:00
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
max-width: 450rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
|
|
|
|
.icon-top {
|
2024-11-26 08:51:36 +00:00
|
|
|
|
margin-right: 6rpx;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.ellipsis {
|
|
|
|
|
display: -webkit-inline-box;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
-webkit-line-clamp: 3;
|
|
|
|
|
-webkit-box-orient: vertical;
|
2025-03-10 07:09:26 +00:00
|
|
|
|
overflow: hidden;
|
2024-11-22 09:00:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&: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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
|
|
|
|
|
.content-placeholder {
|
|
|
|
|
height: 58rpx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.quillBox {
|
|
|
|
|
:deep(.ql-clipboard) {
|
2024-11-28 08:55:45 +00:00
|
|
|
|
position: relative;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
height: 1rpx;
|
|
|
|
|
overflow: auto;
|
2025-04-09 02:02:58 +00:00
|
|
|
|
display: none;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.ql-editor) {
|
|
|
|
|
padding: 14rpx 22rpx;
|
2025-02-05 08:22:32 +00:00
|
|
|
|
background-color: #f9f9f9;
|
2024-11-26 08:51:36 +00:00
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
outline: none !important;
|
2024-11-28 08:55:45 +00:00
|
|
|
|
max-height: 294rpx;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
line-height: 44rpx;
|
|
|
|
|
font-size: 32rpx;
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
2025-04-09 07:08:54 +00:00
|
|
|
|
.ed-emoji {
|
|
|
|
|
width: 44rpx;
|
|
|
|
|
height: 44rpx;
|
|
|
|
|
display: inline-block;
|
2024-11-28 08:55:45 +00:00
|
|
|
|
}
|
2024-11-26 08:51:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-19 03:02:47 +00:00
|
|
|
|
|
|
|
|
|
:deep(.wd-action-sheet) {
|
|
|
|
|
background-color: #8b8b8b !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
:deep(.wd-action-sheet__panel-title) {
|
|
|
|
|
color: #fff !important;
|
|
|
|
|
}
|
2024-12-20 08:59:58 +00:00
|
|
|
|
|
|
|
|
|
.component-content {
|
|
|
|
|
position: relative;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
/* 确保 z-index 低于 deepBubble */
|
|
|
|
|
}
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2024-12-24 08:28:44 +00:00
|
|
|
|
.divider {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 1rpx;
|
2025-02-05 08:22:32 +00:00
|
|
|
|
background-color: #e7e7e7;
|
2024-12-24 08:28:44 +00:00
|
|
|
|
}
|
2025-03-11 11:56:43 +00:00
|
|
|
|
|
|
|
|
|
.mention-select-drawer {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
2025-03-12 08:25:42 +00:00
|
|
|
|
padding: 36rpx 32rpx 0;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
.cancel-btns {
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
.hide-btn {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
position: relative;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
text {
|
|
|
|
|
}
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
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;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
span {
|
|
|
|
|
color: #bababa;
|
|
|
|
|
line-height: 40rpx;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mention-done-btn-can-do {
|
|
|
|
|
background-color: #46299d;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
span {
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.mention-edit-btn {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
flex-shrink: 0;
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-11 11:56:43 +00:00
|
|
|
|
span {
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-28 08:13:45 +00:00
|
|
|
|
|
2025-03-20 11:12:46 +00:00
|
|
|
|
:deep(.mention) {
|
|
|
|
|
color: #1890ff;
|
2025-03-20 03:02:29 +00:00
|
|
|
|
}
|
2024-11-22 01:06:37 +00:00
|
|
|
|
</style>
|