@tencentcloud/ai-desk-customer-vue 1.5.2 → 1.5.4
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 +18 -0
- package/README.md +316 -71
- package/assets/language_arrow_down.svg +3 -0
- package/assets/language_check.svg +3 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +215 -13
- package/components/CustomerServiceChat/emoji-config/index.ts +3 -2
- package/components/CustomerServiceChat/index-web.vue +87 -25
- package/components/CustomerServiceChat/message-input/index-web.vue +9 -2
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +11 -0
- package/components/CustomerServiceChat/message-input/message-input-quote/index.vue +31 -6
- package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +14 -4
- package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +19 -16
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +4 -4
- package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +10 -3
- package/components/CustomerServiceChat/message-list/index-web.vue +27 -14
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +6 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +20 -13
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/index.vue +1 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +73 -29
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-transfer-with-desc.vue +51 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue +18 -9
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +13 -2
- package/components/CustomerServiceChat/style/web.scss +2 -0
- package/components/CustomerServiceChat/utils/sendMessage.ts +5 -0
- package/constant.ts +21 -1
- package/interface.ts +16 -3
- package/locales/en/TUIChat.ts +2 -1
- package/locales/en/aidesk.ts +4 -4
- package/locales/en/index.ts +2 -2
- package/locales/en/time.ts +2 -2
- package/locales/fil/TUIChat.ts +1 -0
- package/locales/fil/index.ts +2 -2
- package/locales/fil/time.ts +2 -2
- package/locales/id/TUIChat.ts +161 -160
- package/locales/id/index.ts +2 -2
- package/locales/id/time.ts +2 -2
- package/locales/ja/TUIChat.ts +162 -161
- package/locales/ja/index.ts +2 -2
- package/locales/ja/time.ts +2 -2
- package/locales/ms/TUIChat.ts +162 -161
- package/locales/ms/index.ts +2 -2
- package/locales/ms/time.ts +2 -2
- package/locales/ru/TUIChat.ts +155 -154
- package/locales/ru/index.ts +2 -2
- package/locales/ru/time.ts +2 -2
- package/locales/th/TUIChat.ts +162 -161
- package/locales/th/index.ts +2 -2
- package/locales/th/time.ts +2 -2
- package/locales/vi/TUIChat.ts +153 -152
- package/locales/vi/index.ts +2 -2
- package/locales/vi/time.ts +2 -2
- package/locales/zh_cn/TUIChat.ts +1 -0
- package/locales/zh_cn/aidesk.ts +1 -1
- package/locales/zh_cn/index.ts +2 -2
- package/locales/zh_cn/time.ts +2 -2
- package/locales/zh_tw/TUIChat.ts +1 -0
- package/locales/zh_tw/aidesk.ts +1 -1
- package/locales/zh_tw/index.ts +2 -2
- package/locales/zh_tw/time.ts +2 -2
- package/package.json +5 -6
- package/server.ts +63 -10
- package/utils/index.ts +6 -13
- package/utils/utils.ts +96 -2
|
@@ -1,17 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="['chat-header', !isPC && 'chat-header-h5']">
|
|
3
|
-
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
<div class="chat-header-name">
|
|
4
|
+
<div
|
|
5
|
+
v-if="!isPC && props.canCloseChat"
|
|
6
|
+
:class="['chat-header-back', !isPC && 'chat-header-h5-back']"
|
|
7
|
+
@click="closeChat(currentConversation.conversationID)"
|
|
8
|
+
>
|
|
9
|
+
<Icon :file="backSVG" />
|
|
10
|
+
</div>
|
|
11
|
+
<div class="chat-header-container">
|
|
12
|
+
<Icon v-if="!isPC" width="32px" :file="customerAvatarMobile" />
|
|
13
|
+
<div :class="['chat-header-content', !isPC && 'chat-header-h5-content']">
|
|
14
|
+
{{ currentConversationName }}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
9
17
|
</div>
|
|
10
|
-
<div class="
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
<div v-if="props.enableMultilingual === 1" class="language-selector">
|
|
19
|
+
<div class="selected-language-option" @click="toggleDropdown">
|
|
20
|
+
{{ currentLanguageOption.name }}
|
|
21
|
+
<span class="arrow" :class="{ 'arrow-up': showDropdown }">
|
|
22
|
+
<Icon :file="arrowDown" width="12px" height="12px" />
|
|
23
|
+
</span>
|
|
14
24
|
</div>
|
|
25
|
+
|
|
26
|
+
<transition name="fade">
|
|
27
|
+
<div v-if="showDropdown" class="dropdown-popup">
|
|
28
|
+
<div
|
|
29
|
+
v-for="option in languageOptionList"
|
|
30
|
+
:key="option.code"
|
|
31
|
+
:class="['dropdown-item',currentLanguageOption.code === option.code ? 'dropdown-item-selected' : '']"
|
|
32
|
+
@click="selectLanguage(option)"
|
|
33
|
+
>
|
|
34
|
+
<div class="language">
|
|
35
|
+
<div class="language-code">
|
|
36
|
+
{{ option.codeForShow }}
|
|
37
|
+
</div>
|
|
38
|
+
<div class="language-name">
|
|
39
|
+
{{ option.name }}
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<Icon v-if="currentLanguageOption.code === option.code" :file="languageSelectedIcon" width="20px" height="20px" />
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</transition>
|
|
15
47
|
</div>
|
|
16
48
|
</div>
|
|
17
49
|
</template>
|
|
@@ -25,24 +57,51 @@ import {
|
|
|
25
57
|
} from '@tencentcloud/chat-uikit-engine';
|
|
26
58
|
import Icon from '../../common/Icon.vue';
|
|
27
59
|
import backSVG from '../../../assets/back.svg';
|
|
60
|
+
import arrowDown from '../../../assets/language_arrow_down.svg';
|
|
28
61
|
import customerAvatarMobile from '../../../assets/customer_avatar_mobile.png';
|
|
62
|
+
import languageSelectedIcon from '../../../assets/language_check.svg';
|
|
29
63
|
import { isPC } from '../../../utils/env';
|
|
30
64
|
import state from '../../../utils/state';
|
|
65
|
+
import { SUPPORTED_LANGUAGES } from '../../../constant';
|
|
31
66
|
const { ref, onMounted, onUnmounted } = vue;
|
|
32
67
|
|
|
33
68
|
interface IProps {
|
|
34
69
|
canCloseChat?: boolean;
|
|
70
|
+
currentLang?: string;
|
|
71
|
+
enableMultilingual: number;
|
|
72
|
+
langList?: Array<string>;
|
|
73
|
+
}
|
|
74
|
+
interface ILanguage {
|
|
75
|
+
name: string;
|
|
76
|
+
code: string;
|
|
77
|
+
codeForShow: string;
|
|
35
78
|
}
|
|
36
79
|
|
|
37
|
-
const emits = defineEmits(['closeChat']);
|
|
80
|
+
const emits = defineEmits(['closeChat','changeLanguage']);
|
|
38
81
|
const currentConversation = ref<IConversationModel>();
|
|
39
82
|
const currentConversationName = ref('');
|
|
40
83
|
const isTyping = ref(false);
|
|
41
|
-
|
|
84
|
+
const showDropdown = ref(false);
|
|
85
|
+
const languageOptionList = ref<Array<ILanguage>>([]);
|
|
86
|
+
const currentLanguageOption = ref<ILanguage>({name:'',code:'',codeForShow:''});
|
|
87
|
+
|
|
42
88
|
const props = withDefaults(defineProps<IProps>(), {
|
|
43
89
|
canCloseChat: true,
|
|
90
|
+
currentLang: '',
|
|
91
|
+
enableMultilingual: 0,
|
|
92
|
+
langList: () => [],
|
|
44
93
|
});
|
|
45
94
|
|
|
95
|
+
if (props.enableMultilingual === 1) {
|
|
96
|
+
languageOptionList.value = props.langList
|
|
97
|
+
.map(key => ({
|
|
98
|
+
code: key,
|
|
99
|
+
codeForShow: SUPPORTED_LANGUAGES[key].codeForShow,
|
|
100
|
+
name: SUPPORTED_LANGUAGES[key].name,
|
|
101
|
+
}));
|
|
102
|
+
currentLanguageOption.value = languageOptionList.value.find(option => option.code === props.currentLang);
|
|
103
|
+
}
|
|
104
|
+
|
|
46
105
|
onMounted(() => {
|
|
47
106
|
TUIStore.watch(StoreName.CONV, {
|
|
48
107
|
currentConversation: onCurrentConversationUpdated,
|
|
@@ -84,8 +143,24 @@ function onTypingStatusUpdated(status: boolean) {
|
|
|
84
143
|
}
|
|
85
144
|
}
|
|
86
145
|
}
|
|
146
|
+
|
|
147
|
+
function toggleDropdown() {
|
|
148
|
+
showDropdown.value = !showDropdown.value
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function selectLanguage(languageOption) {
|
|
152
|
+
showDropdown.value = false;
|
|
153
|
+
currentLanguageOption.value = languageOption;
|
|
154
|
+
emits('changeLanguage', languageOption.code);
|
|
155
|
+
}
|
|
87
156
|
</script>
|
|
88
157
|
<style lang="scss" scoped>
|
|
158
|
+
.chat-header-name {
|
|
159
|
+
display: flex;
|
|
160
|
+
flex-direction: row;
|
|
161
|
+
flex: 1;
|
|
162
|
+
min-width: 0;
|
|
163
|
+
}
|
|
89
164
|
.chat-header {
|
|
90
165
|
display: flex;
|
|
91
166
|
min-width: 0;
|
|
@@ -93,9 +168,12 @@ function onTypingStatusUpdated(status: boolean) {
|
|
|
93
168
|
align-items: center;
|
|
94
169
|
justify-content: space-between;
|
|
95
170
|
border-bottom:1px solid #f3f4f7;
|
|
171
|
+
font-family: PingFangSC-Regular;
|
|
172
|
+
width: 100%;
|
|
96
173
|
|
|
97
174
|
&-container {
|
|
98
175
|
display: flex;
|
|
176
|
+
flex: 1;
|
|
99
177
|
min-width: 0;
|
|
100
178
|
flex-direction: row;
|
|
101
179
|
justify-content: flex-start;
|
|
@@ -113,6 +191,7 @@ function onTypingStatusUpdated(status: boolean) {
|
|
|
113
191
|
overflow: hidden;
|
|
114
192
|
white-space: nowrap;
|
|
115
193
|
text-overflow: ellipsis;
|
|
194
|
+
min-width: 0;
|
|
116
195
|
}
|
|
117
196
|
|
|
118
197
|
&-back,
|
|
@@ -137,7 +216,130 @@ function onTypingStatusUpdated(status: boolean) {
|
|
|
137
216
|
}
|
|
138
217
|
|
|
139
218
|
&-content {
|
|
140
|
-
|
|
219
|
+
margin: 0 20px 0 10px;
|
|
141
220
|
}
|
|
142
221
|
}
|
|
222
|
+
|
|
223
|
+
.language-selector {
|
|
224
|
+
position: relative;
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
user-select: none;
|
|
227
|
+
flex-shrink: 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.selected-language-option {
|
|
231
|
+
padding: 8px 6px;
|
|
232
|
+
border-radius: 4px;
|
|
233
|
+
display: flex;
|
|
234
|
+
justify-content: flex-end;
|
|
235
|
+
align-items: center;
|
|
236
|
+
font-size: 12px;
|
|
237
|
+
color: #0F1014;
|
|
238
|
+
gap: 5px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.arrow {
|
|
242
|
+
transition: transform 0.2s;
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.arrow-up {
|
|
247
|
+
transform: rotate(180deg);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.dropdown-popup {
|
|
251
|
+
position: absolute;
|
|
252
|
+
top: 100%;
|
|
253
|
+
right: 10px;
|
|
254
|
+
font-size: 12px;
|
|
255
|
+
max-width: 200px;
|
|
256
|
+
max-height: 400px;
|
|
257
|
+
border-radius: 8px;
|
|
258
|
+
background-color: white;
|
|
259
|
+
box-shadow: 0px 1px 8px 0px var(---Black-8, rgba(0, 0, 0, 0.06)), 0px 4px 12px 0px var(---Black-8, rgba(0, 0, 0, 0.06)), 0px 10px 30px 0px var(---Black-8, rgba(0, 0, 0, 0.06));
|
|
260
|
+
z-index: 1000;
|
|
261
|
+
margin-top: 4px;
|
|
262
|
+
padding: 8px 0px;
|
|
263
|
+
overflow-y: auto;
|
|
264
|
+
scrollbar-width: 4px;
|
|
265
|
+
scrollbar-color: #E7EAEF;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.dropdown-popup::-webkit-scrollbar {
|
|
269
|
+
width: 4px;
|
|
270
|
+
}
|
|
271
|
+
.dropdown-popup::-webkit-scrollbar-track {
|
|
272
|
+
background: transparent;
|
|
273
|
+
}
|
|
274
|
+
.dropdown-popup::-webkit-scrollbar-thumb {
|
|
275
|
+
background-color: #E7EAEF;
|
|
276
|
+
border-radius: 2px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.dropdown-item {
|
|
280
|
+
transition: background-color 0.2s;
|
|
281
|
+
display: flex;
|
|
282
|
+
flex-direction: row;
|
|
283
|
+
padding: 5px 12px;
|
|
284
|
+
justify-content: space-between;
|
|
285
|
+
align-items: center;
|
|
286
|
+
width: 100%;
|
|
287
|
+
box-sizing: border-box;
|
|
288
|
+
.language {
|
|
289
|
+
display: flex;
|
|
290
|
+
gap: 8px;
|
|
291
|
+
align-items: center;
|
|
292
|
+
flex: 1;
|
|
293
|
+
min-width: 0;
|
|
294
|
+
font-size: 12px;
|
|
295
|
+
.language-code {
|
|
296
|
+
color: #71798A;
|
|
297
|
+
display: flex;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
align-items: center;
|
|
300
|
+
border-radius: 2px;
|
|
301
|
+
border: 1px solid rgba(114, 122, 138, 0.20);
|
|
302
|
+
padding: 0 8px;
|
|
303
|
+
font-weight: 600;
|
|
304
|
+
min-width: 12px;
|
|
305
|
+
flex-shrink: 0;
|
|
306
|
+
}
|
|
307
|
+
.language-name {
|
|
308
|
+
color: #0F1014;
|
|
309
|
+
white-space: nowrap;
|
|
310
|
+
overflow: hidden;
|
|
311
|
+
text-overflow: ellipsis;
|
|
312
|
+
flex: 1;
|
|
313
|
+
min-width: 0;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.dropdown-item:hover,.dropdown-item-selected {
|
|
319
|
+
background-color: #F2F6FF;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.dropdown-item-selected {
|
|
323
|
+
position: relative;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.dropdown-item-selected::after {
|
|
327
|
+
content: '';
|
|
328
|
+
position: absolute;
|
|
329
|
+
left: 0;
|
|
330
|
+
right: 0;
|
|
331
|
+
top: 0;
|
|
332
|
+
bottom: 0;
|
|
333
|
+
background-color: #F2F6FF;
|
|
334
|
+
z-index: -1;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.fade-enter-active, .fade-leave-active {
|
|
338
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.fade-enter, .fade-leave-to {
|
|
342
|
+
opacity: 0;
|
|
343
|
+
transform: translateY(-10px);
|
|
344
|
+
}
|
|
143
345
|
</style>
|
|
@@ -2,9 +2,10 @@ 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
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';
|
|
4
4
|
import { default as emojiCNLocales } from './locales/zh_cn';
|
|
5
|
+
import { default as emojiENLocales } from './locales/en';
|
|
5
6
|
import { IEmojiGroupList } from '../../../interface';
|
|
6
7
|
import { EMOJI_TYPE } from '../../../constant';
|
|
7
|
-
import
|
|
8
|
+
import state from '../../../utils/state.js';
|
|
8
9
|
|
|
9
10
|
const hasCustomBasicEmoji = CUSTOM_BASIC_EMOJI_URL && Object.keys(CUSTOM_BASIC_EMOJI_URL_MAPPING).length;
|
|
10
11
|
|
|
@@ -32,7 +33,7 @@ const EMOJI_GROUP_LIST: IEmojiGroupList = [
|
|
|
32
33
|
*/
|
|
33
34
|
const convertKeyToEmojiName = (key: string): string => {
|
|
34
35
|
// WeChat does not support emoji translation
|
|
35
|
-
return
|
|
36
|
+
return state.get('currentLanguage') == 'zh' ? emojiCNLocales[key] : emojiENLocales[key];
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="['tui-chat', !isPC && 'tui-chat-h5']">
|
|
2
|
+
<div :class="['tui-chat', !isPC && 'tui-chat-h5']" :key="currentLanguage">
|
|
3
3
|
<div
|
|
4
4
|
v-if="currentConversationID"
|
|
5
5
|
:class="['tui-chat', !isPC && 'tui-chat-h5']"
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
!isPC && 'tui-chat-H5-header'
|
|
11
11
|
]"
|
|
12
12
|
:canCloseChat="props.canCloseChat"
|
|
13
|
+
:enableMultilingual="props.enableMultilingual"
|
|
14
|
+
:langList="languageForShowList"
|
|
15
|
+
:currentLang="currentLanguage"
|
|
13
16
|
@closeChat="closeChat"
|
|
17
|
+
@changeLanguage="changeLanguage"
|
|
14
18
|
/>
|
|
15
19
|
<MessageList
|
|
16
20
|
ref="messageListRef"
|
|
@@ -99,14 +103,13 @@ import MessageInputToolbar from './message-input-toolbar/index-web.vue';
|
|
|
99
103
|
import EmojiDialog from './message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue';
|
|
100
104
|
import { isH5, isPC } from '../../utils/env';
|
|
101
105
|
import { ToolbarButtonModel, ToolbarDisplayType, InputToolbarModel, QuickOrderModel } from '../../interface';
|
|
102
|
-
import { isSupportedLang } from '../../utils/';
|
|
103
106
|
import Log from '../../utils/logger';
|
|
104
107
|
import MessageToolbarButton from './message-toolbar-button/index.vue';
|
|
105
108
|
import TUILocales from '../../locales';
|
|
106
109
|
import { Toast, TOAST_TYPE } from '../common/Toast/index-web';
|
|
107
110
|
import state from '../../utils/state.js';
|
|
108
111
|
import { switchReadStatus,isNonEmptyObject } from '../../utils/utils';
|
|
109
|
-
|
|
112
|
+
import { getCountryForTimezone } from 'countries-and-timezones';
|
|
110
113
|
const { ref, onMounted, onUnmounted, computed } = vue;
|
|
111
114
|
|
|
112
115
|
interface IProps {
|
|
@@ -129,6 +132,8 @@ interface IProps {
|
|
|
129
132
|
showReadStatus?: number;
|
|
130
133
|
showTyping?: number;
|
|
131
134
|
bottomQuickOrder?: QuickOrderModel;
|
|
135
|
+
enableMultilingual?: number;
|
|
136
|
+
langList?: Array<string>;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
const emits = defineEmits(['closeChat']);
|
|
@@ -144,6 +149,10 @@ const toolShowH5 = ref(false);
|
|
|
144
149
|
const languages = Object.keys(TUILocales);
|
|
145
150
|
const quoteMessage = ref<IMessageModel>();
|
|
146
151
|
const showBottomQuickOrder = ref(false);
|
|
152
|
+
const currentLanguage = ref('');
|
|
153
|
+
const languageForShowList = ref<Array<string>>([]);
|
|
154
|
+
let timezone = '';
|
|
155
|
+
let countryID = '';
|
|
147
156
|
const props = withDefaults(defineProps<IProps>(), {
|
|
148
157
|
canCloseChat: true,
|
|
149
158
|
SDKAppID: 0,
|
|
@@ -161,6 +170,8 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
161
170
|
staffNickName: '',
|
|
162
171
|
userNickName: '',
|
|
163
172
|
showTyping: 0,
|
|
173
|
+
enableMultilingual: 0,
|
|
174
|
+
langList: () => [],
|
|
164
175
|
});
|
|
165
176
|
|
|
166
177
|
const loginCustomerUIKit = () => {
|
|
@@ -185,6 +196,12 @@ const loginCustomerUIKit = () => {
|
|
|
185
196
|
})
|
|
186
197
|
}
|
|
187
198
|
|
|
199
|
+
const getTimeZoneAndCountry = () => {
|
|
200
|
+
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
201
|
+
const country = getCountryForTimezone(timezone);
|
|
202
|
+
countryID = country && country.id ? country.id : '';
|
|
203
|
+
}
|
|
204
|
+
|
|
188
205
|
const convertLanguageToLowercase = (language) => {
|
|
189
206
|
let lowercase = language.toLowerCase();
|
|
190
207
|
if (lowercase === 'zh-cn' || lowercase === 'zh_cn') {
|
|
@@ -195,27 +212,53 @@ const convertLanguageToLowercase = (language) => {
|
|
|
195
212
|
return lowercase;
|
|
196
213
|
}
|
|
197
214
|
|
|
215
|
+
const getValidLanguage = (language: string) => {
|
|
216
|
+
let validLanguage = '';
|
|
217
|
+
if (props.enableMultilingual === 1 && languageForShowList.value.length !== 0) {
|
|
218
|
+
if (languageForShowList.value.includes(language)) {
|
|
219
|
+
validLanguage = language;
|
|
220
|
+
} else {
|
|
221
|
+
// choose default language (languageForShowList.value[0] for uikit) if language is not supported
|
|
222
|
+
validLanguage = languageForShowList.value[0];
|
|
223
|
+
}
|
|
224
|
+
} else if (languages.includes(language)) {
|
|
225
|
+
validLanguage = language;
|
|
226
|
+
} else {
|
|
227
|
+
if (props.userLang !== ''){
|
|
228
|
+
Log.w(`userLang:${props.userLang} is not supported`);
|
|
229
|
+
}
|
|
230
|
+
validLanguage = 'en';
|
|
231
|
+
}
|
|
232
|
+
return validLanguage;
|
|
233
|
+
}
|
|
234
|
+
|
|
198
235
|
const initLanguage = () => {
|
|
199
236
|
Log.i(`initLanguage ${props.userLang}`);
|
|
200
237
|
TUITranslateService.provideLanguages({ ...TUILocales });
|
|
201
238
|
TUITranslateService.useI18n();
|
|
239
|
+
if (props.enableMultilingual === 1) {
|
|
240
|
+
languageForShowList.value = props.langList.filter(language => languages.includes(language));
|
|
241
|
+
}
|
|
202
242
|
let language;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
language = 'en';
|
|
208
|
-
} else {
|
|
209
|
-
language = userLang;
|
|
243
|
+
try {
|
|
244
|
+
const prevLanguage = localStorage.getItem('AIDesk_language');
|
|
245
|
+
if (prevLanguage) {
|
|
246
|
+
language = prevLanguage;
|
|
210
247
|
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
248
|
+
} catch {
|
|
249
|
+
Log.w('No Previous Language');
|
|
250
|
+
}
|
|
251
|
+
if (!language) {
|
|
252
|
+
if (props.userLang !== '') {
|
|
253
|
+
let userLang = convertLanguageToLowercase(props.userLang);
|
|
254
|
+
language = getValidLanguage(userLang);
|
|
215
255
|
} else {
|
|
216
|
-
|
|
256
|
+
let navigatorLang = convertLanguageToLowercase(navigator.language);
|
|
257
|
+
language = getValidLanguage(navigatorLang);
|
|
217
258
|
}
|
|
218
|
-
}
|
|
259
|
+
}
|
|
260
|
+
currentLanguage.value = language;
|
|
261
|
+
state.set('currentLanguage', language);
|
|
219
262
|
TUITranslateService.changeLanguage(language);
|
|
220
263
|
}
|
|
221
264
|
|
|
@@ -244,7 +287,7 @@ try {
|
|
|
244
287
|
const userContext = TUILogin.getContext();
|
|
245
288
|
if (userContext.userID == '' && props.SDKAppID !==0 && props.userID !=='' && props.userSig !==''){
|
|
246
289
|
loginCustomerUIKit();
|
|
247
|
-
if (props.robotLang && !
|
|
290
|
+
if (props.robotLang && !languages.includes(props.robotLang)) {
|
|
248
291
|
Log.w(`robotLang:${props.robotLang} is not supported`);
|
|
249
292
|
}
|
|
250
293
|
}
|
|
@@ -252,6 +295,7 @@ try {
|
|
|
252
295
|
setAvatarNickName();
|
|
253
296
|
setShowReadStatus();
|
|
254
297
|
setShowTyping();
|
|
298
|
+
getTimeZoneAndCountry();
|
|
255
299
|
if (isNonEmptyObject(props.bottomQuickOrder)) {
|
|
256
300
|
showBottomQuickOrder.value = true;
|
|
257
301
|
}
|
|
@@ -355,14 +399,7 @@ function onCurrentConversationIDUpdate(conversationID: string) {
|
|
|
355
399
|
currentConversationID.value = conversationID;
|
|
356
400
|
|
|
357
401
|
// The TUICustomerServicePlugin plugin determines if the current conversation is a customer service conversation, then sets chatType and activates the conversation.
|
|
358
|
-
|
|
359
|
-
serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
|
|
360
|
-
method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
|
|
361
|
-
params: {
|
|
362
|
-
conversationID: conversationID,
|
|
363
|
-
robotLang: props.robotLang && isSupportedLang(props.robotLang) ? props.robotLang : undefined,
|
|
364
|
-
},
|
|
365
|
-
});
|
|
402
|
+
activeConversation();
|
|
366
403
|
}
|
|
367
404
|
|
|
368
405
|
function emojiShow(){
|
|
@@ -401,6 +438,31 @@ function onQuoteMessageUpdated(options?: {
|
|
|
401
438
|
function closeBottomQuickOrder() {
|
|
402
439
|
showBottomQuickOrder.value = false;
|
|
403
440
|
}
|
|
441
|
+
|
|
442
|
+
function changeLanguage(languageCode: string) {
|
|
443
|
+
Log.l(`multilingual: change language to ${languageCode}`);
|
|
444
|
+
TUITranslateService.changeLanguage(languageCode).then(() => {
|
|
445
|
+
currentLanguage.value = languageCode;
|
|
446
|
+
try {
|
|
447
|
+
localStorage.setItem('AIDesk_language', languageCode);
|
|
448
|
+
} catch {
|
|
449
|
+
Log.w("Failed to set language to localStorage.");
|
|
450
|
+
}
|
|
451
|
+
activeConversation();
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
function activeConversation() {
|
|
455
|
+
TUICore.callService({
|
|
456
|
+
serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
|
|
457
|
+
method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
|
|
458
|
+
params: {
|
|
459
|
+
conversationID: currentConversationID.value,
|
|
460
|
+
robotLang: props.robotLang && languages.includes(props.robotLang) ? props.robotLang : currentLanguage.value === 'zh_tw' ? 'zh-TW' : currentLanguage.value,
|
|
461
|
+
country: countryID,
|
|
462
|
+
timezone: timezone,
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
}
|
|
404
466
|
</script>
|
|
405
467
|
|
|
406
468
|
<style scoped lang="scss" src="./style/index.scss">
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="message-input-wrapper">
|
|
3
|
-
<MessageInputQuote
|
|
3
|
+
<MessageInputQuote
|
|
4
|
+
@getQuoteMessageCloudCustomData="getQuoteMessageCloudCustomData"
|
|
5
|
+
/>
|
|
4
6
|
<div
|
|
5
7
|
:class="[
|
|
6
8
|
'message-input-container',
|
|
@@ -96,6 +98,7 @@ const editor = ref<InstanceType<typeof MessageInputEditor>>();
|
|
|
96
98
|
const currentConversation = ref<IConversationModel>();
|
|
97
99
|
const h5Dialog = ref<HTMLElement>();
|
|
98
100
|
const showSendButton = ref(false);
|
|
101
|
+
let quoteMessageCloudCustomData:string = '';
|
|
99
102
|
|
|
100
103
|
onMounted(() => {
|
|
101
104
|
// document.addEventListener('click', handleClick);
|
|
@@ -136,13 +139,17 @@ const sendMessage = async () => {
|
|
|
136
139
|
}
|
|
137
140
|
return editor;
|
|
138
141
|
});
|
|
139
|
-
await sendMessages(editorContentList, currentConversation.value);
|
|
142
|
+
await sendMessages(editorContentList, currentConversation.value, quoteMessageCloudCustomData);
|
|
140
143
|
// 注意这里不要 emit 'sendMessage',避免写出死循环
|
|
141
144
|
emit('messageSent');
|
|
142
145
|
editor.value?.resetEditor();
|
|
143
146
|
showSendButton.value = false;
|
|
144
147
|
};
|
|
145
148
|
|
|
149
|
+
const getQuoteMessageCloudCustomData = (cloudCustomData: string) => {
|
|
150
|
+
quoteMessageCloudCustomData = cloudCustomData;
|
|
151
|
+
};
|
|
152
|
+
|
|
146
153
|
const insertEmoji = (emoji: any) => {
|
|
147
154
|
editor.value?.addEmoji(emoji);
|
|
148
155
|
showSendButton.value = true;
|
|
@@ -121,6 +121,17 @@ function onQuoteMessageUpdated(options?: {
|
|
|
121
121
|
type: string;
|
|
122
122
|
}) {
|
|
123
123
|
currentQuoteMessage.value = options;
|
|
124
|
+
if (options && options.message) {
|
|
125
|
+
focusEditor();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function focusEditor() {
|
|
130
|
+
if (isH5 && editorDom.value) {
|
|
131
|
+
editorDom.value.focus();
|
|
132
|
+
} else if (editor) {
|
|
133
|
+
editor.commands.focus()
|
|
134
|
+
}
|
|
124
135
|
}
|
|
125
136
|
|
|
126
137
|
onMounted(() => {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
<Icon
|
|
22
22
|
class="input-quote-close-icon"
|
|
23
23
|
:file="closeIcon"
|
|
24
|
-
width="
|
|
25
|
-
height="
|
|
24
|
+
width="14px"
|
|
25
|
+
height="14px"
|
|
26
26
|
@onClick="cancelQuote"
|
|
27
27
|
/>
|
|
28
28
|
</div>
|
|
@@ -42,6 +42,8 @@ import closeIcon from '../../../../assets/close-quote-icon.svg';
|
|
|
42
42
|
import { isPC,isH5 } from '../../../../utils/env';
|
|
43
43
|
import { transformTextWithKeysToEmojiNames } from '../../emoji-config';
|
|
44
44
|
import { InputDisplayType } from '../../../../interface';
|
|
45
|
+
import { getQuoteContentForDesk } from '../../../../utils/utils';
|
|
46
|
+
import { MessageQuoteTypeEnum } from '../../message-list/message-elements/message-quote/interface';
|
|
45
47
|
const { ref, computed, onMounted, onUnmounted } = vue;
|
|
46
48
|
|
|
47
49
|
interface IProps {
|
|
@@ -54,6 +56,9 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
54
56
|
|
|
55
57
|
const TYPES = TUIChatEngine.TYPES;
|
|
56
58
|
const quoteMessage = ref<IMessageModel>();
|
|
59
|
+
const quoteMessageType = ref<number>(0);
|
|
60
|
+
|
|
61
|
+
const emits = defineEmits(['getQuoteMessageCloudCustomData']);
|
|
57
62
|
|
|
58
63
|
onMounted(() => {
|
|
59
64
|
TUIStore.watch(StoreName.CHAT, {
|
|
@@ -74,30 +79,39 @@ const quoteContentText = computed(() => {
|
|
|
74
79
|
_quoteContentText = transformTextWithKeysToEmojiNames(
|
|
75
80
|
quoteMessage.value.payload?.text,
|
|
76
81
|
);
|
|
82
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_TEXT;
|
|
77
83
|
break;
|
|
78
84
|
case TYPES.MSG_IMAGE:
|
|
79
85
|
_quoteContentText = TUITranslateService.t('TUIChat.图片');
|
|
86
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_IMAGE;
|
|
80
87
|
break;
|
|
81
88
|
case TYPES.MSG_AUDIO:
|
|
82
89
|
_quoteContentText = TUITranslateService.t('TUIChat.语音');
|
|
90
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_SOUND;
|
|
83
91
|
break;
|
|
84
92
|
case TYPES.MSG_VIDEO:
|
|
85
93
|
_quoteContentText = TUITranslateService.t('TUIChat.视频');
|
|
94
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_VIDEO;
|
|
86
95
|
break;
|
|
87
96
|
case TYPES.MSG_FILE:
|
|
88
97
|
_quoteContentText = TUITranslateService.t('TUIChat.文件');
|
|
98
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_FILE;
|
|
89
99
|
break;
|
|
90
100
|
case TYPES.MSG_CUSTOM:
|
|
91
|
-
_quoteContentText =
|
|
101
|
+
_quoteContentText = getQuoteContentForDesk(quoteMessage.value);
|
|
102
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_CUSTOM;
|
|
92
103
|
break;
|
|
93
104
|
case TYPES.MSG_FACE:
|
|
94
105
|
_quoteContentText = TUITranslateService.t('TUIChat.表情');
|
|
106
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_FACE;
|
|
95
107
|
break;
|
|
96
108
|
case TYPES.MSG_MERGER:
|
|
97
109
|
_quoteContentText = TUITranslateService.t('TUIChat.聊天记录');
|
|
110
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_MERGER;
|
|
98
111
|
break;
|
|
99
112
|
default:
|
|
100
113
|
_quoteContentText = TUITranslateService.t('TUIChat.消息');
|
|
114
|
+
quoteMessageType.value = MessageQuoteTypeEnum.TYPE_NONE;
|
|
101
115
|
break;
|
|
102
116
|
}
|
|
103
117
|
return _quoteContentText;
|
|
@@ -114,10 +128,21 @@ function onQuoteMessageUpdated(options?: {
|
|
|
114
128
|
message: IMessageModel;
|
|
115
129
|
type: string;
|
|
116
130
|
}) {
|
|
117
|
-
if (options
|
|
131
|
+
if (options && options.message && options.type === 'quote') {
|
|
118
132
|
quoteMessage.value = options.message;
|
|
133
|
+
const quoteMessageCloudCustomData = JSON.stringify({
|
|
134
|
+
messageReply: {
|
|
135
|
+
messageAbstract: quoteContentText.value,
|
|
136
|
+
messageID: quoteMessage.value.ID,
|
|
137
|
+
messageSender: quoteMessage.value.from,
|
|
138
|
+
messageTime: quoteMessage.value.time,
|
|
139
|
+
messageType: quoteMessageType.value,
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
emits('getQuoteMessageCloudCustomData', quoteMessageCloudCustomData);
|
|
119
143
|
} else {
|
|
120
144
|
quoteMessage.value = undefined;
|
|
145
|
+
emits('getQuoteMessageCloudCustomData', undefined);
|
|
121
146
|
}
|
|
122
147
|
}
|
|
123
148
|
</script>
|
|
@@ -152,7 +177,7 @@ function onQuoteMessageUpdated(options?: {
|
|
|
152
177
|
.input-quote-content-h5 {
|
|
153
178
|
display: flex;
|
|
154
179
|
justify-content: space-between;
|
|
155
|
-
background-color:
|
|
180
|
+
background-color: rgba(255, 255, 255, 0.5);
|
|
156
181
|
padding: 8px 16px 8px 8px;
|
|
157
182
|
font-size: 12px;
|
|
158
183
|
align-items: center;
|
|
@@ -197,6 +222,6 @@ function onQuoteMessageUpdated(options?: {
|
|
|
197
222
|
.input-quote-container-h5 {
|
|
198
223
|
@extend %common-container-style;
|
|
199
224
|
width:100%;
|
|
200
|
-
margin:
|
|
225
|
+
margin: 5px 0 5px 0px;
|
|
201
226
|
}
|
|
202
227
|
</style>
|