@tencentcloud/ai-desk-customer-vue 1.5.6 → 1.5.9
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/assets/feedback_dislike_after.svg +1 -1
- package/assets/feedback_dislike_before.svg +2 -9
- package/assets/feedback_dislike_hover.svg +2 -9
- package/assets/feedback_like_after.svg +2 -13
- package/assets/feedback_like_before.svg +2 -9
- package/assets/feedback_like_hover.svg +2 -9
- package/components/CustomerServiceChat/chat-header/index-web.vue +19 -12
- package/components/CustomerServiceChat/feedback-modal/index.vue +391 -0
- package/components/CustomerServiceChat/index-web.vue +34 -1
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +0 -1
- package/components/CustomerServiceChat/message-input/message-input-quote/index.vue +0 -3
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +4 -2
- package/components/CustomerServiceChat/message-list/bottom-quick-order/index.vue +0 -1
- package/components/CustomerServiceChat/message-list/index-web.vue +92 -62
- package/components/CustomerServiceChat/message-list/message-elements/feedback-button.vue +96 -251
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +51 -16
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-concurrency-limit.vue +0 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-ivr-form/form-branch.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/branch-pc.vue +0 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +34 -29
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-pc.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-order.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-product-card.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-rating/message-rating-star.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-transfer-with-desc.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +0 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-plugin-layout-web.vue +16 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-plugin-web.vue +18 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue +0 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +26 -19
- package/components/CustomerServiceChat/message-list/message-elements/message-timestamp.vue +0 -1
- package/components/CustomerServiceChat/message-list/message-elements/read-status/index.vue +4 -2
- package/components/CustomerServiceChat/message-list/scroll-button/index.vue +8 -4
- package/components/CustomerServiceChat/message-list/style/web.scss +0 -2
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +13 -9
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-end-human-service.vue +1 -1
- package/components/CustomerServiceChat/style/common.scss +4 -0
- package/components/CustomerServiceChat/style/web.scss +2 -1
- package/components/common/BottomPopup/style/h5.scss +0 -1
- package/components/common/Dialog/style/color.scss +0 -1
- package/components/common/Toast/index-web.vue +1 -1
- package/constant.ts +3 -2
- package/locales/en/aidesk.ts +18 -15
- package/locales/fil/aidesk.ts +17 -15
- package/locales/id/aidesk.ts +17 -15
- package/locales/ja/aidesk.ts +17 -15
- package/locales/ms/aidesk.ts +17 -15
- package/locales/ru/aidesk.ts +17 -15
- package/locales/th/aidesk.ts +17 -15
- package/locales/vi/aidesk.ts +17 -15
- package/locales/zh_cn/aidesk.ts +17 -14
- package/locales/zh_tw/aidesk.ts +17 -15
- package/package.json +1 -1
- package/server.ts +5 -4
- package/utils/index.ts +6 -0
- package/utils/utils.ts +42 -0
- package/assets/customer_avatar.png +0 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
@onClose="closeDialog"
|
|
16
16
|
title=""
|
|
17
17
|
>
|
|
18
|
-
<div style="height:100%;
|
|
18
|
+
<div style="height:100%;">
|
|
19
19
|
<div class="dialog-title">
|
|
20
20
|
<div class="dialog-title-tip">
|
|
21
21
|
{{ props.payload.content.tip }}
|
|
@@ -24,28 +24,30 @@
|
|
|
24
24
|
<Icon :src="iconClose" width="16px" height="16px"/>
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
|
-
<div
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
<div v-else-if="item.formType == 1 && props.payload.nodeStatus == 0">
|
|
35
|
-
<RadioMobile :chooseItemList="item.chooseItemList" :name="item.name" :isRequired="item.isRequired" @input-change="handleInputChange" :validator="item.isRequired == 1 && isValid(item.name)"/>
|
|
36
|
-
</div>
|
|
37
|
-
<div v-else class="variable-value-container-mobile">
|
|
38
|
-
<div class="variable-value-label-mobile">
|
|
39
|
-
{{ item.name }}
|
|
27
|
+
<div class="dialog-show-content">
|
|
28
|
+
<div
|
|
29
|
+
v-for="(item, index) in props.payload.content.inputVariables"
|
|
30
|
+
:key="index"
|
|
31
|
+
>
|
|
32
|
+
<div v-if="item.formType == 0 && props.payload.nodeStatus == 0">
|
|
33
|
+
<InputMobile :placeholder="item.placeholder" :variableValue="item.variableValue" :name="item.name" :isRequired="item.isRequired" @input-change="handleInputChange" :validator="item.isRequired == 1 && isValid(item.name)"/>
|
|
40
34
|
</div>
|
|
41
|
-
<div
|
|
42
|
-
|
|
35
|
+
<div v-else-if="item.formType == 1 && props.payload.nodeStatus == 0">
|
|
36
|
+
<RadioMobile :chooseItemList="item.chooseItemList" :name="item.name" :isRequired="item.isRequired" @input-change="handleInputChange" :validator="item.isRequired == 1 && isValid(item.name)"/>
|
|
37
|
+
</div>
|
|
38
|
+
<div v-else class="variable-value-container-mobile">
|
|
39
|
+
<div class="variable-value-label-mobile">
|
|
40
|
+
{{ item.name }}
|
|
41
|
+
</div>
|
|
42
|
+
<div class="variable-value">
|
|
43
|
+
{{ item.variableValue == '' || item.variableValue == null ? mapValue[item.name] : item.variableValue}}
|
|
44
|
+
</div>
|
|
43
45
|
</div>
|
|
44
46
|
</div>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
<div class="button-container" v-if="props.payload.nodeStatus === 0">
|
|
48
|
+
<div class="button" @click="handleSendForm">
|
|
49
|
+
{{ TUITranslateService.t("AIDesk.提交") }}
|
|
50
|
+
</div>
|
|
49
51
|
</div>
|
|
50
52
|
</div>
|
|
51
53
|
</div>
|
|
@@ -75,7 +77,7 @@ import RadioMobile from './component-mobile/radios-mobile.vue';
|
|
|
75
77
|
import LabelMobile from './component-mobile/label-mobile.vue';
|
|
76
78
|
import FormPopup from './component-mobile/form-popup.vue';
|
|
77
79
|
import { CUSTOM_MESSAGE_SRC } from '../../../../../../../constant';
|
|
78
|
-
import {TUITranslateService} from '@tencentcloud/chat-uikit-engine';
|
|
80
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
79
81
|
const { ref, onMounted } = vue;
|
|
80
82
|
interface Props {
|
|
81
83
|
payload: customerServicePayloadType;
|
|
@@ -163,6 +165,7 @@ export default {
|
|
|
163
165
|
};
|
|
164
166
|
emit('sendMessage', submitData);
|
|
165
167
|
isSubmit.value = false;
|
|
168
|
+
closeDialog();
|
|
166
169
|
};
|
|
167
170
|
const handleInputChange = ({name,value}) => {
|
|
168
171
|
mapValue.value[name] = value;
|
|
@@ -197,10 +200,6 @@ export default {
|
|
|
197
200
|
<style lang="scss">
|
|
198
201
|
@import "../styles/common.scss";
|
|
199
202
|
|
|
200
|
-
.form-mobile-container {
|
|
201
|
-
font-family: PingFangSC-Regular;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
203
|
.edit-profile-container {
|
|
205
204
|
@extend .container;
|
|
206
205
|
font-size: 14px;
|
|
@@ -311,7 +310,6 @@ export default {
|
|
|
311
310
|
display:flex;
|
|
312
311
|
flex-direction: column;
|
|
313
312
|
justify-content: center;
|
|
314
|
-
font-family: PingFangSC-Regular;
|
|
315
313
|
.form-button {
|
|
316
314
|
display:flex;
|
|
317
315
|
justify-content: center;
|
|
@@ -374,6 +372,12 @@ export default {
|
|
|
374
372
|
color: rgba(153,153,153,1);
|
|
375
373
|
}
|
|
376
374
|
}
|
|
375
|
+
|
|
376
|
+
.dialog-show-content {
|
|
377
|
+
overflow-y: auto;
|
|
378
|
+
max-height: 68vh;
|
|
379
|
+
}
|
|
380
|
+
|
|
377
381
|
.variable-value-container-mobile {
|
|
378
382
|
padding: 16px;
|
|
379
383
|
display: flex;
|
|
@@ -399,15 +403,16 @@ export default {
|
|
|
399
403
|
.button-container {
|
|
400
404
|
display: flex;
|
|
401
405
|
justify-content: center;
|
|
402
|
-
|
|
406
|
+
padding: 20px;
|
|
403
407
|
.button {
|
|
404
408
|
display: flex;
|
|
405
409
|
justify-content: center;
|
|
406
|
-
width:
|
|
407
|
-
padding:
|
|
410
|
+
width: 100%;
|
|
411
|
+
padding: 9px 33px;
|
|
408
412
|
background-color: #1c66e5;
|
|
409
413
|
color: white;
|
|
410
414
|
border-radius: 20px;
|
|
415
|
+
font-weight: 500;
|
|
411
416
|
}
|
|
412
417
|
}
|
|
413
418
|
</style>
|
|
@@ -109,7 +109,6 @@
|
|
|
109
109
|
.title-name {
|
|
110
110
|
font-size: 18px;
|
|
111
111
|
font-weight: 500;
|
|
112
|
-
font-family: PingFangSC-Medium;
|
|
113
112
|
}
|
|
114
113
|
}
|
|
115
114
|
}
|
|
@@ -124,7 +123,6 @@
|
|
|
124
123
|
justify-content: flex-start;
|
|
125
124
|
margin: 0;
|
|
126
125
|
padding: 0;
|
|
127
|
-
font-family: PingFangSC-Regular;
|
|
128
126
|
user-select: text;
|
|
129
127
|
|
|
130
128
|
.message-marked_code-container {
|
|
@@ -22,7 +22,11 @@
|
|
|
22
22
|
:content="messageModel.getMessageContent()"
|
|
23
23
|
:blinkMessageIDList="props.blinkMessageIDList"
|
|
24
24
|
:classNameList="props.bubbleClassNameList"
|
|
25
|
+
:enableFeedback="props.enableFeedback"
|
|
26
|
+
:enableAINote="props.enableAINote"
|
|
25
27
|
@resendMessage="resendMessage(messageModel)"
|
|
28
|
+
@like="onLike"
|
|
29
|
+
@dislike="onDislike"
|
|
26
30
|
>
|
|
27
31
|
<!-- web message-bubble is a named slot, content area slotName is messageElement -->
|
|
28
32
|
<template #messageElement>
|
|
@@ -45,6 +49,8 @@ interface IProps {
|
|
|
45
49
|
showStyle: string;
|
|
46
50
|
bubbleClassNameList?: string[];
|
|
47
51
|
blinkMessageIDList?: string[];
|
|
52
|
+
enableFeedback: number;
|
|
53
|
+
enableAINote: number;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
const props = withDefaults(defineProps<IProps>(), {
|
|
@@ -52,12 +58,16 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
52
58
|
showStyle: '',
|
|
53
59
|
bubbleClassNameList: () => [] as string[],
|
|
54
60
|
blinkMessageIDList: () => [] as string[],
|
|
61
|
+
enableFeedback: 0,
|
|
62
|
+
enableAINote: 1,
|
|
55
63
|
});
|
|
56
64
|
|
|
57
65
|
const emits = defineEmits([
|
|
58
66
|
'resendMessage',
|
|
59
67
|
'handleToggleMessageItem',
|
|
60
68
|
'handleH5LongPress',
|
|
69
|
+
'like',
|
|
70
|
+
'dislike',
|
|
61
71
|
]);
|
|
62
72
|
const messageModel = computed(() =>
|
|
63
73
|
TUIStore.getMessageModel(props.message?.ID),
|
|
@@ -77,6 +87,12 @@ const handleToggleMessageItem = (
|
|
|
77
87
|
const handleH5LongPress = (e: any, message: IMessageModel, type: string) => {
|
|
78
88
|
emits('handleH5LongPress', e, message, type);
|
|
79
89
|
};
|
|
90
|
+
const onLike = (messageInfo: Object) => {
|
|
91
|
+
emits('like', messageInfo);
|
|
92
|
+
};
|
|
93
|
+
const onDislike = (messageInfo: Object) => {
|
|
94
|
+
emits('dislike', messageInfo);
|
|
95
|
+
};
|
|
80
96
|
</script>
|
|
81
97
|
|
|
82
98
|
<style lang="scss" scoped>
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
@resendMessage="resendMessage"
|
|
10
10
|
@handleToggleMessageItem="handleToggleMessageItem"
|
|
11
11
|
@handleH5LongPress="handleH5LongPress"
|
|
12
|
+
:enableFeedback="props.enableFeedback"
|
|
13
|
+
:enableAINote="props.enableAINote"
|
|
14
|
+
@like="onLike"
|
|
15
|
+
@dislike="onDislike"
|
|
12
16
|
>
|
|
13
17
|
<template #messageBubble>
|
|
14
18
|
<MessageCustomerService
|
|
@@ -43,11 +47,15 @@ const { computed } = vue;
|
|
|
43
47
|
interface IProps {
|
|
44
48
|
message: IMessageModel;
|
|
45
49
|
blinkMessageIDList?: string[];
|
|
50
|
+
enableFeedback: number;
|
|
51
|
+
enableAINote: number;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
const props = withDefaults(defineProps<IProps>(), {
|
|
49
55
|
message: () => ({} as IMessageModel),
|
|
50
56
|
blinkMessageIDList: () => [] as string[],
|
|
57
|
+
enableFeedback: 0,
|
|
58
|
+
enableAINote: 1,
|
|
51
59
|
});
|
|
52
60
|
|
|
53
61
|
const emits = defineEmits([
|
|
@@ -56,6 +64,8 @@ const emits = defineEmits([
|
|
|
56
64
|
'handleH5LongPress',
|
|
57
65
|
'heightChanged',
|
|
58
66
|
'messageSent',
|
|
67
|
+
'like',
|
|
68
|
+
'dislike',
|
|
59
69
|
]);
|
|
60
70
|
const messageModel = computed(() => TUIStore.getMessageModel(props.message.ID));
|
|
61
71
|
|
|
@@ -101,6 +111,14 @@ const onHeightChanged = () => {
|
|
|
101
111
|
const onMessageSent = () => {
|
|
102
112
|
emits('messageSent');
|
|
103
113
|
};
|
|
114
|
+
|
|
115
|
+
function onLike(messageInfo: Object) {
|
|
116
|
+
emits('like', messageInfo);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
function onDislike(messageInfo: Object) {
|
|
120
|
+
emits('dislike', messageInfo);
|
|
121
|
+
};
|
|
104
122
|
</script>
|
|
105
123
|
|
|
106
124
|
<style lang="scss" scoped>
|
package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue
CHANGED
|
@@ -256,13 +256,10 @@ async function scrollToOriginalMessage() {
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
.mobile-quote-sender{
|
|
259
|
-
font-family: PingFangSC-Regular;
|
|
260
259
|
font-size: 10px;
|
|
261
|
-
|
|
262
260
|
}
|
|
263
261
|
|
|
264
262
|
.max-double-line {
|
|
265
|
-
font-family: PingFangSC-Regular;
|
|
266
263
|
font-size: 14px;
|
|
267
264
|
overflow-wrap: break-word;
|
|
268
265
|
word-break: normal;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="['message-text-container', isPC && 'text-select']">
|
|
3
3
|
<span
|
|
4
|
-
v-for="(item, index) in
|
|
4
|
+
v-for="(item, index) in textMessageData.text"
|
|
5
5
|
:key="index"
|
|
6
|
-
>
|
|
6
|
+
>
|
|
7
|
+
<span v-if="item.name === 'text' && enableURLDetection === 1"
|
|
8
|
+
class="text"
|
|
9
|
+
v-html="item.text"
|
|
10
|
+
></span>
|
|
7
11
|
<span
|
|
8
|
-
v-if="item.name === 'text'"
|
|
12
|
+
v-else-if="item.name === 'text'"
|
|
9
13
|
class="text"
|
|
10
14
|
>{{ item.text }}</span>
|
|
11
15
|
<img
|
|
@@ -25,17 +29,23 @@ import {
|
|
|
25
29
|
CUSTOM_BASIC_EMOJI_URL_MAPPING,
|
|
26
30
|
} from '../../emoji-config';
|
|
27
31
|
import { isPC } from '../../../../utils/env';
|
|
28
|
-
|
|
32
|
+
import state from '../../../../utils/state.js';
|
|
33
|
+
const {ref, computed } = vue;
|
|
29
34
|
interface IProps {
|
|
30
35
|
content: Record<string, any>;
|
|
36
|
+
flow: string;
|
|
31
37
|
}
|
|
32
38
|
const props = withDefaults(defineProps<IProps>(), {
|
|
33
39
|
content: () => ({}),
|
|
40
|
+
flow: 'in',
|
|
41
|
+
});
|
|
42
|
+
const enableURLDetection = ref(state.get('enableURLDetection'));
|
|
43
|
+
const linkColor = computed(() => {
|
|
44
|
+
return props.flow === 'out' && isPC ? '#fff' : '#0052d9';
|
|
34
45
|
});
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
data.value.text?.forEach(
|
|
46
|
+
const textMessageData = computed(() => {
|
|
47
|
+
const contentCopy = JSON.parse(JSON.stringify(props.content));
|
|
48
|
+
contentCopy.text?.forEach(
|
|
39
49
|
(item: {
|
|
40
50
|
name: string;
|
|
41
51
|
text?: string;
|
|
@@ -45,24 +55,22 @@ watchEffect(() => {
|
|
|
45
55
|
}) => {
|
|
46
56
|
if (item.name === 'img' && item?.type === 'custom') {
|
|
47
57
|
if (!CUSTOM_BASIC_EMOJI_URL) {
|
|
48
|
-
console.warn(
|
|
49
|
-
|
|
50
|
-
);
|
|
51
|
-
} else if (
|
|
52
|
-
!item.emojiKey
|
|
53
|
-
|| !CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey]
|
|
54
|
-
) {
|
|
55
|
-
console.warn(
|
|
56
|
-
'emojiKey is required for custom emoji, please check your emojiKey.',
|
|
57
|
-
);
|
|
58
|
+
console.warn('CUSTOM_BASIC_EMOJI_URL is required for custom emoji, please check your CUSTOM_BASIC_EMOJI_URL.');
|
|
59
|
+
} else if (!item.emojiKey || !CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey]) {
|
|
60
|
+
console.warn('emojiKey is required for custom emoji, please check your emojiKey.');
|
|
58
61
|
} else {
|
|
59
62
|
item.src
|
|
60
63
|
= CUSTOM_BASIC_EMOJI_URL
|
|
61
64
|
+ CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey];
|
|
62
65
|
}
|
|
66
|
+
} else if (item.name === 'text' && enableURLDetection.value) {
|
|
67
|
+
item.text = item.text.replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (url) => {
|
|
68
|
+
return `<a href="${url}" target="_blank" rel="noopener noreferrer" class="message-text-link" style="color: ${linkColor.value}; text-decoration: underline;">${url}</a>`;
|
|
69
|
+
}) || '';
|
|
63
70
|
}
|
|
64
71
|
},
|
|
65
72
|
);
|
|
73
|
+
return contentCopy;
|
|
66
74
|
});
|
|
67
75
|
</script>
|
|
68
76
|
<style lang="scss" scoped>
|
|
@@ -87,7 +95,6 @@ watchEffect(() => {
|
|
|
87
95
|
white-space: pre-wrap;
|
|
88
96
|
font-size: 14px;
|
|
89
97
|
text-size-adjust: none;
|
|
90
|
-
font-family: PingFangSC-Regular;
|
|
91
98
|
overflow-wrap: break-word;
|
|
92
99
|
word-break: normal;
|
|
93
100
|
}
|
|
@@ -62,8 +62,10 @@ onUnmounted(() => {
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
const onInHumanServiceUpdate = (value: boolean) => {
|
|
66
|
-
|
|
65
|
+
const onInHumanServiceUpdate = (data: {conversationID: string, value: boolean}) => {
|
|
66
|
+
if (data && data.conversationID === props.message.conversationID) {
|
|
67
|
+
isInHumanService.value = data.value;
|
|
68
|
+
}
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
const isShowReadStatus = computed<boolean>(() => {
|
|
@@ -33,6 +33,7 @@ import { JSONToObject } from '../../../../utils';
|
|
|
33
33
|
|
|
34
34
|
interface IEmits {
|
|
35
35
|
(key: 'scrollToLatestMessage'): void;
|
|
36
|
+
(key: 'scrollNearToBottom'): void;
|
|
36
37
|
}
|
|
37
38
|
const emits = defineEmits<IEmits>();
|
|
38
39
|
|
|
@@ -89,11 +90,11 @@ function isTypingMessage(message: IMessageModel): boolean {
|
|
|
89
90
|
|
|
90
91
|
function onMessageListUpdated(newMessageList: IMessageModel[]) {
|
|
91
92
|
messageList.value = newMessageList || [];
|
|
92
|
-
const lastMessage = messageList.value
|
|
93
|
+
const lastMessage = messageList.value[messageList.value.length - 1];
|
|
93
94
|
isExistLastMessage.value = !!(
|
|
94
95
|
// 过滤在线消息
|
|
95
96
|
// @ts-ignore
|
|
96
|
-
lastMessage && !lastMessage
|
|
97
|
+
lastMessage && !lastMessage._onlineOnlyFlag && lastMessage.time < currentLastMessageTime.value
|
|
97
98
|
);
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -108,7 +109,7 @@ function onNewMessageList(newMessageList: IMessageModel[]) {
|
|
|
108
109
|
&& !isTypingMessage(message)
|
|
109
110
|
// 过滤在线消息
|
|
110
111
|
// @ts-ignore
|
|
111
|
-
&& !message.
|
|
112
|
+
&& !message._onlineOnlyFlag
|
|
112
113
|
) {
|
|
113
114
|
newMessageCount.value += 1;
|
|
114
115
|
}
|
|
@@ -147,6 +148,10 @@ async function judgeScrollOverOneScreen(e: Event) {
|
|
|
147
148
|
isScrollOverOneScreen.value = true;
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
151
|
+
if (scrollHeight - scrollTop < height + 20) {
|
|
152
|
+
// 滚动接近底部,通知 message-list
|
|
153
|
+
emits('scrollNearToBottom');
|
|
154
|
+
}
|
|
150
155
|
isScrollOverOneScreen.value = false;
|
|
151
156
|
} catch (error) {
|
|
152
157
|
isScrollOverOneScreen.value = false;
|
|
@@ -205,7 +210,6 @@ defineExpose({
|
|
|
205
210
|
-webkit-tap-highlight-color: transparent;
|
|
206
211
|
|
|
207
212
|
&-text {
|
|
208
|
-
font-family: PingFangSC-Regular, system-ui;
|
|
209
213
|
font-size: 10px;
|
|
210
214
|
color: #147aff;
|
|
211
215
|
margin-left: 3px;
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
background-color: rgba(255, 149, 0, 0.1);
|
|
21
21
|
color: #ff8c39;
|
|
22
22
|
line-height: 18px;
|
|
23
|
-
font-family: PingFangSC-Regular;
|
|
24
23
|
font-style: normal;
|
|
25
24
|
font-weight: 400;
|
|
26
25
|
text-align: justify;
|
|
@@ -76,7 +75,6 @@
|
|
|
76
75
|
cursor: pointer;
|
|
77
76
|
|
|
78
77
|
&-text {
|
|
79
|
-
font-family: PingFangSC-Regular;
|
|
80
78
|
font-weight: 400;
|
|
81
79
|
font-size: 10px;
|
|
82
80
|
color: #147aff;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<template v-for="(item, index) in props.toolbarButtonList">
|
|
4
4
|
<ToolbarButtonHumanService v-if="item.presetId === TOOLBAR_BUTTON_TYPE.HUMAN_SERVICE && shouldRender(item) && !isInHumanService" :title="item.title" :icon="item.icon"/>
|
|
5
5
|
<ToolbarButtonServiceRating v-else-if="item.presetId === TOOLBAR_BUTTON_TYPE.SERVICE_RATING && shouldRender(item) && isInHumanService" :title="item.title" :icon="item.icon"/>
|
|
6
|
-
<ToolbarButtonEndHumanService v-else-if="item.presetId === TOOLBAR_BUTTON_TYPE.END_HUMAN_SERVICE && shouldRender(item) && ((item.displayFlag === 1 &&
|
|
6
|
+
<ToolbarButtonEndHumanService v-else-if="item.presetId === TOOLBAR_BUTTON_TYPE.END_HUMAN_SERVICE && shouldRender(item) && ((item.displayFlag === 1 && canEndConversation) || isInHumanService)" :title="item.title" :icon="item.icon"/>
|
|
7
7
|
<div v-else-if="shouldRender(item) && !item.presetId" :key="index"
|
|
8
8
|
:class="['toolbar-button', isH5 ? 'toolbar-button-h5' : '']" @click="onClick(item, index)">
|
|
9
9
|
<Icon v-if="item.icon" class="toolbar-button-icon" :file="item.icon" width="18px" height="18px"/>
|
|
@@ -39,7 +39,7 @@ const props = withDefaults(defineProps<IProps>(), {});
|
|
|
39
39
|
|
|
40
40
|
const isInHumanService = ref(false);
|
|
41
41
|
const currentConversation = ref<IConversationModel>();
|
|
42
|
-
const
|
|
42
|
+
const canEndConversation = ref(false);
|
|
43
43
|
|
|
44
44
|
onMounted(() => {
|
|
45
45
|
TUIStore.watch(StoreName.CONV, {
|
|
@@ -47,7 +47,7 @@ onMounted(() => {
|
|
|
47
47
|
});
|
|
48
48
|
TUIStore.watch(StoreName.CUSTOM, {
|
|
49
49
|
isInHumanService: onInHumanServiceUpdate,
|
|
50
|
-
|
|
50
|
+
canEndConversation: onCanEndConversationUpdate
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
|
|
@@ -57,7 +57,7 @@ onUnmounted(() => {
|
|
|
57
57
|
});
|
|
58
58
|
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
59
59
|
isInHumanService: onInHumanServiceUpdate,
|
|
60
|
-
|
|
60
|
+
canEndConversation: onCanEndConversationUpdate
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
63
|
|
|
@@ -65,12 +65,16 @@ const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
|
65
65
|
currentConversation.value = conversation;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const onInHumanServiceUpdate = (value: boolean) => {
|
|
69
|
-
|
|
68
|
+
const onInHumanServiceUpdate = (data: {conversationID: string, value: boolean}) => {
|
|
69
|
+
if (data && data.conversationID === currentConversation.value.conversationID) {
|
|
70
|
+
isInHumanService.value = data.value;
|
|
71
|
+
}
|
|
70
72
|
};
|
|
71
73
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
+
const onCanEndConversationUpdate = (data: {conversationID: string, value: boolean}) => {
|
|
75
|
+
if (data && data.conversationID === currentConversation.value.conversationID) {
|
|
76
|
+
canEndConversation.value = data.value;
|
|
77
|
+
}
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
function onClick(item:ToolbarButtonModel, index: number) {
|
|
@@ -115,6 +119,7 @@ function shouldRender(item: ToolbarButtonModel) {
|
|
|
115
119
|
overflow-x: auto; /* 允许横向滚动 */
|
|
116
120
|
scrollbar-width: none; /* Firefox 隐藏滚动条 */
|
|
117
121
|
-ms-overflow-style: none; /* IE/Edge 隐藏滚动条 */
|
|
122
|
+
min-height: 28px;
|
|
118
123
|
&::-webkit-scrollbar {
|
|
119
124
|
display: none; /* Chrome 隐藏滚动条 */
|
|
120
125
|
}
|
|
@@ -150,6 +155,5 @@ function shouldRender(item: ToolbarButtonModel) {
|
|
|
150
155
|
text-overflow: ellipsis;
|
|
151
156
|
max-width: 100px;
|
|
152
157
|
overflow: hidden;
|
|
153
|
-
font-family: PingFangSC-Regular;
|
|
154
158
|
}
|
|
155
159
|
</style>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
display: flex;
|
|
8
8
|
flex-direction: column;
|
|
9
9
|
position: relative;
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', '微软雅黑', 'Segoe UI', 'Noto Sans CJK SC', 'Noto Sans CJK TC', 'Noto Sans CJK JP', 'Noto Sans CJK KR', 'Roboto', 'Helvetica Neue', 'MIUI', Arial, sans-serif;
|
|
10
11
|
|
|
11
12
|
&-default {
|
|
12
13
|
width: 100%;
|
|
@@ -45,4 +46,4 @@
|
|
|
45
46
|
height: 160px;
|
|
46
47
|
display: flex;
|
|
47
48
|
}
|
|
48
|
-
}
|
|
49
|
+
}
|
|
@@ -129,6 +129,7 @@ const handleStyle = (type?: string) => {
|
|
|
129
129
|
width: fit-content;
|
|
130
130
|
overflow-wrap: break-word;
|
|
131
131
|
word-break: normal;
|
|
132
|
+
font-size: 14px;
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
|
|
@@ -144,7 +145,6 @@ const handleStyle = (type?: string) => {
|
|
|
144
145
|
padding: 10px 15px;
|
|
145
146
|
|
|
146
147
|
span {
|
|
147
|
-
font-family: PingFangSC-Regular;
|
|
148
148
|
font-weight: 400;
|
|
149
149
|
font-size: 14px;
|
|
150
150
|
letter-spacing: 0;
|
package/constant.ts
CHANGED
|
@@ -25,7 +25,7 @@ export const CUSTOM_MESSAGE_SRC = {
|
|
|
25
25
|
USER_SATISFACTION: '24',
|
|
26
26
|
BOT_STATUS: '25',
|
|
27
27
|
SEAT_STATUS: '26',
|
|
28
|
-
|
|
28
|
+
USER_END_CONVERSATION: '27',
|
|
29
29
|
ORDER:'28',
|
|
30
30
|
ROBOT_MSG: '29',
|
|
31
31
|
RICH_TEXT: '30',
|
|
@@ -37,7 +37,8 @@ export const CUSTOM_MESSAGE_SRC = {
|
|
|
37
37
|
CONCURRENCY_LIMIT: '36',
|
|
38
38
|
TIMEOUT_WARNING: '37',
|
|
39
39
|
TRANSFER_TO_HUMAN: '39',
|
|
40
|
-
|
|
40
|
+
GET_FEEDBACK_MENU: '42',
|
|
41
|
+
SEND_FEEDBACK: '43',
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
// im message extra type
|