1543 lines
42 KiB
Vue
1543 lines
42 KiB
Vue
<template>
|
||
<div class="input-root">
|
||
<div class="msg-input-wrapper">
|
||
<!-- 当回复他人消息时,输入框上方需要展示被回复消息相关内容 -->
|
||
<div v-if="isReplyMsg" class="reply-message-wrapper">
|
||
<div class="reply-message-close" @tap="removeReplyMsg">
|
||
<Icon
|
||
color="#929299"
|
||
:iconStyle="{ fontWeight: '200' }"
|
||
:size="13"
|
||
type="icon-guanbi1"
|
||
/>
|
||
</div>
|
||
<div class="reply-line">|</div>
|
||
<div class="reply-title">{{ t('replyText') }}</div>
|
||
<div class="reply-to">
|
||
<Appellation
|
||
:account="replyMsg && replyMsg.senderId"
|
||
:team-id="
|
||
props.conversationType ===
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
? to
|
||
: ''
|
||
"
|
||
color="#929299"
|
||
:fontSize="13"
|
||
>
|
||
</Appellation>
|
||
</div>
|
||
<div class="reply-to-colon">:</div>
|
||
<div
|
||
v-if="replyMsg && replyMsg.messageClientId === 'noFind'"
|
||
class="reply-noFind"
|
||
>
|
||
{{ t('replyNotFindText') }}
|
||
</div>
|
||
<div class="reply-message" v-else>
|
||
<message-one-line
|
||
v-if="
|
||
replyMsg &&
|
||
replyMsg.messageType ===
|
||
V2NIMConst.V2NIMMessageType.V2NIM_MESSAGE_TYPE_TEXT
|
||
"
|
||
:text="replyMsg && replyMsg.text"
|
||
></message-one-line>
|
||
<div v-else>
|
||
{{
|
||
replyMsg
|
||
? '[' + REPLY_MSG_TYPE_MAP[replyMsg.messageType] + ']'
|
||
: ''
|
||
}}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 输入框上按钮组 -->
|
||
<div class="msg-button-group">
|
||
<div
|
||
@tap="handleAudioVisible"
|
||
v-if="!(isWeb || isHarmonyOs || isGroupSend)"
|
||
class="msg-input-button"
|
||
>
|
||
<Icon
|
||
v-if="audioPanelVisible"
|
||
:size="20"
|
||
type="audio-btn-selected"
|
||
key="audio-btn-selected"
|
||
/>
|
||
<Icon v-else :size="20" type="icon-audio" key="icon-audio" />
|
||
</div>
|
||
<div class="msg-input-button">
|
||
<Icon @tap="handleEmojiVisible" :size="20" type="icon-biaoqing" />
|
||
</div>
|
||
<div class="msg-input-button">
|
||
<div>
|
||
<Icon @tap="handleSendImageMsg" :size="20" type="icon-tupian" />
|
||
</div>
|
||
</div>
|
||
<div class="msg-input-button">
|
||
<Icon @tap="handleSendMoreVisible" type="send-more" :size="20" />
|
||
</div>
|
||
<!-- <div class="msg-input-button">
|
||
<Icon @tap="handleSetting" type="icon-shezhi" :size="20" />
|
||
</div> -->
|
||
</div>
|
||
<div v-if="inputVisible" class="msg-input">
|
||
<!-- 当从表情面板切换到文字输入时,直接唤起键盘,会导致input框滚动消失,故此处需要用EmojiInput兼容下,保证先隐藏表情面板,再弹出键盘 -->
|
||
<div
|
||
v-show="showEmojiInput"
|
||
@click="onClickEmojiInput"
|
||
class="input-emoji"
|
||
>
|
||
<div v-if="inputText" class="input-text">{{ inputText }}</div>
|
||
<div v-else class="input-placeholder">
|
||
{{
|
||
isTeamMute ? t('teamMutePlaceholder') : t('chatInputPlaceHolder')
|
||
}}
|
||
</div>
|
||
</div>
|
||
<input
|
||
v-show="!showEmojiInput"
|
||
:focus="isFocus"
|
||
class="msg-input-input"
|
||
:maxlength="-1"
|
||
:placeholder="
|
||
isTeamMute ? t('teamMutePlaceholder') : t('chatInputPlaceHolder')
|
||
"
|
||
v-model="inputText"
|
||
type="text"
|
||
:disabled="isTeamMute"
|
||
:confirm-hold="true"
|
||
cursor-spacing="20"
|
||
adjust-position="true"
|
||
confirm-type="send"
|
||
@confirm="handleSendTextMsg"
|
||
@blur="handleInputBlur"
|
||
@input="handleInput"
|
||
id="msg-input"
|
||
/>
|
||
</div>
|
||
<!-- 表情面板 -->
|
||
<div v-if="emojiVisible" class="msg-emoji-panel" @click.stop="() => {}">
|
||
<Face
|
||
@emojiClick="handleEmoji"
|
||
@emojiDelete="handleEmojiDelete"
|
||
@emojiSend="handleSendTextMsg"
|
||
/>
|
||
</div>
|
||
<!-- 发送语音消息面板 -->
|
||
<div
|
||
v-if="audioPanelVisible"
|
||
class="msg-audio-panel"
|
||
@click.stop="() => {}"
|
||
>
|
||
<VoicePanel @handleSendAudioMsg="handleSendAudioMsg"></VoicePanel>
|
||
</div>
|
||
<!-- 发送更多面板 -->
|
||
<div
|
||
v-if="sendMoreVisible"
|
||
class="send-more-panel"
|
||
@click.stop="() => {}"
|
||
>
|
||
<div class="send-more-panel-item-wrapper" v-if="!(isGroupSend)">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event:any) => handleSendVideoMsg('camera', event)"
|
||
>
|
||
<Icon type="icon-paishe" :size="30"></Icon>
|
||
</div>
|
||
<div class="icon-text">{{ t('shootText') }}</div>
|
||
</div>
|
||
<div class="send-more-panel-item-wrapper" v-if="!(isGroupSend)">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleSendVideoMsg('album', event)"
|
||
>
|
||
<Icon type="icon-shipin2" :size="30"></Icon>
|
||
</div>
|
||
<div class="icon-text">{{ t('albumText') }}</div>
|
||
</div>
|
||
<div class="send-more-panel-item-wrapper">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleCustom('reply', event)"
|
||
>
|
||
<image :src="quickImg" mode="widthFix"></image>
|
||
</div>
|
||
<div class="icon-text">快捷回复</div>
|
||
</div>
|
||
<div class="send-more-panel-item-wrapper">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleCustom('hj', event)"
|
||
>
|
||
<image :src="quickImg" mode="widthFix"></image>
|
||
</div>
|
||
<div class="icon-text">患教</div>
|
||
</div>
|
||
<div class="send-more-panel-item-wrapper">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleCustom('outpatient', event)"
|
||
>
|
||
<image :src="chuzhenImg" mode="widthFix"></image>
|
||
</div>
|
||
<div class="icon-text">出/停诊公告</div>
|
||
</div>
|
||
<div class="send-more-panel-item-wrapper">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleCustom('mall', event)"
|
||
>
|
||
<image :src="mallImg" mode="widthFix"></image>
|
||
</div>
|
||
<div class="icon-text">商城</div>
|
||
</div>
|
||
|
||
<!-- <div class="send-more-panel-item-wrapper">
|
||
<div
|
||
class="send-more-panel-item"
|
||
@tap="(event: any) => handleCustom('hospital', event)"
|
||
>
|
||
<image :src="hospitalImg" mode="widthFix"></image>
|
||
</div>
|
||
<div class="icon-text">互联网医院</div>
|
||
</div> -->
|
||
<!-- 音频呼叫 -->
|
||
<!-- <div
|
||
class="send-more-panel-item-wrapper"
|
||
v-if="
|
||
isAndroidOrIosApp &&
|
||
props.conversationType !==
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
"
|
||
>
|
||
<div class="send-more-panel-item" @tap="handleCall(1)">
|
||
<Icon type="icon-audio-call" :size="30"></Icon>
|
||
</div>
|
||
<div class="icon-text">{{ t('voiceCallText') }}</div>
|
||
</div> -->
|
||
|
||
<!-- 视频呼叫 -->
|
||
<!-- <div
|
||
class="send-more-panel-item-wrapper"
|
||
v-if="
|
||
isAndroidOrIosApp &&
|
||
props.conversationType !==
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
"
|
||
>
|
||
<div class="send-more-panel-item" @tap="() => handleCall(2)">
|
||
<Icon type="icon-video-call" :size="30"></Icon>
|
||
</div>
|
||
<div class="icon-text">{{ t('videoCallText') }}</div>
|
||
</div> -->
|
||
<!-- <div
|
||
v-if="isWeb"
|
||
class="send-more-panel-item-wrapper"
|
||
@tap="handleSendFileMsg"
|
||
>
|
||
<div class="send-more-panel-item">
|
||
<Icon type="icon-file" :size="30"></Icon>
|
||
</div>
|
||
<div class="icon-text">{{ t('fileText') }}</div>
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
<!-- @消息相关 popup -->
|
||
<UniPopup
|
||
ref="popupRef"
|
||
background-color="#ffffff"
|
||
type="bottom"
|
||
mask-background-color="rgba(0,0,0,0.4)"
|
||
@change="onPopupChange"
|
||
>
|
||
<MentionMemberList :team-id="to"></MentionMemberList>
|
||
</UniPopup>
|
||
<!-- 复制自 groupSend 的遮罩与弹窗 -->
|
||
<view v-if="showModal" class="mask" @tap="closeModal"></view>
|
||
<view v-if="showModal" class="center-modal">
|
||
<view class="modal-title">温馨提示</view>
|
||
<view class="modal-divider"></view>
|
||
<view class="modal-item" @tap="onSelectSince('article')">
|
||
<text>图文科普</text>
|
||
</view>
|
||
<view class="modal-divider"></view>
|
||
<view class="modal-item" @tap="onSelectSince('video')">
|
||
<text>视频科普</text>
|
||
</view>
|
||
</view>
|
||
<!-- 商城弹窗 -->
|
||
<view v-if="showMallModal" class="mask" @tap="closeMallModal"></view>
|
||
<view v-if="showMallModal" class="center-modal">
|
||
<view class="modal-title">温馨提示</view>
|
||
<view class="modal-divider"></view>
|
||
<view class="modal-item" @tap="sendMallMsg">
|
||
<text>纽娃复合营养素固体饮料</text>
|
||
</view>
|
||
<view class="modal-divider"></view>
|
||
<view class="modal-item" >
|
||
<text>更多商品正在准备中</text>
|
||
</view>
|
||
</view>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
/** 消息页面输入框组件 */
|
||
import docUrl from '@/utils/docUrl'
|
||
import Face from './face.vue'
|
||
import VoicePanel from './voice-panel.vue'
|
||
import Icon from '@/components/Icon.vue'
|
||
import { ref, getCurrentInstance, computed, onUnmounted, onMounted } from 'vue'
|
||
import { ALLOW_AT, events, REPLY_MSG_TYPE_MAP } from '@/utils/im/constants'
|
||
import { emojiMap } from '@/utils/im/emoji'
|
||
import { t } from '@/utils/im/i18n'
|
||
import { handleNoPermission } from '@/utils/im/permission'
|
||
import { customNavigateTo } from '@/utils/im/customNavigate'
|
||
import MessageOneLine from '@/components/MessageOneLine.vue'
|
||
import {
|
||
isAndroidApp,
|
||
stopAllAudio,
|
||
isIosWeb,
|
||
isWeb,
|
||
isWxApp,
|
||
startCall,
|
||
isAndroidOrIosApp,
|
||
isHarmonyOs,
|
||
} from '@/utils/im/index'
|
||
|
||
// @ts-ignore
|
||
import UniPopup from '@/components/uni-components/uni-popup/components/uni-popup/uni-popup.vue'
|
||
// @ts-ignore
|
||
import MentionMemberList from './mention-member-list.vue'
|
||
import Appellation from '@/components/Appellation.vue'
|
||
import { AT_ALL_ACCOUNT } from '@/utils/im/constants'
|
||
import { replaceEmoji } from '@/utils/im/index'
|
||
import { autorun } from 'mobx'
|
||
import quickImg from '@/static/quck_message.png'
|
||
import chuzhenImg from '@/static/outpatient_true.png'
|
||
import mallImg from '@/static/ytx_chattingfooter_shopping.png'
|
||
import hospitalImg from '@/static/ytx_chatting_hospital.png'
|
||
import {onShow,onUnload} from '@dcloudio/uni-app'
|
||
|
||
import {
|
||
V2NIMTeam,
|
||
V2NIMTeamChatBannedMode,
|
||
V2NIMTeamMember,
|
||
} from 'nim-web-sdk-ng/dist/esm/nim/src/V2NIMTeamService'
|
||
import {
|
||
V2NIMMessageForUI,
|
||
YxServerExt,
|
||
YxAitMsg,
|
||
} from '@xkit-yx/im-store-v2/dist/types/types'
|
||
//@ts-ignore
|
||
import { V2NIMConst } from '@/utils/im/nim'
|
||
import { V2NIMMessage } from 'nim-web-sdk-ng/dist/esm/nim/src/V2NIMMessageService'
|
||
export type MentionedMember = { accountId: string; appellation: string }
|
||
import navTo from '@/utils/navTo'
|
||
import api from '@/api/api.js'
|
||
let userInfo=uni.getStorageSync('userInfo');
|
||
let expert_uuid=userInfo.uuid;
|
||
let expert_name=userInfo.realName;
|
||
let patient_uuid='';
|
||
const articleInfo=ref({});
|
||
const videoInfo=ref({});
|
||
const patientListByGBK = async () => {
|
||
|
||
const res = await api.patientListByGBK();
|
||
if(res.code == 1){
|
||
//patientList.value = res.data;
|
||
for (let i = 0; i < res.data.length; i++) {
|
||
if (res.data[i].uuid.toLowerCase() === props.to) {
|
||
patient_uuid = res.data[i].uuid;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
};
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
conversationType: V2NIMConst.V2NIMConversationType
|
||
to: string
|
||
isGroupSend?: boolean
|
||
replyMsgsMap?: {
|
||
[key: string]: V2NIMMessageForUI
|
||
}
|
||
}>(),
|
||
{}
|
||
)
|
||
const emits = defineEmits(['send'])
|
||
/** 会话ID */
|
||
const conversationId =
|
||
props.conversationType ===
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P
|
||
? uni.$UIKitNIM.V2NIMConversationIdUtil.p2pConversationId(props.to)
|
||
: uni.$UIKitNIM.V2NIMConversationIdUtil.teamConversationId(props.to)
|
||
|
||
/** 输入框内容 */
|
||
const inputText = ref('')
|
||
const extVisible = ref(false)
|
||
/** 群发选择弹窗 */
|
||
const showModal = ref(false)
|
||
/** 商城弹窗 */
|
||
const showMallModal = ref(false)
|
||
/** 音频面板flag */
|
||
const audioPanelVisible = ref(false)
|
||
/** 发送更多面板flag */
|
||
const sendMoreVisible = ref(false)
|
||
/** 表情面板flag */
|
||
const emojiVisible = ref(false)
|
||
/** input框flag */
|
||
const inputVisible = computed(() => {
|
||
if (audioPanelVisible.value || sendMoreVisible.value) {
|
||
return false
|
||
} else {
|
||
return true
|
||
}
|
||
})
|
||
|
||
/** 发起呼叫,type: 1 音频呼叫,2 视频呼叫 */
|
||
const handleCall = (type: number) => {
|
||
const myAccount = uni.$UIKitStore.userStore.myUserInfo.accountId
|
||
|
||
const remoteShowName = uni.$UIKitStore.uiStore.getAppellation({
|
||
account: props.to,
|
||
})
|
||
if (myAccount) {
|
||
startCall({
|
||
remoteUserAccid: props.to,
|
||
currentUserAccid: myAccount,
|
||
type: type,
|
||
remoteShowName: remoteShowName,
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: t('callFailedText'),
|
||
icon: 'none',
|
||
})
|
||
}
|
||
}
|
||
const outPatientList = ref([]);
|
||
const getListOutPatient = async () => {
|
||
const res = await api.listOutPatient({
|
||
page:1,
|
||
});
|
||
if(res.code == 200){
|
||
outPatientList.value = res.data.list.list;
|
||
}
|
||
}
|
||
const stopOutPatientList = ref([]);
|
||
const getStopOutPatientList = async () => {
|
||
const res = await api.stopOutPatientList();
|
||
if(res.code == 200){
|
||
stopOutPatientList.value = res.data;
|
||
}
|
||
}
|
||
onShow(() => {
|
||
uni.$on('articelItem', (article) => {
|
||
console.log('article', article);
|
||
articleInfo.value = article;
|
||
senCustomMsg('article');
|
||
//handleSendTextMsg('article', article);
|
||
});
|
||
uni.$on('videoItem', (video) => {
|
||
videoInfo.value = video;
|
||
senCustomMsg('video');
|
||
//handleSendTextMsg('video', video);
|
||
});
|
||
uni.$on('quickReply', (reply) => {
|
||
inputText.value= reply;
|
||
});
|
||
getListOutPatient();
|
||
getStopOutPatientList();
|
||
});
|
||
onUnload(() => {
|
||
uni.$off('articelItem');
|
||
uni.$off('videoItem');
|
||
uni.$off('quickReply');
|
||
});
|
||
/** 商城弹窗 */
|
||
let rawStr="{\"gdxz_content\":\"我已入驻肝胆相照互联网医院,复诊购药一站式服务,快来看看吧\",\"gdxz_ext_data\":\"[互联网医院]\",\"gdxz_id\":\"1681174885629431808\",\"gdxz_img\":\"https://img.applets.igandanyiyuan.com/applet/admin/avatar/2023071813261420200708181049.png\",\"gdxz_title\":\"肝胆相照互联网医院\",\"gdxz_type\":\"[互联网医院]\",\"gdxz_url\":\"\"}";
|
||
const sendMallMsg = () => {
|
||
showMallModal.value = false;
|
||
handleSendTextMsg('mall');
|
||
|
||
}
|
||
|
||
/** 商城弹窗 */
|
||
const closeMallModal = () => {
|
||
showMallModal.value = false
|
||
}
|
||
|
||
/** 用于解决表情面板和键盘冲突,导致输入框滚动消失问题 */
|
||
const showEmojiInput = ref(false)
|
||
|
||
/** 回复消息相关 */
|
||
const isReplyMsg = ref(false)
|
||
const isFocus = ref(false)
|
||
const replyMsg = ref<V2NIMMessageForUI>()
|
||
|
||
/** @ 消息相关 */
|
||
const ctx = getCurrentInstance()
|
||
const popupRef = ref(null)
|
||
|
||
/** @ 成员列表 */
|
||
const selectedAtMembers = ref<MentionedMember[]>([])
|
||
|
||
/** 群相关 */
|
||
const team = ref<V2NIMTeam>()
|
||
/** 群成员 */
|
||
const teamMembers = ref<V2NIMTeamMember[]>([])
|
||
/** 群禁言模式 */
|
||
const teamMute = ref<V2NIMTeamChatBannedMode>(
|
||
V2NIMConst.V2NIMTeamChatBannedMode.V2NIM_TEAM_CHAT_BANNED_MODE_UNBAN
|
||
)
|
||
/** 是否是群主 */
|
||
const isGroupOwner = ref(false)
|
||
/** 是否是群管理员 */
|
||
const isGroupManager = ref(false)
|
||
/** 群是否禁言 */
|
||
const isTeamMute = ref(false)
|
||
|
||
/** 是否允许@ 所有人 */
|
||
const allowAtAll = computed(() => {
|
||
let ext: YxServerExt = {}
|
||
try {
|
||
ext = JSON.parse((team.value || {}).serverExtension || '{}')
|
||
} catch (error) {
|
||
//
|
||
}
|
||
if (ext[ALLOW_AT] === 'manager') {
|
||
return isGroupOwner.value || isGroupManager.value
|
||
}
|
||
return true
|
||
})
|
||
/** 更新群禁言 */
|
||
const updateTeamMute = () => {
|
||
if (
|
||
teamMute.value ===
|
||
V2NIMConst.V2NIMTeamChatBannedMode.V2NIM_TEAM_CHAT_BANNED_MODE_UNBAN
|
||
) {
|
||
isTeamMute.value = false
|
||
return
|
||
}
|
||
|
||
/** 群主或者群管理员在群禁言时,可以发送消息 */
|
||
if (isGroupOwner.value || isGroupManager.value) {
|
||
isTeamMute.value = false
|
||
return
|
||
}
|
||
isTeamMute.value = true
|
||
return
|
||
}
|
||
|
||
/** 弹窗*/
|
||
const onPopupChange = (e: any) => {
|
||
uni.$emit(events.HANDLE_MOVE_THROUGH, e.value)
|
||
}
|
||
|
||
/** 打开/关闭群发选择弹窗(与 groupSend 保持一致) */
|
||
const openModal = () => {
|
||
showModal.value = true;
|
||
|
||
}
|
||
const closeModal = () => {
|
||
showModal.value = false
|
||
}
|
||
const toggleModal = () => {
|
||
showModal.value = !showModal.value
|
||
}
|
||
const onSelectSince = (type: string) => {
|
||
showModal.value = false
|
||
if (type === 'article') {
|
||
navTo({ url: '/pages_chat/article/article' })
|
||
} else if (type === 'video') {
|
||
navTo({ url: '/pages_chat/video/video' })
|
||
}
|
||
}
|
||
|
||
|
||
/** 点击@ 群成员 */
|
||
const handleMentionItemClick = (member: MentionedMember) => {
|
||
//@ts-ignore
|
||
ctx.refs.popupRef.close()
|
||
uni.$emit(events.HANDLE_MOVE_THROUGH, false)
|
||
const nickInTeam = member.appellation
|
||
selectedAtMembers.value = [
|
||
...selectedAtMembers.value.filter(
|
||
(item) => item.accountId !== member.accountId
|
||
),
|
||
member,
|
||
]
|
||
const newInputText = inputText.value + nickInTeam + ' '
|
||
// 更新input框的内容
|
||
inputText.value = newInputText
|
||
}
|
||
|
||
/** 关闭popup */
|
||
const closePopup = () => {
|
||
//@ts-ignore
|
||
ctx.refs.popupRef.close()
|
||
}
|
||
|
||
/** 点击表情输入框,隐藏表情面板,显示键盘 */
|
||
const onClickEmojiInput = () => {
|
||
showEmojiInput.value = false
|
||
extVisible.value = false
|
||
emojiVisible.value = false
|
||
if (isIosWeb) {
|
||
showKeyboard()
|
||
} else if (!isHarmonyOs) {
|
||
const timeout = setTimeout(() => {
|
||
showKeyboard()
|
||
clearTimeout(timeout)
|
||
}, 500)
|
||
}
|
||
}
|
||
|
||
/** 输入框失焦 */
|
||
const handleInputBlur = () => {
|
||
isFocus.value = false
|
||
}
|
||
|
||
/** 滚动到底部 */
|
||
const scrollBottom = () => {
|
||
if (!isWeb) {
|
||
setTimeout(() => {
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
}, 300)
|
||
} else {
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
}
|
||
}
|
||
|
||
/** 输入框输入事件 */
|
||
const handleInput = (event: any) => {
|
||
const text = event?.detail?.value
|
||
const isAit = text.endsWith('@') || text.endsWith('@\n')
|
||
if (
|
||
props.conversationType ==
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
) {
|
||
if (isAit) {
|
||
/** 当前输入的是@ */
|
||
uni.hideKeyboard()
|
||
// @ts-ignore
|
||
ctx.refs.popupRef.open('bottom')
|
||
isFocus.value = false
|
||
uni.$emit(events.HANDLE_MOVE_THROUGH, true)
|
||
}
|
||
}
|
||
}
|
||
|
||
/** 发送文本消息 */
|
||
const handleSendTextMsg = (type:string) => {
|
||
if (inputText.value.trim() === '') return
|
||
const ext = onAtMembersExtHandler()
|
||
let mallText='纽娃复合营养素固体饮料主要成分是:蜂花粉、乳清蛋白粉、灰树花粉、低聚木糖、蚕蛹氨基酸、麦芽粉、薏苡仁粉、烟酸、磷脂,以及其他调味品、辅助原料。科学配比制成,含有丰富的蛋白质、氨基酸、维生素、微量元素及其他营养元素,点击链接了解详情。'
|
||
let text = type==='mall'?mallText:replaceEmoji(inputText.value)
|
||
const textMsg = uni.$UIKitNIM.V2NIMMessageCreator.createTextMessage(text)
|
||
//let serverExtension={"gdxz_nickName":"测试","gdxz_sessionType":"general"};
|
||
if(props.isGroupSend){
|
||
emits('send',{
|
||
content:textMsg,
|
||
msg_type:1,
|
||
})
|
||
inputText.value = ''
|
||
isReplyMsg.value = false
|
||
replyMsg.value = undefined
|
||
selectedAtMembers.value = [];
|
||
}else{
|
||
|
||
uni.$UIKitStore.msgStore
|
||
.sendMessageActive({
|
||
msg: textMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
serverExtension:selectedAtMembers.value.length && (ext as any),
|
||
sendBefore: () => {
|
||
scrollBottom();
|
||
|
||
},
|
||
})
|
||
.catch(() => {
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: t('sendMsgFailedText'),
|
||
})
|
||
})
|
||
.finally(() => {
|
||
scrollBottom()
|
||
})
|
||
|
||
inputText.value = ''
|
||
isReplyMsg.value = false
|
||
replyMsg.value = undefined
|
||
selectedAtMembers.value = [];
|
||
if(type=='mall'){
|
||
senCustomMsg('mall');
|
||
}
|
||
}
|
||
}
|
||
|
||
/** 发送文件消息 */
|
||
const handleSendFileMsg = () => {
|
||
uni.chooseFile({
|
||
count: 1,
|
||
type: 'all',
|
||
success: (res) => {
|
||
const filePath = res?.tempFilePaths?.[0]
|
||
// @ts-ignore
|
||
const fileName = res?.tempFiles?.[0]?.name
|
||
if (filePath && fileName) {
|
||
const fileMsg = uni.$UIKitNIM.V2NIMMessageCreator.createFileMessage(
|
||
filePath,
|
||
fileName
|
||
)
|
||
uni.$UIKitStore.msgStore.sendMessageActive({
|
||
msg: fileMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
sendBefore: () => {
|
||
scrollBottom()
|
||
},
|
||
})
|
||
}
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: t('sendFileFailedText'),
|
||
icon: 'none',
|
||
})
|
||
},
|
||
})
|
||
}
|
||
|
||
/** 移除回复消息 */
|
||
const removeReplyMsg = () => {
|
||
uni.$UIKitStore.msgStore.removeReplyMsgActive(
|
||
replyMsg?.value?.conversationId as string
|
||
)
|
||
isReplyMsg.value = false
|
||
}
|
||
|
||
/** 显示表情面板 */
|
||
const handleEmojiVisible = () => {
|
||
if (isTeamMute.value) return
|
||
if (isWxApp || isAndroidApp || isHarmonyOs) {
|
||
const timeout = setTimeout(() => {
|
||
emojiVisible.value = true
|
||
extVisible.value = true
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
clearTimeout(timeout)
|
||
}, 300)
|
||
} else {
|
||
emojiVisible.value = true
|
||
extVisible.value = true
|
||
}
|
||
showEmojiInput.value = true
|
||
audioPanelVisible.value = false
|
||
sendMoreVisible.value = false
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
}
|
||
|
||
/** 显示发送更多"+"面板 */
|
||
const handleSendMoreVisible = () => {
|
||
if (isTeamMute.value) return
|
||
audioPanelVisible.value = false
|
||
emojiVisible.value = false
|
||
sendMoreVisible.value = !sendMoreVisible.value
|
||
setTimeout(() => {
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
}, 300)
|
||
}
|
||
|
||
/** 点击表情 */
|
||
const handleEmoji = (emoji: { key: string; type: string }) => {
|
||
inputText.value += emoji.key
|
||
}
|
||
|
||
/** 删除表情 */
|
||
const handleEmojiDelete = () => {
|
||
let target = ''
|
||
const isEmojiEnd = Object.keys(emojiMap).reduce((prev, cur) => {
|
||
const isEnd = inputText.value.endsWith(cur)
|
||
if (isEnd) {
|
||
target = cur
|
||
}
|
||
return prev || isEnd
|
||
}, false)
|
||
if (isEmojiEnd && target) {
|
||
inputText.value = inputText.value.replace(target, '')
|
||
} else {
|
||
inputText.value = inputText.value.slice(0, -1)
|
||
}
|
||
}
|
||
|
||
/** 显示语音面板 */
|
||
const handleAudioVisible = () => {
|
||
if (isTeamMute.value) return
|
||
audioPanelVisible.value = !audioPanelVisible.value
|
||
emojiVisible.value = false
|
||
setTimeout(() => {
|
||
uni.$emit(events.ON_SCROLL_BOTTOM)
|
||
}, 300)
|
||
}
|
||
|
||
/** 发送图片消息 */
|
||
const handleSendImageMsg = () => {
|
||
if (isTeamMute.value) return
|
||
stopAllAudio()
|
||
uni.chooseImage({
|
||
count: 1,
|
||
sizeType: ['compressed'],
|
||
success: (res) => {
|
||
const imgMsg = uni.$UIKitNIM.V2NIMMessageCreator.createImageMessage(
|
||
res.tempFilePaths[0]
|
||
)
|
||
if(props.isGroupSend){
|
||
const fileManager = uni.getFileSystemManager();
|
||
fileManager.readFile({
|
||
filePath: res.tempFilePaths[0],
|
||
encoding: 'base64',
|
||
success: (res) => {
|
||
emits('send',{
|
||
content:res.data,
|
||
msg_type:2,
|
||
})
|
||
},
|
||
fail: (error) => {
|
||
console.log('chooseImage', error)
|
||
}
|
||
})
|
||
}else{
|
||
uni.$UIKitStore.msgStore
|
||
.sendMessageActive({
|
||
msg: imgMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
progress: () => true,
|
||
sendBefore: () => {
|
||
scrollBottom()
|
||
},
|
||
})
|
||
.then(() => {
|
||
scrollBottom()
|
||
})
|
||
.catch(() => {
|
||
scrollBottom()
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: t('sendImageFailedText'),
|
||
})
|
||
})
|
||
}
|
||
|
||
},
|
||
/** uniapp 提供的chooseImage api 在鸿蒙上表现为不支持选择gif,在其他端支持 */
|
||
fail: (error) => {
|
||
console.log('chooseImage', error)
|
||
},
|
||
/** 没有开启权限时,提示开启权限 */
|
||
complete: handleNoPermission,
|
||
})
|
||
|
||
}
|
||
const senCustomMsg = (type:string) => {
|
||
let rawStr="";
|
||
let text="";
|
||
let msg_type=0;
|
||
let msg_content="";
|
||
let doctor_id="";
|
||
if(type == 'hospital'){
|
||
doctor_id='';
|
||
msg_type=8;
|
||
msg_content="https://img.applets.igandanyiyuan.com/applet/admin/avatar/2023071813261420200708181049.png";
|
||
text="[互联网医院]";
|
||
rawStr=`{\"gdxz_content\":\"我已入驻肝胆相照互联网医院,复诊购药一站式服务,快来看看吧\",\"gdxz_ext_data\":\"[互联网医院]\",\"gdxz_id\":\"1681174885629431808\",\"gdxz_img\":\"https://img.applets.igandanyiyuan.com/applet/admin/avatar/2023071813261420200708181049.png\",\"gdxz_title\":\"肝胆相照互联网医院\",\"gdxz_type\":\"[互联网医院]\",\"gdxz_url\":\"\"}`;
|
||
}else if(type == 'mall'){
|
||
msg_type=6;
|
||
msg_content="";
|
||
text="[肝胆商城]";
|
||
rawStr=`{\"gdxz_content\":\"肝胆相照®肝胆病在线公共服务平台\",\"gdxz_ext_data\":\"[肝胆商城]\",\"gdxz_id\":\"\",\"gdxz_img\":\"\",\"gdxz_title\":\"纽娃复合营养素固体饮料\",\"gdxz_type\":\"[肝胆商城]\",\"gdxz_url\":\"https://wx.igandan.com/shop_notify/setInfo?patient_uuid=${patient_uuid}&expert_uuid=${expert_uuid}\"}`;
|
||
}else if(type == 'outpatient'){
|
||
msg_type=5;
|
||
msg_content="";
|
||
text="[门诊公告]";
|
||
rawStr=`{\"gdxz_content\":\"门诊详情\",\"gdxz_ext_data\":\"[门诊公告]\",\"gdxz_id\":\"\",\"gdxz_img\":\"\",\"gdxz_title\":\"${expert_name}医生门诊详情\",\"gdxz_type\":\"[门诊公告]\",\"gdxz_url\":\"https://dev-wx.igandan.com/wxPatient/index.htm#/outPatient?link=share&expertUuid=${expert_uuid}\"}`
|
||
}else if(type == 'article'){
|
||
msg_type=3;
|
||
msg_content=articleInfo.value.uuid;
|
||
text="[图文科普]";
|
||
let content='"'+articleInfo.value.summary+'"';
|
||
let id='"'+articleInfo.value.uuid+'"';
|
||
let title='"'+articleInfo.value.title+'"';
|
||
let path='"'+docUrl+articleInfo.value.path+'"';
|
||
rawStr=`{\"gdxz_content\":${content},\"gdxz_ext_data\":\"[图文科普]\",\"gdxz_id\":${id},\"gdxz_img\":\"http://doc.igandan.org/app/book/pdf/2019/20190613152617.png\",\"gdxz_title\":${title},\"gdxz_type\":\"[图文科普]\",\"gdxz_url\":${path}}`
|
||
}else if(type == 'video'){
|
||
msg_type=4;
|
||
msg_content=videoInfo.value.uuid;
|
||
let content='"'+videoInfo.value.note+'"';
|
||
let id='"'+videoInfo.value.uuid+'"';
|
||
let title='"'+videoInfo.value.name+'"';
|
||
let path='"'+docUrl+videoInfo.value.path+'"';
|
||
text="[视频科普]";
|
||
rawStr=`{\"gdxz_content\":${content},\"gdxz_ext_data\":\"[视频科普]\",\"gdxz_id\":${id},\"gdxz_img\":\"http://doc.igandan.org/app/book/pdf/2019/20190613152617.png\",\"gdxz_title\":${title},\"gdxz_type\":\"[视频科普]\",\"gdxz_url\":${path}}`
|
||
}
|
||
const customMsg = uni.$UIKitNIM.V2NIMMessageCreator.createCustomMessage(text,rawStr)
|
||
if(props.isGroupSend){
|
||
emits('send',{
|
||
content:msg_content,
|
||
msg_type:msg_type,
|
||
})
|
||
}else{
|
||
uni.$UIKitStore.msgStore
|
||
.sendMessageActive({
|
||
msg: customMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
progress: () => true,
|
||
sendBefore: () => {
|
||
scrollBottom()
|
||
},
|
||
})
|
||
.then(() => {
|
||
scrollBottom();
|
||
})
|
||
.catch(() => {
|
||
scrollBottom()
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: '发送失败',
|
||
})
|
||
})
|
||
}
|
||
}
|
||
|
||
const handleCustom = (type: string, event: any) => {
|
||
if (isTeamMute.value) return
|
||
if(type == 'reply'){
|
||
navTo({
|
||
url: '/pages_chat/quickReply/quickReply',
|
||
})
|
||
}else if(type == 'hj'){
|
||
showModal.value = true
|
||
}else if(type == 'mall'){
|
||
showMallModal.value = true
|
||
patientListByGBK();
|
||
}else if(type == 'outpatient'){
|
||
// navTo({
|
||
// url: '/pages_chat/outpatient/outpatient',
|
||
// })
|
||
if( outPatientList.value.length==0 && stopOutPatientList.value.length==0 ){
|
||
navTo({
|
||
url: '/pages_chat/outpatient/outpatient',
|
||
})
|
||
}else{
|
||
senCustomMsg('outpatient');
|
||
}
|
||
|
||
|
||
}else if(type == 'hospital'){
|
||
senCustomMsg('hospital');
|
||
}
|
||
}
|
||
/** 发送视频消息(使用相机或者从相册选择) */
|
||
const handleSendVideoMsg = (type: string, event: any) => {
|
||
if (isTeamMute.value) return
|
||
stopAllAudio()
|
||
// 这里做一层拦截的原因是,微信小程序在input聚焦的时候点击+号按钮,会触发此函数执行,阻止冒泡也无法解决该问题,疑为uniapp编译问题
|
||
if (isWxApp && event?.type == 'blur') {
|
||
return
|
||
}
|
||
|
||
uni.chooseVideo({
|
||
sourceType: [type],
|
||
compressed: true,
|
||
maxDuration: 60,
|
||
success: (res) => {
|
||
const videoMsg = uni.$UIKitNIM.V2NIMMessageCreator.createVideoMessage(
|
||
res.tempFilePath
|
||
)
|
||
|
||
uni.$UIKitStore.msgStore
|
||
.sendMessageActive({
|
||
msg: videoMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
progress: () => true,
|
||
sendBefore: () => {
|
||
scrollBottom()
|
||
},
|
||
})
|
||
.then(() => {
|
||
scrollBottom()
|
||
})
|
||
.catch(() => {
|
||
scrollBottom()
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: t('sendVideoFailedText'),
|
||
})
|
||
})
|
||
},
|
||
/** 没有开启权限时,提示开启权限 */
|
||
complete: handleNoPermission,
|
||
})
|
||
}
|
||
|
||
/** 发送语音消息 */
|
||
const handleSendAudioMsg = (filePath: string, duration: number) => {
|
||
const audioMsg =
|
||
uni.$UIKitNIM.V2NIMMessageCreator.createAudioMessage(filePath)
|
||
|
||
uni.$UIKitStore.msgStore
|
||
.sendMessageActive({
|
||
msg: audioMsg as unknown as V2NIMMessage,
|
||
conversationId,
|
||
progress: () => true,
|
||
sendBefore: (msg) => {
|
||
scrollBottom()
|
||
uni.$UIKitStore.msgStore.addMsg(msg.conversationId, [
|
||
{
|
||
...msg,
|
||
//@ts-ignore
|
||
attachment: {
|
||
duration: duration,
|
||
},
|
||
},
|
||
])
|
||
},
|
||
})
|
||
.then(() => {
|
||
scrollBottom()
|
||
})
|
||
.catch(() => {
|
||
uni.showToast({
|
||
icon: 'error',
|
||
title: t('sendAudioFailedText'),
|
||
})
|
||
scrollBottom()
|
||
})
|
||
}
|
||
|
||
/** 跳转设置页 */
|
||
const handleSetting = () => {
|
||
uni.hideKeyboard()
|
||
if (
|
||
props.conversationType ===
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_P2P
|
||
) {
|
||
customNavigateTo({
|
||
url: `/pages/Chat/message/p2p-set?id=${props.to}`,
|
||
})
|
||
} else if (
|
||
props.conversationType ===
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
) {
|
||
customNavigateTo({
|
||
url: `/pages/Team/team-set/index?id=${props.to}`,
|
||
})
|
||
}
|
||
}
|
||
|
||
let teamWatch = () => {}
|
||
/** 编译到鸿蒙上时,通过isFocus来唤起键盘,会导致input框滚动消失,故鸿蒙不使用isFocus来唤起键盘,由用户手动唤起 */
|
||
const showKeyboard = () => {
|
||
isFocus.value = true
|
||
}
|
||
|
||
onMounted(() => {
|
||
/** 群监听 */
|
||
teamWatch = autorun(() => {
|
||
if (
|
||
props.conversationType ===
|
||
V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM
|
||
) {
|
||
//@ts-expect-error
|
||
const _team: V2NIMTeam = uni.$UIKitStore.teamStore.teams.get(props.to)
|
||
|
||
teamMembers.value = uni.$UIKitStore.teamMemberStore.getTeamMember(
|
||
props.to
|
||
)
|
||
|
||
const myUser = uni.$UIKitStore.userStore.myUserInfo
|
||
isGroupOwner.value = _team?.ownerAccountId == myUser.accountId
|
||
isGroupManager.value = teamMembers.value
|
||
.filter(
|
||
(item) =>
|
||
item.memberRole ===
|
||
V2NIMConst.V2NIMTeamMemberRole.V2NIM_TEAM_MEMBER_ROLE_MANAGER
|
||
)
|
||
.some((member) => member.accountId === (myUser ? myUser.accountId : ''))
|
||
team.value = _team
|
||
if (_team) {
|
||
teamMute.value = _team.chatBannedMode
|
||
}
|
||
updateTeamMute()
|
||
}
|
||
})
|
||
|
||
/** 撤回后,重新编辑消息 */
|
||
uni.$on(events.ON_REEDIT_MSG, (msg: V2NIMMessageForUI) => {
|
||
const _replyMsg = props.replyMsgsMap?.[msg.messageClientId]
|
||
|
||
// 为了解决 1.撤回回复消息A 2.再撤回普通文本消息B 3.重新编辑消息A 4.再重新编辑消息B后 输入框显示A的引用内容,发送后显示A的引用内容的问题
|
||
|
||
if (msg.conversationId) {
|
||
uni.$UIKitStore.msgStore.removeReplyMsgActive(msg.conversationId)
|
||
isReplyMsg.value = false
|
||
}
|
||
|
||
/** 如果重新编辑的是回复消息,则需要将回复消息展示在输入框上方 */
|
||
if (_replyMsg?.messageClientId) {
|
||
_replyMsg && uni.$UIKitStore.msgStore.replyMsgActive(_replyMsg)
|
||
replyMsg.value = _replyMsg
|
||
isReplyMsg.value = true
|
||
}
|
||
|
||
/** 如果重新编辑的是@消息,则需要将被@ 的成员重新加入selectedAtMembers */
|
||
if (msg.serverExtension) {
|
||
const extObj = JSON.parse(msg.serverExtension)
|
||
const yxAitMsg = extObj.yxAitMsg
|
||
if (yxAitMsg) {
|
||
const _mentionedMembers: MentionedMember[] = []
|
||
Object.keys(yxAitMsg).forEach((key) => {
|
||
if (key == AT_ALL_ACCOUNT) {
|
||
_mentionedMembers.push({
|
||
accountId: key,
|
||
appellation: '所有人',
|
||
})
|
||
} else {
|
||
_mentionedMembers.push({
|
||
accountId: key,
|
||
appellation: uni.$UIKitStore.uiStore.getAppellation({
|
||
account: key,
|
||
teamId: props.to,
|
||
ignoreAlias: true,
|
||
}),
|
||
})
|
||
}
|
||
})
|
||
selectedAtMembers.value = _mentionedMembers
|
||
}
|
||
}
|
||
inputText.value = msg?.oldText || ''
|
||
if (!isHarmonyOs) {
|
||
showKeyboard()
|
||
}
|
||
})
|
||
|
||
uni.$on(events.REPLY_MSG, (msg: V2NIMMessageForUI) => {
|
||
isReplyMsg.value = true
|
||
replyMsg.value = msg
|
||
if (!isHarmonyOs) {
|
||
showKeyboard()
|
||
}
|
||
})
|
||
|
||
uni.$on(events.AIT_TEAM_MEMBER, (member: MentionedMember) => {
|
||
selectedAtMembers.value = [
|
||
...selectedAtMembers.value.filter(
|
||
(item) => item.accountId !== member.accountId
|
||
),
|
||
member,
|
||
]
|
||
const newInputText = inputText.value + '@' + member.appellation + ' '
|
||
/** 更新input框的内容 */
|
||
inputText.value = newInputText
|
||
})
|
||
|
||
/** 关闭表情、语音、发送更多面板 */
|
||
uni.$on(events.CLOSE_PANEL, () => {
|
||
emojiVisible.value = false
|
||
extVisible.value = false
|
||
audioPanelVisible.value = false
|
||
sendMoreVisible.value = false
|
||
})
|
||
|
||
/** @ 消息 @ 群成员 */
|
||
uni.$on(events.HANDLE_AIT_MEMBER, (member: MentionedMember) => {
|
||
handleMentionItemClick(member)
|
||
})
|
||
|
||
/** 关闭@ 群成员面板 */
|
||
uni.$on(events.CLOSE_AIT_POPUP, () => {
|
||
closePopup()
|
||
})
|
||
|
||
/** 表情点击 */
|
||
uni.$on(events.EMOJI_CLICK, (emoji) => {
|
||
handleEmoji(emoji)
|
||
})
|
||
|
||
/** 表情删除 */
|
||
uni.$on(events.EMOJI_DELETE, () => {
|
||
handleEmojiDelete()
|
||
})
|
||
|
||
/** 表情发送 */
|
||
uni.$on(events.EMOJI_SEND, () => {
|
||
emojiVisible.value = false
|
||
extVisible.value = false
|
||
handleSendTextMsg()
|
||
})
|
||
|
||
if (uni.onKeyboardHeightChange) {
|
||
uni.onKeyboardHeightChange((res) => {
|
||
const isAndroidWxapp =
|
||
uni.getSystemInfoSync().platform == 'android' && isWxApp
|
||
// 此处是为了点击安卓键盘上的收起按钮时,表情面板需要隐藏
|
||
if (
|
||
(res.height === 0 && isAndroidApp) ||
|
||
(res.height === 0 && isAndroidWxapp)
|
||
) {
|
||
emojiVisible.value = false
|
||
extVisible.value = false
|
||
}
|
||
})
|
||
}
|
||
})
|
||
|
||
/** 处理选中的@ 成员 */
|
||
const onAtMembersExtHandler = () => {
|
||
let ext: YxServerExt
|
||
if (selectedAtMembers.value.length) {
|
||
selectedAtMembers.value
|
||
.filter((member) => {
|
||
if (!allowAtAll.value && member.accountId === AT_ALL_ACCOUNT) {
|
||
return false
|
||
}
|
||
return true
|
||
})
|
||
.forEach((member) => {
|
||
const substr = `@${member.appellation}`
|
||
const positions: number[] = []
|
||
let pos = inputText.value?.indexOf(substr)
|
||
while (pos !== -1) {
|
||
positions.push(pos)
|
||
pos = inputText.value?.indexOf(substr, pos + 1)
|
||
}
|
||
if (positions.length) {
|
||
if (!ext) {
|
||
ext = {
|
||
yxAitMsg: {
|
||
[member.accountId]: {
|
||
text: substr,
|
||
segments: [],
|
||
},
|
||
},
|
||
}
|
||
} else {
|
||
;(ext.yxAitMsg as YxAitMsg)[member.accountId] = {
|
||
text: substr,
|
||
segments: [],
|
||
}
|
||
}
|
||
positions.forEach((position) => {
|
||
const start = position
|
||
;(ext?.yxAitMsg as YxAitMsg)[member.accountId].segments.push({
|
||
start,
|
||
end: start + substr.length,
|
||
broken: false,
|
||
})
|
||
})
|
||
}
|
||
})
|
||
}
|
||
// @ts-ignore
|
||
return ext
|
||
}
|
||
|
||
onUnmounted(() => {
|
||
uni.$off(events.REPLY_MSG)
|
||
uni.$off(events.ON_REEDIT_MSG)
|
||
uni.$off(events.REPLY_MSG)
|
||
uni.$off(events.AIT_TEAM_MEMBER)
|
||
// 关闭表情面板
|
||
uni.$off(events.CLOSE_PANEL)
|
||
// @消息 @群成员
|
||
uni.$off(events.HANDLE_AIT_MEMBER)
|
||
// 关闭@群成员面板
|
||
uni.$off(events.CLOSE_AIT_POPUP)
|
||
// 表情点击
|
||
uni.$off(events.EMOJI_CLICK)
|
||
// 表情删除
|
||
uni.$off(events.EMOJI_DELETE)
|
||
// 表情发送
|
||
uni.$off(events.EMOJI_SEND)
|
||
removeReplyMsg()
|
||
teamWatch()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import '@/styles/common.scss';
|
||
|
||
.input-root {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: auto;
|
||
max-height: 300px;
|
||
}
|
||
|
||
.input-root-h5 {
|
||
height: auto;
|
||
position: relative;
|
||
order: 1;
|
||
}
|
||
|
||
.msg-input-wrapper {
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: #eff1f3;
|
||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||
z-index: 999;
|
||
}
|
||
|
||
.msg-input {
|
||
overflow-x: hidden;
|
||
padding: 7px;
|
||
background-color: #eff1f3;
|
||
|
||
&-input {
|
||
background-color: #fff;
|
||
height: 40px;
|
||
font-size: 16px;
|
||
padding: 0 12px;
|
||
border-radius: 6px;
|
||
margin-bottom: 5px;
|
||
|
||
&::placeholder {
|
||
padding: 0 12px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.msg-button-group {
|
||
padding: 12px 20px 2px 20px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
}
|
||
|
||
.msg-input-button {
|
||
flex: 1;
|
||
// &:not(:last-child) {
|
||
// margin-right: 60px;
|
||
// }
|
||
|
||
&.msg-input-loading {
|
||
animation: loadingCircle 1s infinite linear;
|
||
z-index: 1;
|
||
width: 20px;
|
||
height: 20px;
|
||
margin-top: 4px;
|
||
|
||
.loading {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
.msg-ext {
|
||
overflow-y: auto;
|
||
width: 100%;
|
||
height: 300px;
|
||
background-color: #eff1f3;
|
||
z-index: 1;
|
||
}
|
||
|
||
.msg-emoji-panel {
|
||
overflow-y: auto;
|
||
width: 100%;
|
||
height: 246px;
|
||
background-color: #eff1f3;
|
||
z-index: 1;
|
||
}
|
||
|
||
.msg-audio-panel {
|
||
overflow-y: hidden;
|
||
width: 100%;
|
||
height: 300px;
|
||
background-color: #eff1f3;
|
||
z-index: 1;
|
||
}
|
||
|
||
.send-more-panel {
|
||
padding: 15px;
|
||
overflow-y: hidden;
|
||
width: 100%;
|
||
height: 300px;
|
||
background-color: #eff1f3;
|
||
z-index: 1;
|
||
flex-wrap: wrap;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.send-more-panel-item-wrapper {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
display: inline-block;
|
||
margin-bottom: 10px;
|
||
.send-more-panel-item {
|
||
background-color: #fff;
|
||
border-radius: 8px;
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
display: flex;
|
||
overflow: hidden;
|
||
align-items: center;
|
||
margin: 0 15px;
|
||
justify-content: center;
|
||
image{
|
||
width: 100rpx;
|
||
height: 100rpx;
|
||
border-radius: 8px;
|
||
}
|
||
}
|
||
.icon-text {
|
||
font-size: 12px;
|
||
color: #747475;
|
||
margin-top: 8px;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
.reply-message-wrapper {
|
||
display: flex;
|
||
font-size: 13px;
|
||
background-color: #eff1f2;
|
||
height: 25px;
|
||
padding-top: 6px;
|
||
align-items: center;
|
||
color: #929299;
|
||
|
||
.reply-noFind {
|
||
width: fit-content;
|
||
}
|
||
|
||
.reply-to-colon {
|
||
flex-basis: 3px;
|
||
margin-right: 2px;
|
||
}
|
||
|
||
.reply-message-close {
|
||
flex-basis: 14px;
|
||
margin-left: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.reply-message {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
message-one-line {
|
||
flex: 1;
|
||
font-size: 13px;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
}
|
||
|
||
.reply-title {
|
||
flex-basis: 30px;
|
||
white-space: nowrap;
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.reply-to {
|
||
max-width: 120px;
|
||
flex: 0 0 auto;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
|
||
.input-emoji {
|
||
background-color: #fff;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
font-size: 16px;
|
||
padding: 0 12px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.input-text {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.input-placeholder {
|
||
background-color: #fff;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
font-size: 16px;
|
||
padding: 0 12px;
|
||
border-radius: 6px;
|
||
color: gray;
|
||
}
|
||
.file-picker-wrapper {
|
||
position: absolute;
|
||
width: 60px;
|
||
height: 60px;
|
||
z-index: 1;
|
||
.files-button {
|
||
width: 60px;
|
||
height: 60px;
|
||
}
|
||
}
|
||
|
||
/* 复制自 groupSend 的遮罩与弹窗样式 */
|
||
.mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
z-index: 1000;
|
||
}
|
||
|
||
.center-modal {
|
||
position: fixed;
|
||
left: 50%;
|
||
top: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 650rpx;
|
||
background: #ffffff;
|
||
border-radius: 16rpx;
|
||
z-index: 1001;
|
||
overflow: hidden;
|
||
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.modal-title {
|
||
text-align: center;
|
||
font-size: 34rpx;
|
||
color: #d32f2f;
|
||
padding: 28rpx 20rpx;
|
||
}
|
||
|
||
.modal-item {
|
||
padding: 36rpx 28rpx;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
background: #ffffff;
|
||
}
|
||
|
||
.modal-divider {
|
||
height: 2rpx;
|
||
background: #eeeeee;
|
||
}
|
||
</style>
|