【新增】:mall 客服选择并发送图片信息
parent
b0b62eb250
commit
e45cade877
|
@ -71,10 +71,14 @@
|
|||
</el-main>
|
||||
<el-footer height="230px">
|
||||
<div class="h-[100%]">
|
||||
<div class="chat-tools">
|
||||
<div class="chat-tools flex items-center">
|
||||
<EmojiSelectPopover @select-emoji="handleEmojiSelect" />
|
||||
<PictureSelectUpload
|
||||
class="ml-15px mt-3px cursor-pointer"
|
||||
@send-picture="handleSendPicture"
|
||||
/>
|
||||
</div>
|
||||
<el-input v-model="message" :rows="6" type="textarea" />
|
||||
<el-input v-model="message" :rows="6" style="border-style: none" type="textarea" />
|
||||
<div class="h-45px flex justify-end">
|
||||
<el-button class="mt-10px" type="primary" @click="handleSendMessage">发送</el-button>
|
||||
</div>
|
||||
|
@ -88,9 +92,10 @@
|
|||
import { ElScrollbar as ElScrollbarType } from 'element-plus'
|
||||
import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message'
|
||||
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
|
||||
import EmojiSelectPopover from './EmojiSelectPopover.vue'
|
||||
import { Emoji, useEmoji } from './emoji'
|
||||
import { KeFuMessageContentTypeEnum } from './constants'
|
||||
import EmojiSelectPopover from './tools/EmojiSelectPopover.vue'
|
||||
import PictureSelectUpload from './tools/PictureSelectUpload.vue'
|
||||
import { Emoji, useEmoji } from './tools/emoji'
|
||||
import { KeFuMessageContentTypeEnum } from './tools/constants'
|
||||
import { isEmpty } from '@/utils/is'
|
||||
import { UserTypeEnum } from '@/utils/constants'
|
||||
import { createImageViewer } from '@/components/ImageViewer'
|
||||
|
@ -126,6 +131,16 @@ const showChatBox = computed(() => !isEmpty(keFuConversation.value))
|
|||
const handleEmojiSelect = (item: Emoji) => {
|
||||
message.value += item.name
|
||||
}
|
||||
// 处理图片发送
|
||||
const handleSendPicture = async (picUrl: string) => {
|
||||
// 组织发送消息
|
||||
const msg = {
|
||||
conversationId: keFuConversation.value.id,
|
||||
contentType: KeFuMessageContentTypeEnum.IMAGE,
|
||||
content: picUrl
|
||||
}
|
||||
await sendMessage(msg)
|
||||
}
|
||||
// 发送消息
|
||||
const handleSendMessage = async () => {
|
||||
// 1. 校验消息是否为空
|
||||
|
@ -139,6 +154,11 @@ const handleSendMessage = async () => {
|
|||
contentType: KeFuMessageContentTypeEnum.TEXT,
|
||||
content: message.value
|
||||
}
|
||||
await sendMessage(msg)
|
||||
}
|
||||
|
||||
// 发送消息 【共用】
|
||||
const sendMessage = async (msg: any) => {
|
||||
await KeFuMessageApi.sendKeFuMessage(msg)
|
||||
message.value = ''
|
||||
// 3. 加载消息列表
|
||||
|
@ -248,9 +268,8 @@ onBeforeUnmount(() => {
|
|||
.chat-tools {
|
||||
width: 100%;
|
||||
border: #e4e0e0 solid 1px;
|
||||
border-radius: 10px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::v-deep(textarea) {
|
||||
|
|
|
@ -35,9 +35,9 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { KeFuConversationApi, KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
|
||||
import { useEmoji } from './emoji'
|
||||
import { useEmoji } from './tools/emoji'
|
||||
import { formatDate, getNowDateTime } from '@/utils/formatTime'
|
||||
import { KeFuMessageContentTypeEnum } from '@/views/mall/promotion/kefu/components/constants'
|
||||
import { KeFuMessageContentTypeEnum } from './tools/constants'
|
||||
|
||||
defineOptions({ name: 'KeFuConversationBox' })
|
||||
const { replaceEmoji } = useEmoji()
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg t="1720063872285" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6895"
|
||||
width="200" height="200">
|
||||
<path d="M782.16 880.98c-179.31 23.91-361 23.91-540.32 0C138.89 867.25 62 779.43 62 675.57V348.43c0-103.86 76.89-191.69 179.84-205.41 179.31-23.91 361-23.91 540.31 0C885.11 156.75 962 244.57 962 348.43v327.13c0 103.87-76.89 191.69-179.84 205.42z"
|
||||
fill="#FF554D" p-id="6896"></path>
|
||||
<path d="M226.11 596.86c-9.74 47.83 17.26 95.6 63.48 111.3C333.49 723.08 394.55 737 469.53 737c59.25 0 105.46-8.69 140.23-19.7 51.59-16.34 79.94-71.16 63.37-122.68-24.47-76.11-65.57-180.7-106.68-180.7-64.62 0-64.62 96.92-64.62 96.92S437.22 317 372.61 317c-82.11 0-117.85 139.12-146.5 279.86z"
|
||||
fill="#FFFFFF" p-id="6897"></path>
|
||||
<path d="M782 347m-60 0a60 60 0 1 0 120 0 60 60 0 1 0-120 0Z" fill="#FFBC55" p-id="6898"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -1,5 +1,5 @@
|
|||
import KeFuConversationBox from './KeFuConversationBox.vue'
|
||||
import KeFuChatBox from './KeFuChatBox.vue'
|
||||
import * as Constants from './constants'
|
||||
import * as Constants from './tools/constants'
|
||||
|
||||
export { KeFuConversationBox, KeFuChatBox, Constants }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<template>
|
||||
<el-popover :width="500" placement="top" trigger="click">
|
||||
<template #reference>
|
||||
<Icon :size="30" class="ml-10px" icon="twemoji:grinning-face" />
|
||||
<Icon :size="30" class="ml-10px cursor-pointer" icon="twemoji:grinning-face" />
|
||||
</template>
|
||||
<ElScrollbar height="300px">
|
||||
<ul class="ml-2 flex flex-wrap px-2">
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div>
|
||||
<img :src="Picture" style="width: 35px; height: 35px" @click="selectAndUpload" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Picture from '@/views/mall/promotion/kefu/components/images/picture.svg'
|
||||
import * as FileApi from '@/api/infra/file'
|
||||
|
||||
defineOptions({ name: 'PictureSelectUpload' })
|
||||
const message = useMessage()
|
||||
const emits = defineEmits<{
|
||||
(e: 'send-picture', v: string): void
|
||||
}>()
|
||||
// 选择并上传文件
|
||||
const selectAndUpload = async () => {
|
||||
const files: any = await getFiles()
|
||||
message.success('图片发送请稍等。。。')
|
||||
const res = await FileApi.updateFile({ file: files[0].file })
|
||||
message.success('图片发送成功!')
|
||||
emits('send-picture', res.data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 唤起文件选择窗口,并获取选择的文件
|
||||
* @param {Object} options - 配置选项
|
||||
* @param {boolean} [options.multiple=true] - 是否支持多选
|
||||
* @param {string} [options.accept=''] - 文件上传格式限制
|
||||
* @param {number} [options.limit=1] - 单次上传最大文件数
|
||||
* @param {number} [options.fileSize=500] - 单个文件大小限制(单位:MB)
|
||||
* @returns {Promise<Array>} 选择的文件列表,每个文件带有一个uid
|
||||
*/
|
||||
async function getFiles(options = {}) {
|
||||
const { multiple, accept, limit, fileSize } = {
|
||||
multiple: true,
|
||||
accept: 'image/jpeg, image/png, image/gif',
|
||||
limit: 1,
|
||||
fileSize: 500,
|
||||
...options
|
||||
}
|
||||
|
||||
// 创建文件选择元素
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.style.display = 'none'
|
||||
if (multiple) input.multiple = true
|
||||
if (accept) input.accept = accept
|
||||
|
||||
// 将文件选择元素添加到文档中
|
||||
document.body.appendChild(input)
|
||||
|
||||
// 触发文件选择元素的点击事件
|
||||
input.click()
|
||||
|
||||
// 等待文件选择元素的 change 事件
|
||||
try {
|
||||
const files = await new Promise((resolve, reject) => {
|
||||
input.addEventListener('change', (event: any) => {
|
||||
const filesArray = Array.from(event?.target?.files || [])
|
||||
|
||||
// 从文档中移除文件选择元素
|
||||
document.body.removeChild(input)
|
||||
|
||||
// 判断是否超出上传数量限制
|
||||
if (filesArray.length > limit) {
|
||||
reject({ errorType: 'limit', files: filesArray })
|
||||
return
|
||||
}
|
||||
|
||||
// 判断是否超出上传文件大小限制
|
||||
const oversizedFiles = filesArray.filter((file: File) => file.size / 1024 ** 2 > fileSize)
|
||||
if (oversizedFiles.length > 0) {
|
||||
reject({ errorType: 'fileSize', files: oversizedFiles })
|
||||
return
|
||||
}
|
||||
|
||||
// 生成文件列表,并添加 uid
|
||||
const fileList = filesArray.map((file, index) => ({ file, uid: Date.now() + index }))
|
||||
resolve(fileList)
|
||||
})
|
||||
})
|
||||
|
||||
return files
|
||||
} catch (error) {
|
||||
console.error('选择文件出错:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
Loading…
Reference in New Issue