@tencentcloud/ai-desk-customer-vue 1.6.2 → 1.6.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 +19 -0
- package/components/CustomerServiceChat/customer-queue-page/index.vue +138 -0
- package/components/CustomerServiceChat/feedback-modal/index.vue +20 -8
- package/components/CustomerServiceChat/index-web.vue +29 -7
- package/components/CustomerServiceChat/message-input/index-web.vue +3 -4
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +3 -3
- package/components/CustomerServiceChat/message-list/index-web.vue +7 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +33 -15
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +9 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +4 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +1 -0
- package/locales/en/aidesk.ts +4 -0
- package/locales/fil/aidesk.ts +4 -0
- package/locales/id/aidesk.ts +4 -0
- package/locales/ja/aidesk.ts +4 -0
- package/locales/ms/aidesk.ts +4 -0
- package/locales/ru/aidesk.ts +4 -0
- package/locales/th/aidesk.ts +4 -0
- package/locales/vi/aidesk.ts +4 -0
- package/locales/zh_cn/aidesk.ts +4 -0
- package/locales/zh_tw/aidesk.ts +4 -0
- package/package.json +1 -1
- package/utils/utils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
## 1.6.4 @2025.11.25
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
- 支持区分用户端上行消息的来源(用户输入或用户点击分支选项)
|
|
5
|
+
|
|
6
|
+
### Fixed
|
|
7
|
+
- vue2 已知问题
|
|
8
|
+
|
|
9
|
+
## 1.6.3 @2025.11.13
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
- 转人工排队阶段支持展示排队信息,提升用户体验。
|
|
13
|
+
- 转人工成功后支持展示人工客服的昵称和头像。
|
|
14
|
+
- 优化 markdown 图片尺寸。
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- 没有消息时显示查看更多。
|
|
18
|
+
- 流式消息的字体跟主字体不一致的问题。
|
|
19
|
+
|
|
1
20
|
## 1.6.2 @2025.10.30
|
|
2
21
|
|
|
3
22
|
### Features
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="customer-queue">
|
|
3
|
+
<div class="customer-queue-header">
|
|
4
|
+
{{ TUITranslateService.t("AIDesk.排队等待中") }}...
|
|
5
|
+
</div>
|
|
6
|
+
<div class="customer-queue-info">
|
|
7
|
+
{{ TUITranslateService.t("AIDesk.排队等待话术") }}
|
|
8
|
+
</div>
|
|
9
|
+
<div class="customer-queue-container">
|
|
10
|
+
<div class="customer-queue-content-title">
|
|
11
|
+
{{ TUITranslateService.t("AIDesk.当前前方排队人数") }}
|
|
12
|
+
</div>
|
|
13
|
+
<div class="customer-queue-content-number">
|
|
14
|
+
{{ props.queueNumber }}
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="customer-queue-end-button">
|
|
18
|
+
<div :class="['customer-queue-end-button-content', isClicked ? 'button-clicked' : '']" @click="endQueuing">
|
|
19
|
+
{{ TUITranslateService.t("AIDesk.结束排队") }}
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
<script lang="ts" setup>
|
|
25
|
+
import vue from '../../../adapter-vue';
|
|
26
|
+
const { ref, onMounted, onUnmounted } = vue;
|
|
27
|
+
import { IConversationModel, StoreName, TUIChatService, TUIStore, TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
28
|
+
import { CUSTOM_MESSAGE_SRC } from '../../../constant';
|
|
29
|
+
import { getTo, isEnabledMessageReadReceiptGlobal } from '../../../utils/utils';
|
|
30
|
+
const currentConversation = ref<IConversationModel>();
|
|
31
|
+
const isClicked = ref(false);
|
|
32
|
+
const props = defineProps({
|
|
33
|
+
queueNumber: {
|
|
34
|
+
type: Number,
|
|
35
|
+
default: 0
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
onMounted(() => {
|
|
39
|
+
TUIStore.watch(StoreName.CONV, {
|
|
40
|
+
currentConversation: onCurrentConversationUpdate,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
onUnmounted(() => {
|
|
45
|
+
TUIStore.unwatch(StoreName.CONV, {
|
|
46
|
+
currentConversation: onCurrentConversationUpdate,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
51
|
+
currentConversation.value = conversation;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const endQueuing = () => {
|
|
55
|
+
if (isClicked.value) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
isClicked.value = true;
|
|
59
|
+
TUIChatService.sendCustomMessage({
|
|
60
|
+
to: getTo(currentConversation.value),
|
|
61
|
+
conversationType: currentConversation.value.type,
|
|
62
|
+
payload: {
|
|
63
|
+
data: JSON.stringify({
|
|
64
|
+
customerServicePlugin: 0,
|
|
65
|
+
src: CUSTOM_MESSAGE_SRC.USER_END_CONVERSATION,
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
69
|
+
},{ onlineUserOnly:true });
|
|
70
|
+
}
|
|
71
|
+
</script>
|
|
72
|
+
<style lang="scss">
|
|
73
|
+
.customer-queue {
|
|
74
|
+
width: 100%;
|
|
75
|
+
height: 100%;
|
|
76
|
+
max-width: 100%;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
box-sizing: border-box;
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
}
|
|
82
|
+
.customer-queue-header {
|
|
83
|
+
height: 52px;
|
|
84
|
+
background-color: #1C66E5;
|
|
85
|
+
color: white;
|
|
86
|
+
line-height: 52px;
|
|
87
|
+
padding-left: 20px;
|
|
88
|
+
}
|
|
89
|
+
.customer-queue-info {
|
|
90
|
+
padding: 20px;
|
|
91
|
+
color: #666;
|
|
92
|
+
}
|
|
93
|
+
.customer-queue-container {
|
|
94
|
+
flex: 1;
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
color: #1C66E5;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.customer-queue-content-title {
|
|
103
|
+
font-size: 20px;
|
|
104
|
+
margin-bottom: 10px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.customer-queue-content-number {
|
|
108
|
+
font-size: 40px;
|
|
109
|
+
font-weight: bold;
|
|
110
|
+
}
|
|
111
|
+
.customer-queue-end-button {
|
|
112
|
+
color: white;
|
|
113
|
+
padding: 8px 23px;
|
|
114
|
+
border-radius: 10px;
|
|
115
|
+
}
|
|
116
|
+
.customer-queue-end-button {
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
margin-bottom: 20px;
|
|
121
|
+
&-content {
|
|
122
|
+
background: #1c66e5;
|
|
123
|
+
color: white;
|
|
124
|
+
padding: 8px 23px;
|
|
125
|
+
border-radius: 10px;
|
|
126
|
+
width: fit-content;
|
|
127
|
+
min-width: 70px;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
display: flex;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
.button-clicked {
|
|
134
|
+
cursor: default;
|
|
135
|
+
background: #cccccc;
|
|
136
|
+
color: #666666;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
{{ TUITranslateService.t("AIDesk.感谢您的反馈,我们会持续优化改进") }}
|
|
9
9
|
</span>
|
|
10
10
|
</div>
|
|
11
|
-
<
|
|
11
|
+
<div @click="closeFeedbackModal">
|
|
12
|
+
<Icon :file="DialogCloseIcon" width="20px" height="20px"/>
|
|
13
|
+
</div>
|
|
12
14
|
</div>
|
|
13
15
|
|
|
14
16
|
<div class="dialog-select-container">
|
|
@@ -86,6 +88,7 @@
|
|
|
86
88
|
</template>
|
|
87
89
|
<script lang="ts">
|
|
88
90
|
import vue from '../../../adapter-vue';
|
|
91
|
+
import { vueVersion } from '../../../adapter-vue-web';
|
|
89
92
|
import Icon from '../../common/Icon.vue';
|
|
90
93
|
import { StoreName, TUIStore, TUITranslateService, TUIChatService } from '@tencentcloud/chat-uikit-engine';
|
|
91
94
|
import GreenCheck from '../../../assets/green_check.svg';
|
|
@@ -178,7 +181,20 @@ export default {
|
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
const dialogButtonClick = (item) => {
|
|
181
|
-
|
|
184
|
+
if (vueVersion === 3) {
|
|
185
|
+
// vue 3
|
|
186
|
+
item.isSelected = !item.isSelected;
|
|
187
|
+
} else {
|
|
188
|
+
// vue 2.6 or vue 2.7
|
|
189
|
+
const index = feedbackButtonList.value.findIndex(i => i.id === item.id);
|
|
190
|
+
if (index === -1) return;
|
|
191
|
+
const newList = feedbackButtonList.value.slice();
|
|
192
|
+
newList[index] = {
|
|
193
|
+
...newList[index],
|
|
194
|
+
isSelected: !newList[index].isSelected
|
|
195
|
+
};
|
|
196
|
+
feedbackButtonList.value = newList;
|
|
197
|
+
}
|
|
182
198
|
};
|
|
183
199
|
|
|
184
200
|
const isSubmitEnabled = computed(() => {
|
|
@@ -212,12 +228,6 @@ export default {
|
|
|
212
228
|
const onDislike = (messageInfo) => {
|
|
213
229
|
_messageInfo = messageInfo;
|
|
214
230
|
};
|
|
215
|
-
|
|
216
|
-
expose({
|
|
217
|
-
onLike,
|
|
218
|
-
onDislike,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
231
|
return {
|
|
222
232
|
isPC,
|
|
223
233
|
GreenCheck,
|
|
@@ -230,6 +240,8 @@ export default {
|
|
|
230
240
|
submit,
|
|
231
241
|
isSubmitEnabled,
|
|
232
242
|
feedbackButtonListFromStore,
|
|
243
|
+
onLike,
|
|
244
|
+
onDislike,
|
|
233
245
|
};
|
|
234
246
|
}
|
|
235
247
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="['tui-chat', !isPC && 'tui-chat-h5']" :key="currentLanguage">
|
|
3
3
|
<div
|
|
4
|
-
v-if="currentConversationID"
|
|
4
|
+
v-if="currentConversationID && (!props.showQueuePage || queueNumber < 0 || queueNumber === undefined)"
|
|
5
5
|
:class="['tui-chat', !isPC && 'tui-chat-h5']"
|
|
6
6
|
>
|
|
7
7
|
<ChatHeader
|
|
@@ -94,6 +94,9 @@
|
|
|
94
94
|
@close="() => { showFeedbackModal = false }"
|
|
95
95
|
/>
|
|
96
96
|
</div>
|
|
97
|
+
<div v-if="props.showQueuePage && queueNumber >= 0" :class="['tui-chat', !isPC && 'tui-chat-h5']">
|
|
98
|
+
<CustomerQueuePage :queueNumber="queueNumber"/>
|
|
99
|
+
</div>
|
|
97
100
|
</div>
|
|
98
101
|
</template>
|
|
99
102
|
<script lang="ts" setup>
|
|
@@ -122,6 +125,7 @@ import state from '../../utils/state.js';
|
|
|
122
125
|
import { switchReadStatus,isNonEmptyObject } from '../../utils/utils';
|
|
123
126
|
import { getCountryForTimezone } from 'countries-and-timezones';
|
|
124
127
|
import FeedbackModal from './feedback-modal/index.vue';
|
|
128
|
+
import CustomerQueuePage from './customer-queue-page/index.vue';
|
|
125
129
|
const { ref, onMounted, onUnmounted, computed } = vue;
|
|
126
130
|
|
|
127
131
|
interface IProps {
|
|
@@ -134,12 +138,13 @@ interface IProps {
|
|
|
134
138
|
toolbarButtonList?: ToolbarButtonModel[];
|
|
135
139
|
showAvatar?: number;
|
|
136
140
|
robotAvatar?: string;
|
|
137
|
-
|
|
141
|
+
memberAvatar?: string;
|
|
138
142
|
userAvatar?: string;
|
|
139
143
|
showNickName?: number;
|
|
140
144
|
robotNickName?: string;
|
|
141
|
-
|
|
145
|
+
memberNickName?: string;
|
|
142
146
|
userNickName?: string;
|
|
147
|
+
enableUnifiedMemberProfile?: number;
|
|
143
148
|
inputToolbarList?: InputToolbarModel[];
|
|
144
149
|
showReadStatus?: number;
|
|
145
150
|
showTyping?: number;
|
|
@@ -151,6 +156,7 @@ interface IProps {
|
|
|
151
156
|
enableURLDetection?: number;
|
|
152
157
|
headerConfig?: IHeaderConfig;
|
|
153
158
|
enableSendingAudio?: number;
|
|
159
|
+
showQueuePage?: number;
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
const emits = defineEmits(['closeChat']);
|
|
@@ -170,6 +176,7 @@ const currentLanguage = ref('');
|
|
|
170
176
|
const languageForShowList = ref<Array<string>>([]);
|
|
171
177
|
const feedbackModalRef = ref();
|
|
172
178
|
const showFeedbackModal = ref(false);
|
|
179
|
+
const queueNumber = ref(-1);
|
|
173
180
|
let timezone = '';
|
|
174
181
|
let countryID = '';
|
|
175
182
|
const props = withDefaults(defineProps<IProps>(), {
|
|
@@ -182,12 +189,13 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
182
189
|
showReadStatus: 1,
|
|
183
190
|
showAvatar: 1,
|
|
184
191
|
robotAvatar: '',
|
|
185
|
-
|
|
192
|
+
memberAvatar: '',
|
|
186
193
|
userAvatar: '',
|
|
187
194
|
showNickName: 0,
|
|
188
195
|
robotNickName: '',
|
|
189
|
-
|
|
196
|
+
memberNickName: '',
|
|
190
197
|
userNickName: '',
|
|
198
|
+
enableUnifiedMemberProfile: 1,
|
|
191
199
|
showTyping: 0,
|
|
192
200
|
enableMultilingual: 0,
|
|
193
201
|
enableFeedback: 0,
|
|
@@ -195,6 +203,7 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
195
203
|
langList: () => [],
|
|
196
204
|
enableURLDetection: 0,
|
|
197
205
|
enableSendingAudio: 0,
|
|
206
|
+
showQueuePage: 0,
|
|
198
207
|
});
|
|
199
208
|
|
|
200
209
|
const loginCustomerUIKit = () => {
|
|
@@ -290,11 +299,12 @@ const setAvatarNickName = () => {
|
|
|
290
299
|
showAvatar: props.showAvatar,
|
|
291
300
|
showNickName: props.showNickName,
|
|
292
301
|
userAvatar: props.userAvatar,
|
|
293
|
-
|
|
302
|
+
memberAvatar: props.memberAvatar,
|
|
294
303
|
robotAvatar: props.robotAvatar,
|
|
295
304
|
userNickName: props.userNickName,
|
|
296
|
-
|
|
305
|
+
memberNickName: props.memberNickName,
|
|
297
306
|
robotNickName: props.robotNickName,
|
|
307
|
+
enableUnifiedMemberProfile: props.enableUnifiedMemberProfile,
|
|
298
308
|
});
|
|
299
309
|
}
|
|
300
310
|
|
|
@@ -346,6 +356,9 @@ onMounted(() => {
|
|
|
346
356
|
TUIStore.watch(StoreName.CHAT, {
|
|
347
357
|
quoteMessage: onQuoteMessageUpdated,
|
|
348
358
|
});
|
|
359
|
+
TUIStore.watch(StoreName.CUSTOM, {
|
|
360
|
+
isQueuing: onIsQueuingUpdate,
|
|
361
|
+
});
|
|
349
362
|
});
|
|
350
363
|
|
|
351
364
|
onUnmounted(() => {
|
|
@@ -358,6 +371,9 @@ onUnmounted(() => {
|
|
|
358
371
|
TUIStore.unwatch(StoreName.CHAT, {
|
|
359
372
|
quoteMessage: onQuoteMessageUpdated,
|
|
360
373
|
});
|
|
374
|
+
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
375
|
+
isQueuing: onIsQueuingUpdate,
|
|
376
|
+
});
|
|
361
377
|
});
|
|
362
378
|
|
|
363
379
|
const isInputToolbarShow = computed<boolean>(() => {
|
|
@@ -501,6 +517,12 @@ function onDislike(messageInfo: Object) {
|
|
|
501
517
|
showFeedbackModal.value = true;
|
|
502
518
|
feedbackModalRef.value.onDislike(messageInfo);
|
|
503
519
|
}
|
|
520
|
+
|
|
521
|
+
function onIsQueuingUpdate(data: {conversationID: string, value: number}) {
|
|
522
|
+
if (data && data.conversationID === currentConversationID.value) {
|
|
523
|
+
queueNumber.value = data.value;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
504
526
|
</script>
|
|
505
527
|
|
|
506
528
|
<style scoped lang="scss" src="./style/index.scss">
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
:enableInput="props.enableInput"
|
|
21
21
|
:enableTyping="props.enableTyping"
|
|
22
22
|
:enableDragUpload="props.enableDragUpload"
|
|
23
|
-
:
|
|
23
|
+
:isInAudioModeFromProps="isInAudioMode"
|
|
24
24
|
:shouldShowToolbar="shouldShowToolbar"
|
|
25
25
|
:shouldShowEmoji="shouldShowEmoji"
|
|
26
26
|
:shouldShowAudio="shouldShowAudio"
|
|
@@ -60,7 +60,7 @@ import MessageInputButton from './message-input-button.vue';
|
|
|
60
60
|
import MessageInputQuote from './message-input-quote/index.vue';
|
|
61
61
|
import { sendMessages, sendTyping } from '../utils/sendMessage';
|
|
62
62
|
import { transformTextWithEmojiNamesToKeys } from '../emoji-config';
|
|
63
|
-
import { isPC,isH5 } from '../../../utils/env';
|
|
63
|
+
import { isPC, isH5 } from '../../../utils/env';
|
|
64
64
|
import Icon from '../../common/Icon.vue';
|
|
65
65
|
import emojiIcon from '../../../assets/emoji.png';
|
|
66
66
|
import toolIcon from '../../../assets/more_tools.png';
|
|
@@ -68,9 +68,8 @@ import sendButtonIcon from '../../../assets/send_button_h5.svg';
|
|
|
68
68
|
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
|
-
import { onUnmounted } from 'vue';
|
|
72
71
|
import Log from '../../../utils/logger';
|
|
73
|
-
const { ref, onMounted, onBeforeUnmount, computed } = vue;
|
|
72
|
+
const { ref, onMounted, onBeforeUnmount, computed, onUnmounted } = vue;
|
|
74
73
|
|
|
75
74
|
const props = defineProps({
|
|
76
75
|
isMuted: {
|
|
@@ -116,7 +116,7 @@ const props = defineProps({
|
|
|
116
116
|
type: Boolean,
|
|
117
117
|
default: true,
|
|
118
118
|
},
|
|
119
|
-
|
|
119
|
+
isInAudioModeFromProps:{
|
|
120
120
|
type: Boolean,
|
|
121
121
|
default: false,
|
|
122
122
|
},
|
|
@@ -146,7 +146,7 @@ let editor: Editor | null = null;
|
|
|
146
146
|
const fileMap = new Map<string, any>();
|
|
147
147
|
const recorder = ref();
|
|
148
148
|
const recordTime = ref(0);
|
|
149
|
-
const isInAudioMode = ref(props.
|
|
149
|
+
const isInAudioMode = ref(props.isInAudioModeFromProps);
|
|
150
150
|
const isRecording = ref(false);
|
|
151
151
|
let startRecordY = 0;
|
|
152
152
|
const recordCancel = ref(false);
|
|
@@ -194,7 +194,7 @@ function focusEditor() {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
watch(
|
|
197
|
-
() => [props.
|
|
197
|
+
() => [props.isInAudioModeFromProps],
|
|
198
198
|
(newValue) => {
|
|
199
199
|
isInAudioMode.value = newValue[0];
|
|
200
200
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
@click="onMessageListBackgroundClick"
|
|
17
17
|
>
|
|
18
18
|
<p
|
|
19
|
-
v-if="!isCompleted"
|
|
19
|
+
v-if="!isCompleted && messageList && messageList.length"
|
|
20
20
|
class="message-more"
|
|
21
21
|
@click="getHistoryMessageList"
|
|
22
22
|
>
|
|
@@ -382,6 +382,11 @@ function onNewMessageList(list: IMessageModel[]) {
|
|
|
382
382
|
} else if (data.src === CUSTOM_MESSAGE_SRC.SEAT_STATUS) {
|
|
383
383
|
updateCustomStore("canEndConversation", { conversationID, value: true });
|
|
384
384
|
if (data.content.command === "updateSeatStatus") {
|
|
385
|
+
if (data.content.content === 'queuing') {
|
|
386
|
+
updateCustomStore("isQueuing", { conversationID, value: data.content.waitingQueueLength });
|
|
387
|
+
} else if (data.content.content !== 'WaitingForAgentAnswering') {
|
|
388
|
+
updateCustomStore("isQueuing", { conversationID, value: -1 });
|
|
389
|
+
}
|
|
385
390
|
if (data.content.content === 'inSeat') {
|
|
386
391
|
updateCustomStore("isInHumanService", { conversationID, value: true });
|
|
387
392
|
} else if (data.content.content === 'outSeat') {
|
|
@@ -396,6 +401,7 @@ function onNewMessageList(list: IMessageModel[]) {
|
|
|
396
401
|
}
|
|
397
402
|
} else if (data.src === CUSTOM_MESSAGE_SRC.NO_SEAT_ONLINE || data.src === CUSTOM_MESSAGE_SRC.TIMEOUT || data.src === CUSTOM_MESSAGE_SRC.END) {
|
|
398
403
|
updateCustomStore("canEndConversation", { conversationID, value: false });
|
|
404
|
+
updateCustomStore("isQueuing", { conversationID, value: -1 });
|
|
399
405
|
} else if (data.src === CUSTOM_MESSAGE_SRC.GET_FEEDBACK_MENU) {
|
|
400
406
|
TUIStore.update(StoreName.CUSTOM, "feedbackTags", data.content.menu);
|
|
401
407
|
}
|
|
@@ -207,13 +207,24 @@ const {
|
|
|
207
207
|
showAvatar,
|
|
208
208
|
showNickName,
|
|
209
209
|
robotAvatar,
|
|
210
|
-
|
|
210
|
+
memberAvatar,
|
|
211
211
|
userAvatar,
|
|
212
212
|
robotNickName,
|
|
213
|
-
|
|
213
|
+
memberNickName,
|
|
214
214
|
userNickName,
|
|
215
|
+
enableUnifiedMemberProfile,
|
|
215
216
|
} = state.get('avatarNickName');
|
|
216
217
|
let prevStatus = ReadState.Unread;
|
|
218
|
+
|
|
219
|
+
const getCloudCustomData = () => {
|
|
220
|
+
try {
|
|
221
|
+
return JSONToObject(message.value.cloudCustomData);
|
|
222
|
+
} catch (e) {
|
|
223
|
+
return {};
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
let cloudCustomData = getCloudCustomData();
|
|
227
|
+
|
|
217
228
|
const isDisplayUnplayMark = computed<boolean>(() => {
|
|
218
229
|
return (
|
|
219
230
|
message.value.flow === 'in'
|
|
@@ -252,22 +263,23 @@ const computedShowAINote = computed(() => {
|
|
|
252
263
|
return props.enableAINote === 1 && (state.get('currentLanguage') === 'zh' || state.get('currentLanguage') === 'en') && canShowAINote(message.value.cloudCustomData);
|
|
253
264
|
});
|
|
254
265
|
|
|
255
|
-
function
|
|
256
|
-
|
|
257
|
-
const jsonObj = JSONToObject(cloudCustomData);
|
|
258
|
-
return jsonObj.hasOwnProperty("role") && jsonObj.role === "robot";
|
|
259
|
-
} catch (e) {
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
266
|
+
function isFromSeat() {
|
|
267
|
+
return cloudCustomData.hasOwnProperty("role") && cloudCustomData.role === "seat";
|
|
262
268
|
}
|
|
263
269
|
|
|
264
270
|
const avatarUrl = computed(() => {
|
|
265
271
|
let url = '';
|
|
266
272
|
if (message.value.flow === 'in') {
|
|
267
|
-
if (
|
|
268
|
-
|
|
273
|
+
if (isFromSeat()) {
|
|
274
|
+
if (enableUnifiedMemberProfile) {
|
|
275
|
+
url = memberAvatar || message.value.avatar;
|
|
276
|
+
} else if (cloudCustomData.memberInfo && cloudCustomData.memberInfo.memberAvatar) {
|
|
277
|
+
url = cloudCustomData.memberInfo.memberAvatar
|
|
278
|
+
} else {
|
|
279
|
+
url = message.value.avatar;
|
|
280
|
+
}
|
|
269
281
|
} else {
|
|
270
|
-
url =
|
|
282
|
+
url = robotAvatar || message.value.avatar;
|
|
271
283
|
}
|
|
272
284
|
} else {
|
|
273
285
|
url = userAvatar || message.value.avatar || '';
|
|
@@ -278,10 +290,16 @@ const avatarUrl = computed(() => {
|
|
|
278
290
|
const nickName = computed(() => {
|
|
279
291
|
let nick = '';
|
|
280
292
|
if (message.value.flow === 'in') {
|
|
281
|
-
if (
|
|
282
|
-
|
|
293
|
+
if (isFromSeat()) {
|
|
294
|
+
if (enableUnifiedMemberProfile) {
|
|
295
|
+
nick = memberNickName || props.content.showName;
|
|
296
|
+
} else if (cloudCustomData.memberInfo && cloudCustomData.memberInfo.memberNickName) {
|
|
297
|
+
nick = cloudCustomData.memberInfo.memberNickName;
|
|
298
|
+
} else {
|
|
299
|
+
nick = props.content.showName;
|
|
300
|
+
}
|
|
283
301
|
} else {
|
|
284
|
-
nick =
|
|
302
|
+
nick = robotNickName || props.content.showName;
|
|
285
303
|
}
|
|
286
304
|
} else {
|
|
287
305
|
nick = userNickName || props.content.showName;
|
|
@@ -11,7 +11,7 @@ export const marked = new Marked(
|
|
|
11
11
|
class="image-container"
|
|
12
12
|
onclick="onMarkdownImageClicked('${safeHref}')"
|
|
13
13
|
style="cursor:pointer;" >
|
|
14
|
-
<img src="${href}" alt="${text}" onload="onMarkdownMediaLoad()"/>
|
|
14
|
+
<img src="${href}" alt="${text}" onload="onMarkdownMediaLoad()" style="max-width: 100%; height: auto; max-height: 300px; object-fit: contain; margin: 8px 0;"/>
|
|
15
15
|
</div>
|
|
16
16
|
`;
|
|
17
17
|
},
|
|
@@ -130,9 +130,17 @@ export default {
|
|
|
130
130
|
return props.message && JSONToObject(props.message?.payload?.data);
|
|
131
131
|
});
|
|
132
132
|
const sendTextMessage = async (payload: TextMessagePayload, cloudCustomData?: string) => {
|
|
133
|
+
let cloudCustomDataFinal = cloudCustomData || '';
|
|
134
|
+
if (!cloudCustomDataFinal) {
|
|
135
|
+
cloudCustomDataFinal = JSON.stringify({
|
|
136
|
+
deskExtInfo: {
|
|
137
|
+
isPresetContent : 1
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
133
141
|
await TUIChatService.sendTextMessage({
|
|
134
142
|
payload,
|
|
135
|
-
cloudCustomData:
|
|
143
|
+
cloudCustomData: cloudCustomDataFinal,
|
|
136
144
|
needReadReceipt: isEnabledMessageReadReceiptGlobal()
|
|
137
145
|
});
|
|
138
146
|
emit('messageSent');
|
|
@@ -62,7 +62,10 @@ export default {
|
|
|
62
62
|
taskID: props.payload.taskInfo?.taskID,
|
|
63
63
|
nodeID: props.payload.taskInfo?.nodeID,
|
|
64
64
|
env: props.payload.taskInfo?.env,
|
|
65
|
-
}
|
|
65
|
+
},
|
|
66
|
+
deskExtInfo: {
|
|
67
|
+
isPresetContent: 1
|
|
68
|
+
},
|
|
66
69
|
});
|
|
67
70
|
}
|
|
68
71
|
emit('input-click', branch, cloudCustomData);
|
package/locales/en/aidesk.ts
CHANGED
|
@@ -35,5 +35,9 @@ const AIDesk = {
|
|
|
35
35
|
"userID 长度不能超过45字节": "The length of the userID cannot exceed 45 bytes",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "We appreciate your feedback. Please share any suggestions to help us improve.",
|
|
37
37
|
"该回复由AI生成,内容仅供参考": "AI-Generated Content",
|
|
38
|
+
"排队等待中": "In Queue",
|
|
39
|
+
"排队等待话术": "We apologize for the wait. All agents are currently assisting other customers. You will be connected shortly. Thank you for your patience.",
|
|
40
|
+
"当前前方排队人数": "Queue Position",
|
|
41
|
+
"结束排队": "Exit Queue"
|
|
38
42
|
}
|
|
39
43
|
export default AIDesk;
|
package/locales/fil/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "Ang UserID ay hindi dapat maglaman ng 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "Ang haba ng UserID ay hindi dapat lumampas sa 45 bytes",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "Pinahahalagahan namin ang iyong feedback. Mangyaring ibahagi ang anumang mga mungkahi upang matulungan kaming mapabuti.",
|
|
37
|
+
"排队等待中": "Nasa pila na",
|
|
38
|
+
"排队等待话术": "Paumanhin, puno na ang aming mga customer service. Mangyaring maghintay nang matiisin, tutulungan ka namin agad. Salamat sa iyong pag-unawa.",
|
|
39
|
+
"当前前方排队人数": "Bilang ng mga tao sa unahan sa pila",
|
|
40
|
+
"结束排队": "Umalis sa pila",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/id/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserID tidak boleh mengandung 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "Panjang UserID tidak boleh melebihi 45 byte",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "Kami menghargai masukan Anda. Silakan bagikan saran apa pun untuk membantu kami meningkatkan layanan.",
|
|
37
|
+
"排队等待中": "Sedang antre",
|
|
38
|
+
"排队等待话术": "Mohon maaf, seluruh customer service kami sedang sibuk. Silakan tunggu dengan sabar, kami akan segera membantu Anda. Terima kasih atas pengertiannya.",
|
|
39
|
+
"当前前方排队人数": "Jumlah orang di depan antrian saat ini",
|
|
40
|
+
"结束排队": "Keluar dari antrian",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/ja/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserIDに'administrator'を含めることはできません",
|
|
35
35
|
"userID 长度不能超过45字节": "UserIDの長さは45バイトを超えてはいけません",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "皆様からのフィードバックをお待ちしております。改善に役立つご提案がございましたら、ぜひお聞かせください。",
|
|
37
|
+
"排队等待中": "ただいま待機中",
|
|
38
|
+
"排队等待话术": "申し訳ございません、現在すべてのカスタマーサービスが対応中です。しばらくお待ちください。ご理解いただきありがとうございます。",
|
|
39
|
+
"当前前方排队人数": "現在の前方待機人数",
|
|
40
|
+
"结束排队": "待機を終了する",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/ms/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserID tidak boleh mengandung 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "Panjang UserID tidak boleh melebihi 45 bait",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "Kami menghargai maklum balas anda. Sila kongsi sebarang cadangan untuk membantu kami menambah baik.",
|
|
37
|
+
"排队等待中": "Sedang beratur",
|
|
38
|
+
"排队等待话术": "Maaf, semua wakil khidmat pelanggan kami sedang sibuk. Sila tunggu sebentar, kami akan membantu anda tidak lama lagi. Terima kasih atas pemahaman anda.",
|
|
39
|
+
"当前前方排队人数": "Bilangan orang di hadapan dalam barisan sekarang",
|
|
40
|
+
"结束排队": "Tinggalkan barisan",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/ru/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserID не должен содержать 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "Длина UserID не должна превышать 45 байт",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "Мы ценим ваши отзывы. Пожалуйста, поделитесь предложениями, которые помогут нам стать лучше.",
|
|
37
|
+
"排队等待中": "В ожидании в очереди",
|
|
38
|
+
"排队等待话术": "Извините, все наши операторы сейчас заняты. Пожалуйста, ожидайте, мы скоро будем с вами. Благодарим за понимание.",
|
|
39
|
+
"当前前方排队人数": "Текущее количество человек впереди в очереди",
|
|
40
|
+
"结束排队": "Выйти из очереди",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/th/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserID ห้ามมี 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "ความยาว UserID ต้องไม่เกิน 45 ไบต์",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "เราขอขอบคุณสำหรับความคิดเห็นของคุณ โปรดแบ่งปันข้อเสนอแนะใดๆ เพื่อช่วยเราปรับปรุง",
|
|
37
|
+
"排队等待中": "กำลังรอคิว",
|
|
38
|
+
"排队等待话术": "ขออภัย เจ้าหน้าที่ให้บริการลูกค้าทุกคนกำลังให้บริการเต็มประสิทธิภาพ กรุณารอคอยอย่างอดทน เราจะให้บริการคุณในไม่ช้า ขอบคุณสำหรับความเข้าใจ",
|
|
39
|
+
"当前前方排队人数": "จำนวนผู้รอคิวด้านหน้าในขณะนี้",
|
|
40
|
+
"结束排队": "ออกจากคิว",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/vi/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "UserID không được chứa 'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "Độ dài UserID không được vượt quá 45 byte",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "Chúng tôi rất cảm kích phản hồi của bạn. Vui lòng chia sẻ bất kỳ đề xuất nào để giúp chúng tôi cải thiện.",
|
|
37
|
+
"排队等待中": "Đang chờ trong hàng",
|
|
38
|
+
"排队等待话术": "Xin lỗi, tất cả nhân viên chăm sóc khách hàng hiện đang bận. Vui lòng chờ đợi, chúng tôi sẽ phục vụ bạn sớm nhất có thể. Cảm ơn bạn đã thông cảm.",
|
|
39
|
+
"当前前方排队人数": "Số người đang chờ trước bạn trong hàng",
|
|
40
|
+
"结束排队": "Rời khỏi hàng",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/locales/zh_cn/aidesk.ts
CHANGED
|
@@ -35,5 +35,9 @@ const AIDesk = {
|
|
|
35
35
|
"userID 长度不能超过45字节": "userID 长度不能超过45字节",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "我们想知道你对此回答不满意的原因,你认为更好的回答是什么?",
|
|
37
37
|
"该回复由AI生成,内容仅供参考": "该回复由AI生成,内容仅供参考",
|
|
38
|
+
"排队等待中": "排队等待中",
|
|
39
|
+
"排队等待话术": "抱歉,当前所有人工客服已达到服务上限,请耐心等待,我们很快就来接待您,感谢您的理解。",
|
|
40
|
+
"当前前方排队人数": "当前前方排队人数",
|
|
41
|
+
"结束排队": "结束排队",
|
|
38
42
|
}
|
|
39
43
|
export default AIDesk;
|
package/locales/zh_tw/aidesk.ts
CHANGED
|
@@ -34,5 +34,9 @@ const AIDesk = {
|
|
|
34
34
|
"userID 不能包含'administrator'": "userID 不能包含'administrator'",
|
|
35
35
|
"userID 长度不能超过45字节": "userID 長度不能超過45位元組",
|
|
36
36
|
"我们想知道你对此回答不满意的原因,你认为更好的回答是什么?": "我們想知道你對此回答不滿意的原因,你認為更好的答案是什麼?",
|
|
37
|
+
"排队等待中": "排隊等待中",
|
|
38
|
+
"排队等待话术": "抱歉,目前所有人工客服已達到服務上限,請耐心等待,我們很快就來接待您,感謝您的理解。",
|
|
39
|
+
"当前前方排队人数": "目前前方排隊人數",
|
|
40
|
+
"结束排队": "結束排隊",
|
|
37
41
|
}
|
|
38
42
|
export default AIDesk;
|
package/package.json
CHANGED
package/utils/utils.ts
CHANGED
|
@@ -361,7 +361,7 @@ export function validateUserID(userID: string) {
|
|
|
361
361
|
return ret;
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
export function updateCustomStore(key: string, data: {conversationID: string, value:
|
|
364
|
+
export function updateCustomStore(key: string, data: {conversationID: string, value: any}) {
|
|
365
365
|
TUIStore.update(StoreName.CUSTOM, key, data);
|
|
366
366
|
}
|
|
367
367
|
|