mirror of
https://gitee.com/lijingbo-2021/open-anylink-web.git
synced 2025-12-30 02:52:26 +00:00
支持复制媒体消息
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
<script setup>
|
||||
import { msgContentType } from '@/const/msgConst'
|
||||
import MsgBoxDocument from '@/views/message/components/MsgBoxDocument.vue'
|
||||
import { watch, onUnmounted } from 'vue'
|
||||
|
||||
const props = defineProps(['isShow', 'target', 'contentType', 'fileName', 'fileSize', 'src'])
|
||||
const emit = defineEmits(['update:isShow', 'confirm'])
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('keydown', handleKeyPress)
|
||||
})
|
||||
|
||||
const handleConfirm = () => {
|
||||
emit('confirm')
|
||||
emit('update:isShow', false)
|
||||
@@ -13,6 +18,24 @@ const handleConfirm = () => {
|
||||
const handleClose = () => {
|
||||
emit('update:isShow', false)
|
||||
}
|
||||
|
||||
const handleKeyPress = (event) => {
|
||||
if (event.key === 'Enter' && props.isShow) {
|
||||
handleConfirm()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.isShow,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
document.addEventListener('keydown', handleKeyPress)
|
||||
} else {
|
||||
document.removeEventListener('keydown', handleKeyPress)
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -3,7 +3,13 @@ import { QuillEditor, Delta, Quill } from '@vueup/vue-quill'
|
||||
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||
import { computed, onMounted, onUnmounted, onBeforeUnmount, ref, watch, nextTick } from 'vue'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useMessageStore, useImageStore } from '@/stores'
|
||||
import {
|
||||
useMessageStore,
|
||||
useImageStore,
|
||||
useAudioStore,
|
||||
useDocumentStore,
|
||||
useVideoStore
|
||||
} from '@/stores'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { emojis } from '@/js/utils/emojis'
|
||||
import { base64ToFile, jsonParseSafe } from '@/js/utils/common'
|
||||
@@ -13,6 +19,7 @@ import { getMd5 } from '@/js/utils/file'
|
||||
import { prehandleImage } from '@/js/utils/image'
|
||||
import { MsgType } from '@/proto/msg'
|
||||
import AtList from '@/views/message/components/AtList.vue'
|
||||
import AgreeBeforeSend from '@/views/message/components/AgreeBeforeSend.vue'
|
||||
|
||||
/**
|
||||
* 处理粘贴格式问题
|
||||
@@ -67,6 +74,9 @@ const props = defineProps(['sessionId', 'draft'])
|
||||
const emit = defineEmits(['saveLocalMsg', 'sendMessage'])
|
||||
const messageData = useMessageStore()
|
||||
const imageData = useImageStore()
|
||||
const audioData = useAudioStore()
|
||||
const documentData = useDocumentStore()
|
||||
const videoData = useVideoStore()
|
||||
const inputEditorRef = ref()
|
||||
const editorRef = ref()
|
||||
const isShowAtList = ref(false)
|
||||
@@ -75,11 +85,22 @@ const atKey = ref('')
|
||||
const atListOffsetX = ref(0)
|
||||
const atListOffsetY = ref(0)
|
||||
const toSendAtList = ref([])
|
||||
const showAgreeDialog = ref(false)
|
||||
|
||||
const session = computed(() => {
|
||||
return messageData.sessionList[props.sessionId]
|
||||
})
|
||||
|
||||
const remoteName = computed(() => {
|
||||
if (session.value.sessionType === MsgType.CHAT) {
|
||||
return session.value.objectInfo.nickName
|
||||
} else if (session.value.sessionType === MsgType.GROUP_CHAT) {
|
||||
return session.value.objectInfo.groupName
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const quill = computed(() => {
|
||||
return editorRef.value?.getQuill()
|
||||
})
|
||||
@@ -377,6 +398,12 @@ watch(
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
let pasteContent
|
||||
let pasteContentType
|
||||
let pasteFileName
|
||||
let pasteFileSize
|
||||
let pasteUrl
|
||||
|
||||
/**
|
||||
* 把输入框的字符串内容渲染成富媒体内容
|
||||
* @param content 字符串内容
|
||||
@@ -386,14 +413,33 @@ const renderContent = (content) => {
|
||||
quill.value.setText('')
|
||||
return
|
||||
}
|
||||
|
||||
pasteContent = content
|
||||
const jsonContent = jsonParseSafe(content)
|
||||
if (jsonContent && jsonContent['type'] && jsonContent['value']) {
|
||||
// TODO 暂时直接渲染成文本
|
||||
const range = quill.value.getSelection()
|
||||
const delta = new Delta().retain(range.index).delete(range.length).insert(content)
|
||||
quill.value.updateContents(delta, Quill.sources.USER)
|
||||
quill.value.setSelection(delta.length() - range.length, Quill.sources.USER)
|
||||
pasteContentType = jsonContent['type']
|
||||
const fileId = jsonContent['value']
|
||||
switch (pasteContentType) {
|
||||
case msgContentType.IMAGE:
|
||||
pasteFileName = imageData.image[fileId]?.fileName
|
||||
pasteFileSize = imageData.image[fileId]?.size
|
||||
pasteUrl = imageData.image[fileId]?.thumbUrl
|
||||
break
|
||||
case msgContentType.AUDIO:
|
||||
pasteFileName = audioData.audio[fileId]?.fileName
|
||||
pasteFileSize = audioData.audio[fileId]?.size
|
||||
break
|
||||
case msgContentType.VIDEO:
|
||||
pasteFileName = videoData.video[fileId]?.fileName
|
||||
pasteFileSize = videoData.video[fileId]?.size
|
||||
break
|
||||
case msgContentType.DOCUMENT:
|
||||
pasteFileName = documentData.document[fileId]?.fileName
|
||||
pasteFileSize = documentData.document[fileId]?.size
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
showAgreeDialog.value = true
|
||||
} else {
|
||||
let contentArray = []
|
||||
//匹配内容中的图片
|
||||
@@ -456,7 +502,9 @@ const handleEnter = async () => {
|
||||
allUploadedSuccessFn: () => {}
|
||||
}
|
||||
|
||||
const contentObj = await parseContent(callbacks)
|
||||
const contentObj = pasteContent
|
||||
? { contentFromLocal: [pasteContent], contentFromServer: [pasteContent] }
|
||||
: await parseContent(callbacks)
|
||||
|
||||
const content = contentObj.contentFromLocal.join('').trim()
|
||||
if (!content) {
|
||||
@@ -513,6 +561,7 @@ const handleEnter = async () => {
|
||||
emit('sendMessage', { msg, atTargets })
|
||||
}
|
||||
|
||||
pasteContent = ''
|
||||
quill.value.setText('') // 编辑窗口置空
|
||||
toSendAtList.value = []
|
||||
}
|
||||
@@ -595,6 +644,15 @@ defineExpose({
|
||||
:atKey="atKey"
|
||||
@selected="onSelectedAtTarget"
|
||||
></AtList>
|
||||
<AgreeBeforeSend
|
||||
v-model:isShow="showAgreeDialog"
|
||||
:target="remoteName"
|
||||
:contentType="pasteContentType"
|
||||
:fileName="pasteFileName"
|
||||
:fileSize="pasteFileSize"
|
||||
:src="pasteUrl"
|
||||
@confirm="handleEnter"
|
||||
></AgreeBeforeSend>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ const onConfirmSendFile = () => {
|
||||
requestApi(requestBody, files)
|
||||
.then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
setStoreData(contentType, res.data.data)
|
||||
setStoreData(res.data.data)
|
||||
messageData.updateMsg(msg.sessionId, msg.msgId, {
|
||||
uploadStatus: msgFileUploadStatus.UPLOAD_SUCCESS,
|
||||
uploadProgress: 100
|
||||
|
||||
@@ -178,6 +178,7 @@ const renderVideo = (content) => {
|
||||
const url = videoData.video[videoId]?.downloadUrl
|
||||
if (url) {
|
||||
return h(MsgBoxVideo, {
|
||||
msgId: msg.value.msgId,
|
||||
videoId,
|
||||
url,
|
||||
fileName: videoData.video[videoId].fileName,
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'xgplayer/dist/index.min.css'
|
||||
import { formatFileSize } from '@/js/utils/common'
|
||||
import VideoloadfailedIcon from '@/assets/svg/videoloadfailed.svg'
|
||||
|
||||
const props = defineProps(['videoId', 'url', 'fileName', 'size', 'width', 'height'])
|
||||
const props = defineProps(['msgId', 'videoId', 'url', 'fileName', 'size', 'width', 'height'])
|
||||
const emits = defineEmits(['load'])
|
||||
|
||||
const isLoaded = ref(0) // 0未加载,1加载成功,2加载失败
|
||||
@@ -38,7 +38,7 @@ const renderHeight = computed(() => {
|
||||
|
||||
onMounted(() => {
|
||||
const player = new Player({
|
||||
id: `msg-xgplayer-${props.videoId}`,
|
||||
id: `msg-xgplayer-${props.msgId}-${props.videoId}`,
|
||||
url: props.url,
|
||||
fluid: true,
|
||||
autoplay: false,
|
||||
@@ -78,7 +78,11 @@ onMounted(() => {
|
||||
:class="{ loading: isLoaded === 0 }"
|
||||
:style="{ width: `${renderWidth}px`, height: `${renderHeight}px` }"
|
||||
>
|
||||
<div v-show="isLoaded === 1" ref="videoWrapperRef" :id="`msg-xgplayer-${props.videoId}`"></div>
|
||||
<div
|
||||
v-show="isLoaded === 1"
|
||||
ref="videoWrapperRef"
|
||||
:id="`msg-xgplayer-${props.msgId}-${props.videoId}`"
|
||||
></div>
|
||||
<div v-show="isLoaded === 2" class="error">
|
||||
<VideoloadfailedIcon style="width: 48px; height: 48px; fill: #fff" />
|
||||
<span style="color: #fff">视频加载失败</span>
|
||||
|
||||
Reference in New Issue
Block a user