This commit is contained in:
pengxiaolong
2025-05-13 19:39:53 +08:00
parent 37da6765b8
commit c006a8e63d
1232 changed files with 96963 additions and 883 deletions

View File

@@ -0,0 +1,185 @@
<template>
<div
ref="emojiPickerDialog"
:class="{
'emoji-picker': true,
'emoji-picker-h5': !isPC
}"
>
<ul
ref="emojiPickerListRef"
:class="['emoji-picker-list', !isPC && 'emoji-picker-h5-list']"
>
<li
v-for="(childrenItem, childrenIndex) in currentEmojiList"
:key="childrenIndex"
class="emoji-picker-list-item"
@click="select(childrenItem, childrenIndex)"
>
<img
v-if="currentTabItem.type === EMOJI_TYPE.BASIC"
class="emoji"
:src="currentTabItem.url + BASIC_EMOJI_URL_MAPPING[childrenItem]"
>
<img
v-else-if="currentTabItem.type === EMOJI_TYPE.BIG"
class="emoji-big"
:src="currentTabItem.url + childrenItem + '@2x.png'"
>
<img
v-else
class="emoji-custom emoji-big"
:src="currentTabItem.url + childrenItem"
>
</li>
</ul>
<ul class="emoji-picker-tab">
<li
v-for="(item, index) in list"
:key="index"
class="emoji-picker-tab-item"
@click="toggleEmojiTab(index)"
>
<Icon
v-if="item.type === EMOJI_TYPE.BASIC"
class="icon"
:file="faceIcon"
/>
<img
v-else-if="item.type === EMOJI_TYPE.BIG"
class="icon-big"
:src="item.url + item.list[0] + '@2x.png'"
>
<img
v-else
class="icon-custom icon-big"
:src="item.url + item.list[0]"
>
</li>
<li
v-if="isUniFrameWork"
class="send-btn"
@click="sendMessage"
>
发送
</li>
</ul>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from '../../../../adapter-vue';
import {
TUIChatService,
TUIStore,
StoreName,
IConversationModel,
SendMessageParams,
} from '@tencentcloud/chat-uikit-engine';
import Icon from '../../../common/Icon.vue';
import faceIconLight from '../../../../assets/icon/face-light.svg';
import faceIconDark from '../../../../assets/icon/face-dark.svg';
import { EMOJI_TYPE } from '.././../../../constant';
import { isPC, isUniFrameWork } from '../../../../utils/env';
import { IEmojiGroupList, IEmojiGroup } from '../../../../interface';
import { isEnabledMessageReadReceiptGlobal } from '../../utils/utils';
import { EMOJI_GROUP_LIST, BASIC_EMOJI_URL_MAPPING, convertKeyToEmojiName } from '../../emoji-config';
import TUIChatConfig from '../../config';
const faceIcon = TUIChatConfig.getTheme() === 'dark' ? faceIconDark : faceIconLight;
const emits = defineEmits(['insertEmoji', 'onClose', 'sendMessage']);
const currentTabIndex = ref<number>(0);
const currentConversation = ref();
const emojiPickerDialog = ref();
const emojiPickerListRef = ref();
const featureConfig = TUIChatConfig.getFeatureConfig();
const list = ref<IEmojiGroupList>(initEmojiList());
const currentTabItem = ref<IEmojiGroup>(list?.value[0]);
const currentEmojiList = ref<string[]>(list?.value[0]?.list);
onMounted(() => {
TUIStore.watch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdate,
});
});
onUnmounted(() => {
TUIStore.unwatch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdate,
});
});
const toggleEmojiTab = (index: number) => {
currentTabIndex.value = index;
currentTabItem.value = list?.value[index];
currentEmojiList.value = list?.value[index]?.list;
// web & h5 side scroll to top
if (!isUniFrameWork) {
emojiPickerListRef?.value && (emojiPickerListRef.value.scrollTop = 0);
}
};
const select = (item: any, index: number) => {
const options: any = {
emoji: { key: item, name: convertKeyToEmojiName(item) },
type: currentTabItem?.value?.type,
};
switch (currentTabItem?.value?.type) {
case EMOJI_TYPE.BASIC:
options.url = currentTabItem?.value?.url + BASIC_EMOJI_URL_MAPPING[item];
if (isUniFrameWork) {
uni.$emit('insert-emoji', options);
} else {
emits('insertEmoji', options);
}
break;
case EMOJI_TYPE.BIG:
sendFaceMessage(index, currentTabItem.value);
break;
case EMOJI_TYPE.CUSTOM:
sendFaceMessage(index, currentTabItem.value);
break;
default:
break;
}
isPC && emits('onClose');
};
const sendFaceMessage = (index: number, listItem: IEmojiGroup) => {
const options = {
to:
currentConversation?.value?.groupProfile?.groupID
|| currentConversation?.value?.userProfile?.userID,
conversationType: currentConversation?.value?.type,
payload: {
index: listItem.emojiGroupID,
data: listItem.list[index],
},
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
} as SendMessageParams;
TUIChatService.sendFaceMessage(options);
};
function sendMessage() {
uni.$emit('send-message-in-emoji-picker');
}
function onCurrentConversationUpdate(conversation: IConversationModel) {
currentConversation.value = conversation;
}
function initEmojiList() {
return EMOJI_GROUP_LIST.filter((item) => {
if (item.type === EMOJI_TYPE.BASIC) {
return featureConfig.InputEmoji;
}
if (item.type === EMOJI_TYPE.BIG) {
return featureConfig.InputStickers;
}
if (item.type === EMOJI_TYPE.CUSTOM) {
return featureConfig.InputStickers;
}
});
}
</script>
<style lang="scss" scoped src="./style/index.scss"></style>

