Files
uniapp-im-shop/TUIKit/components/TUIChat/message-input/index.vue
bobobobo 2f1b592772 QAQ
2026-02-12 20:25:35 +08:00

309 lines
8.0 KiB
Vue

<template>
<div :class="['message-input', !isPC && 'message-input-h5']">
<div class="audio-main-content-line">
<MessageInputAudio
v-if="(isWeChat || isApp) && isRenderVoice"
:class="{
'message-input-wx-audio-open': displayType === 'audio'
}"
:isEnableAudio="displayType === 'audio'"
@changeDisplayType="changeDisplayType"
/>
<MessageInputEditor
v-show="displayType === 'editor'"
ref="editor"
class="message-input-editor"
:placeholder="props.placeholder"
:isMuted="props.isMuted"
:muteText="props.muteText"
:enableInput="props.enableInput"
:enableAt="props.enableAt"
:enableTyping="props.enableTyping"
:isGroup="isGroup"
:inputToolbarDisplayType="inputToolbarDisplayType"
@onTyping="onTyping"
@onAt="onAt"
@onFocus="onFocus"
/>
<MessageInputAt
v-if="props.enableAt"
ref="messageInputAtRef"
@insertAt="insertAt"
@onAtListOpen="onAtListOpen"
/>
<Icon
v-if="isRenderEmojiPicker"
class="icon icon-face"
:file="faceIcon"
:size="'23px'"
:hotAreaSize="'3px'"
@onClick="changeToolbarDisplayType('emojiPicker')"
/>
<Icon
v-if="isRenderMore"
class="icon icon-more"
:file="moreIcon"
:size="'23px'"
:hotAreaSize="'3px'"
@onClick="changeToolbarDisplayType('tools')"
/>
</div>
<div>
<MessageQuote :style="{ minWidth: 0 }" :displayType="displayType" />
</div>
</div>
</template>
<script setup lang="ts">
import TUIChatEngine, {
TUIStore,
StoreName,
IMessageModel,
IConversationModel,
TUIGroupService
} from '@tencentcloud/chat-uikit-engine-lite'
import {
ref,
watch,
onMounted,
onUnmounted
} from '../../../adapter-vue'
import MessageInputEditor from './message-input-editor.vue'
import MessageInputAt from './message-input-at/index.vue'
import MessageInputAudio from './message-input-audio.vue'
import MessageQuote from './message-input-quote/index.vue'
import Icon from '../../common/Icon.vue'
import faceIcon from '../../../assets/icon/face-uni.png'
import moreIcon from '../../../assets/icon/more-uni.png'
import { isPC, isH5, isWeChat, isApp } from '../../../utils/env'
import { sendTyping } from '../utils/sendMessage'
import {
ToolbarDisplayType,
InputDisplayType
} from '../../../interface'
import TUIChatConfig from '../config'
import { useAuthUser } from '../../../../composables/useAuthUser'
import { useUI } from '../../../../utils/use-ui'
import { getGroupBanList } from '../../../../api'
interface IProps {
placeholder: string
groupID?: string
isMuted?: boolean
muteText?: string
enableInput?: boolean
enableAt?: boolean
enableTyping?: boolean
replyOrReference?: Record<string, any>
inputToolbarDisplayType: ToolbarDisplayType
}
interface IEmits {
(e: 'changeToolbarDisplayType', displayType: ToolbarDisplayType): void
}
const { showDialog } = useUI()
const { tencentUserSig } = useAuthUser()
const emits = defineEmits<IEmits>()
const props = withDefaults(defineProps<IProps>(), {
placeholder: 'this is placeholder',
replyOrReference: () => ({}),
isMuted: true,
groupID: '',
muteText: '',
enableInput: true,
enableAt: true,
enableTyping: true,
inputToolbarDisplayType: 'none'
})
const editor = ref()
const messageInputAtRef = ref()
const currentConversation = ref<IConversationModel>()
const isGroup = ref<boolean>(false)
const displayType = ref<InputDisplayType>('editor')
const featureConfig = TUIChatConfig.getFeatureConfig()
const isRenderVoice = ref<boolean>(featureConfig.InputVoice)
const isRenderEmojiPicker = ref<boolean>(
featureConfig.InputEmoji || featureConfig.InputStickers
)
const isRenderMore = ref<boolean>(
featureConfig.InputImage ||
featureConfig.InputVideo ||
featureConfig.InputEvaluation ||
featureConfig.InputQuickReplies
)
onMounted(() => {
TUIStore.watch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated
})
TUIStore.watch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated
})
})
onUnmounted(() => {
TUIStore.unwatch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated
})
TUIStore.unwatch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated
})
})
watch(
() => props.inputToolbarDisplayType,
(newVal: ToolbarDisplayType) => {
if (newVal !== 'none') {
changeDisplayType('editor')
}
}
)
function changeDisplayType(display: InputDisplayType) {
displayType.value = display
if (display === 'audio') {
emits('changeToolbarDisplayType', 'none')
}
}
/** 禁言数据获取 */
const getMuteTime = async (displayType: ToolbarDisplayType) => {
TUIGroupService.getGroupProfile({
groupID: props.groupID
}).then(async res => {
// muteAllMembers
if (res.data.group.muteAllMembers) {
// 禁言了
showDialog('提示', '当前群组已全员禁言', false)
} else {
// emits('changeToolbarDisplayType', displayType)
// 判断某个成员是不是禁言
const list = await getGroupBanList(props.groupID)
const show = list.data.MutedAccountList.find(
(v: any) => v.Member_Account === tencentUserSig.value.userId
)
if (show?.Member_Account) {
showDialog('提示', '你被禁言了', false)
} else {
emits('changeToolbarDisplayType', displayType)
}
}
})
}
const changeToolbarDisplayType = async (
displayType: ToolbarDisplayType
) => {
if (props.groupID) {
const res = await TUIGroupService.getGroupMemberProfile({
groupID: props.groupID,
userIDList: [tencentUserSig.value.userId]
})
if (res.data.memberList[0].role === 'Member') {
getMuteTime(displayType)
} else {
emits('changeToolbarDisplayType', displayType)
}
return
}
emits('changeToolbarDisplayType', displayType)
}
const onTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
sendTyping(inputContentEmpty, inputBlur)
}
const onAt = (show: boolean) => {
messageInputAtRef?.value?.toggleAtList(show)
}
const onFocus = () => {
emits('changeToolbarDisplayType', 'none')
}
const insertEmoji = (emoji: any) => {
editor?.value?.addEmoji && editor?.value?.addEmoji(emoji)
}
const insertAt = (atInfo: any) => {
editor?.value?.insertAt && editor?.value?.insertAt(atInfo)
}
const onAtListOpen = () => {
editor?.value?.blur && editor?.value?.blur()
}
const reEdit = (content: any) => {
editor?.value?.resetEditor()
editor?.value?.setEditorContent(content)
}
function onCurrentConversationUpdated(
conversation: IConversationModel
) {
currentConversation.value = conversation
isGroup.value =
currentConversation.value?.type === TUIChatEngine.TYPES.CONV_GROUP
}
function onQuoteMessageUpdated(options?: {
message: IMessageModel
type: string
}) {
// switch text input mode when there is a quote message
if (options?.message && options?.type === 'quote') {
changeDisplayType('editor')
}
}
defineExpose({
insertEmoji,
reEdit
})
</script>
<style scoped lang="scss">
@import '../../../assets/styles/common';
:not(not) {
display: flex;
flex-direction: column;
min-width: 0;
box-sizing: border-box;
}
.message-input {
position: relative;
display: flex;
flex-direction: column;
border: none;
overflow: hidden;
background: #ffffff;
&-h5 {
padding: 10px 10px 15px;
}
&-editor {
flex: 1;
display: flex;
}
.icon {
margin-left: 3px;
}
&-wx-audio-open {
flex: 1;
}
}
.audio-main-content-line {
display: flex;
flex-direction: row;
align-items: center;
}
</style>