@tencentcloud/ai-desk-customer-vue 1.3.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 +23 -4
- package/assets/customer_avatar.png +0 -0
- package/assets/face.svg +10 -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/files.svg +5 -0
- package/assets/green_check.svg +4 -0
- package/assets/image.svg +8 -0
- package/assets/rating_tool_icon.svg +5 -0
- package/assets/rating_tool_icon_h5.svg +1 -0
- package/assets/video.svg +8 -0
- package/assets/video_h5.svg +1 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +16 -14
- package/components/CustomerServiceChat/index-web.vue +87 -13
- package/components/CustomerServiceChat/message-input/index-web.vue +31 -5
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +25 -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 +36 -36
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/index.vue +1 -1
- package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +6 -8
- package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +11 -16
- package/components/CustomerServiceChat/message-input-toolbar/index-web.vue +61 -18
- package/components/CustomerServiceChat/message-input-toolbar/rating-tool/index.vue +72 -0
- package/components/CustomerServiceChat/message-input-toolbar/toolbar-item-container/style/h5.scss +10 -1
- package/components/CustomerServiceChat/message-input-toolbar/user-define-input-tool.vue +80 -0
- package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +9 -14
- package/components/CustomerServiceChat/message-list/index-web.vue +38 -6
- package/components/CustomerServiceChat/message-list/message-elements/feedback-button.vue +369 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +81 -15
- 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 +18 -10
- 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 +13 -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 +25 -9
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-branch/index.vue +5 -3
- 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 +3 -3
- 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-file.vue +1 -1
- 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/CustomerServiceChat/message-list/scroll-button/index.vue +3 -3
- package/components/CustomerServiceChat/message-list/style/web.scss +2 -1
- package/components/CustomerServiceChat/message-toolbar-button/index.vue +111 -42
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-end-human-service.vue +59 -0
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-human-service.vue +55 -0
- package/components/CustomerServiceChat/message-toolbar-button/toolbar-button-service-rating.vue +59 -0
- package/components/common/Toast/index-web.vue +4 -2
- package/constant.ts +25 -0
- package/interface.ts +35 -5
- package/locales/en/aidesk.ts +28 -15
- package/locales/fil/aidesk.ts +28 -15
- package/locales/id/aidesk.ts +28 -15
- package/locales/ja/aidesk.ts +28 -15
- package/locales/ms/aidesk.ts +28 -15
- package/locales/ru/aidesk.ts +28 -15
- package/locales/th/aidesk.ts +28 -15
- package/locales/vi/aidesk.ts +28 -15
- package/locales/zh_cn/aidesk.ts +28 -15
- package/locales/zh_tw/aidesk.ts +28 -15
- package/package.json +1 -1
- package/server.ts +5 -1
- package/utils/state.js +30 -0
- package/utils/utils.ts +48 -1
- package/assets/face.png +0 -0
- package/assets/files.png +0 -0
- package/assets/image.png +0 -0
- package/assets/video.png +0 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-single-form/form-branch.vue +0 -68
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="message-rating-star">
|
|
3
|
-
<p class="rating-head">
|
|
3
|
+
<p class="rating-head-tail">
|
|
4
4
|
{{ props.ratingTemplate.head }}
|
|
5
5
|
</p>
|
|
6
6
|
<div class="rating-card">
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
<p
|
|
51
51
|
v-if="hasReply"
|
|
52
|
-
class="rating-tail"
|
|
52
|
+
class="rating-head-tail"
|
|
53
53
|
:style="{
|
|
54
54
|
marginTop: 20 + 'px',
|
|
55
55
|
}"
|
|
@@ -125,17 +125,15 @@ export default {
|
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
const setValue = (val: number) => {
|
|
128
|
-
if (hasReply.value) {
|
|
129
|
-
|
|
128
|
+
if (!hasReply.value && !hasExpire.value) {
|
|
129
|
+
value.value = val;
|
|
130
130
|
}
|
|
131
|
-
value.value = val;
|
|
132
131
|
};
|
|
133
132
|
|
|
134
133
|
const setHoverValue = (value: number) => {
|
|
135
|
-
if (hasReply.value) {
|
|
136
|
-
|
|
134
|
+
if (!hasReply.value && !hasExpire.value) {
|
|
135
|
+
hoverValue.value = value;
|
|
137
136
|
}
|
|
138
|
-
hoverValue.value = value;
|
|
139
137
|
};
|
|
140
138
|
|
|
141
139
|
const submitRatingStar = async () => {
|
|
@@ -176,16 +174,11 @@ export default {
|
|
|
176
174
|
};
|
|
177
175
|
</script>
|
|
178
176
|
<style lang="scss" scoped>
|
|
179
|
-
.rating-head {
|
|
180
|
-
font-size: 14px;
|
|
181
|
-
font-weight: 400;
|
|
182
|
-
color: #999;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
.rating-tail {
|
|
177
|
+
.rating-head-tail {
|
|
186
178
|
font-size: 14px;
|
|
187
179
|
font-weight: 400;
|
|
188
180
|
color: #999;
|
|
181
|
+
word-break: break-word;
|
|
189
182
|
}
|
|
190
183
|
|
|
191
184
|
.card-title {
|
|
@@ -199,11 +192,11 @@ export default {
|
|
|
199
192
|
border-radius: 20px;
|
|
200
193
|
border: 0;
|
|
201
194
|
margin-top: 10px;
|
|
202
|
-
|
|
203
|
-
padding
|
|
204
|
-
|
|
195
|
+
min-width: 240px;
|
|
196
|
+
padding: 10px;
|
|
205
197
|
button:disabled {
|
|
206
198
|
background: #d8d8d8;
|
|
199
|
+
cursor: default;
|
|
207
200
|
}
|
|
208
201
|
}
|
|
209
202
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
<div>
|
|
3
|
+
<div class="message-stream">
|
|
4
|
+
<span v-if="isCursorBlinking" class="blinking-cursor">|</span>
|
|
5
|
+
<pre ref="preRef" :class="['message-marked']" v-html="displayedContent" />
|
|
6
|
+
</div>
|
|
7
|
+
<div v-if="image" class="rich-image-previewer" @click="closeImage">
|
|
8
|
+
<img
|
|
9
|
+
class="rich-image-preview"
|
|
10
|
+
:src="imageSrc"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
11
13
|
</div>
|
|
12
14
|
</template>
|
|
13
15
|
|
|
@@ -146,9 +148,11 @@ const closeImage = () => {
|
|
|
146
148
|
<style lang="scss" scoped>
|
|
147
149
|
.message-stream {
|
|
148
150
|
overflow-wrap: break-word;
|
|
149
|
-
word-break:
|
|
151
|
+
word-break: normal;
|
|
150
152
|
white-space: normal;
|
|
151
153
|
font-size: 14px;
|
|
154
|
+
font-family: PingFangSC-Regular;
|
|
155
|
+
user-select: text;
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
.blinking-cursor {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
{{ props.payload.content }}
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { customerServicePayloadType } from '../../../../../../interface';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
payload: customerServicePayloadType;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
props: {
|
|
16
|
+
payload: {
|
|
17
|
+
type: Object as () => customerServicePayloadType,
|
|
18
|
+
default: () => ({}),
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
setup(props: Props) {
|
|
22
|
+
return {
|
|
23
|
+
props,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
</script>
|
|
28
|
+
<style lang="scss" scoped>
|
|
29
|
+
</style>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<MessagePluginLayout
|
|
3
3
|
:message="props.message"
|
|
4
|
+
:blinkMessageIDList="props.blinkMessageIDList"
|
|
4
5
|
:showStyle="pluginMessageType.showStyle"
|
|
5
6
|
:bubbleClassNameList="[
|
|
6
7
|
pluginMessageType.pluginType === 'room' ? 'message-bubble-room' : '',
|
|
@@ -14,8 +15,12 @@
|
|
|
14
15
|
v-if="pluginMessageType.pluginType === 'customer'"
|
|
15
16
|
:message="props.message"
|
|
16
17
|
@heightChanged="onHeightChanged"
|
|
18
|
+
@messageSent="onMessageSent"
|
|
17
19
|
/>
|
|
18
20
|
</template>
|
|
21
|
+
<template #messageTip>
|
|
22
|
+
<TimeoutWarning :payload="payload"/>
|
|
23
|
+
</template>
|
|
19
24
|
</MessagePluginLayout>
|
|
20
25
|
</template>
|
|
21
26
|
|
|
@@ -29,6 +34,10 @@ import {
|
|
|
29
34
|
} from './message-desk-elements/index';
|
|
30
35
|
import MessagePluginLayout from './message-plugin-layout-web.vue';
|
|
31
36
|
import MessageCustomerService from './message-desk-elements/message-desk.vue';
|
|
37
|
+
import { CUSTOM_MESSAGE_SRC } from '../../../../../constant';
|
|
38
|
+
import TimeoutWarning from './message-desk-elements/message-timeout-warning.vue';
|
|
39
|
+
import { customerServicePayloadType } from '../../../../../interface';
|
|
40
|
+
import { JSONToObject } from '../../../../../utils/index';
|
|
32
41
|
const { computed } = vue;
|
|
33
42
|
|
|
34
43
|
interface IProps {
|
|
@@ -46,18 +55,26 @@ const emits = defineEmits([
|
|
|
46
55
|
'handleToggleMessageItem',
|
|
47
56
|
'handleH5LongPress',
|
|
48
57
|
'heightChanged',
|
|
58
|
+
'messageSent',
|
|
49
59
|
]);
|
|
50
60
|
const messageModel = computed(() => TUIStore.getMessageModel(props.message.ID));
|
|
51
61
|
|
|
62
|
+
const payload = computed<customerServicePayloadType>(() => {
|
|
63
|
+
return props.message && JSONToObject(props.message?.payload?.data);
|
|
64
|
+
});
|
|
65
|
+
|
|
52
66
|
const pluginMessageType = computed<{ pluginType: string; showStyle: string }>(
|
|
53
67
|
() => {
|
|
54
68
|
let typeObj = { pluginType: '', showStyle: '' };
|
|
55
69
|
if (isCustomerServicePluginMessage(messageModel.value as any)) {
|
|
70
|
+
const src = payload.value.src;
|
|
56
71
|
typeObj = {
|
|
57
|
-
pluginType: 'customer',
|
|
72
|
+
pluginType: src === CUSTOM_MESSAGE_SRC.TIMEOUT_WARNING ? 'customer_tip' : 'customer',
|
|
58
73
|
showStyle: isCustomServiceMessageInvisible(messageModel.value as any)
|
|
59
74
|
? ''
|
|
60
|
-
:
|
|
75
|
+
: src === CUSTOM_MESSAGE_SRC.TIMEOUT_WARNING
|
|
76
|
+
? 'tip'
|
|
77
|
+
: 'bubble',
|
|
61
78
|
};
|
|
62
79
|
}
|
|
63
80
|
return typeObj;
|
|
@@ -81,6 +98,9 @@ const handleH5LongPress = (e: any, message: IMessageModel, type: string) => {
|
|
|
81
98
|
const onHeightChanged = () => {
|
|
82
99
|
emits('heightChanged');
|
|
83
100
|
};
|
|
101
|
+
const onMessageSent = () => {
|
|
102
|
+
emits('messageSent');
|
|
103
|
+
};
|
|
84
104
|
</script>
|
|
85
105
|
|
|
86
106
|
<style lang="scss" scoped>
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
IMessageModel,
|
|
23
23
|
} from '@tencentcloud/chat-uikit-engine';
|
|
24
24
|
import Icon from '../../../common/Icon.vue';
|
|
25
|
-
import files from '../../../../assets/files.
|
|
25
|
+
import files from '../../../../assets/files.svg';
|
|
26
26
|
import { isUniFrameWork } from '../../../../utils/env';
|
|
27
27
|
import type { IFileMessageContent } from '../../../../interface';
|
|
28
28
|
const { withDefaults } = vue;
|
package/components/CustomerServiceChat/message-list/message-elements/message-quote/index-web.vue
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="display:flex;width: fit-content;">
|
|
3
|
-
<div v-if="hasQuoteContent&&isH5" :class="{
|
|
4
|
-
'mobile-left-box': true,
|
|
5
|
-
reverse: message.flow === 'out',
|
|
6
|
-
in:message.flow === 'in',
|
|
7
|
-
}"></div>
|
|
8
3
|
<div
|
|
9
4
|
v-if="hasQuoteContent"
|
|
10
5
|
:class="{
|
|
@@ -218,8 +213,8 @@ async function scrollToOriginalMessage() {
|
|
|
218
213
|
padding: 12px;
|
|
219
214
|
font-size: 12px;
|
|
220
215
|
color: #666;
|
|
221
|
-
|
|
222
|
-
word-break:
|
|
216
|
+
overflow-wrap: break-word;
|
|
217
|
+
word-break: normal;
|
|
223
218
|
background-color: #fbfbfb;
|
|
224
219
|
border-radius: 8px;
|
|
225
220
|
line-height: 16.8px;
|
|
@@ -233,12 +228,12 @@ async function scrollToOriginalMessage() {
|
|
|
233
228
|
.reverse.reference-content {
|
|
234
229
|
margin-right: 44px;
|
|
235
230
|
margin-left: auto;
|
|
236
|
-
border-radius:
|
|
231
|
+
border-radius: 8px;
|
|
237
232
|
}
|
|
238
233
|
.isMobile.reference-content.in {
|
|
239
234
|
margin-right: auto;
|
|
240
235
|
background: #f3f4f7;
|
|
241
|
-
border-radius:
|
|
236
|
+
border-radius: 8px;
|
|
242
237
|
}
|
|
243
238
|
.isMobile.reverse.reference-content {
|
|
244
239
|
margin-right: 10px;
|
|
@@ -247,20 +242,6 @@ async function scrollToOriginalMessage() {
|
|
|
247
242
|
color: white;
|
|
248
243
|
|
|
249
244
|
}
|
|
250
|
-
.mobile-left-box {
|
|
251
|
-
display:inline-block;
|
|
252
|
-
background: #FFFFFF33;
|
|
253
|
-
width: 5px;
|
|
254
|
-
margin-top: 4px;
|
|
255
|
-
border-radius: 8px 0 0 8px;
|
|
256
|
-
}
|
|
257
|
-
.mobile-left-box.in {
|
|
258
|
-
display:inline-block;
|
|
259
|
-
background: #e1e2e5;
|
|
260
|
-
width: 5px;
|
|
261
|
-
margin-top: 4px;
|
|
262
|
-
border-radius: 8px 0 0 8px;
|
|
263
|
-
}
|
|
264
245
|
.revoked-text {
|
|
265
246
|
color: #999;
|
|
266
247
|
}
|
|
@@ -274,7 +255,8 @@ async function scrollToOriginalMessage() {
|
|
|
274
255
|
.max-double-line {
|
|
275
256
|
font-family: PingFangSC-Regular;
|
|
276
257
|
font-size: 14px;
|
|
277
|
-
|
|
258
|
+
overflow-wrap: break-word;
|
|
259
|
+
word-break: normal;
|
|
278
260
|
overflow: hidden;
|
|
279
261
|
display: -webkit-box;
|
|
280
262
|
max-height: 33px;
|
|
@@ -84,15 +84,6 @@ watchEffect(() => {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
.text {
|
|
87
|
-
white-space: pre-wrap;
|
|
88
|
-
font-size: 14px;
|
|
89
|
-
text-size-adjust: none;
|
|
90
|
-
font-family: PingFangSC-Regular;
|
|
91
|
-
overflow-wrap: break-word;
|
|
92
|
-
word-break: break-all;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.text:lang(en) {
|
|
96
87
|
white-space: pre-wrap;
|
|
97
88
|
font-size: 14px;
|
|
98
89
|
text-size-adjust: none;
|
|
@@ -18,24 +18,24 @@ import TUIChatEngine, {
|
|
|
18
18
|
IMessageModel,
|
|
19
19
|
TUITranslateService,
|
|
20
20
|
} from '@tencentcloud/chat-uikit-engine';
|
|
21
|
+
import { ReadState } from '../../../../../constant';
|
|
21
22
|
const { computed, ref, onMounted, onUnmounted } = vue;
|
|
22
23
|
|
|
23
24
|
interface IProps {
|
|
24
25
|
message: IMessageModel;
|
|
26
|
+
prevStatus: ReadState;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const props = withDefaults(defineProps<IProps>(), {
|
|
28
30
|
message: () => ({} as IMessageModel),
|
|
31
|
+
prevStatus: ReadState.Unread,
|
|
29
32
|
});
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Unread,
|
|
35
|
-
AllRead,
|
|
36
|
-
NotShow,
|
|
37
|
-
PartiallyRead,
|
|
33
|
+
const isInHumanService = ref(false);
|
|
34
|
+
|
|
35
|
+
interface IEmits {
|
|
36
|
+
(e: 'setStatus', status:ReadState): void;
|
|
38
37
|
}
|
|
38
|
+
const emits = defineEmits<IEmits>();
|
|
39
39
|
|
|
40
40
|
const TYPES = TUIChatEngine.TYPES;
|
|
41
41
|
// User-level read receipt toggle has the highest priority.
|
|
@@ -48,18 +48,25 @@ onMounted(() => {
|
|
|
48
48
|
TUIStore.watch(StoreName.USER, {
|
|
49
49
|
displayMessageReadReceipt: onDisplayMessageReadReceiptUpdate,
|
|
50
50
|
});
|
|
51
|
+
TUIStore.watch(StoreName.CUSTOM, {
|
|
52
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
53
|
+
});
|
|
51
54
|
});
|
|
52
55
|
|
|
53
56
|
onUnmounted(() => {
|
|
54
57
|
TUIStore.unwatch(StoreName.USER, {
|
|
55
58
|
displayMessageReadReceipt: onDisplayMessageReadReceiptUpdate,
|
|
56
59
|
});
|
|
60
|
+
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
61
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
62
|
+
});
|
|
57
63
|
});
|
|
58
64
|
|
|
65
|
+
const onInHumanServiceUpdate = (value: boolean) => {
|
|
66
|
+
isInHumanService.value = value;
|
|
67
|
+
};
|
|
68
|
+
|
|
59
69
|
const isShowReadStatus = computed<boolean>(() => {
|
|
60
|
-
if (!ReadStatus) {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
70
|
if (!isDisplayMessageReadReceipt.value) {
|
|
64
71
|
return false;
|
|
65
72
|
}
|
|
@@ -127,23 +134,27 @@ const readState = computed<ReadState>(() => {
|
|
|
127
134
|
return isPeerRead ? ReadState.Read : ReadState.Unread;
|
|
128
135
|
}
|
|
129
136
|
} else if (conversationType === 'GROUP') {
|
|
130
|
-
if (needReadReceipt) {
|
|
131
|
-
if (readCount === 0) {
|
|
132
|
-
return ReadState.Unread;
|
|
133
|
-
} else if (unreadCount === 0) {
|
|
134
|
-
return ReadState.AllRead;
|
|
135
|
-
} else {
|
|
136
|
-
return ReadState.PartiallyRead;
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
137
|
+
if (!needReadReceipt) {
|
|
139
138
|
return ReadState.NotShow;
|
|
140
139
|
}
|
|
140
|
+
if (!isInHumanService.value) {
|
|
141
|
+
return ReadState.AllRead;
|
|
142
|
+
}
|
|
143
|
+
// 特殊判断: 群里只有1人时设置已读 (未接到人工时)
|
|
144
|
+
if (readCount === 0) {
|
|
145
|
+
return props.prevStatus === ReadState.AllRead ? ReadState.AllRead : ReadState.Unread;
|
|
146
|
+
} else if (unreadCount === 0) {
|
|
147
|
+
return ReadState.AllRead;
|
|
148
|
+
} else {
|
|
149
|
+
return ReadState.PartiallyRead;
|
|
150
|
+
}
|
|
141
151
|
}
|
|
142
152
|
return ReadState.Unread;
|
|
143
153
|
});
|
|
144
154
|
|
|
145
155
|
const readStatusText = computed(() => {
|
|
146
156
|
const { readCount = 0 } = props.message.readReceiptInfo;
|
|
157
|
+
emits('setStatus', readState.value);
|
|
147
158
|
switch (readState.value) {
|
|
148
159
|
case ReadState.Read:
|
|
149
160
|
return TUITranslateService.t('TUIChat.已读');
|
|
@@ -64,7 +64,7 @@ watch(
|
|
|
64
64
|
onMounted(() => {
|
|
65
65
|
TUIStore.watch(StoreName.CHAT, {
|
|
66
66
|
messageList: onMessageListUpdated,
|
|
67
|
-
newMessageList:
|
|
67
|
+
newMessageList: onNewMessageList,
|
|
68
68
|
});
|
|
69
69
|
TUIStore.watch(StoreName.CONV, {
|
|
70
70
|
currentConversation: onCurrentConversationUpdated,
|
|
@@ -74,7 +74,7 @@ onMounted(() => {
|
|
|
74
74
|
onUnmounted(() => {
|
|
75
75
|
TUIStore.unwatch(StoreName.CHAT, {
|
|
76
76
|
messageList: onMessageListUpdated,
|
|
77
|
-
newMessageList:
|
|
77
|
+
newMessageList: onNewMessageList,
|
|
78
78
|
});
|
|
79
79
|
TUIStore.unwatch(StoreName.CONV, {
|
|
80
80
|
currentConversation: onCurrentConversationUpdated,
|
|
@@ -97,7 +97,7 @@ function onMessageListUpdated(newMessageList: IMessageModel[]) {
|
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function
|
|
100
|
+
function onNewMessageList(newMessageList: IMessageModel[]) {
|
|
101
101
|
if (Array.isArray(newMessageList) && isScrollButtonVisible.value) {
|
|
102
102
|
newMessageList.forEach((message: IMessageModel) => {
|
|
103
103
|
if (
|
|
@@ -1,75 +1,144 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</
|
|
13
|
-
|
|
2
|
+
<div class="toolbar-button-container">
|
|
3
|
+
<template v-for="(item, index) in props.toolbarButtonList">
|
|
4
|
+
<ToolbarButtonHumanService v-if="item.presetId === TOOLBAR_BUTTON_TYPE.HUMAN_SERVICE && shouldRender(item) && !isInHumanService" :title="item.title" :icon="item.icon"/>
|
|
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) && isInHumanService" :title="item.title" :icon="item.icon"/>
|
|
7
|
+
<div v-else-if="shouldRender(item) && !item.presetId" :key="index"
|
|
8
|
+
:class="['toolbar-button', isH5 ? 'toolbar-button-h5' : '']" @click="onClick(item, index)">
|
|
9
|
+
<Icon v-if="item.icon" class="toolbar-button-icon" :file="item.icon" width="18px" height="18px"/>
|
|
10
|
+
<div class="toolbar-button-text">
|
|
11
|
+
{{ item.title }}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
</div>
|
|
14
16
|
</template>
|
|
15
17
|
<script lang="ts" setup>
|
|
18
|
+
import vue from '../../../adapter-vue';
|
|
19
|
+
const { ref, onMounted, onUnmounted } = vue;
|
|
20
|
+
import {
|
|
21
|
+
TUIChatService,
|
|
22
|
+
TUIStore,
|
|
23
|
+
StoreName,
|
|
24
|
+
IConversationModel
|
|
25
|
+
} from '@tencentcloud/chat-uikit-engine';
|
|
16
26
|
import { isH5 } from '../../../utils/env';
|
|
17
27
|
import { ToolbarButtonModel } from '../../../interface';
|
|
18
28
|
import Icon from '../../common/Icon.vue';
|
|
19
|
-
|
|
29
|
+
import { TOOLBAR_BUTTON_TYPE } from '../../../constant';
|
|
30
|
+
import { isEnabledMessageReadReceiptGlobal, openSafeUrl, getTo } from '../../../utils/utils';
|
|
31
|
+
import ToolbarButtonHumanService from './toolbar-button-human-service.vue';
|
|
32
|
+
import ToolbarButtonServiceRating from './toolbar-button-service-rating.vue';
|
|
33
|
+
import ToolbarButtonEndHumanService from './toolbar-button-end-human-service.vue';
|
|
20
34
|
interface IProps {
|
|
21
|
-
|
|
35
|
+
toolbarButtonList?: ToolbarButtonModel[] | undefined;
|
|
22
36
|
}
|
|
23
37
|
|
|
24
|
-
const props = withDefaults(defineProps<IProps>(), {
|
|
25
|
-
|
|
38
|
+
const props = withDefaults(defineProps<IProps>(), {});
|
|
39
|
+
|
|
40
|
+
const isInHumanService = ref(false);
|
|
41
|
+
const currentConversation = ref<IConversationModel>();
|
|
42
|
+
|
|
43
|
+
onMounted(() => {
|
|
44
|
+
TUIStore.watch(StoreName.CONV, {
|
|
45
|
+
currentConversation: onCurrentConversationUpdate,
|
|
46
|
+
});
|
|
47
|
+
TUIStore.watch(StoreName.CUSTOM, {
|
|
48
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
onUnmounted(() => {
|
|
53
|
+
TUIStore.unwatch(StoreName.CONV, {
|
|
54
|
+
currentConversation: onCurrentConversationUpdate,
|
|
55
|
+
});
|
|
56
|
+
TUIStore.unwatch(StoreName.CUSTOM, {
|
|
57
|
+
isInHumanService: onInHumanServiceUpdate,
|
|
58
|
+
});
|
|
26
59
|
});
|
|
27
60
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
61
|
+
const onCurrentConversationUpdate = (conversation: IConversationModel) => {
|
|
62
|
+
currentConversation.value = conversation;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const onInHumanServiceUpdate = (value: boolean) => {
|
|
66
|
+
isInHumanService.value = value;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function onClick(item:ToolbarButtonModel, index: number) {
|
|
70
|
+
if (item.type === 1 && item.content) {
|
|
71
|
+
TUIChatService.sendTextMessage({
|
|
72
|
+
to: getTo(currentConversation?.value),
|
|
73
|
+
conversationType: currentConversation?.value?.type,
|
|
74
|
+
payload: {
|
|
75
|
+
text: item.content
|
|
76
|
+
},
|
|
77
|
+
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
78
|
+
});
|
|
79
|
+
} else if (item.type === 2 && item.content) {
|
|
80
|
+
openSafeUrl(item.content);
|
|
81
|
+
} else if (props.toolbarButtonList !== undefined && typeof props.toolbarButtonList[index].clickEvent === 'function') {
|
|
82
|
+
props.toolbarButtonList[index].clickEvent();
|
|
83
|
+
}
|
|
32
84
|
}
|
|
33
85
|
|
|
34
86
|
function shouldRender(item: ToolbarButtonModel) {
|
|
87
|
+
if (item.isEnabled === 1) {
|
|
88
|
+
return true;
|
|
89
|
+
} else if (item.isEnabled === 0) {
|
|
90
|
+
return false;
|
|
91
|
+
} else if (item.renderCondition) {
|
|
35
92
|
return typeof item.renderCondition === 'function' ? item.renderCondition() : false;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
36
95
|
}
|
|
37
96
|
|
|
38
97
|
</script>
|
|
39
98
|
<style>
|
|
40
99
|
.toolbar-button-container {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: row !important;
|
|
102
|
+
margin: 5px !important;
|
|
103
|
+
align-items: center ;
|
|
104
|
+
overflow-x: auto; /* 允许横向滚动 */
|
|
105
|
+
scrollbar-width: none; /* Firefox 隐藏滚动条 */
|
|
106
|
+
-ms-overflow-style: none; /* IE/Edge 隐藏滚动条 */
|
|
107
|
+
&::-webkit-scrollbar {
|
|
108
|
+
display: none; /* Chrome 隐藏滚动条 */
|
|
109
|
+
}
|
|
45
110
|
}
|
|
46
111
|
|
|
47
112
|
.toolbar-button {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
113
|
+
border: 1px solid #E7EAEF;
|
|
114
|
+
padding: 5px 10px;
|
|
115
|
+
border-radius: 20px;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
margin-left: 10px;
|
|
120
|
+
white-space: nowrap;
|
|
121
|
+
user-select: none;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.toolbar-button:first-child {
|
|
125
|
+
margin-left: 5px;
|
|
57
126
|
}
|
|
58
127
|
|
|
59
128
|
.toolbar-button-h5 {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
129
|
+
border: none;
|
|
130
|
+
background-color: #fff;
|
|
131
|
+
box-shadow: 0px 2px 2px 0px rgba(70, 98, 140, 0.06);
|
|
63
132
|
}
|
|
64
133
|
|
|
65
134
|
.toolbar-button-icon {
|
|
66
|
-
|
|
135
|
+
margin-right: 3px;
|
|
67
136
|
}
|
|
68
137
|
.toolbar-button-text {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
138
|
+
font-size: 12px;
|
|
139
|
+
text-overflow: ellipsis;
|
|
140
|
+
max-width: 100px;
|
|
141
|
+
overflow: hidden;
|
|
142
|
+
font-family: PingFangSC-Regular;
|
|
74
143
|
}
|
|
75
144
|
</style>
|