View File

@@ -0,0 +1,2 @@
import EmojiPicker from './index.vue';
export default EmojiPicker;

View File

@@ -0,0 +1,81 @@
<template>
<ToolbarItemContainer
ref="container"
:iconFile="faceIcon"
title="表情"
@onDialogShow="onDialogShow"
@onDialogClose="onDialogClose"
>
<EmojiPickerDialog
@insertEmoji="insertEmoji"
@sendMessage="sendMessage"
@onClose="onClose"
/>
</ToolbarItemContainer>
</template>
<script lang="ts" setup>
import {
TUIStore,
StoreName,
IConversationModel,
} from '@tencentcloud/chat-uikit-engine';
import { ref } from '../../../../adapter-vue';
import faceIconLight from '../../../../assets/icon/face-light.svg';
import faceIconDark from '../../../../assets/icon/face-dark.svg';
import EmojiPickerDialog from './emoji-picker-dialog.vue';
import ToolbarItemContainer from '../toolbar-item-container/index.vue';
import { isH5 } from '../../../../utils/env';
import { ToolbarDisplayType } from '../../../../interface';
import TUIChatConfig from '../../config';
interface IEmits {
(e: 'sendMessage'): void;
(e: 'toggleComponent'): void;
(e: 'insertEmoji', emoji: any): void;
(e: 'dialogShowInH5', dialogRef: HTMLElement): void;
(e: 'dialogCloseInH5', dialogRef: HTMLElement): void;
(e: 'changeToolbarDisplayType', type: ToolbarDisplayType): void;
}
const faceIcon = TUIChatConfig.getTheme() === 'dark' ? faceIconDark : faceIconLight;
const emits = defineEmits<IEmits>();
const currentConversation = ref();
const container = ref<InstanceType<typeof ToolbarItemContainer>>();
TUIStore.watch(StoreName.CONV, {
currentConversation: (conversation: IConversationModel) => {
currentConversation.value = conversation;
},
});
const onDialogShow = (dialogRef: any) => {
if (!isH5) {
return;
}
emits('changeToolbarDisplayType', 'emojiPicker');
emits('dialogShowInH5', dialogRef.value);
};
const onDialogClose = (dialogRef: any) => {
if (!isH5) {
return;
}
emits('changeToolbarDisplayType', 'none');
emits('dialogCloseInH5', dialogRef.value);
};
const insertEmoji = (emojiObj) => {
emits('insertEmoji', emojiObj);
};
const sendMessage = () => {
emits('sendMessage');
};
const onClose = () => {
container.value?.toggleDialogDisplay(false);
};
defineExpose({
closeEmojiPicker: onClose,
});
</script>
<style lang="scss" scoped src="./style/index.scss"></style>

View File

@@ -0,0 +1,25 @@
.emoji-picker-h5 {
width: 100%;
&-list {
justify-content: space-between;
}
&-list::after {
content: "";
display: block;
flex: 1 1 auto;
}
.send-btn {
width: 50px;
height: 30px;
background-color: #55C06A;
position: absolute;
right: 10px;
font-size: 16px;
color: #fff;
text-align: center;
line-height: 30px;
}
}

View File

@@ -0,0 +1,4 @@
@import "../../../../../assets/styles/common";
@import "./web";
@import "./h5";

View File

@@ -0,0 +1,55 @@
.emoji-picker {
width: 405px;
height: 300px;
display: flex;
flex-direction: column;
&-list {
flex: 1;
display: flex;
flex-wrap: wrap;
overflow-y: auto;
margin: 2px;
&::-webkit-scrollbar {
display: none;
}
&-item {
cursor: pointer;
padding: 5px;
.emoji {
width: 30px;
height: 30px;
}
.emoji-big {
width: 70px;
height: 70px;
}
}
}
&-tab {
display: flex;
align-items: center;
&-item {
padding: 0 10px;
cursor: pointer;
.icon {
margin: 10px;
width: 20px;
height: 20px;
&-big {
margin: 2px 0;
width: 30px;
height: 30px;
}
}
}
}
}