@tencentcloud/ai-desk-customer-vue 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/assets/arrow_down_icon.svg +1 -0
- package/assets/arrow_down_icon_white.svg +1 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +1 -5
- package/components/CustomerServiceChat/emoji-config/default-emoji.ts +11 -0
- package/components/CustomerServiceChat/emoji-config/index.ts +14 -1
- package/components/CustomerServiceChat/message-input/index-web.vue +38 -0
- package/components/CustomerServiceChat/message-input/message-input-button.vue +5 -0
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +13 -9
- package/components/CustomerServiceChat/message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue +26 -46
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +8 -38
- package/components/CustomerServiceChat/message-list/bottom-quick-order/index.vue +1 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +6 -5
- package/components/CustomerServiceChat/message-list/scroll-button/index.vue +17 -9
- package/locales/en/TUIChat.ts +1 -1
- package/locales/en/aidesk.ts +0 -1
- package/locales/fil/TUIChat.ts +1 -1
- package/locales/fil/aidesk.ts +0 -1
- package/locales/id/TUIChat.ts +1 -1
- package/locales/id/aidesk.ts +0 -1
- package/locales/ja/TUIChat.ts +1 -1
- package/locales/ja/aidesk.ts +0 -1
- package/locales/ms/TUIChat.ts +1 -1
- package/locales/ms/aidesk.ts +0 -1
- package/locales/ru/TUIChat.ts +1 -1
- package/locales/ru/aidesk.ts +0 -1
- package/locales/th/TUIChat.ts +1 -1
- package/locales/th/aidesk.ts +0 -1
- package/locales/vi/TUIChat.ts +1 -1
- package/locales/vi/aidesk.ts +0 -1
- package/locales/zh_cn/aidesk.ts +0 -1
- package/locales/zh_tw/aidesk.ts +0 -1
- package/package.json +1 -1
- package/assets/double-arrow.svg +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#444444"><path d="M480-344 240-584l56-56 184 184 184-184 56 56-240 240Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#ffffff"><path d="M480-344 240-584l56-56 184 184 184-184 56 56-240 240Z"/></svg>
|
|
@@ -160,11 +160,7 @@ function setCurrentConversationName() {
|
|
|
160
160
|
if (props.headerConfig && props.headerConfig.title) {
|
|
161
161
|
currentConversationName.value = props.headerConfig.title;
|
|
162
162
|
} else {
|
|
163
|
-
|
|
164
|
-
currentConversationName.value = TUITranslateService.t('AIDesk.Hi,我是') + currentConversation.value.getShowName();
|
|
165
|
-
} else {
|
|
166
|
-
currentConversationName.value = currentConversation.value.getShowName() || '';
|
|
167
|
-
}
|
|
163
|
+
currentConversationName.value = currentConversation.value.getShowName() || '';
|
|
168
164
|
}
|
|
169
165
|
}
|
|
170
166
|
|
|
@@ -80,6 +80,17 @@ export const DEFAULT_BASIC_EMOJI_URL_MAPPING: Record<string, string> = {
|
|
|
80
80
|
'[TUIEmoji_Like]': 'emoji_61@2x.png',
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
+
export const EXCLUDED_EMOJI_LIST = [
|
|
84
|
+
'[TUIEmoji_Pig]',
|
|
85
|
+
'[TUIEmoji_Rich]',
|
|
86
|
+
'[TUIEmoji_Fortune]',
|
|
87
|
+
'[TUIEmoji_857]',
|
|
88
|
+
'[TUIEmoji_666]',
|
|
89
|
+
'[TUIEmoji_Prohibit]',
|
|
90
|
+
'[TUIEmoji_Convinced]',
|
|
91
|
+
'[TUIEmoji_Knife]',
|
|
92
|
+
];
|
|
93
|
+
|
|
83
94
|
export const BIG_EMOJI_GROUP_LIST: IEmojiGroupList = [
|
|
84
95
|
{
|
|
85
96
|
emojiGroupID: 1,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
2
2
|
import { CUSTOM_BASIC_EMOJI_URL, CUSTOM_BIG_EMOJI_URL, CUSTOM_BASIC_EMOJI_URL_MAPPING, CUSTOM_BIG_EMOJI_GROUP_LIST } from './custom-emoji';
|
|
3
|
-
import { DEFAULT_BASIC_EMOJI_URL, BIG_EMOJI_GROUP_LIST, DEFAULT_BASIC_EMOJI_URL_MAPPING, BASIC_EMOJI_NAME_TO_KEY_MAPPING, DEFAULT_BIG_EMOJI_URL } from './default-emoji';
|
|
3
|
+
import { DEFAULT_BASIC_EMOJI_URL, BIG_EMOJI_GROUP_LIST, DEFAULT_BASIC_EMOJI_URL_MAPPING, BASIC_EMOJI_NAME_TO_KEY_MAPPING, DEFAULT_BIG_EMOJI_URL, EXCLUDED_EMOJI_LIST } from './default-emoji';
|
|
4
4
|
import { default as emojiCNLocales } from './locales/zh_cn';
|
|
5
5
|
import { default as emojiENLocales } from './locales/en';
|
|
6
6
|
import { IEmojiGroupList } from '../../../interface';
|
|
@@ -126,6 +126,17 @@ const parseTextToRenderArray = (text: string): Array<{ type: 'text' | 'image'; c
|
|
|
126
126
|
return result;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
const filterEmojisInNonChineseEnv = (list: string[]) => {
|
|
130
|
+
const language = state.get('currentLanguage') || 'zh';
|
|
131
|
+
if (!(language === 'zh' || language === 'zh_tw')) {
|
|
132
|
+
return list.filter((item) => {
|
|
133
|
+
return !EXCLUDED_EMOJI_LIST.includes(item);
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
return list;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
129
140
|
export {
|
|
130
141
|
EMOJI_GROUP_LIST,
|
|
131
142
|
CUSTOM_BIG_EMOJI_URL,
|
|
@@ -138,4 +149,6 @@ export {
|
|
|
138
149
|
transformTextWithKeysToEmojiNames,
|
|
139
150
|
transformTextWithEmojiNamesToKeys,
|
|
140
151
|
emojiConfig,
|
|
152
|
+
BASIC_EMOJI_URL,
|
|
153
|
+
filterEmojisInNonChineseEnv,
|
|
141
154
|
};
|
|
@@ -69,6 +69,7 @@ import audioIcon from '../../../assets/audio-blue.svg';
|
|
|
69
69
|
import keyboardIcon from '../../../assets/keyboard-icon.svg';
|
|
70
70
|
import { INPUT_TOOLBAR_TYPE } from '../../../constant';
|
|
71
71
|
import { onUnmounted } from 'vue';
|
|
72
|
+
import Log from '../../../utils/logger';
|
|
72
73
|
const { ref, onMounted, onBeforeUnmount, computed } = vue;
|
|
73
74
|
|
|
74
75
|
const props = defineProps({
|
|
@@ -111,23 +112,33 @@ const showSendButton = ref(false);
|
|
|
111
112
|
const isInHumanService = ref(false);
|
|
112
113
|
let quoteMessageCloudCustomData:string = '';
|
|
113
114
|
const isInAudioMode = ref(false);
|
|
115
|
+
let hasAudioStream = false;
|
|
116
|
+
let audioStream = null;
|
|
114
117
|
|
|
115
118
|
onMounted(() => {
|
|
116
119
|
// document.addEventListener('click', handleClick);
|
|
117
120
|
TUIStore.watch(StoreName.CUSTOM, {
|
|
118
121
|
isInHumanService: onInHumanServiceUpdate,
|
|
119
122
|
});
|
|
123
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
120
124
|
});
|
|
121
125
|
|
|
122
126
|
onUnmounted(() => {
|
|
123
127
|
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
124
128
|
isInHumanService: onInHumanServiceUpdate,
|
|
125
129
|
});
|
|
130
|
+
stopAudioStream();
|
|
131
|
+
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
126
132
|
});
|
|
127
133
|
|
|
128
134
|
const onInHumanServiceUpdate = (data: {conversationID: string, value: boolean}) => {
|
|
129
135
|
if (data && data.conversationID === currentConversation.value.conversationID) {
|
|
130
136
|
isInHumanService.value = data.value;
|
|
137
|
+
if (!isInHumanService.value) {
|
|
138
|
+
isInAudioMode.value = false;
|
|
139
|
+
placeholder.value = TUITranslateService.t('TUIChat.请输入消息');
|
|
140
|
+
stopAudioStream();
|
|
141
|
+
}
|
|
131
142
|
}
|
|
132
143
|
};
|
|
133
144
|
|
|
@@ -203,9 +214,28 @@ const toolShow = () => {
|
|
|
203
214
|
const blurToolAndEmojiH5 = () =>{
|
|
204
215
|
emit('blurToolAndEmojiH5');
|
|
205
216
|
}
|
|
217
|
+
const getAudioStream = async () => {
|
|
218
|
+
try {
|
|
219
|
+
stopAudioStream();
|
|
220
|
+
audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
221
|
+
hasAudioStream = true;
|
|
222
|
+
} catch (err) {
|
|
223
|
+
Log.e('Error accessing audio stream:', err);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const stopAudioStream = () => {
|
|
227
|
+
if (audioStream) {
|
|
228
|
+
audioStream.getTracks().forEach(track => track.stop());
|
|
229
|
+
audioStream = null;
|
|
230
|
+
hasAudioStream = false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
206
233
|
|
|
207
234
|
const audioShow = () => {
|
|
208
235
|
isInAudioMode.value = !isInAudioMode.value;
|
|
236
|
+
if (isInAudioMode.value && !hasAudioStream) {
|
|
237
|
+
getAudioStream();
|
|
238
|
+
}
|
|
209
239
|
placeholder.value = isInAudioMode.value ? TUITranslateService.t('TUIChat.按住说话') : TUITranslateService.t('TUIChat.请输入消息');
|
|
210
240
|
emit('blurToolAndEmojiH5');
|
|
211
241
|
}
|
|
@@ -228,6 +258,14 @@ const shouldShowAudio = computed(() => {
|
|
|
228
258
|
return isH5 && isInHumanService.value && (props.enableSendingAudio === 1 || (props.inputToolbarList !== undefined && props.inputToolbarList.some(item => item.presetId === INPUT_TOOLBAR_TYPE.AUDIO && item.isEnabled === 1)));
|
|
229
259
|
});
|
|
230
260
|
|
|
261
|
+
const handleVisibilityChange = () => {
|
|
262
|
+
if (document.visibilityState === 'hidden') {
|
|
263
|
+
stopAudioStream();
|
|
264
|
+
} else if (document.visibilityState === 'visible' && isInAudioMode.value) {
|
|
265
|
+
getAudioStream();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
231
269
|
defineExpose({
|
|
232
270
|
insertEmoji,
|
|
233
271
|
reEdit,
|
|
@@ -155,6 +155,7 @@ let recordTimer: any = null;
|
|
|
155
155
|
const audioWaveBars = ref(Array(24).fill({ height: 6 }));
|
|
156
156
|
let audioWaveAnimation = -1;
|
|
157
157
|
let pressStartTime: any = null;
|
|
158
|
+
const hasMicPermission = ref(false);
|
|
158
159
|
|
|
159
160
|
function onCurrentConversationIDUpdated(conversationID: string) {
|
|
160
161
|
if (currentConversationID.value !== conversationID) {
|
|
@@ -795,9 +796,11 @@ watch(
|
|
|
795
796
|
);
|
|
796
797
|
async function initRecorder() {
|
|
797
798
|
clearInterval(recordTimer);
|
|
798
|
-
recordTimer =
|
|
799
|
+
recordTimer = null;
|
|
799
800
|
recordTime.value = 0;
|
|
800
801
|
await recorder.value.stop();
|
|
802
|
+
isRecording.value = false;
|
|
803
|
+
recordTip.value = TUITranslateService.t("TUIChat.松开发送");
|
|
801
804
|
cancelAnimationFrame(audioWaveAnimation);
|
|
802
805
|
}
|
|
803
806
|
|
|
@@ -826,14 +829,19 @@ const startRecording = async(e) => {
|
|
|
826
829
|
isRecording.value = true;
|
|
827
830
|
pressStartTime = new Date();
|
|
828
831
|
recordCancel.value = false;
|
|
829
|
-
Recorder.getPermission().then(
|
|
832
|
+
Recorder.getPermission().then(() => {
|
|
833
|
+
hasMicPermission.value = true;
|
|
830
834
|
if (!isRecording.value) {
|
|
831
835
|
return;
|
|
832
836
|
}
|
|
833
|
-
if (recordTimer !==
|
|
837
|
+
if (recordTimer !== null) {
|
|
834
838
|
initRecorder();
|
|
835
839
|
}
|
|
840
|
+
// 提前获取音频流,避免开始录音时启动过长
|
|
836
841
|
recorder.value.start().then(() => {
|
|
842
|
+
if (!isRecording.value) {
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
837
845
|
updateRecordWave();
|
|
838
846
|
startRecordY = getRecordY(e);
|
|
839
847
|
recordTimer = setInterval(() => {
|
|
@@ -841,7 +849,6 @@ const startRecording = async(e) => {
|
|
|
841
849
|
}, 1000);
|
|
842
850
|
}, (error) => {
|
|
843
851
|
Log.e(`Error in recording ${error.name} : ${error.message}`);
|
|
844
|
-
isRecording.value = false;
|
|
845
852
|
let toastMessage = `${error.name} : ${error.message}`;
|
|
846
853
|
Toast({
|
|
847
854
|
message:toastMessage,
|
|
@@ -851,7 +858,6 @@ const startRecording = async(e) => {
|
|
|
851
858
|
initRecorder();
|
|
852
859
|
});
|
|
853
860
|
}, (error) => {
|
|
854
|
-
isRecording.value = false;
|
|
855
861
|
initRecorder();
|
|
856
862
|
Toast({
|
|
857
863
|
message:TUITranslateService.t("TUIChat.请检查麦克风访问权限"),
|
|
@@ -864,11 +870,10 @@ const startRecording = async(e) => {
|
|
|
864
870
|
};
|
|
865
871
|
|
|
866
872
|
const stopRecording = async () => {
|
|
867
|
-
isRecording.value = false;
|
|
868
873
|
const duration = recordTime.value;
|
|
869
874
|
initRecorder();
|
|
870
875
|
const pressDuration = Date.now() - pressStartTime;
|
|
871
|
-
if (pressDuration < 1000) {
|
|
876
|
+
if (pressDuration < 1000 && hasMicPermission.value) {
|
|
872
877
|
// 按压时间过短,还没开始录音就结束
|
|
873
878
|
Toast({
|
|
874
879
|
message: TUITranslateService.t("TUIChat.按压时间过短,请按压超过1秒"),
|
|
@@ -1179,8 +1184,7 @@ defineExpose({
|
|
|
1179
1184
|
overflow: hidden;
|
|
1180
1185
|
right: 0;
|
|
1181
1186
|
bottom: 0;
|
|
1182
|
-
background: linear-gradient(180deg,
|
|
1183
|
-
background: linear-gradient(180deg, color(display-p3 1 1 1 / 0.00) 0%, color(display-p3 1 1 1) 64.35%);
|
|
1187
|
+
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 64.35%);
|
|
1184
1188
|
display: flex;
|
|
1185
1189
|
flex-direction: column;
|
|
1186
1190
|
justify-content: flex-end;
|
|
@@ -1,60 +1,54 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{{ TUITranslateService.t("发送") }}
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
2
|
+
<div class="emojiDialog">
|
|
3
|
+
<ul ref="emojiPickerListRef" class="emojiDialogList">
|
|
4
|
+
<li
|
|
5
|
+
v-for="(childrenItem, childrenIndex) in currentEmojiList"
|
|
6
|
+
:key="childrenIndex"
|
|
7
|
+
class="emojiDialogList-item"
|
|
8
|
+
@click="select(childrenItem, childrenIndex)"
|
|
9
|
+
>
|
|
10
|
+
<img
|
|
11
|
+
class="emoji"
|
|
12
|
+
:src="BASIC_EMOJI_URL + BASIC_EMOJI_URL_MAPPING[childrenItem]"
|
|
13
|
+
>
|
|
14
|
+
</li>
|
|
15
|
+
</ul>
|
|
16
|
+
<div class="sendButtonContainer">
|
|
17
|
+
<div class="sendButton" @click="sendMessage">
|
|
18
|
+
{{ TUITranslateService.t("发送") }}
|
|
19
|
+
</div>
|
|
23
20
|
</div>
|
|
24
|
-
|
|
21
|
+
</div>
|
|
25
22
|
</template>
|
|
26
23
|
<script lang="ts" setup>
|
|
27
24
|
import vue from '../../../../adapter-vue';
|
|
28
|
-
import { IEmojiGroupList
|
|
25
|
+
import { IEmojiGroupList } from '../../../../interface';
|
|
29
26
|
const { ref, onMounted, onUnmounted } = vue;
|
|
30
27
|
import {
|
|
31
|
-
TUIChatService,
|
|
32
28
|
TUIStore,
|
|
33
29
|
StoreName,
|
|
34
30
|
IConversationModel,
|
|
35
31
|
TUITranslateService,
|
|
36
|
-
SendMessageParams,
|
|
37
32
|
} from '@tencentcloud/chat-uikit-engine';
|
|
38
33
|
import {
|
|
39
34
|
EMOJI_GROUP_LIST,
|
|
40
35
|
BASIC_EMOJI_URL_MAPPING,
|
|
41
36
|
convertKeyToEmojiName,
|
|
37
|
+
BASIC_EMOJI_URL,
|
|
38
|
+
filterEmojisInNonChineseEnv,
|
|
42
39
|
} from '../../emoji-config';
|
|
43
|
-
import { EMOJI_TYPE } from '.././../../../constant';
|
|
44
|
-
import { isPC, } from '../../../../utils/env';
|
|
45
40
|
|
|
46
41
|
const emits = defineEmits(['insertEmoji', 'onClose', 'sendMessage']);
|
|
47
42
|
const list = ref<IEmojiGroupList>(initEmojiList());
|
|
48
43
|
const currentConversation = ref();
|
|
49
44
|
const emojiPickerListRef = ref();
|
|
50
|
-
const currentTabIndex = ref<number>(0);
|
|
51
45
|
const currentEmojiList = ref<string[]>(list?.value[0]?.list);
|
|
52
|
-
const currentTabItem = ref<IEmojiGroup>(list?.value[0]);
|
|
53
46
|
|
|
54
47
|
onMounted(() => {
|
|
55
48
|
TUIStore.watch(StoreName.CONV, {
|
|
56
49
|
currentConversation: onCurrentConversationUpdate,
|
|
57
50
|
});
|
|
51
|
+
currentEmojiList.value = filterEmojisInNonChineseEnv(list.value[0].list);
|
|
58
52
|
});
|
|
59
53
|
|
|
60
54
|
onUnmounted(() => {
|
|
@@ -66,24 +60,10 @@ onUnmounted(() => {
|
|
|
66
60
|
const select = (item: any, index: number) => {
|
|
67
61
|
const options: any = {
|
|
68
62
|
emoji: { key: item, name: convertKeyToEmojiName(item) },
|
|
69
|
-
type:
|
|
63
|
+
type: 'basic',
|
|
64
|
+
url : BASIC_EMOJI_URL + BASIC_EMOJI_URL_MAPPING[item],
|
|
70
65
|
};
|
|
71
|
-
|
|
72
|
-
case EMOJI_TYPE.BASIC:
|
|
73
|
-
options.url = currentTabItem?.value?.url + BASIC_EMOJI_URL_MAPPING[item];
|
|
74
|
-
emits('insertEmoji', options);
|
|
75
|
-
|
|
76
|
-
break;
|
|
77
|
-
case EMOJI_TYPE.BIG:
|
|
78
|
-
// sendFaceMessage(index, currentTabItem.value);
|
|
79
|
-
break;
|
|
80
|
-
case EMOJI_TYPE.CUSTOM:
|
|
81
|
-
// sendFaceMessage(index, currentTabItem.value);
|
|
82
|
-
break;
|
|
83
|
-
default:
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
isPC && emits('onClose');
|
|
66
|
+
emits('insertEmoji', options);
|
|
87
67
|
};
|
|
88
68
|
|
|
89
69
|
function sendMessage(){
|
package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue
CHANGED
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
@click="select(childrenItem, childrenIndex)"
|
|
18
18
|
>
|
|
19
19
|
<img
|
|
20
|
-
v-if="currentTabItem.type === EMOJI_TYPE.BASIC"
|
|
21
20
|
class="emoji"
|
|
22
|
-
:src="
|
|
21
|
+
:src="BASIC_EMOJI_URL + BASIC_EMOJI_URL_MAPPING[childrenItem]"
|
|
23
22
|
>
|
|
24
23
|
<!-- <img-->
|
|
25
24
|
<!-- v-else-if="currentTabItem.type === EMOJI_TYPE.BIG"-->
|
|
@@ -76,9 +75,6 @@ import {
|
|
|
76
75
|
SendMessageParams,
|
|
77
76
|
TUITranslateService
|
|
78
77
|
} from '@tencentcloud/chat-uikit-engine';
|
|
79
|
-
import Icon from '../../../common/Icon.vue';
|
|
80
|
-
import faceIcon from '../../../../assets/face.svg';
|
|
81
|
-
import { EMOJI_TYPE } from '.././../../../constant';
|
|
82
78
|
import { isPC, isH5 } from '../../../../utils/env';
|
|
83
79
|
import { IEmojiGroupList, IEmojiGroup } from '../../../../interface';
|
|
84
80
|
import { isEnabledMessageReadReceiptGlobal } from '../../../../utils/utils';
|
|
@@ -86,22 +82,23 @@ import {
|
|
|
86
82
|
EMOJI_GROUP_LIST,
|
|
87
83
|
BASIC_EMOJI_URL_MAPPING,
|
|
88
84
|
convertKeyToEmojiName,
|
|
85
|
+
BASIC_EMOJI_URL,
|
|
86
|
+
filterEmojisInNonChineseEnv,
|
|
89
87
|
} from '../../emoji-config';
|
|
90
88
|
const { ref, onMounted, onUnmounted } = vue;
|
|
91
89
|
|
|
92
90
|
const emits = defineEmits(['insertEmoji', 'onClose', 'sendMessage']);
|
|
93
|
-
const currentTabIndex = ref<number>(0);
|
|
94
91
|
const currentConversation = ref();
|
|
95
92
|
const emojiPickerDialog = ref();
|
|
96
93
|
const emojiPickerListRef = ref();
|
|
97
|
-
const list = ref<IEmojiGroupList>(
|
|
98
|
-
const currentTabItem = ref<IEmojiGroup>(list?.value[0]);
|
|
94
|
+
const list = ref<IEmojiGroupList>(EMOJI_GROUP_LIST);
|
|
99
95
|
const currentEmojiList = ref<string[]>(list?.value[0]?.list);
|
|
100
96
|
|
|
101
97
|
onMounted(() => {
|
|
102
98
|
TUIStore.watch(StoreName.CONV, {
|
|
103
99
|
currentConversation: onCurrentConversationUpdate,
|
|
104
100
|
});
|
|
101
|
+
currentEmojiList.value = filterEmojisInNonChineseEnv(list.value[0].list);
|
|
105
102
|
});
|
|
106
103
|
|
|
107
104
|
onUnmounted(() => {
|
|
@@ -110,35 +107,13 @@ onUnmounted(() => {
|
|
|
110
107
|
});
|
|
111
108
|
});
|
|
112
109
|
|
|
113
|
-
const toggleEmojiTab = (index: number) => {
|
|
114
|
-
currentTabIndex.value = index;
|
|
115
|
-
currentTabItem.value = list?.value[index];
|
|
116
|
-
currentEmojiList.value = list?.value[index]?.list;
|
|
117
|
-
// web & h5 side scroll to top
|
|
118
|
-
emojiPickerListRef?.value && (emojiPickerListRef.value.scrollTop = 0);
|
|
119
|
-
|
|
120
|
-
};
|
|
121
|
-
|
|
122
110
|
const select = (item: any, index: number) => {
|
|
123
111
|
const options: any = {
|
|
124
112
|
emoji: { key: item, name: convertKeyToEmojiName(item) },
|
|
125
|
-
type:
|
|
113
|
+
type: 'basic',
|
|
126
114
|
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
options.url = currentTabItem?.value?.url + BASIC_EMOJI_URL_MAPPING[item];
|
|
130
|
-
emits('insertEmoji', options);
|
|
131
|
-
|
|
132
|
-
break;
|
|
133
|
-
case EMOJI_TYPE.BIG:
|
|
134
|
-
sendFaceMessage(index, currentTabItem.value);
|
|
135
|
-
break;
|
|
136
|
-
case EMOJI_TYPE.CUSTOM:
|
|
137
|
-
sendFaceMessage(index, currentTabItem.value);
|
|
138
|
-
break;
|
|
139
|
-
default:
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
115
|
+
options.url = BASIC_EMOJI_URL + BASIC_EMOJI_URL_MAPPING[item];
|
|
116
|
+
emits('insertEmoji', options);
|
|
142
117
|
isPC && emits('onClose');
|
|
143
118
|
};
|
|
144
119
|
|
|
@@ -159,16 +134,11 @@ const sendFaceMessage = (index: number, listItem: IEmojiGroup) => {
|
|
|
159
134
|
|
|
160
135
|
function sendMessage() {
|
|
161
136
|
emits('sendMessage');
|
|
162
|
-
|
|
163
137
|
}
|
|
164
138
|
|
|
165
139
|
function onCurrentConversationUpdate(conversation: IConversationModel) {
|
|
166
140
|
currentConversation.value = conversation;
|
|
167
141
|
}
|
|
168
|
-
|
|
169
|
-
function initEmojiList() {
|
|
170
|
-
return EMOJI_GROUP_LIST;
|
|
171
|
-
}
|
|
172
142
|
</script>
|
|
173
143
|
|
|
174
144
|
<style lang="scss" scoped src="./style/index.scss"></style>
|
|
@@ -2,7 +2,7 @@ import {Marked} from 'marked';
|
|
|
2
2
|
import Log from '../../../../../../utils/logger';
|
|
3
3
|
|
|
4
4
|
export const marked = new Marked(
|
|
5
|
-
{mangle: false, headerIds: false, breaks: true},
|
|
5
|
+
{mangle: false, headerIds: false, breaks: true, gfm: false, smartLists: true,},
|
|
6
6
|
{
|
|
7
7
|
renderer: {
|
|
8
8
|
image(this: any, href: string | null, title: string | null, text: string) {
|
|
@@ -24,9 +24,10 @@ export const marked = new Marked(
|
|
|
24
24
|
<video class="message-img video-web" src="${videoSrc}" onloadeddata="onMarkdownMediaLoad()" preload="auto" controls/>
|
|
25
25
|
</div>
|
|
26
26
|
</div>`;
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
return text
|
|
29
|
+
// 在段落中用 p 包裹,避免 \n\n 无法换行
|
|
30
|
+
return `<p>${text}</p>`;
|
|
30
31
|
},
|
|
31
32
|
link(this: any, href: string | null, title: string | null, text: string) {
|
|
32
33
|
if (href) {
|
|
@@ -57,7 +58,7 @@ const extractVideoSrc = (text: string) => {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export const parseMarkdown = (text: string) => {
|
|
60
|
-
//
|
|
61
|
-
let ret = marked.parse(text
|
|
61
|
+
// 不要手动替换,如把 \n\n 替换成 p 或者 <br/>,否则可能会导致Markdown结构被破坏,进而导致 bad case
|
|
62
|
+
let ret = marked.parse(text);
|
|
62
63
|
return typeof ret === 'string' ? ret : '';
|
|
63
64
|
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="isScrollButtonVisible"
|
|
4
|
-
class="scroll-button"
|
|
4
|
+
:class="['scroll-button', isPC ? 'scroll-button-pc' : '']"
|
|
5
5
|
@click="scrollToMessageListBottom"
|
|
6
6
|
>
|
|
7
7
|
<Icon
|
|
8
|
-
width="
|
|
9
|
-
height="
|
|
10
|
-
:file="
|
|
8
|
+
width="15px"
|
|
9
|
+
height="15px"
|
|
10
|
+
:file="isPC ? arrowDownIconWhite : arrowDownIcon"
|
|
11
11
|
/>
|
|
12
|
-
<div class="scroll-button-text">
|
|
12
|
+
<div v-if="scrollButtonContent" :class="isPC ? 'scroll-button-text-pc' : 'scroll-button-text'">
|
|
13
13
|
{{ scrollButtonContent }}
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
@@ -26,10 +26,11 @@ import {
|
|
|
26
26
|
TUITranslateService,
|
|
27
27
|
} from '@tencentcloud/chat-uikit-engine';
|
|
28
28
|
import Icon from '../../../common/Icon.vue';
|
|
29
|
-
import
|
|
29
|
+
import arrowDownIcon from '../../../../assets/arrow_down_icon.svg';
|
|
30
|
+
import arrowDownIconWhite from '../../../../assets/arrow_down_icon_white.svg';
|
|
30
31
|
import { getBoundingClientRect } from '@tencentcloud/universal-api';
|
|
31
32
|
import { JSONToObject } from '../../../../utils';
|
|
32
|
-
|
|
33
|
+
import { isPC } from '../../../../utils/env';
|
|
33
34
|
|
|
34
35
|
interface IEmits {
|
|
35
36
|
(key: 'scrollToLatestMessage'): void;
|
|
@@ -197,7 +198,6 @@ defineExpose({
|
|
|
197
198
|
bottom: 10px;
|
|
198
199
|
right: 10px;
|
|
199
200
|
width: auto;
|
|
200
|
-
height: 28px;
|
|
201
201
|
background: #fff;
|
|
202
202
|
border: 1px solid #e0e0e0;
|
|
203
203
|
box-shadow: 0 4px 12px -5px rgba(0, 0, 0, 0.1);
|
|
@@ -205,7 +205,8 @@ defineExpose({
|
|
|
205
205
|
flex-direction: row;
|
|
206
206
|
align-items: center;
|
|
207
207
|
justify-content: center;
|
|
208
|
-
border-radius:
|
|
208
|
+
border-radius: 20px;
|
|
209
|
+
padding: 8px;
|
|
209
210
|
cursor: pointer;
|
|
210
211
|
-webkit-tap-highlight-color: transparent;
|
|
211
212
|
|
|
@@ -216,4 +217,11 @@ defineExpose({
|
|
|
216
217
|
margin-right: 3px;
|
|
217
218
|
}
|
|
218
219
|
}
|
|
220
|
+
.scroll-button-pc {
|
|
221
|
+
background: #1c66e5;
|
|
222
|
+
}
|
|
223
|
+
.scroll-button-text-pc {
|
|
224
|
+
color: #ffffff;
|
|
225
|
+
font-size: 10px;
|
|
226
|
+
}
|
|
219
227
|
</style>
|
package/locales/en/TUIChat.ts
CHANGED
|
@@ -20,7 +20,7 @@ const TUIChat = {
|
|
|
20
20
|
'关闭阅读状态': 'Read status closed',
|
|
21
21
|
'管理员开启全员禁言': 'The admin enables Mute All',
|
|
22
22
|
'欢迎使用TUICallKit': 'Welcome to TUICallKit',
|
|
23
|
-
'回到最新位置': '
|
|
23
|
+
'回到最新位置': '',
|
|
24
24
|
'回复': 'Reply',
|
|
25
25
|
'回复详情': 'Replies',
|
|
26
26
|
'集成TUICallKit': ' Integrate TUICallKit ',
|
package/locales/en/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Submit",
|
|
8
8
|
"查看内容": "View content",
|
|
9
9
|
"请填写必填项": "Please fill in the required fields",
|
|
10
|
-
"Hi,我是": "Hi, I'm ",
|
|
11
10
|
"请输入内容":"Please enter the content",
|
|
12
11
|
"如果满意请给好评哦~":"If you're satisfied, please give a good review~",
|
|
13
12
|
"请对本次服务进行评价": "Please rate this service",
|
package/locales/fil/TUIChat.ts
CHANGED
|
@@ -42,7 +42,7 @@ const TUIChat = {
|
|
|
42
42
|
'该消息不存在': 'Ang mensaheng ito ay hindi umiiral',
|
|
43
43
|
'无法定位到原消息': 'Hindi mahanap ang orihinal na mensahe',
|
|
44
44
|
'对方正在输入': 'Ang kabilang panig ay nagta-type...',
|
|
45
|
-
'回到最新位置': '
|
|
45
|
+
'回到最新位置': '',
|
|
46
46
|
'条新消息': 'bagong mensahe',
|
|
47
47
|
'点此投诉': 'I-click dito para magreklamo',
|
|
48
48
|
'语音通话': 'Voice Call',
|
package/locales/fil/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Isumite",
|
|
8
8
|
"查看内容": "Tingnan ang Nilalaman",
|
|
9
9
|
"请填写必填项": "Mangyaring punan ang mga kinakailangang field",
|
|
10
|
-
"Hi,我是": "Hi, ako ",
|
|
11
10
|
"请输入内容":"Pakilagay ang nilalaman",
|
|
12
11
|
"如果满意请给好评哦~":"Kung nasiyahan ka, mangyaring magbigay ng magandang pagsusuri~",
|
|
13
12
|
"请对本次服务进行评价": "Mangyaring suriin ang serbisyong ito",
|
package/locales/id/TUIChat.ts
CHANGED
package/locales/id/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Kirim",
|
|
8
8
|
"查看内容": "Lihat konten",
|
|
9
9
|
"请填写必填项": "Harap isi bidang yang wajib diisi",
|
|
10
|
-
"Hi,我是": "Hai, saya adalah ",
|
|
11
10
|
"请输入内容":"Silakan masukkan konten",
|
|
12
11
|
"如果满意请给好评哦~":"Jika Anda puas, silakan berikan ulasan yang bagus~",
|
|
13
12
|
"请对本次服务进行评价": "Silakan beri penilaian untuk layanan ini",
|
package/locales/ja/TUIChat.ts
CHANGED
package/locales/ja/aidesk.ts
CHANGED
package/locales/ms/TUIChat.ts
CHANGED
|
@@ -47,7 +47,7 @@ const TUIChat = {
|
|
|
47
47
|
'该消息不存在': 'Mesej Ini Tidak Wujud',
|
|
48
48
|
'无法定位到原消息': 'Tidak Dapat Menemukan Mesej Asal',
|
|
49
49
|
'对方正在输入': 'Pihak Lain Sedang Menulis...',
|
|
50
|
-
'回到最新位置': '
|
|
50
|
+
'回到最新位置': '',
|
|
51
51
|
'条新消息': 'Mesej Baru',
|
|
52
52
|
'点此投诉': 'Klik Sini Untuk Aduan',
|
|
53
53
|
'语音通话': 'Panggilan Suara',
|
package/locales/ms/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Hantar",
|
|
8
8
|
"查看内容": "Lihat Kandungan",
|
|
9
9
|
"请填写必填项": "Sila isi ruangan yang wajib",
|
|
10
|
-
"Hi,我是": "Hai, saya ",
|
|
11
10
|
"请输入内容":"Sila masukkan kandungan",
|
|
12
11
|
"如果满意请给好评哦~":"Jika anda berpuas hati, sila berikan ulasan yang baik~",
|
|
13
12
|
"请对本次服务进行评价": "Sila beri penilaian untuk perkhidmatan ini",
|
package/locales/ru/TUIChat.ts
CHANGED
|
@@ -20,7 +20,7 @@ const TUIChat = {
|
|
|
20
20
|
'关闭阅读状态': 'Отключить статус прочтения',
|
|
21
21
|
'管理员开启全员禁言': 'Админ включил режим "Только чтение"',
|
|
22
22
|
'欢迎使用TUICallKit': 'Добро пожаловать в TUICallKit',
|
|
23
|
-
'回到最新位置': '
|
|
23
|
+
'回到最新位置': '',
|
|
24
24
|
'回复': 'Ответить',
|
|
25
25
|
'回复详情': 'Детали ответа',
|
|
26
26
|
'集成TUICallKit': 'Интеграция TUICallKit',
|
package/locales/ru/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Отправить",
|
|
8
8
|
"查看内容": "Просмотреть содержимое",
|
|
9
9
|
"请填写必填项": "Пожалуйста, заполните обязательные поля",
|
|
10
|
-
"Hi,我是": "Привет, я ",
|
|
11
10
|
"请输入内容":"Пожалуйста, введите содержание",
|
|
12
11
|
"如果满意请给好评哦~":"Если вы удовлетворены, пожалуйста, оставьте хороший отзыв~",
|
|
13
12
|
"请对本次服务进行评价": "Оцените обслуживание",
|
package/locales/th/TUIChat.ts
CHANGED
|
@@ -47,7 +47,7 @@ const TUIChat = {
|
|
|
47
47
|
'该消息不存在': 'ข้อความนี้ไม่มีอยู่',
|
|
48
48
|
'无法定位到原消息': 'ไม่สามารถระบุตำแหน่งข้อความต้นฉบับได้',
|
|
49
49
|
'对方正在输入': 'อีกฝ่ายกำลังพิมพ์...',
|
|
50
|
-
'回到最新位置': '
|
|
50
|
+
'回到最新位置': '',
|
|
51
51
|
'条新消息': 'ข้อความใหม่',
|
|
52
52
|
'点此投诉': 'คลิกที่นี่เพื่อร้องเรียน',
|
|
53
53
|
'语音通话': 'การโทรด้วยเสียง',
|
package/locales/th/aidesk.ts
CHANGED
package/locales/vi/TUIChat.ts
CHANGED
package/locales/vi/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Gửi",
|
|
8
8
|
"查看内容": "Xem nội dung",
|
|
9
9
|
"请填写必填项": "Vui lòng điền vào các mục bắt buộc",
|
|
10
|
-
"Hi,我是": "Xin chào, tôi là ",
|
|
11
10
|
"请输入内容":"Vui lòng nhập nội dung",
|
|
12
11
|
"如果满意请给好评哦~":"Nếu bạn hài lòng, hãy cho chúng tôi một đánh giá tốt nhé~",
|
|
13
12
|
"请对本次服务进行评价": "Vui lòng đánh giá dịch vụ này",
|
package/locales/zh_cn/aidesk.ts
CHANGED
package/locales/zh_tw/aidesk.ts
CHANGED
package/package.json
CHANGED
package/assets/double-arrow.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg t="1660053550964" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3181" width="200" height="200"><path d="M95.658667 461.354667a71.637333 71.637333 0 0 0 0 101.290666l365.696 365.696a71.637333 71.637333 0 0 0 101.290666 0l365.696-365.696a71.637333 71.637333 0 1 0-101.248-101.290666L512 776.448l-315.093333-315.093333a71.594667 71.594667 0 0 0-101.248 0z" p-id="3182" fill="#bfbfbf"></path><path d="M95.658667 95.658667a71.637333 71.637333 0 0 0 0 101.248l365.696 365.738666a71.594667 71.594667 0 0 0 101.290666 0l365.696-365.738666a71.637333 71.637333 0 0 0-101.248-101.248L512 410.709333 196.906667 95.658667a71.637333 71.637333 0 0 0-101.248 0z" p-id="3183" fill="#bfbfbf"></path></svg>
|