【新增】:mall 客服选择并发送图片信息

This commit is contained in:
puhui999
2024-07-04 15:28:34 +08:00
parent b0b62eb250
commit e45cade877
8 changed files with 132 additions and 11 deletions

View File

@@ -0,0 +1,41 @@
<!-- emoji 表情选择组件 -->
<template>
<el-popover :width="500" placement="top" trigger="click">
<template #reference>
<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">
<li
v-for="(item, index) in emojiList"
:key="index"
:style="{
borderColor: 'var(--el-color-primary)',
color: 'var(--el-color-primary)'
}"
:title="item.name"
class="icon-item mr-2 mt-1 w-1/10 flex cursor-pointer items-center justify-center border border-solid p-2"
@click="handleSelect(item)"
>
<img :src="item.url" style="width: 24px; height: 24px" />
</li>
</ul>
</ElScrollbar>
</el-popover>
</template>
<script lang="ts" setup>
defineOptions({ name: 'EmojiSelectPopover' })
import { Emoji, useEmoji } from './emoji'
const { getEmojiList } = useEmoji()
const emojiList = computed(() => getEmojiList())
const emits = defineEmits<{
(e: 'select-emoji', v: Emoji)
}>()
const handleSelect = (item: Emoji) => {
// 整个 emoji 数据传递出去,方便以后输入框直接显示表情
emits('select-emoji', item)
}
</script>

View File

@@ -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>

View File

@@ -0,0 +1,10 @@
export const KeFuMessageContentTypeEnum = {
TEXT: 1, // 文本消息
IMAGE: 2, // 图片消息
VOICE: 3, // 语音消息
VIDEO: 4, // 视频消息
SYSTEM: 5, // 系统消息
// ========== 商城特殊消息 ==========
PRODUCT: 10, // 商品消息
ORDER: 11 // 订单消息"
}

View File

@@ -0,0 +1,115 @@
import { isEmpty } from '@/utils/is'
const emojiList = [
{ name: '[笑掉牙]', file: 'xiaodiaoya.png' },
{ name: '[可爱]', file: 'keai.png' },
{ name: '[冷酷]', file: 'lengku.png' },
{ name: '[闭嘴]', file: 'bizui.png' },
{ name: '[生气]', file: 'shengqi.png' },
{ name: '[惊恐]', file: 'jingkong.png' },
{ name: '[瞌睡]', file: 'keshui.png' },
{ name: '[大笑]', file: 'daxiao.png' },
{ name: '[爱心]', file: 'aixin.png' },
{ name: '[坏笑]', file: 'huaixiao.png' },
{ name: '[飞吻]', file: 'feiwen.png' },
{ name: '[疑问]', file: 'yiwen.png' },
{ name: '[开心]', file: 'kaixin.png' },
{ name: '[发呆]', file: 'fadai.png' },
{ name: '[流泪]', file: 'liulei.png' },
{ name: '[汗颜]', file: 'hanyan.png' },
{ name: '[惊悚]', file: 'jingshu.png' },
{ name: '[困~]', file: 'kun.png' },
{ name: '[心碎]', file: 'xinsui.png' },
{ name: '[天使]', file: 'tianshi.png' },
{ name: '[晕]', file: 'yun.png' },
{ name: '[啊]', file: 'a.png' },
{ name: '[愤怒]', file: 'fennu.png' },
{ name: '[睡着]', file: 'shuizhuo.png' },
{ name: '[面无表情]', file: 'mianwubiaoqing.png' },
{ name: '[难过]', file: 'nanguo.png' },
{ name: '[犯困]', file: 'fankun.png' },
{ name: '[好吃]', file: 'haochi.png' },
{ name: '[呕吐]', file: 'outu.png' },
{ name: '[龇牙]', file: 'ziya.png' },
{ name: '[懵比]', file: 'mengbi.png' },
{ name: '[白眼]', file: 'baiyan.png' },
{ name: '[饿死]', file: 'esi.png' },
{ name: '[凶]', file: 'xiong.png' },
{ name: '[感冒]', file: 'ganmao.png' },
{ name: '[流汗]', file: 'liuhan.png' },
{ name: '[笑哭]', file: 'xiaoku.png' },
{ name: '[流口水]', file: 'liukoushui.png' },
{ name: '[尴尬]', file: 'ganga.png' },
{ name: '[惊讶]', file: 'jingya.png' },
{ name: '[大惊]', file: 'dajing.png' },
{ name: '[不好意思]', file: 'buhaoyisi.png' },
{ name: '[大闹]', file: 'danao.png' },
{ name: '[不可思议]', file: 'bukesiyi.png' },
{ name: '[爱你]', file: 'aini.png' },
{ name: '[红心]', file: 'hongxin.png' },
{ name: '[点赞]', file: 'dianzan.png' },
{ name: '[恶魔]', file: 'emo.png' }
]
export interface Emoji {
name: string
url: string
}
export const useEmoji = () => {
const emojiPathList = ref<any[]>([])
// 加载本地图片
const getStaticEmojiPath = async () => {
const pathList = import.meta.glob(
'@/views/mall/promotion/kefu/components/images/*.{png,jpg,jpeg,svg}'
)
for (const path in pathList) {
const imageModule: any = await pathList[path]()
emojiPathList.value.push(imageModule.default)
}
}
// 初始化
onMounted(async () => {
if (isEmpty(emojiPathList.value)) {
await getStaticEmojiPath()
}
})
// 处理表情
function replaceEmoji(data: string) {
let newData = data
if (typeof newData !== 'object') {
const reg = /\[(.+?)\]/g // [] 中括号
const zhEmojiName = newData.match(reg)
if (zhEmojiName) {
zhEmojiName.forEach((item) => {
const emojiFile = selEmojiFile(item)
newData = newData.replace(
item,
`<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${emojiFile}"/>`
)
})
}
}
return newData
}
// 获得所有表情
function getEmojiList(): Emoji[] {
return emojiList.map((item) => ({
url: selEmojiFile(item.name),
name: item.name
})) as Emoji[]
}
function selEmojiFile(name: string) {
for (const emoji of emojiList) {
if (emoji.name === name) {
return emojiPathList.value.find((item: string) => item.indexOf(emoji.file) > -1)
}
}
return false
}
return { replaceEmoji, getEmojiList }
}