chat-pc/src/views/message/inner/panel/PanelFooter.vue

301 lines
6.9 KiB
Vue
Raw Normal View History

2024-12-24 08:14:21 +00:00
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import {
useTalkStore,
useDialogueStore,
useSettingsStore,
useUploadsStore,
useEditorStore,
useUserStore
2024-12-24 08:14:21 +00:00
} from '@/store'
import ws from '@/connect'
import { ServePublishMessage, ServeSendVote } from '@/api/chat'
import { throttle, getVideoImage } from '@/utils/common'
import { parseTime } from '@/utils/datetime'
2024-12-24 08:14:21 +00:00
import Editor from '@/components/editor/Editor.vue'
import MultiSelectFooter from './MultiSelectFooter.vue'
import HistoryRecord from '@/components/talk/HistoryRecord.vue'
import { uploadImg } from '@/api/upload'
const userStore = useUserStore()
2024-12-24 08:14:21 +00:00
const talkStore = useTalkStore()
const editorStore = useEditorStore()
const settingsStore = useSettingsStore()
const uploadsStore = useUploadsStore()
const dialogueStore = useDialogueStore()
const props = defineProps({
uid: {
type: Number,
default: 0
},
talk_type: {
type: Number,
default: 0
},
receiver_id: {
type: Number,
default: 0
},
index_name: {
type: String,
default: ''
},
online: {
type: Boolean,
default: false
},
members: {
default: () => []
}
})
const isShowHistory = ref(false)
const onSendMessage = (data = {}, callBack: any) => {
let message = {
...data,
receiver: {
receiver_id: props.receiver_id,
talk_type: props.talk_type
}
}
ServePublishMessage(message)
.then(({ code, message }) => {
if (code == 200) {
callBack(true)
} else {
window['$message'].warning(message)
}
})
.catch(() => {
window['$message'].warning('网络繁忙,请稍后重试!')
})
}
// 发送文本消息
const onSendTextEvent = throttle((value: any) => {
let { data, callBack } = value
let message = {
type: 'text',
content: data.items[0].content,
quote_id: data.quoteId,
mentions: data.mentionUids
}
onSendMessage(message, (ok: boolean) => {
if (!ok) return
let el = document.getElementById('talk-session-list')
el?.scrollTo({ top: 0, behavior: 'smooth' })
callBack(true)
})
}, 1000)
// 发送图片消息
const onSendImageEvent = ({ data, callBack }) => {
onSendMessage({ type: 'image', ...data }, callBack)
}
// 发送视频消息
const onSendVideoEvent = async ({ data }) => {
console.log('onSendVideoEvent')
// 获取视频首帧作为封面图
// let resp = await getVideoImage(data)
// 先创建一个带有上传ID的临时消息对象用于显示进度
const uploadId = `video-${Date.now()}-${Math.floor(Math.random() * 1000)}`
// 创建临时消息记录
const tempMessage = {
msg_id: uploadId,
sequence: Date.now(),
talk_type: props.talk_type,
msg_type: 5, // 视频消息类型
user_id: props.uid,
receiver_id: props.receiver_id,
is_revoke: 0,
is_mark: 0,
is_read: 1,
content: '',
created_at: parseTime(new Date(), '{y}-{m}-{d} {h}:{i}'),
extra: {
url: '',
size: data.size,
is_uploading: true,
upload_id: uploadId,
percentage: 0
},
isCheck: false,
send_status: 1,
float: 'right' // 我发送的消息显示在右侧
2024-12-24 08:14:21 +00:00
}
// 直接添加到对话记录中
dialogueStore.addDialogueRecord(tempMessage)
uploadsStore.initUploadFile(
data,
props.talk_type,
props.receiver_id,
uploadId,
async (percentage) => {
dialogueStore.updateUploadProgress(uploadId, percentage)
},
async () => {
dialogueStore.batchDelDialogueRecord([uploadId])
}
)
2024-12-24 08:14:21 +00:00
}
// 发送代码消息
const onSendCodeEvent = ({ data, callBack }) => {
onSendMessage({ type: 'code', code: data.code, lang: data.lang }, callBack)
}
// 发送文件消息
const onSendFileEvent = ({ data }) => {
let maxsize = 200 * 1024 * 1024
if (data.size > maxsize) {
return window['$message'].warning('上传文件不能超过100M!')
}
const clientUploadId = `file-${Date.now()}-${Math.floor(Math.random() * 1000)}`
const tempMessage = {
msg_id: clientUploadId,
sequence: Date.now(),
talk_type: props.talk_type,
msg_type: 6,
user_id: props.uid,
receiver_id: props.receiver_id,
nickname: dialogueStore.talk.username,
avatar: userStore.avatar,
is_revoke: 0,
is_read: 0,
created_at: parseTime(new Date(), '{y}-{m}-{d} {h}:{i}'),
extra: {
name: data.name,
url: '',
size: data.size,
is_uploading: true,
upload_id: clientUploadId,
percentage: 0
},
float: 'right'
}
dialogueStore.addDialogueRecord(tempMessage)
uploadsStore.initUploadFile(data, props.talk_type, props.receiver_id,clientUploadId,
async (percentage) => {
dialogueStore.updateUploadProgress(clientUploadId, percentage)
},
async () => {
dialogueStore.batchDelDialogueRecord([clientUploadId])
}
)
2024-12-24 08:14:21 +00:00
}
// 发送投票消息
const onSendVoteEvent = ({ data, callBack }) => {
let response = ServeSendVote({
receiver_id: props.receiver_id,
mode: data.mode,
anonymous: data.anonymous,
title: data.title,
options: data.options
})
response.then(({ code, message }) => {
if (code == 200) {
callBack(true)
} else {
window['$message'].warning(message)
}
})
response.catch(() => callBack(false))
}
// 发送表情消息
const onSendEmoticonEvent = ({ data, callBack }) => {
onSendMessage({ type: 'emoticon', emoticon_id: data }, callBack)
}
const onSendMixedEvent = ({ data, callBack }) => {
let message = {
type: 'mixed',
quote_id: data.quoteId,
items: data.items
}
onSendMessage(message, callBack)
}
const onKeyboardPush = throttle(() => {
ws.emit('im.message.keyboard', {
sender_id: props.uid,
receiver_id: props.receiver_id
})
}, 3000)
// 编辑器输入事件
const onInputEvent = ({ data }) => {
talkStore.updateItem({
index_name: props.index_name,
draft_text: data
})
// 判断对方是否在线和是否需要推送
// 3秒时间内推送一次
if (settingsStore.isKeyboard && props.online) {
onKeyboardPush()
}
}
// 注册事件
const evnets = {
text_event: onSendTextEvent,
image_event: onSendImageEvent,
video_event: onSendVideoEvent,
code_event: onSendCodeEvent,
file_event: onSendFileEvent,
input_event: onInputEvent,
vote_event: onSendVoteEvent,
emoticon_event: onSendEmoticonEvent,
history_event: () => {
isShowHistory.value = true
},
mixed_event: onSendMixedEvent
}
// 编辑器事件
const onEditorEvent = (msg: any) => {
evnets[msg.event] && evnets[msg.event](msg)
}
onMounted(() => {
editorStore.loadUserEmoticon()
})
</script>
<template>
<footer class="el-footer">
<MultiSelectFooter v-if="dialogueStore.isOpenMultiSelect" />
<Editor v-else @editor-event="onEditorEvent" :vote="talk_type == 2" :members="members" />
</footer>
<HistoryRecord
v-if="isShowHistory"
:talk-type="talk_type"
:receiver-id="receiver_id"
@close="isShowHistory = false"
/>
</template>
<style lang="less">
.el-footer {
height: inherit;
}
</style>