This commit is contained in:
左哥 2025-11-11 23:14:54 +08:00
parent 5240206f55
commit 032094652a

View File

@ -27,6 +27,16 @@
<div class="chat-footer"> <div class="chat-footer">
<div class="footer-left" style=""> <div class="footer-left" style="">
<!-- 附件预览区粘贴的图片先进入此处点击发送后再发送 -->
<div v-if="attachments.length" class="attach-preview-row" style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:4px 8px;">
<div v-for="(att, idx) in attachments" :key="att._id" class="attach-item"
style="position:relative;width:64px;height:64px;border:1px solid var(--el-border-color);border-radius:6px;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#fff;">
<img :src="att.previewUrl" alt="preview" style="max-width:100%;max-height:100%;" />
<span @click="removeAttachment(idx)"
style="position:absolute;top:2px;right:2px;background:rgba(0,0,0,.55);color:#fff;border-radius:10px;line-height:16px;height:16px;width:16px;text-align:center;cursor:pointer;font-size:12px;">×</span>
</div>
<el-link type="danger" @click="clearAttachments">清空</el-link>
</div>
<div class="upload-row" <div class="upload-row"
style="display:flex; align-items:center; gap:12px;margin-left: 6px;position: relative; top: 10px;"> style="display:flex; align-items:center; gap:12px;margin-left: 6px;position: relative; top: 10px;">
<el-icon style="font-size:24px;cursor:pointer" @click="triggerImageInput"> <el-icon style="font-size:24px;cursor:pointer" @click="triggerImageInput">
@ -34,7 +44,7 @@
<use xlink:href="#icon-tupian1"></use> <use xlink:href="#icon-tupian1"></use>
</svg> </svg>
</el-icon> </el-icon>
<input ref="imageInput" type="file" accept="image/*" style="display:none" <input ref="imageInput" type="file" accept="image/*" multiple style="display:none"
@change="handleImageChange" /> @change="handleImageChange" />
<V3Emoji @click-emoji="onEmojiSelect" :recent="true"></V3Emoji> <V3Emoji @click-emoji="onEmojiSelect" :recent="true"></V3Emoji>
</div> </div>
@ -43,7 +53,7 @@
</div> </div>
<!-- 发送按钮 --> <!-- 发送按钮 -->
<div class="send-button-container" style="margin-left: 12px;"> <div class="send-button-container" style="margin-left: 12px;">
<el-button type="primary" @click="send" :disabled="!draft.trim() || isSending || isUploading" <el-button type="primary" @click="send" :disabled="(!draft.trim() && attachments.length === 0) || isSending || isUploading"
:loading="isSending" style="height: 60px;"> :loading="isSending" style="height: 60px;">
{{ isSending ? '发送中...' : '发送' }} {{ isSending ? '发送中...' : '发送' }}
</el-button> </el-button>
@ -81,6 +91,8 @@ const draft = ref('')
const imageInput = ref(null) const imageInput = ref(null)
const chatBody = ref(null) const chatBody = ref(null)
const isLoadingMessages = ref(false) const isLoadingMessages = ref(false)
//
const attachments = ref([])
// //
const sendeInfo = reactive({ const sendeInfo = reactive({
@ -476,7 +488,7 @@ const loadMoreMessages = () => {
// //
const send = async () => { const send = async () => {
const content = draft.value.trim() const content = draft.value.trim()
if (!content || isSending.value || isUploading.value) return if ((!content && attachments.value.length === 0) || isSending.value || isUploading.value) return
// //
const now = Date.now() const now = Date.now()
@ -485,6 +497,8 @@ const send = async () => {
return return
} }
//
if (content) {
// //
const hasSendingMessage = messages.value.some(msg => const hasSendingMessage = messages.value.some(msg =>
msg._sending && msg._sending &&
@ -497,9 +511,7 @@ const send = async () => {
if (hasSendingMessage) { if (hasSendingMessage) {
// console.log('') // console.log('')
return } else {
}
isSending.value = true isSending.value = true
lastSendTime.value = now lastSendTime.value = now
@ -537,8 +549,6 @@ const send = async () => {
}).then((response) => { }).then((response) => {
msg._sending = false msg._sending = false
msg._failed = false msg._failed = false
// console.log('', response)
// ID // ID
setTimeout(() => { setTimeout(() => {
getMessages(false, 1) // getMessages(false, 1) //
@ -546,12 +556,39 @@ const send = async () => {
}).catch((error) => { }).catch((error) => {
msg._sending = false msg._sending = false
msg._failed = true msg._failed = true
// console.error(':', error)
ElMessage({ type: 'error', message: '消息发送失败' }) ElMessage({ type: 'error', message: '消息发送失败' })
}).finally(() => { }).finally(() => {
// //
isSending.value = false isSending.value = false
}) })
}
}
//
if (attachments.value.length > 0) {
const filesToSend = attachments.value.map(a => a.file)
// URL
attachments.value.forEach(a => {
if (a.previewUrl && a.previewUrl.startsWith('blob:')) {
URL.revokeObjectURL(a.previewUrl)
}
})
attachments.value = []
//
const queue = filesToSend.slice()
const processNext = () => {
if (queue.length === 0) return
if (isUploading.value) {
setTimeout(processNext, 150)
return
}
const f = queue.shift()
uploadImageFile(f)
setTimeout(processNext, 150)
}
processNext()
}
} }
// //
@ -676,9 +713,12 @@ const uploadImageFile = (file) => {
} }
const handleImageChange = (e) => { const handleImageChange = (e) => {
const file = e.target.files[0] const files = Array.from(e.target.files || [])
if (file) { if (files.length) {
uploadImageFile(file) //
const imageFiles = files.filter(f => f && f.type && f.type.startsWith('image/'))
if (imageFiles.length === 0) ElMessage({ type: 'error', message: '只能上传图片文件' })
addAttachmentFiles(imageFiles)
} }
// input便change // input便change
e.target.value = '' e.target.value = ''
@ -712,18 +752,48 @@ const handlePaste = (e) => {
// //
e.preventDefault() e.preventDefault()
// //
if (imageFiles.length > 1) { addAttachmentFiles(imageFiles)
ElMessage({ type: 'info', message: '一次仅发送第一张图片' })
}
// 使
uploadImageFile(imageFiles[0])
} catch (err) { } catch (err) {
// //
} }
} }
//
const addAttachmentFiles = (files) => {
const list = Array.from(files || [])
list.forEach((file) => {
if (!file || !file.type || !file.type.startsWith('image/')) return
if (file.size > 10 * 1024 * 1024) {
ElMessage({ type: 'error', message: '图片大小不能超过10MB' })
return
}
const previewUrl = URL.createObjectURL(file)
attachments.value.push({
_id: `att_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
file,
previewUrl
})
})
}
const removeAttachment = (index) => {
const item = attachments.value[index]
if (item && item.previewUrl && item.previewUrl.startsWith('blob:')) {
URL.revokeObjectURL(item.previewUrl)
}
attachments.value.splice(index, 1)
}
const clearAttachments = () => {
attachments.value.forEach(a => {
if (a.previewUrl && a.previewUrl.startsWith('blob:')) {
URL.revokeObjectURL(a.previewUrl)
}
})
attachments.value = []
}
// //
const handleDragEnter = (e) => { const handleDragEnter = (e) => {
e.preventDefault() e.preventDefault()
@ -781,10 +851,8 @@ const handleDrop = (e) => {
return return
} }
// //
if (imageFiles.length > 0) { addAttachmentFiles(imageFiles)
uploadImageFile(imageFiles[0])
}
} }
// //
@ -1244,4 +1312,8 @@ watch(messages, async (newVal, oldVal) => {
display: flex; display: flex;
align-items: center align-items: center
} }
.attach-preview-row{
position: absolute;
bottom: 90px;
}
</style> </style>