@tencentcloud/ai-desk-customer-vue 1.4.0 → 1.5.0
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 +12 -0
- package/assets/feedback_dialog_close.svg +3 -0
- package/assets/feedback_dislike_after.svg +3 -0
- package/assets/feedback_dislike_before.svg +10 -0
- package/assets/feedback_dislike_hover.svg +10 -0
- package/assets/feedback_like_after.svg +14 -0
- package/assets/feedback_like_before.svg +10 -0
- package/assets/feedback_like_hover.svg +10 -0
- package/assets/green_check.svg +4 -0
- package/components/CustomerServiceChat/index-web.vue +18 -0
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +1 -0
- package/components/CustomerServiceChat/message-input/message-input-quote/index.vue +29 -20
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +35 -35
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +1 -1
- package/components/CustomerServiceChat/message-list/index-web.vue +5 -0
- package/components/CustomerServiceChat/message-list/message-elements/feedback-button.vue +369 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +30 -11
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +17 -10
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-branch.vue +13 -5
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-concurrency-limit.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +8 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-ivr-form/form-branch.vue +117 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/{message-single-form → message-ivr-form}/form-input.vue +65 -111
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/{message-single-form → message-ivr-form}/index.vue +7 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +5 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/index.vue +3 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/input-mobile.vue +1 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-mobile/label-mobile.vue +4 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/label-pc.vue +5 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +17 -5
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-pc.vue +21 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-order.vue +2 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-product-card.vue +2 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-number.vue +9 -13
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-star.vue +11 -18
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +1 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +14 -10
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-timeout-warning.vue +29 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +1 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-plugin-web.vue +22 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue +6 -24
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +0 -9
- package/components/CustomerServiceChat/message-list/message-elements/read-status/index.vue +31 -20
- package/components/CustomerServiceChat/message-list/message-elements/simple-message-list/index.vue +2 -1
- package/components/common/Toast/index-web.vue +4 -2
- package/constant.ts +11 -1
- package/locales/en/aidesk.ts +28 -16
- package/locales/fil/aidesk.ts +28 -16
- package/locales/id/aidesk.ts +28 -16
- package/locales/ja/aidesk.ts +28 -16
- package/locales/ms/aidesk.ts +28 -16
- package/locales/ru/aidesk.ts +28 -16
- package/locales/th/aidesk.ts +28 -16
- package/locales/vi/aidesk.ts +28 -16
- package/locales/zh_cn/aidesk.ts +28 -16
- package/locales/zh_tw/aidesk.ts +28 -16
- package/package.json +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-single-form/form-branch.vue +0 -68
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div class="feedback-container">
|
|
4
|
+
<div
|
|
5
|
+
class="feedback-like"
|
|
6
|
+
@mouseenter="isFeedbackLikeHover = true"
|
|
7
|
+
@mouseleave="isFeedbackLikeHover = false"
|
|
8
|
+
@click="feedbackLikeClick"
|
|
9
|
+
>
|
|
10
|
+
<Icon :file="feedbackLikeIcon" width="16px" height="16px"/>
|
|
11
|
+
<div
|
|
12
|
+
class="tooltip"
|
|
13
|
+
>
|
|
14
|
+
{{ TUITranslateService.t("AIDesk.满意") }}
|
|
15
|
+
<div class="tooltip-arrow"></div>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<span class="divider"></span>
|
|
19
|
+
<div
|
|
20
|
+
class="feedback-dislike"
|
|
21
|
+
@mouseenter="isFeedbackDislikeHover = true"
|
|
22
|
+
@mouseleave="isFeedbackDislikeHover = false"
|
|
23
|
+
@click="feedbackDislikeClick"
|
|
24
|
+
>
|
|
25
|
+
<Icon :file="feedbackDislikeIcon" width="16px" height="16px" @click="dislickClick"/>
|
|
26
|
+
<div
|
|
27
|
+
class="tooltip"
|
|
28
|
+
>
|
|
29
|
+
{{ TUITranslateService.t("AIDesk.不满意") }}
|
|
30
|
+
<div class="tooltip-arrow"></div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div v-if="showDialog" class="feedback-dialog">
|
|
35
|
+
<div class="feedback-dialog-main">
|
|
36
|
+
<div class="feedback-dialog-header">
|
|
37
|
+
<div class="dialog-header-content">
|
|
38
|
+
<Icon :file="GreenCheck" width="24px" height="24px"/>
|
|
39
|
+
<span class="dialog-header-title">
|
|
40
|
+
{{ TUITranslateService.t("AIDesk.感谢您的反馈,我们会持续优化改进") }}
|
|
41
|
+
</span>
|
|
42
|
+
</div>
|
|
43
|
+
<Icon :file="DialogCloseIcon" width="24px" height="24px" @click="closeDialog"/>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="dialog-select">
|
|
47
|
+
<span class="dialog-session-title">
|
|
48
|
+
{{ TUITranslateService.t("AIDesk.您遇到了哪方面的问题") }}
|
|
49
|
+
</span>
|
|
50
|
+
<div class="dialog-button-list">
|
|
51
|
+
<div class="dialog-button-row" v-for="(item) in feedbackButton">
|
|
52
|
+
<div :class="['dialog-button',item.isSelected ? 'dialog-button-selected': '']" @click="dialogButtonClick(item)">
|
|
53
|
+
{{ TUITranslateService.t(`AIDesk.${item.text}`) }}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="dialog-other">
|
|
60
|
+
<span class="dialog-session-title">
|
|
61
|
+
{{ TUITranslateService.t("AIDesk.其他反馈内容") }}
|
|
62
|
+
</span>
|
|
63
|
+
<textarea type="text" :placeholder="TUITranslateService.t('AIDesk.请输入内容')" v-model="feedbackText" class="dialog-other-input"/>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="dialog-foot">
|
|
66
|
+
<div class="dialog-submit" @click="submitBadFeeback">
|
|
67
|
+
{{ TUITranslateService.t("AIDesk.提交") }}
|
|
68
|
+
</div>
|
|
69
|
+
<div class="dialog-cancel" @click="closeDialog">
|
|
70
|
+
{{ TUITranslateService.t("AIDesk.取消") }}
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
<script lang="ts">
|
|
78
|
+
import vue from '../../../../adapter-vue';
|
|
79
|
+
import Icon from '../../../common/Icon.vue';
|
|
80
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
81
|
+
import FeedbackLikeBefore from '../../../../assets/feedback_like_before.svg';
|
|
82
|
+
import FeedbackLikeAfter from '../../../../assets/feedback_like_after.svg';
|
|
83
|
+
import FeedbackLikeHover from '../../../../assets/feedback_like_hover.svg';
|
|
84
|
+
import FeedbackDislikeBefore from '../../../../assets/feedback_dislike_before.svg';
|
|
85
|
+
import FeedbackDislikeAfter from '../../../../assets/feedback_dislike_after.svg';
|
|
86
|
+
import FeedbackDislikeHover from '../../../../assets/feedback_dislike_hover.svg';
|
|
87
|
+
import GreenCheck from '../../../../assets/green_check.svg';
|
|
88
|
+
import DialogCloseIcon from '../../../../assets/feedback_dialog_close.svg';
|
|
89
|
+
const { ref,computed } = vue;
|
|
90
|
+
|
|
91
|
+
export default {
|
|
92
|
+
components:{
|
|
93
|
+
Icon
|
|
94
|
+
},
|
|
95
|
+
setup(){
|
|
96
|
+
const isFeedbackLikeHover = ref(false);
|
|
97
|
+
const isFeedbackLikeClick = ref(false);
|
|
98
|
+
const isFeedbackDislikeHover = ref(false);
|
|
99
|
+
const isFeedbackDislikeClick = ref(false);
|
|
100
|
+
const showDialog = ref(false);
|
|
101
|
+
const feedbackText = ref('');
|
|
102
|
+
const feedbackButton = ref([
|
|
103
|
+
{ id:'nonResponsiveAnswer', text: '答非所问', isSelected: false },
|
|
104
|
+
{ id:'unmatchedContentRetrieval', text: '未匹配相关内容', isSelected: false },
|
|
105
|
+
{ id:'incorrectInfoAnswer', text: '信息错误', isSelected: false },
|
|
106
|
+
{ id:'contextMisunderstandingQuery', text: '上下文理解错误', isSelected: false },
|
|
107
|
+
{ id:'nonStandardFormatAnswer', text: '格式不规范', isSelected: false },
|
|
108
|
+
{ id:'incompleteContentRetrieval', text: '内容不完整', isSelected: false },
|
|
109
|
+
]);
|
|
110
|
+
const feedbackReply = {
|
|
111
|
+
isSupport:1, //1:点赞。0:点踩
|
|
112
|
+
nonResponsiveAnswer:0, // 是否答非所问
|
|
113
|
+
incorrectInfoAnswer:0, // 是否信息错误
|
|
114
|
+
nonStandardFormatAnswer:0, // 是否信息不规范
|
|
115
|
+
incompleteContentRetrieval:0, // 是否回答不完整
|
|
116
|
+
unmatchedContentRetrieval:0, // 是否信息不匹配
|
|
117
|
+
contextMisunderstandingQuery:0, //是否上下文理解错误
|
|
118
|
+
feedbackText:"" //文字反馈
|
|
119
|
+
};
|
|
120
|
+
const feedbackLikeIcon = computed(() => {
|
|
121
|
+
if (isFeedbackLikeClick.value) {
|
|
122
|
+
return FeedbackLikeAfter;
|
|
123
|
+
} else if (isFeedbackLikeHover.value) {
|
|
124
|
+
return FeedbackLikeHover;
|
|
125
|
+
} else {
|
|
126
|
+
return FeedbackLikeBefore;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const feedbackLikeClick = () => {
|
|
130
|
+
isFeedbackLikeClick.value = !isFeedbackLikeClick.value;
|
|
131
|
+
if(isFeedbackLikeClick.value){
|
|
132
|
+
isFeedbackDislikeClick.value = false;
|
|
133
|
+
feedbackReply.isSupport = 1;
|
|
134
|
+
}
|
|
135
|
+
resetFeedback();
|
|
136
|
+
}
|
|
137
|
+
const feedbackDislikeIcon = computed(() => {
|
|
138
|
+
if (isFeedbackDislikeClick.value) {
|
|
139
|
+
return FeedbackDislikeAfter;
|
|
140
|
+
} else if (isFeedbackDislikeHover.value) {
|
|
141
|
+
return FeedbackDislikeHover;
|
|
142
|
+
} else {
|
|
143
|
+
return FeedbackDislikeBefore;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
const dialogButtonClick = (item) => {
|
|
147
|
+
item.isSelected = !item.isSelected;
|
|
148
|
+
}
|
|
149
|
+
const feedbackDislikeClick = () => {
|
|
150
|
+
isFeedbackDislikeClick.value = true;
|
|
151
|
+
if(isFeedbackDislikeClick.value){
|
|
152
|
+
isFeedbackLikeClick.value = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const dislickClick = () => {
|
|
156
|
+
showDialog.value = true;
|
|
157
|
+
}
|
|
158
|
+
const closeDialog = () => {
|
|
159
|
+
isFeedbackDislikeClick.value = false;
|
|
160
|
+
showDialog.value = false;
|
|
161
|
+
resetFeedback();
|
|
162
|
+
}
|
|
163
|
+
const resetFeedback = () => {
|
|
164
|
+
feedbackButton.value.forEach(item => {
|
|
165
|
+
item.isSelected = false;
|
|
166
|
+
});
|
|
167
|
+
feedbackText.value = "";
|
|
168
|
+
}
|
|
169
|
+
const submitBadFeeback = () => {
|
|
170
|
+
feedbackReply.isSupport = 0;
|
|
171
|
+
feedbackButton.value.forEach(item => {
|
|
172
|
+
feedbackReply[item.id] = item.isSelected ? 1 : 0;
|
|
173
|
+
feedbackReply.feedbackText = feedbackText.value;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
feedbackLikeIcon,
|
|
179
|
+
isFeedbackLikeHover,
|
|
180
|
+
feedbackLikeClick,
|
|
181
|
+
isFeedbackDislikeHover,
|
|
182
|
+
feedbackDislikeIcon,
|
|
183
|
+
feedbackDislikeClick,
|
|
184
|
+
GreenCheck,
|
|
185
|
+
DialogCloseIcon,
|
|
186
|
+
feedbackButton,
|
|
187
|
+
showDialog,
|
|
188
|
+
closeDialog,
|
|
189
|
+
dislickClick,
|
|
190
|
+
feedbackText,
|
|
191
|
+
dialogButtonClick,
|
|
192
|
+
TUITranslateService,
|
|
193
|
+
submitBadFeeback
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
</script>
|
|
198
|
+
<style lang="scss">
|
|
199
|
+
.feedback-container {
|
|
200
|
+
display: flex;
|
|
201
|
+
flex-direction: row !important;
|
|
202
|
+
padding: 4px 10px;
|
|
203
|
+
align-items: center;
|
|
204
|
+
gap: 10px;
|
|
205
|
+
border-radius: 8px;
|
|
206
|
+
border: 1px solid var(---G61, #DBE1EB);
|
|
207
|
+
.feedback-like, .feedback-dislike {
|
|
208
|
+
position: relative;
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
justify-content: center;
|
|
212
|
+
cursor: pointer;
|
|
213
|
+
&:hover .tooltip {
|
|
214
|
+
display: block;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
.divider {
|
|
218
|
+
width: 1px;
|
|
219
|
+
height: 14px;
|
|
220
|
+
background-color: rgba(0,0,0,0.05);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
.feedback-dialog {
|
|
224
|
+
position: fixed;
|
|
225
|
+
top: 0;
|
|
226
|
+
left: 0;
|
|
227
|
+
right: 0;
|
|
228
|
+
bottom: 0;
|
|
229
|
+
background: rgba(13, 17, 26, 0.4);
|
|
230
|
+
z-index: 1000;
|
|
231
|
+
display: flex;
|
|
232
|
+
justify-content: center;
|
|
233
|
+
align-items: center;
|
|
234
|
+
font-family: PingFangSC-Regular;
|
|
235
|
+
&-main {
|
|
236
|
+
width: 418px;
|
|
237
|
+
min-height: 442px;
|
|
238
|
+
background: white;
|
|
239
|
+
border-radius: 16px;
|
|
240
|
+
padding: 30px;
|
|
241
|
+
overflow: hidden;
|
|
242
|
+
|
|
243
|
+
.feedback-dialog-header {
|
|
244
|
+
display: flex;
|
|
245
|
+
justify-content: space-between;
|
|
246
|
+
.dialog-header-content {
|
|
247
|
+
display: flex;
|
|
248
|
+
gap: 8px;
|
|
249
|
+
align-items: center;
|
|
250
|
+
.dialog-header-title {
|
|
251
|
+
font-weight: 600;
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
.dialog-session-title {
|
|
259
|
+
color: #4F586B;
|
|
260
|
+
font-size: 14px;
|
|
261
|
+
}
|
|
262
|
+
.dialog-select {
|
|
263
|
+
margin-top: 30px;
|
|
264
|
+
.dialog-button-list {
|
|
265
|
+
display: flex;
|
|
266
|
+
flex-wrap: wrap;
|
|
267
|
+
justify-content: center;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 8px;
|
|
270
|
+
margin-top: 10px;
|
|
271
|
+
.dialog-button-row {
|
|
272
|
+
flex: 0 0 49%;
|
|
273
|
+
.dialog-button {
|
|
274
|
+
border-radius: 8px;
|
|
275
|
+
border: 1px solid #E4E8EE;
|
|
276
|
+
background: #F9FAFC;
|
|
277
|
+
padding: 10px 16px;
|
|
278
|
+
display: flex;
|
|
279
|
+
justify-content: center;
|
|
280
|
+
font-size: 12px;
|
|
281
|
+
color: #0f1014;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
text-align: center;
|
|
284
|
+
align-items: center;
|
|
285
|
+
&-selected {
|
|
286
|
+
border-radius: 8px;
|
|
287
|
+
border: 1px solid #1C66E5;
|
|
288
|
+
background: rgba(28, 102, 229, 0.10);
|
|
289
|
+
color: #0052d9;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
.dialog-other {
|
|
297
|
+
margin: 20px 0 10px 0;
|
|
298
|
+
display: flex;
|
|
299
|
+
flex-direction: column;
|
|
300
|
+
gap: 10px;
|
|
301
|
+
.dialog-other-input {
|
|
302
|
+
border-radius: 12px;
|
|
303
|
+
border: 1px solid #E4E8EE;
|
|
304
|
+
background: #F9FAFC;
|
|
305
|
+
height: 102px;
|
|
306
|
+
padding: 10px 16px;
|
|
307
|
+
display: flex;
|
|
308
|
+
align-items: flex-start;
|
|
309
|
+
align-self: stretch;
|
|
310
|
+
resize: none;
|
|
311
|
+
&::placeholder {
|
|
312
|
+
color: #929CB2;
|
|
313
|
+
font-size: 14px;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
.dialog-foot {
|
|
318
|
+
width: 100%;
|
|
319
|
+
display: flex;
|
|
320
|
+
margin-top: 30px;
|
|
321
|
+
gap: 10px;
|
|
322
|
+
justify-content: center;
|
|
323
|
+
.dialog-submit {
|
|
324
|
+
padding: 9px 33px;
|
|
325
|
+
border-radius: 20px;
|
|
326
|
+
background: #1C66E5;
|
|
327
|
+
font-weight: 600;
|
|
328
|
+
color: #fff;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
}
|
|
331
|
+
.dialog-cancel {
|
|
332
|
+
padding: 9px 33px;
|
|
333
|
+
border-radius: 20px;
|
|
334
|
+
border: 1px solid #1C66E5;
|
|
335
|
+
font-weight: 600;
|
|
336
|
+
color: #1C66E5;
|
|
337
|
+
cursor: pointer;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.tooltip {
|
|
342
|
+
position: absolute;
|
|
343
|
+
z-index: 100;
|
|
344
|
+
font-size: 14px;
|
|
345
|
+
bottom: calc(100% + 13px);
|
|
346
|
+
left: 50%;
|
|
347
|
+
transform: translateX(-50%);
|
|
348
|
+
background: #fff;
|
|
349
|
+
color: #000;
|
|
350
|
+
padding: 8px 16px;
|
|
351
|
+
border-radius: 6px;
|
|
352
|
+
box-shadow: var(--shadow-md-offsetx-1, 0px) var(--shadow-md-offsety-1, 8px) var(--shadow-md-blur-1, 12px) var(--shadow-md-spread-1, -8px) var(--shadow-md-color-1, rgba(0, 0, 0, 0.05)), var(--shadow-md-offsetx-2, 0px) var(--shadow-md-offsety-2, 8px) var(--shadow-md-blur-2, 24px) var(--shadow-md-spread-2, -4px) var(--shadow-md-color-2, rgba(0, 0, 0, 0.10));
|
|
353
|
+
text-align: center;
|
|
354
|
+
display: none;
|
|
355
|
+
white-space: nowrap;
|
|
356
|
+
|
|
357
|
+
&-arrow {
|
|
358
|
+
position: absolute;
|
|
359
|
+
bottom: -8px;
|
|
360
|
+
left: 50%;
|
|
361
|
+
transform: translateX(-50%);
|
|
362
|
+
width: 0;
|
|
363
|
+
height: 0;
|
|
364
|
+
border-left: 8px solid transparent;
|
|
365
|
+
border-right: 8px solid transparent;
|
|
366
|
+
border-top: 8px solid #fff;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
</style>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
:class="[message.flow === 'in' ? '' : 'reverse']"
|
|
13
13
|
>
|
|
14
14
|
<Avatar
|
|
15
|
-
v-if="
|
|
15
|
+
v-if="showAvatar === 1"
|
|
16
16
|
useSkeletonAnimation
|
|
17
17
|
:url="avatarUrl"
|
|
18
18
|
/>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
@click.stop
|
|
22
22
|
>
|
|
23
23
|
<div
|
|
24
|
-
v-if="
|
|
24
|
+
v-if="showNickName === 1"
|
|
25
25
|
class="message-body-nick-name"
|
|
26
26
|
>
|
|
27
27
|
{{ nickName }}
|
|
@@ -107,8 +107,13 @@
|
|
|
107
107
|
<ReadStatus
|
|
108
108
|
class="message-label align-self-bottom"
|
|
109
109
|
:message="shallowCopyMessage(message)"
|
|
110
|
+
@setStatus="setStatus"
|
|
111
|
+
:prevStatus="prevStatus"
|
|
110
112
|
/>
|
|
111
113
|
</div>
|
|
114
|
+
<!-- <div class="message-bubble-feedback-button">
|
|
115
|
+
<FeedbackButton v-if="isFromRobot(message.cloudCustomData)"/>
|
|
116
|
+
</div> -->
|
|
112
117
|
</main>
|
|
113
118
|
</div>
|
|
114
119
|
<!-- message extra area -->
|
|
@@ -143,6 +148,8 @@ import { isPC,isH5 } from '../../../../utils/env';
|
|
|
143
148
|
import { JSONToObject } from '../../../../utils/index';
|
|
144
149
|
import state from '../../../../utils/state.js';
|
|
145
150
|
import { CUSTOM_MESSAGE_SRC } from '../../../../constant';
|
|
151
|
+
import FeedbackButton from './feedback-button.vue';
|
|
152
|
+
import { ReadState } from '../../../../constant';
|
|
146
153
|
const { computed, toRefs } = vue;
|
|
147
154
|
|
|
148
155
|
interface IProps {
|
|
@@ -192,7 +199,7 @@ const {
|
|
|
192
199
|
staffNickName,
|
|
193
200
|
userNickName,
|
|
194
201
|
} = state.get('avatarNickName');
|
|
195
|
-
|
|
202
|
+
let prevStatus = ReadState.Unread;
|
|
196
203
|
const isDisplayUnplayMark = computed<boolean>(() => {
|
|
197
204
|
return (
|
|
198
205
|
message.value.flow === 'in'
|
|
@@ -313,6 +320,10 @@ function blinkMessage(messageID: string) {
|
|
|
313
320
|
function scrollTo(scrollHeight: number) {
|
|
314
321
|
emits('scrollTo', scrollHeight);
|
|
315
322
|
}
|
|
323
|
+
|
|
324
|
+
function setStatus(status: ReadState) {
|
|
325
|
+
prevStatus = status;
|
|
326
|
+
}
|
|
316
327
|
</script>
|
|
317
328
|
|
|
318
329
|
<style lang="scss" scoped>
|
|
@@ -324,7 +335,7 @@ function scrollTo(scrollHeight: number) {
|
|
|
324
335
|
}
|
|
325
336
|
|
|
326
337
|
.message-bubble {
|
|
327
|
-
padding: 10px
|
|
338
|
+
padding: 10px 5px;
|
|
328
339
|
display: flex;
|
|
329
340
|
flex-direction: row;
|
|
330
341
|
user-select: none;
|
|
@@ -407,12 +418,12 @@ function scrollTo(scrollHeight: number) {
|
|
|
407
418
|
flex-direction: column;
|
|
408
419
|
min-width: 0;
|
|
409
420
|
box-sizing: border-box;
|
|
410
|
-
padding: 16px;
|
|
421
|
+
padding: 8px 16px;
|
|
411
422
|
font-size: 14px;
|
|
412
423
|
color: #000;
|
|
413
424
|
letter-spacing: 0;
|
|
414
|
-
|
|
415
|
-
word-break:
|
|
425
|
+
overflow-wrap: break-word;
|
|
426
|
+
word-break: normal;
|
|
416
427
|
position: relative;
|
|
417
428
|
|
|
418
429
|
.content-main {
|
|
@@ -445,7 +456,7 @@ function scrollTo(scrollHeight: number) {
|
|
|
445
456
|
|
|
446
457
|
.content-in {
|
|
447
458
|
background: #f3f4f7;
|
|
448
|
-
border-radius: 0
|
|
459
|
+
border-radius: 0 8px 8px;
|
|
449
460
|
}
|
|
450
461
|
|
|
451
462
|
.body-mobile {
|
|
@@ -454,7 +465,7 @@ function scrollTo(scrollHeight: number) {
|
|
|
454
465
|
|
|
455
466
|
.multi-branch-message {
|
|
456
467
|
background-color: transparent;
|
|
457
|
-
border-radius: 0
|
|
468
|
+
border-radius: 0 8px 8px;
|
|
458
469
|
padding: 0px;
|
|
459
470
|
}
|
|
460
471
|
|
|
@@ -469,7 +480,7 @@ function scrollTo(scrollHeight: number) {
|
|
|
469
480
|
.content-out {
|
|
470
481
|
background: linear-gradient(26deg, #1C66E5 2.07%, #03C8FD 152.75%);
|
|
471
482
|
color:#fff;
|
|
472
|
-
border-radius:
|
|
483
|
+
border-radius: 8px 0 8px 8px;
|
|
473
484
|
}
|
|
474
485
|
|
|
475
486
|
.content-no-padding {
|
|
@@ -501,7 +512,10 @@ function scrollTo(scrollHeight: number) {
|
|
|
501
512
|
.blink-content {
|
|
502
513
|
@keyframes reference-blink {
|
|
503
514
|
50% {
|
|
504
|
-
background-color
|
|
515
|
+
// 消息气泡的底色是渐变色,实际是 background-image,background-image 优先级高于 background-color
|
|
516
|
+
// 所以这里如果设置 background-color,动画将不会生效
|
|
517
|
+
// 闪烁时背景不渐变
|
|
518
|
+
background: linear-gradient(90deg, #ff9c19, #ff9c19);
|
|
505
519
|
}
|
|
506
520
|
}
|
|
507
521
|
|
|
@@ -551,6 +565,11 @@ function scrollTo(scrollHeight: number) {
|
|
|
551
565
|
align-self: flex-end;
|
|
552
566
|
}
|
|
553
567
|
}
|
|
568
|
+
.message-bubble-feedback-button {
|
|
569
|
+
display: flex;
|
|
570
|
+
flex-direction: row;
|
|
571
|
+
margin-top: 8px;
|
|
572
|
+
}
|
|
554
573
|
}
|
|
555
574
|
}
|
|
556
575
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Marked} from 'marked';
|
|
2
|
+
import Log from '../../../../../../utils/logger';
|
|
2
3
|
|
|
3
4
|
export const marked = new Marked(
|
|
4
5
|
{mangle: false, headerIds: false},
|
|
@@ -7,19 +8,25 @@ export const marked = new Marked(
|
|
|
7
8
|
image(this: any, href: string | null, title: string | null, text: string) {
|
|
8
9
|
const safeHref = encodeURIComponent(href || '');
|
|
9
10
|
return `<div
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
class="image-container"
|
|
12
|
+
onclick="onMarkdownImageClicked('${safeHref}')"
|
|
13
|
+
style="cursor:pointer;" >
|
|
14
|
+
<img src="${href}" alt="${text}" onload="onMarkdownImageLoad()"/>
|
|
15
|
+
</div>
|
|
16
|
+
`;
|
|
16
17
|
},
|
|
17
18
|
link(this: any, href: string | null, title: string | null, text: string) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if (href) {
|
|
20
|
+
// 匹配以 http:// 或 https:// 开头,所有 URL 主体字符,遇到第一个非主体字符(如中文括号、空格、表情符号等)时停止
|
|
21
|
+
let ret = href.replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (matchedUrl) => {
|
|
22
|
+
return `<a target="_blank" rel="noreferrer noopenner" class="message-marked_link" href="${matchedUrl || ''}" title="${title}">${matchedUrl}</a>`;
|
|
23
|
+
});
|
|
24
|
+
if (ret === href) {
|
|
25
|
+
Log.w(`Unable to extract url, href:${href}`);
|
|
26
|
+
}
|
|
27
|
+
return ret;
|
|
21
28
|
}
|
|
22
|
-
return
|
|
29
|
+
return text;
|
|
23
30
|
},
|
|
24
31
|
},
|
|
25
32
|
},
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
:class="['branch-body',isPC ? 'branch-bubble':'branch-bubble-h5']"
|
|
6
6
|
>
|
|
7
7
|
<Icon :src="iconQuestion" class="branch-title-icon"/>
|
|
8
|
-
|
|
8
|
+
<div class="branch-title-text">
|
|
9
|
+
{{ content.header || content.title }}
|
|
10
|
+
</div>
|
|
9
11
|
</div>
|
|
10
12
|
<div
|
|
11
13
|
v-for="(item, index) in content.items"
|
|
@@ -91,14 +93,15 @@ export default {
|
|
|
91
93
|
display: flex;
|
|
92
94
|
min-width: 0;
|
|
93
95
|
box-sizing: border-box;
|
|
94
|
-
padding:
|
|
96
|
+
padding: 8px 16px;
|
|
95
97
|
font-size: 14px;
|
|
96
98
|
color: #000;
|
|
97
99
|
letter-spacing: 0;
|
|
98
|
-
|
|
99
|
-
word-break:
|
|
100
|
+
overflow-wrap: break-word;
|
|
101
|
+
word-break: normal;
|
|
100
102
|
position: relative;
|
|
101
|
-
|
|
103
|
+
width: 100%;
|
|
104
|
+
max-width: fit-content;
|
|
102
105
|
.branch-main {
|
|
103
106
|
box-sizing: border-box;
|
|
104
107
|
display: flex;
|
|
@@ -124,6 +127,7 @@ export default {
|
|
|
124
127
|
.branch-item {
|
|
125
128
|
color: #1c66e5;
|
|
126
129
|
cursor: pointer;
|
|
130
|
+
display: inline-block;
|
|
127
131
|
}
|
|
128
132
|
.warning-item {
|
|
129
133
|
color: #ff9800;
|
|
@@ -145,4 +149,8 @@ export default {
|
|
|
145
149
|
align-items: flex-start !important;
|
|
146
150
|
margin-top: 2px;
|
|
147
151
|
}
|
|
152
|
+
.branch-title-text {
|
|
153
|
+
display: inline-block;
|
|
154
|
+
min-width: 0;
|
|
155
|
+
}
|
|
148
156
|
</style>
|
|
@@ -82,7 +82,7 @@ import { JSONToObject } from '../../../../../../utils/index';
|
|
|
82
82
|
import { isEnabledMessageReadReceiptGlobal } from '../../../../../../utils/utils';
|
|
83
83
|
import { CUSTOM_MESSAGE_SRC } from '../../../../../../constant';
|
|
84
84
|
import MessageBranch from './message-branch.vue';
|
|
85
|
-
import MessageForm from './message-
|
|
85
|
+
import MessageForm from './message-ivr-form/index.vue';
|
|
86
86
|
import MessageIMRobotWelcome from './message-robot-welcome.vue';
|
|
87
87
|
import MessageProductCard from './message-product-card.vue';
|
|
88
88
|
import MessageRichText from './message-rich-text.vue';
|
|
@@ -119,20 +119,22 @@ export default {
|
|
|
119
119
|
default: () => ({}),
|
|
120
120
|
},
|
|
121
121
|
},
|
|
122
|
-
emits: ['showFormPopup', 'heightChanged'],
|
|
122
|
+
emits: ['showFormPopup', 'heightChanged', 'messageSent'],
|
|
123
123
|
setup(props: Props, { emit }) {
|
|
124
124
|
const payload = computed<customerServicePayloadType>(() => {
|
|
125
125
|
return props.message && JSONToObject(props.message?.payload?.data);
|
|
126
126
|
});
|
|
127
|
-
const sendTextMessage = (payload: TextMessagePayload, cloudCustomData?: string) => {
|
|
128
|
-
TUIChatService.sendTextMessage({
|
|
127
|
+
const sendTextMessage = async (payload: TextMessagePayload, cloudCustomData?: string) => {
|
|
128
|
+
await TUIChatService.sendTextMessage({
|
|
129
129
|
payload,
|
|
130
130
|
cloudCustomData: cloudCustomData || '',
|
|
131
131
|
needReadReceipt: isEnabledMessageReadReceiptGlobal()
|
|
132
132
|
});
|
|
133
|
+
emit('messageSent');
|
|
133
134
|
};
|
|
134
|
-
const sendCustomMessage = (payload: CustomMessagePayload) => {
|
|
135
|
-
TUIChatService.sendCustomMessage({ payload });
|
|
135
|
+
const sendCustomMessage = async (payload: CustomMessagePayload) => {
|
|
136
|
+
await TUIChatService.sendCustomMessage({ payload });
|
|
137
|
+
emit('messageSent');
|
|
136
138
|
};
|
|
137
139
|
const handleShowFormPopup = (data: boolean) => {
|
|
138
140
|
emit('showFormPopup', data);
|