chat-pc/src/components/editor/MeEditorEmoticon.vue
2024-12-24 16:14:21 +08:00

264 lines
5.6 KiB
Vue

<script lang="ts" setup>
import { ref, computed } from 'vue'
import { useEditorStore } from '@/store'
import { UploadOne, Delete } from '@icon-park/vue-next'
import { emojis } from '@/utils/emojis'
const emit = defineEmits(['on-select'])
const editorStore = useEditorStore()
const fileImageRef = ref()
const tabIndex = ref(0)
const items = computed<any[]>(() => editorStore.emoticon.items)
// 触发上传按钮事件
const onTriggerUpload = () => {
fileImageRef.value.click()
}
// 上传表情包
const onUpload = (e: any) => {
let file = e.target.files[0]
editorStore.uploadUserEmoticon(file)
}
// 删除表情包
const onDelete = (index: number, id: number) => {
editorStore.removeUserEmoticon({ index, id })
}
const onTabs = (index: number) => {
tabIndex.value = index
}
const onSendEmoticon = (type: any, value: any, img = '') => {
if (img) {
const imgSrcReg = /<img.*?src='(.*?)'/g
let match = imgSrcReg.exec(img)
if (match) {
emit('on-select', { type, value, img: match[1] })
}
} else {
emit('on-select', { type, value, img })
}
}
</script>
<template>
<form enctype="multipart/form-data" style="display: none">
<input type="file" ref="fileImageRef" accept="image/*" @change="onUpload" />
</form>
<section class="el-container is-vertical section height100">
<header class="el-header em-header bdr-b">
<span>{{ items[tabIndex].name }}</span>
</header>
<main class="el-main em-main me-scrollbar me-scrollbar-thumb">
<div class="symbol-box" v-if="tabIndex == 0">
<div class="options">
<div
v-for="(img, key) in emojis"
v-html="img"
:key="key"
@click="onSendEmoticon(1, key, img)"
class="option pointer flex-center"
/>
</div>
</div>
<div class="collect-box" v-else>
<div v-if="tabIndex == 1" class="item pointer upload-btn" @click="onTriggerUpload">
<n-icon size="28" class="icon" :component="UploadOne" />
<span>自定义</span>
</div>
<div class="item pointer" v-for="(item, index) in items[tabIndex].children" :key="index">
<img :src="item.src" @click="onSendEmoticon(2, item.media_id)" />
<div v-if="tabIndex == 1" class="mask" @click="onDelete(index, item.media_id)">
<n-icon size="18" color="#ff5722" class="icon" :component="Delete" />
</div>
</div>
</div>
</main>
<footer class="el-footer em-footer tabs">
<div
class="tab pointer"
v-for="(item, index) in items"
:key="index"
@click="onTabs(index)"
:class="{ active: index == tabIndex }"
>
<p class="tip">{{ item.name }}</p>
<img width="20" height="20" :src="item.icon" />
</div>
</footer>
</section>
</template>
<style lang="less" scoped>
.section {
width: 500px;
height: 250px;
overflow: hidden;
background-color: var(--im-bg-color);
border-radius: 3px;
.em-header {
height: 32px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
.sys-btn {
color: #409eff;
cursor: pointer;
}
}
.em-main {
height: 100px;
padding-bottom: 20px;
}
.em-footer {
height: 32px;
}
.tabs {
display: flex;
align-items: center;
.tab {
position: relative;
height: 26px;
width: 26px;
margin: 2px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
&.active {
background-color: var(--im-active-bg-color);
}
.tip {
position: absolute;
left: 0;
top: -32px;
height: 26px;
min-width: 20px;
white-space: pre;
padding: 0 5px;
font-size: 12px;
border-radius: 2px;
background-color: var(--im-active-bg-color);
display: none;
align-items: center;
color: var(--im-text-color);
}
&:hover {
.tip {
display: flex;
}
background-color: var(--im-active-bg-color);
}
}
}
.symbol-box {
.title {
width: 50%;
height: 25px;
line-height: 25px;
color: #ccc;
font-weight: 400;
padding-left: 8px;
font-size: 12px;
}
.options {
width: 100%;
display: flex;
flex-wrap: wrap;
.option {
height: 32px;
width: 32px;
margin: 2px;
font-size: 24px;
user-select: none;
transition: all 0.5s;
&:hover {
transform: scale(1.5);
}
}
}
}
.collect-box {
display: flex;
flex-wrap: wrap;
padding: 5px;
.upload-btn {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #858585;
span {
font-size: 13px;
}
}
.item {
position: relative;
width: 70px;
height: 70px;
background-color: #eff1f7;
margin: 5px;
border-radius: 5px;
overflow: hidden;
.mask {
display: none;
position: absolute;
top: 0;
right: 0;
width: 25px;
height: 25px;
background-color: #f5f5f5;
align-items: center;
justify-content: center;
border-radius: 3px;
}
&:hover {
.mask {
display: flex;
align-items: center;
justify-content: center;
}
}
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
}
html[theme-mode='dark'] {
.collect-box .item {
background-color: #2c2c32;
}
}
</style>