+
@@ -92,6 +107,8 @@ const messageTimer = ref(null) // 定时器实例
const isSending = ref(false) // 防止重复发送
const lastSendTime = ref(0) // 最后发送时间,用于防抖
const isUploading = ref(false) // 防止重复上传
+const isDragging = ref(false) // 拖拽状态
+const dragCounter = ref(0) // 拖拽计数器,用于处理嵌套元素
// 小程序状态轮询定时器
const appStatusTimer = ref(null)
@@ -556,16 +573,28 @@ const triggerImageInput = () => {
imageInput.value && imageInput.value.click()
}
-const handleImageChange = (e) => {
- const file = e.target.files[0]
+// 提取图片上传逻辑为可复用函数
+const uploadImageFile = (file) => {
if (!file) return
+ // 检查是否有选中用户
+ if (!activeUser.value.sender_id) {
+ ElMessage({ type: 'warning', message: '请先选择用户' })
+ return
+ }
+
// 防止重复上传
if (isUploading.value) {
console.log('图片正在上传中,请稍候')
return
}
+ // 检查文件类型是否为图片
+ if (!file.type.startsWith('image/')) {
+ ElMessage({ type: 'error', message: '只能上传图片文件' })
+ return
+ }
+
// 检查文件大小(限制为10MB)
if (file.size > 10 * 1024 * 1024) {
ElMessage({ type: 'error', message: '图片大小不能超过10MB' })
@@ -592,7 +621,6 @@ const handleImageChange = (e) => {
_tempImageFile: file // 保存文件信息用于匹配
}
messages.value.push(msg)
- e.target.value = ''
// 滚动到底部
setTimeout(() => scrollToBottom(), 100)
@@ -650,6 +678,78 @@ const handleImageChange = (e) => {
})
}
+const handleImageChange = (e) => {
+ const file = e.target.files[0]
+ if (file) {
+ uploadImageFile(file)
+ }
+ // 清空input值,以便下次选择同一文件时也能触发change事件
+ e.target.value = ''
+}
+
+// 拖拽事件处理
+const handleDragEnter = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ dragCounter.value++
+ // 检查拖拽内容是否包含文件
+ if (e.dataTransfer.types.includes('Files')) {
+ isDragging.value = true
+ }
+}
+
+const handleDragOver = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ // 设置拖拽效果为复制
+ if (e.dataTransfer) {
+ e.dataTransfer.dropEffect = 'copy'
+ }
+}
+
+const handleDragLeave = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ dragCounter.value--
+ // 只有当计数器为0时才取消拖拽状态(处理嵌套元素)
+ if (dragCounter.value === 0) {
+ isDragging.value = false
+ }
+}
+
+const handleDrop = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ dragCounter.value = 0
+ isDragging.value = false
+
+ // 检查是否有选中用户
+ if (!activeUser.value.sender_id) {
+ ElMessage({ type: 'warning', message: '请先选择用户' })
+ return
+ }
+
+ // 获取拖拽的文件
+ const files = Array.from(e.dataTransfer.files)
+
+ if (files.length === 0) {
+ return
+ }
+
+ // 过滤出图片文件
+ const imageFiles = files.filter(file => file.type.startsWith('image/'))
+
+ if (imageFiles.length === 0) {
+ ElMessage({ type: 'warning', message: '请拖拽图片文件' })
+ return
+ }
+
+ // 只处理第一个图片文件
+ if (imageFiles.length > 0) {
+ uploadImageFile(imageFiles[0])
+ }
+}
+
// 重发消息
const handleRetry = (id) => {
const msg = messages.value.find((m) => m._id === id)
@@ -1013,6 +1113,39 @@ watch(messages, async (newVal, oldVal) => {
padding: 16px;
overflow: auto;
background: #f5f7fa;
+ position: relative;
+}
+
+.chat-body--dragging {
+ background: rgba(64, 158, 255, 0.05);
+}
+
+.drag-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(64, 158, 255, 0.1);
+ border: 2px dashed var(--el-color-primary);
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ pointer-events: none;
+}
+
+.drag-hint {
+ text-align: center;
+ color: var(--el-color-primary);
+ font-size: 16px;
+ font-weight: 500;
+}
+
+.drag-hint p {
+ margin-top: 12px;
+ margin-bottom: 0;
}
/* Hide scrollbar but keep scrolling functionality */