|
|
|
|
|
<template>
|
|
|
|
|
|
<div style="" class="pbInput" :style="writeStyle">
|
|
|
|
|
|
<div class="input-root" style="position: relative;">
|
|
|
|
|
|
<!-- 以下这个 div 用于确保 vue2 的 ref 会更新 -->
|
|
|
|
|
|
<div style="display: none">
|
|
|
|
|
|
<div>{{ teamMute ? "禁言" : "不禁言" }}</div>
|
|
|
|
|
|
<div>{{ isTeamMute ? "禁言" : "不禁言" }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<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-guanbi" />
|
|
|
|
|
|
</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>
|
|
|
|
|
|
{{ "[" + REPLY_MSG_TYPE_MAP[replyMsg && replyMsg.messageType] + "]" }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 输入框上按钮组 -->
|
|
|
|
|
|
<!-- <div class="msg-button-group">
|
|
|
|
|
|
<div @tap="handleAudioVisible" v-if="!isWeb" 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 class="g_flex_c">
|
|
|
|
|
|
<div @tap="handleAudioVisible" v-if="!isWeb && false" class="msg-input-button g_p_5" style="padding-right: 7px; padding-left: 10px">
|
|
|
|
|
|
<Icon v-if="audioPanelVisible" :size="28" type="audio-btn-selected" key="audio-btn-selected" />
|
|
|
|
|
|
<Icon v-else :size="28" type="icon-audio" key="icon-audio" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- v-if="inputVisible" ↓↓↓↓↓↓↓ -->
|
|
|
|
|
|
<div class="msg-input g_flex_1">
|
|
|
|
|
|
<!-- 当从表情面板切换到文字输入时,直接唤起键盘,会导致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" style="padding-left: 0">
|
|
|
|
|
|
{{ isTeamMute ? t("teamMutePlaceholder") : t("chatInputPlaceHolder") }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- {{ssff}}键盘高度{{keyHeight}} 输入框距离底部距离{{writeStyle}}屏幕高度{{screenHeight}}顶部聊天区域高度{{msgKeyHeight}} -->
|
|
|
|
|
|
<input v-show="!showEmojiInput" :focus="isFocus" class="msg-input-input g_flex_1" :maxlength="-1" :placeholder="isTeamMute ? t('teamMutePlaceholder') : t('chatInputPlaceHolder')" v-model="inputText" type="text" :disabled="isTeamMute" :confirm-hold="true" cursor-spacing="20" :adjust-position="pushUp" confirm-type="send" @keyboardheightchange="keyboardheightchange" @focus="handleInputFocus" @confirm="handleSendTextMsg" @blur="handleInputBlur" @input="handleInput" id="msg-input" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="msg-input-button" @tap="(event) => handleSendJob()">
|
|
|
|
|
|
<div class="iconfont icon-5gongdanguanli g_c_6 g_fs_24"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- <div class="send-more-panel-item-wrapper">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => handleSendJob()">
|
|
|
|
|
|
<div class="iconfont icon-5gongdanguanli g_c_6 g_fs_24 g_fw_600"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<!-- <div class="msg-input-button" v-if="false">
|
|
|
|
|
|
<Icon @tap="handleEmojiVisible" class="g_p_6" style="padding-right: 5px" :size="28" type="icon-biaoqing" />
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<div class="msg-input-button" v-if="true">
|
|
|
|
|
|
<Icon @tap="handleSendMoreVisible" class="g_p_6" style="padding-left: 5px; padding-right: 8px" type="send-more" :size="28" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</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">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => handleSendImageMsg()">
|
|
|
|
|
|
<Icon type="icon-tupian" :size="30"></Icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="icon-text">{{ t("imgText") }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="send-more-panel-item-wrapper">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => 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">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => 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" v-if="isApp && 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="isApp && 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 class="send-more-panel-item-wrapper" v-if="corpUserFlag">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => handleSendCustomMsg('album', event)">
|
|
|
|
|
|
<Icon type="icon-touxiang5" :size="30"></Icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="icon-text">{{ t("customText") }}</div>
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<div class="send-more-panel-item-wrapper" v-if="corpUserFlag">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => handleSendJob()">
|
|
|
|
|
|
<div class="iconfont icon-fasong1 g_c_6 g_fs_24 g_fw_600"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="icon-text">{{ "发送职位" }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- <div class="send-more-panel-item-wrapper">
|
|
|
|
|
|
<div class="send-more-panel-item" @tap="(event) => handleSetting()">
|
|
|
|
|
|
<Icon type="icon-shezhi" :size="30"></Icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="icon-text">设置</div>
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- <div class="msg-input-button">
|
|
|
|
|
|
<Icon @tap="handleSetting" type="icon-shezhi" :size="20" />
|
|
|
|
|
|
</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>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="choose-job-send"
|
|
|
|
|
|
style="
|
|
|
|
|
|
width: calc(100vw - 48px);
|
|
|
|
|
|
min-height: 50px;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
top: -92px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
"
|
|
|
|
|
|
v-if="chooseData"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="g_w_all g_h_all">
|
|
|
|
|
|
<div class="g_mb_12 g_flex_row_between">
|
|
|
|
|
|
<div style="font-weight:bold;font-size:16px;color:#000" class="g_flex_1">{{ chooseData.title }}</div>
|
|
|
|
|
|
<div class="g_flex_none g_flex_column_center">
|
|
|
|
|
|
<i class="iconfont icon-guanbi" style="font-size: 14px;color: #666;"></i>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="g_flex_row_between">
|
|
|
|
|
|
<div class="g_flex_1 g_flex_column_center">
|
|
|
|
|
|
<div class="g_flex_row_start">
|
|
|
|
|
|
<view class="g_fs_16 g_fw_600 g_c_f40 g_lh_1_2 g_flex_column_center"
|
|
|
|
|
|
v-if="chooseData.salaryClassifyValue"
|
|
|
|
|
|
v-html="chooseData.salaryClassifyValue"> </view>
|
|
|
|
|
|
<view class="g_fs_14 g_c_9" v-if="chooseData.monthPay">
|
|
|
|
|
|
{{ chooseData.monthPay ? "丨" + chooseData.monthPay : "" }}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="g_flex_none g_flex_column_center">
|
|
|
|
|
|
<div style="
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
height: 26px;
|
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
|
width: 70px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
background-color: #1890ff;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
">
|
|
|
|
|
|
发送职位
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import Face from "./face.vue";
|
|
|
|
|
|
import VoicePanel from "./voice-panel.vue";
|
|
|
|
|
|
import Icon from "../../../components/Icon.vue";
|
|
|
|
|
|
import { ref, getCurrentInstance, computed, onUnmounted, onMounted, defineProps, withDefaults, defineEmits, watch } from "../../../utils/transformVue";
|
|
|
|
|
|
import { ALLOW_AT, events, REPLY_MSG_TYPE_MAP } from "../../../utils/constants";
|
|
|
|
|
|
import { emojiMap } from "../../../utils/emoji";
|
|
|
|
|
|
import { t } from "../../../utils/i18n";
|
|
|
|
|
|
import { handleNoPermission } from "../../../utils/permission";
|
|
|
|
|
|
import { customNavigateTo } from "../../../utils/customNavigate";
|
|
|
|
|
|
import MessageOneLine from "../../../components/MessageOneLine.vue";
|
|
|
|
|
|
import { isAndroidApp, stopAllAudio, isIosWeb, isWeb, isWxApp, startCall, isApp, isIosApp } from "../../../utils";
|
|
|
|
|
|
// @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 { autorun } from "mobx";
|
|
|
|
|
|
import Appellation from "../../../components/Appellation.vue";
|
|
|
|
|
|
import { AT_ALL_ACCOUNT } from "../../../utils/constants";
|
|
|
|
|
|
import { deepClone } from "../../../utils";
|
|
|
|
|
|
import { V2NIMTeam, V2NIMTeamChatBannedMode, V2NIMTeamMember } from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK/V2NIMTeamService";
|
|
|
|
|
|
import { V2NIMMessageForUI, YxServerExt, YxAitMsg } from "@xkit-yx/im-store-v2/dist/types/types";
|
|
|
|
|
|
import { V2NIMConst } from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK";
|
|
|
|
|
|
|
|
|
|
|
|
export type MentionedMember = { accountId: string; appellation: string };
|
|
|
|
|
|
const corpUserFlag = ref(uni.getStorageSync("apply-userinfo").corpUserFlag);
|
|
|
|
|
|
|
|
|
|
|
|
const props = withDefaults(
|
|
|
|
|
|
defineProps<{
|
|
|
|
|
|
conversationType: V2NIMConst.V2NIMConversationType;
|
|
|
|
|
|
to: string;
|
|
|
|
|
|
replyMsgsMap?: {
|
|
|
|
|
|
[key: string]: V2NIMMessageForUI;
|
|
|
|
|
|
};
|
|
|
|
|
|
jobListShow: Boolean;
|
|
|
|
|
|
}>(),
|
|
|
|
|
|
{}
|
|
|
|
|
|
);
|
|
|
|
|
|
const emits = defineEmits(["jobListShow"]);
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
// 音频面板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 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 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 isTeamMute = computed(() => {
|
|
|
|
|
|
// // console.log(
|
|
|
|
|
|
// 'isGroupOwner, isGroupManager',
|
|
|
|
|
|
// isGroupOwner.value,
|
|
|
|
|
|
// isGroupManager.value
|
|
|
|
|
|
// )
|
|
|
|
|
|
|
|
|
|
|
|
// if (!teamMute.value) {
|
|
|
|
|
|
// return false
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // 群主或者群管理员在群禁言时,可以发送消息
|
|
|
|
|
|
// if (isGroupOwner.value || isGroupManager.value) {
|
|
|
|
|
|
// return false
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return true
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
|
|
const isTeamMute = ref(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);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 点击@群成员
|
|
|
|
|
|
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;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const closePopup = () => {
|
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
|
ctx.refs.popupRef.close();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 点击表情输入框,隐藏表情面板,显示键盘
|
|
|
|
|
|
const onClickEmojiInput = () => {
|
|
|
|
|
|
showEmojiInput.value = false;
|
|
|
|
|
|
extVisible.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
emojiVisible.value = false;
|
|
|
|
|
|
extVisible.value = false;
|
|
|
|
|
|
audioPanelVisible.value = false;
|
|
|
|
|
|
sendMoreVisible.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
|
|
|
if (uni.getSystemInfoSync().osName == "ios") {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
if (isIosWeb) {
|
|
|
|
|
|
isFocus.value = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
isFocus.value = true;
|
|
|
|
|
|
}, 500);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const writeStyle = ref("");
|
|
|
|
|
|
const isIOS = ref(false);
|
|
|
|
|
|
writeStyle.value = "bottom:0";
|
|
|
|
|
|
// // #ifdef MP-WEIXIN
|
|
|
|
|
|
// const pushUp = ref(false)
|
|
|
|
|
|
// // #endif
|
|
|
|
|
|
// // #ifdef APP-PLUS
|
|
|
|
|
|
// const pushUp = ref(true)
|
|
|
|
|
|
// // #endif
|
|
|
|
|
|
|
|
|
|
|
|
const pushUp = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
const keyHeight = ref(350);
|
|
|
|
|
|
const msgKeyHeight = ref("100%");
|
|
|
|
|
|
const ssff = ref(uni.getWindowInfo().safeArea.top);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleInputFocus = (e) => {
|
|
|
|
|
|
emojiVisible.value = false;
|
|
|
|
|
|
extVisible.value = false;
|
|
|
|
|
|
audioPanelVisible.value = false;
|
|
|
|
|
|
sendMoreVisible.value = false;
|
|
|
|
|
|
const systemInfo = uni.getSystemInfoSync();
|
|
|
|
|
|
const availableHeight = systemInfo.windowHeight - e.detail.height - ssff.value;
|
|
|
|
|
|
setTimeout(()=>{
|
|
|
|
|
|
|
|
|
|
|
|
console.log("获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点获取焦点");
|
|
|
|
|
|
uni.$emit("msgKeyHeight", availableHeight); // 传递实际可用高度
|
|
|
|
|
|
writeStyle.value = `bottom: calc(${e.detail.height}px - env(safe-area-inset-bottom))`;
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
},80)
|
|
|
|
|
|
// if (e.detail.height === 0) {
|
|
|
|
|
|
// writeStyle.value = "bottom: 0";
|
|
|
|
|
|
// uni.$emit("msgKeyHeight", "100%"); // 键盘收起时恢复全屏高度
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// // 隐藏其他面板
|
|
|
|
|
|
// emojiVisible.value = false;
|
|
|
|
|
|
// extVisible.value = false;
|
|
|
|
|
|
// audioPanelVisible.value = false;
|
|
|
|
|
|
// sendMoreVisible.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
// const systemInfo = uni.getSystemInfoSync();
|
|
|
|
|
|
// const availableHeight = systemInfo.windowHeight - e.detail.height - ssff.value;
|
|
|
|
|
|
// uni.$emit("msgKeyHeight", availableHeight); // 传递实际可用高度
|
|
|
|
|
|
// writeStyle.value = `bottom: calc(${e.detail.height}px - env(safe-area-inset-bottom))`;
|
|
|
|
|
|
// // let safeBottom = 0;
|
|
|
|
|
|
// }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在message-input.vue的keyboardheightchange事件中修改
|
|
|
|
|
|
// 在message-input.vue的keyboardheightchange事件中修改
|
|
|
|
|
|
const keyboardheightchange = (e) => {
|
|
|
|
|
|
keyHeight.value = e.detail.height;
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, e.detail.height);
|
|
|
|
|
|
uni.$emit("KeyboardHeight", e.detail.height);
|
|
|
|
|
|
|
|
|
|
|
|
if (e.detail.height === 0) {
|
|
|
|
|
|
writeStyle.value = "bottom: 0";
|
|
|
|
|
|
uni.$emit("msgKeyHeight", "100%"); // 键盘收起时恢复全屏高度
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 隐藏其他面板
|
|
|
|
|
|
console.log("触发输入框触发输入框触发输入框触发输入框触发输入框触发输入框触发输入框触发输入框");
|
|
|
|
|
|
emojiVisible.value = false;
|
|
|
|
|
|
extVisible.value = false;
|
|
|
|
|
|
audioPanelVisible.value = false;
|
|
|
|
|
|
sendMoreVisible.value = false;
|
|
|
|
|
|
const systemInfo = uni.getSystemInfoSync();
|
|
|
|
|
|
const availableHeight = systemInfo.windowHeight - e.detail.height - ssff.value;
|
|
|
|
|
|
uni.$emit("msgKeyHeight", availableHeight); // 传递实际可用高度
|
|
|
|
|
|
writeStyle.value = `bottom: calc(${e.detail.height}px - env(safe-area-inset-bottom))`;
|
|
|
|
|
|
}
|
|
|
|
|
|
setTimeout(()=>{
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
},80)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// const handleInputBlur = () => {
|
|
|
|
|
|
// isFocus.value = false;
|
|
|
|
|
|
// uni.$emit("msgKeyHeight", "100%");
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到底部
|
|
|
|
|
|
const scrollBottom = () => {
|
|
|
|
|
|
if (isAndroidApp || isWxApp || isIosApp) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
}, 80);
|
|
|
|
|
|
} 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 = () => {
|
|
|
|
|
|
if (inputText.value.trim() === "") return;
|
|
|
|
|
|
const ext = onAtMembersExtHandler();
|
|
|
|
|
|
|
|
|
|
|
|
const textMsg = uni.$UIKitNIM.V2NIMMessageCreator.createTextMessage(inputText.value);
|
|
|
|
|
|
uni.$UIKitStore.msgStore
|
|
|
|
|
|
.sendMessageActive({
|
|
|
|
|
|
msg: textMsg,
|
|
|
|
|
|
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;
|
|
|
|
|
|
selectedAtMembers.value = [];
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0); //点击发送消息list会多一段paddingBottom 需要键盘高度设置为0
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送文件消息
|
|
|
|
|
|
const handleSendFileMsg = () => {
|
|
|
|
|
|
uni.chooseFile({
|
|
|
|
|
|
count: 1,
|
|
|
|
|
|
type: "all",
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
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,
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
sendBefore: () => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: () => {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: t("sendFileFailedText"),
|
|
|
|
|
|
icon: "none",
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
const handleSendJob = () => {
|
|
|
|
|
|
console.log("props.jobListShow", props.jobListShow);
|
|
|
|
|
|
emits("jobListShow", true);
|
|
|
|
|
|
};
|
|
|
|
|
|
const handleSendCustomMsg = () => {
|
|
|
|
|
|
const customMsg = uni.$UIKitNIM.V2NIMMessageCreator.createCustomMessage(
|
|
|
|
|
|
"这是PGQ的自定义消息",
|
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
|
type: "0",
|
|
|
|
|
|
content: "测试自定义消息",
|
|
|
|
|
|
msgurl: "https://nim-nosdn.netease.im/MTAxMTAwMg==/bmltYV8yNTQ5NjkyNDA0XzE3MzA5ODYyNTU3NzdfZjM1ODJhMjQtMTM0Yi00NTk4LWIwNWEtODA0ZGEyYjMxN2Y5?imageView&createTime=1730986256503",
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
uni.$UIKitStore.msgStore.sendMessageActive({
|
|
|
|
|
|
msg: customMsg,
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
sendBefore: () => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 移除回复消息
|
|
|
|
|
|
const removeReplyMsg = () => {
|
|
|
|
|
|
uni.$UIKitStore.msgStore.removeReplyMsgActive(replyMsg?.value?.conversationId as string);
|
|
|
|
|
|
isReplyMsg.value = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示表情面板
|
|
|
|
|
|
const handleEmojiVisible = () => {
|
|
|
|
|
|
showEmojiInput.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
extVisible.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
audioPanelVisible.value = false;
|
|
|
|
|
|
sendMoreVisible.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
emojiVisible.value = !emojiVisible.value;
|
|
|
|
|
|
if (emojiVisible.value) {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 230);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
}, 80);
|
|
|
|
|
|
};
|
|
|
|
|
|
// watch(sendMoreVisible, (val) => {
|
|
|
|
|
|
// if (val) {
|
|
|
|
|
|
// uni.$emit("msgKeyHeight", uni.getSystemInfoSync().windowHeight - 270); // 传递实际可用高度
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// uni.$emit("msgKeyHeight", "100%"); // 传递实际可用高度
|
|
|
|
|
|
// }
|
|
|
|
|
|
// });
|
|
|
|
|
|
// 显示发送更多"+"面板
|
|
|
|
|
|
const handleSendMoreVisible = () => {
|
|
|
|
|
|
if (isTeamMute.value) return;
|
|
|
|
|
|
audioPanelVisible.value = false;
|
|
|
|
|
|
emojiVisible.value = false;
|
|
|
|
|
|
sendMoreVisible.value = !sendMoreVisible.value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(()=>{
|
|
|
|
|
|
if (sendMoreVisible.value) {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 230);
|
|
|
|
|
|
uni.$emit("msgKeyHeight", uni.getSystemInfoSync().windowHeight - 360); // 传递实际可用高度
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
uni.$emit("msgKeyHeight", '100%'); // 传递实际可用高度
|
|
|
|
|
|
}
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
},80)
|
|
|
|
|
|
// }, 300)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 删除表情
|
|
|
|
|
|
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;
|
|
|
|
|
|
if (audioPanelVisible.value) {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 230);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.$emit(events.ON_SCROLL_BOTTOM);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送图片消息
|
|
|
|
|
|
const handleSendImageMsg = () => {
|
|
|
|
|
|
if (isTeamMute.value) return;
|
|
|
|
|
|
stopAllAudio();
|
|
|
|
|
|
uni.chooseImage({
|
|
|
|
|
|
count: 1,
|
|
|
|
|
|
sizeType: ["compressed"],
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
const imgMsg = uni.$UIKitNIM.V2NIMMessageCreator.createImageMessage(res.tempFilePaths[0]);
|
|
|
|
|
|
|
|
|
|
|
|
uni.$UIKitStore.msgStore
|
|
|
|
|
|
.sendMessageActive({
|
|
|
|
|
|
msg: imgMsg,
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
progress: () => true,
|
|
|
|
|
|
sendBefore: () => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
icon: "error",
|
|
|
|
|
|
title: t("sendImageFailedText"),
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
//没有开启权限时,提示开启权限
|
|
|
|
|
|
complete: handleNoPermission,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送视频消息(使用相机或者从相册选择)
|
|
|
|
|
|
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,
|
|
|
|
|
|
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,
|
|
|
|
|
|
conversationId,
|
|
|
|
|
|
progress: () => true,
|
|
|
|
|
|
sendBefore: (msg) => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
uni.$UIKitStore.msgStore.addMsg(msg.conversationId, [
|
|
|
|
|
|
{
|
|
|
|
|
|
...msg,
|
|
|
|
|
|
attachment: {
|
|
|
|
|
|
duration: duration,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]);
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
icon: "error",
|
|
|
|
|
|
title: t("sendAudioFailedText"),
|
|
|
|
|
|
});
|
|
|
|
|
|
scrollBottom();
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转设置页
|
|
|
|
|
|
const handleSetting = () => {
|
|
|
|
|
|
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/Group/group-set/index?id=${props.to}`,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let uninstallTeamWatch = () => {};
|
|
|
|
|
|
const msgHeight = ref(0);
|
|
|
|
|
|
const screenHeight = ref(0);
|
|
|
|
|
|
screenHeight.value = uni.getSystemInfoSync().windowHeight;
|
|
|
|
|
|
const chooseData = ref({});
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
if(uni.getStorageSync("im_sendParams")){
|
|
|
|
|
|
chooseData.value = JSON.parse(uni.getStorageSync("im_sendParams")).jobDetail;
|
|
|
|
|
|
}
|
|
|
|
|
|
uninstallTeamWatch = autorun(() => {
|
|
|
|
|
|
if (props.conversationType === V2NIMConst.V2NIMConversationType.V2NIM_CONVERSATION_TYPE_TEAM) {
|
|
|
|
|
|
const _team: V2NIMTeam = deepClone(uni.$UIKitStore.teamStore.teams.get(props.to));
|
|
|
|
|
|
teamMembers.value = deepClone(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];
|
|
|
|
|
|
// 如果重新编辑的是回复消息,则需要将回复消息展示在输入框上方
|
|
|
|
|
|
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 || "";
|
|
|
|
|
|
isFocus.value = true;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on(events.REPLY_MSG, (msg: V2NIMMessageForUI) => {
|
|
|
|
|
|
isReplyMsg.value = true;
|
|
|
|
|
|
isFocus.value = true;
|
|
|
|
|
|
replyMsg.value = msg;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
|
|
|
if (uni.getSystemInfoSync().osName == "ios") {
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// @消息 @群成员
|
|
|
|
|
|
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();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// #ifdef MP-WEIXIN
|
|
|
|
|
|
if (uni.getSystemInfoSync().osName == "ios") {
|
|
|
|
|
|
isIOS.value = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
|
|
|
|
|
|
if (uni.onKeyboardHeightChange) {
|
|
|
|
|
|
uni.onKeyboardHeightChange((res) => {
|
|
|
|
|
|
const isAndroidWxapp = uni.getSystemInfoSync().platform == "android" && isWxApp;
|
|
|
|
|
|
// 此处是为了点击安卓键盘上的收起按钮时,表情面板需要隐藏
|
|
|
|
|
|
if ((res.height === 0 && isAndroidApp) || (res.height === 0 && isAndroidWxapp)) {
|
|
|
|
|
|
writeStyle.value = "bottom: 0";
|
|
|
|
|
|
emojiVisible.value = false;
|
|
|
|
|
|
extVisible.value = false;
|
|
|
|
|
|
uni.$emit(events.KeyboardEvent, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.$on("msgHeight", (res) => {
|
|
|
|
|
|
// console.log('inputinputinputinputinputinputinputinput')
|
|
|
|
|
|
// console.log(res)
|
|
|
|
|
|
msgHeight.value = res;
|
|
|
|
|
|
});
|
|
|
|
|
|
uni.$on("screenHeight", (res) => {
|
|
|
|
|
|
// console.log(res)
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
screenHeight.value = res;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
screenHeight.value = uni.getSystemInfoSync().windowHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
isTeamMute.value = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
// // 点击表情
|
|
|
|
|
|
// const handleEmoji = (emoji: { key: string; type: string }) => {
|
|
|
|
|
|
// inputText.value += emoji.key;
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// const handleEmoji = (emoji: Emoji) => {
|
|
|
|
|
|
const handleEmoji = (emoji: { key: string; type: string; emoji: string; text: string }) => {
|
|
|
|
|
|
if (emoji.type === "emoji") {
|
|
|
|
|
|
inputText.value += emoji.emoji;
|
|
|
|
|
|
} else if (emoji.type === "text") {
|
|
|
|
|
|
inputText.value += emoji.text;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
uninstallTeamWatch();
|
|
|
|
|
|
});
|
|
|
|
|
|
</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 {
|
|
|
|
|
|
padding-bottom: calc(env(safe-area-inset-bottom) + 10px);
|
|
|
|
|
|
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;
|
|
|
|
|
|
width: 25%;
|
|
|
|
|
|
|
|
|
|
|
|
.send-more-panel-item {
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
width: 60px;
|
|
|
|
|
|
height: 60px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin: 0 15px;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.pbInput {
|
|
|
|
|
|
height: "auto";
|
|
|
|
|
|
position: fixed;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 临时处理方案, 全局样式在这里不生效
|
|
|
|
|
|
.g_flex_c {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
display: -webkit-flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.g_p_5 {
|
|
|
|
|
|
padding: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.g_p_6 {
|
|
|
|
|
|
padding: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.g_flex_1 {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|