@tencentcloud/ai-desk-customer-vue 1.5.11 → 1.6.2
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 +21 -0
- package/assets/arrow_down_icon.svg +1 -0
- package/assets/arrow_down_icon_white.svg +1 -0
- package/assets/audio-blue.svg +4 -0
- package/assets/audio_icon_1.svg +3 -0
- package/assets/audio_icon_2.svg +3 -0
- package/assets/audio_icon_3.svg +3 -0
- package/assets/keyboard-icon.svg +9 -0
- package/components/CustomerServiceChat/chat-header/index-web.vue +1 -5
- package/components/CustomerServiceChat/emoji-config/default-emoji.ts +11 -0
- package/components/CustomerServiceChat/emoji-config/index.ts +14 -1
- package/components/CustomerServiceChat/index-web.vue +10 -2
- package/components/CustomerServiceChat/message-input/index-web.vue +95 -10
- package/components/CustomerServiceChat/message-input/message-input-button.vue +5 -0
- package/components/CustomerServiceChat/message-input/message-input-editor-web.vue +346 -11
- package/components/CustomerServiceChat/message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue +26 -46
- package/components/CustomerServiceChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue +8 -38
- package/components/CustomerServiceChat/message-list/bottom-quick-order/index.vue +1 -0
- package/components/CustomerServiceChat/message-list/index-web.vue +13 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-audio-web.vue +50 -78
- package/components/CustomerServiceChat/message-list/message-elements/message-bubble-web.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +5 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-robot-welcome.vue +13 -6
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +3 -2
- package/components/CustomerServiceChat/message-list/scroll-button/index.vue +17 -9
- package/components/common/Toast/index-web.ts +16 -3
- package/components/common/Toast/index-web.vue +16 -6
- package/constant.ts +1 -0
- package/locales/en/TUIChat.ts +7 -3
- package/locales/en/aidesk.ts +0 -1
- package/locales/fil/TUIChat.ts +7 -3
- package/locales/fil/aidesk.ts +0 -1
- package/locales/id/TUIChat.ts +76 -72
- package/locales/id/aidesk.ts +0 -1
- package/locales/ja/TUIChat.ts +76 -72
- package/locales/ja/aidesk.ts +0 -1
- package/locales/ms/TUIChat.ts +76 -72
- package/locales/ms/aidesk.ts +0 -1
- package/locales/ru/TUIChat.ts +7 -3
- package/locales/ru/aidesk.ts +0 -1
- package/locales/th/TUIChat.ts +76 -72
- package/locales/th/aidesk.ts +0 -1
- package/locales/vi/TUIChat.ts +76 -72
- package/locales/vi/aidesk.ts +0 -1
- package/locales/zh_cn/TUIChat.ts +6 -2
- package/locales/zh_cn/aidesk.ts +0 -1
- package/locales/zh_tw/TUIChat.ts +6 -2
- package/locales/zh_tw/aidesk.ts +0 -1
- package/package.json +2 -1
- package/server.ts +22 -3
- package/assets/double-arrow.svg +0 -1
- package/assets/keyboard_icon.png +0 -0
|
@@ -548,8 +548,21 @@ const onCurrentConversationIDUpdated = (conversationID: string) => {
|
|
|
548
548
|
// Synchronize storage about whether the audio has been played when converstaion switched
|
|
549
549
|
chatStorage.setChatStorage('audioPlayedMapping', audioPlayedMapping.value);
|
|
550
550
|
}
|
|
551
|
+
preloadEmoji();
|
|
551
552
|
};
|
|
552
553
|
|
|
554
|
+
const preloadEmoji = () => {
|
|
555
|
+
setTimeout(() => {
|
|
556
|
+
let url;
|
|
557
|
+
let img;
|
|
558
|
+
for (let i = 0; i <= 61; i++) {
|
|
559
|
+
url = `https://web.sdk.qcloud.com/im/assets/emoji-plugin/emoji_${i}@2x.png`;
|
|
560
|
+
img = new Image();
|
|
561
|
+
img.src = url;
|
|
562
|
+
}
|
|
563
|
+
}, 0);
|
|
564
|
+
}
|
|
565
|
+
|
|
553
566
|
const getHistoryMessageList = () => {
|
|
554
567
|
TUIChatService.getMessageList().then((res: any) => {
|
|
555
568
|
const { nextReqMessageID: ID } = res.data;
|
|
@@ -9,24 +9,22 @@
|
|
|
9
9
|
@click.stop="play"
|
|
10
10
|
>
|
|
11
11
|
<div class="audio-icon-container">
|
|
12
|
-
<!-- <div :class="{ mask: true, play: isAudioPlaying }" /> -->
|
|
13
12
|
<Icon
|
|
14
13
|
:class="{icon:true,play: isAudioPlaying}"
|
|
15
14
|
width="16px"
|
|
16
|
-
height="
|
|
17
|
-
:file="
|
|
18
|
-
|
|
15
|
+
height="16px"
|
|
16
|
+
:file="currentAudioIcon"
|
|
19
17
|
/>
|
|
20
18
|
</div>
|
|
21
19
|
<span
|
|
22
20
|
class="time"
|
|
23
|
-
:style="{ width: `${data.second *
|
|
21
|
+
:style="{ width: `${data.second * 2 + 20}px` }"
|
|
24
22
|
>
|
|
25
|
-
{{ data.second || 1 }}
|
|
23
|
+
{{ data.second || 1 }}"
|
|
26
24
|
</span>
|
|
27
25
|
<audio
|
|
28
26
|
ref="audioRef"
|
|
29
|
-
:src="
|
|
27
|
+
:src="audioUrl"
|
|
30
28
|
/>
|
|
31
29
|
</div>
|
|
32
30
|
</template>
|
|
@@ -34,9 +32,16 @@
|
|
|
34
32
|
<script lang="ts" setup>
|
|
35
33
|
import vue from '../../../../adapter-vue';
|
|
36
34
|
import Icon from '../../../common/Icon.vue';
|
|
37
|
-
import
|
|
35
|
+
import audioIcon1 from '../../../../assets/audio_icon_1.svg';
|
|
36
|
+
import audioIcon2 from '../../../../assets/audio_icon_2.svg';
|
|
37
|
+
import audioIcon3 from '../../../../assets/audio_icon_3.svg';
|
|
38
38
|
import { isMobile } from '../../../../utils/env';
|
|
39
|
-
|
|
39
|
+
import {
|
|
40
|
+
Toast,
|
|
41
|
+
TOAST_TYPE,
|
|
42
|
+
} from '../../../common/Toast/index-web';
|
|
43
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
44
|
+
const { watchEffect, ref, onMounted, onUnmounted, computed } = vue;
|
|
40
45
|
|
|
41
46
|
interface IEmits {
|
|
42
47
|
(e: 'setAudioPlayed', messageID: string): void;
|
|
@@ -58,6 +63,11 @@ const data = ref();
|
|
|
58
63
|
const message = ref();
|
|
59
64
|
const isAudioPlaying = ref();
|
|
60
65
|
const audioRef = ref<HTMLAudioElement>();
|
|
66
|
+
const audioIcons = [audioIcon1, audioIcon2, audioIcon3];
|
|
67
|
+
const currentAudioIconIndex = ref(2);
|
|
68
|
+
const audioUrl = ref('');
|
|
69
|
+
const currentAudioIcon = computed(() => audioIcons[currentAudioIconIndex.value]);
|
|
70
|
+
let audioIconTimer: any = null;
|
|
61
71
|
|
|
62
72
|
onMounted(() => {
|
|
63
73
|
if (audioRef.value) {
|
|
@@ -76,6 +86,7 @@ onUnmounted(() => {
|
|
|
76
86
|
watchEffect(() => {
|
|
77
87
|
message.value = props.messageItem;
|
|
78
88
|
data.value = props.content;
|
|
89
|
+
audioUrl.value = data.value.url || message.value.payload.remoteAudioUrl;
|
|
79
90
|
});
|
|
80
91
|
|
|
81
92
|
function play() {
|
|
@@ -95,45 +106,57 @@ function play() {
|
|
|
95
106
|
audio.currentTime = 0;
|
|
96
107
|
}
|
|
97
108
|
});
|
|
98
|
-
|
|
109
|
+
try {
|
|
110
|
+
if (!audioUrl.value) {
|
|
111
|
+
const message = `${TUITranslateService.t("TUIChat.语音播放失败")}`;
|
|
112
|
+
Toast({
|
|
113
|
+
message,
|
|
114
|
+
type: TOAST_TYPE.ERROR,
|
|
115
|
+
duration: 2000,
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
audioRef.value.play();
|
|
120
|
+
if (!audioIconTimer) {
|
|
121
|
+
audioIconTimer = setInterval(() => {
|
|
122
|
+
currentAudioIconIndex.value = (currentAudioIconIndex.value + 1) % audioIcons.length;
|
|
123
|
+
}, 500);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} catch (e) {
|
|
127
|
+
console.warn(e);
|
|
128
|
+
}
|
|
99
129
|
isAudioPlaying.value = true;
|
|
100
130
|
if (message.value.flow === 'in') {
|
|
101
131
|
emits('setAudioPlayed', message.value.ID);
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
134
|
|
|
135
|
+
function initAudioIcon() {
|
|
136
|
+
clearInterval(audioIconTimer);
|
|
137
|
+
audioIconTimer = null;
|
|
138
|
+
currentAudioIconIndex.value = 2;
|
|
139
|
+
}
|
|
140
|
+
|
|
105
141
|
function onAudioEnded() {
|
|
106
142
|
isAudioPlaying.value = false;
|
|
143
|
+
initAudioIcon();
|
|
107
144
|
}
|
|
108
145
|
|
|
109
146
|
function onAudioPaused() {
|
|
110
147
|
isAudioPlaying.value = false;
|
|
148
|
+
initAudioIcon();
|
|
111
149
|
}
|
|
112
150
|
</script>
|
|
113
151
|
<style lang="scss" scoped>
|
|
114
152
|
@import "../../style/common";
|
|
115
|
-
|
|
116
|
-
$flow-in-bg-color: #fbfbfb;
|
|
117
|
-
$flow-out-bg-color: #dceafd;
|
|
118
|
-
|
|
119
|
-
@keyframes blink {
|
|
120
|
-
0% {
|
|
121
|
-
opacity: 1;
|
|
122
|
-
}
|
|
123
|
-
50% {
|
|
124
|
-
opacity: 0;
|
|
125
|
-
}
|
|
126
|
-
100% {
|
|
127
|
-
opacity: 1;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
153
|
.message-audio {
|
|
132
154
|
flex-direction: row;
|
|
133
155
|
display: flex;
|
|
134
156
|
flex: 0 0 auto;
|
|
135
157
|
cursor: pointer;
|
|
136
158
|
overflow: hidden;
|
|
159
|
+
align-items: center;
|
|
137
160
|
|
|
138
161
|
.time {
|
|
139
162
|
flex: 1 1 auto;
|
|
@@ -156,47 +179,6 @@ $flow-out-bg-color: #dceafd;
|
|
|
156
179
|
position: relative;
|
|
157
180
|
margin: 0 7px 0 0;
|
|
158
181
|
overflow: hidden;
|
|
159
|
-
|
|
160
|
-
.mask {
|
|
161
|
-
position: absolute;
|
|
162
|
-
z-index: 2;
|
|
163
|
-
width: 100%;
|
|
164
|
-
height: 100%;
|
|
165
|
-
left: 0;
|
|
166
|
-
top: 0;
|
|
167
|
-
transform-origin: right;
|
|
168
|
-
transform: scaleX(0);
|
|
169
|
-
background-color: $flow-in-bg-color;
|
|
170
|
-
|
|
171
|
-
&.play {
|
|
172
|
-
animation: audio-play 2s steps(1, end) infinite;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
.icon{
|
|
176
|
-
&.play{
|
|
177
|
-
animation: blink 1s infinite;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@keyframes audio-play {
|
|
183
|
-
0% {
|
|
184
|
-
transform: scaleX(0.7056);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
50% {
|
|
188
|
-
transform: scaleX(0.3953);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
75% {
|
|
192
|
-
transform: scaleX(0);
|
|
193
|
-
visibility: hidden;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
100% {
|
|
197
|
-
transform: scaleX(0);
|
|
198
|
-
visibility: hidden;
|
|
199
|
-
}
|
|
200
182
|
}
|
|
201
183
|
|
|
202
184
|
.message-audio.reserve {
|
|
@@ -206,18 +188,8 @@ $flow-out-bg-color: #dceafd;
|
|
|
206
188
|
text-align: end;
|
|
207
189
|
}
|
|
208
190
|
|
|
209
|
-
.icon {
|
|
210
|
-
transform: rotate(180deg);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
191
|
.audio-icon-container {
|
|
214
|
-
margin: 0 0 0
|
|
215
|
-
|
|
216
|
-
.mask {
|
|
217
|
-
transform-origin: left;
|
|
218
|
-
background-color: $flow-out-bg-color;
|
|
219
|
-
// mask: linear-gradient(0deg, transparent 50%);
|
|
220
|
-
}
|
|
192
|
+
margin: 0 0 0 4px;
|
|
221
193
|
}
|
|
222
194
|
}
|
|
223
195
|
</style>
|
|
@@ -2,7 +2,7 @@ import {Marked} from 'marked';
|
|
|
2
2
|
import Log from '../../../../../../utils/logger';
|
|
3
3
|
|
|
4
4
|
export const marked = new Marked(
|
|
5
|
-
{mangle: false, headerIds: false},
|
|
5
|
+
{mangle: false, headerIds: false, breaks: true, gfm: false, smartLists: true,},
|
|
6
6
|
{
|
|
7
7
|
renderer: {
|
|
8
8
|
image(this: any, href: string | null, title: string | null, text: string) {
|
|
@@ -24,9 +24,10 @@ export const marked = new Marked(
|
|
|
24
24
|
<video class="message-img video-web" src="${videoSrc}" onloadeddata="onMarkdownMediaLoad()" preload="auto" controls/>
|
|
25
25
|
</div>
|
|
26
26
|
</div>`;
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
return text
|
|
29
|
+
// 在段落中用 p 包裹,避免 \n\n 无法换行
|
|
30
|
+
return `<p>${text}</p>`;
|
|
30
31
|
},
|
|
31
32
|
link(this: any, href: string | null, title: string | null, text: string) {
|
|
32
33
|
if (href) {
|
|
@@ -57,6 +58,7 @@ const extractVideoSrc = (text: string) => {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export const parseMarkdown = (text: string) => {
|
|
61
|
+
// 不要手动替换,如把 \n\n 替换成 p 或者 <br/>,否则可能会导致Markdown结构被破坏,进而导致 bad case
|
|
60
62
|
let ret = marked.parse(text);
|
|
61
63
|
return typeof ret === 'string' ? ret : '';
|
|
62
64
|
};
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
class="welcome-item"
|
|
25
25
|
@click="handleContentListItemClick(item)"
|
|
26
26
|
>
|
|
27
|
-
<div class="item-
|
|
27
|
+
<div class="item-container">
|
|
28
|
+
<div class="item-content">{{ item.content }}</div>
|
|
29
|
+
</div>
|
|
28
30
|
</div>
|
|
29
31
|
<div class="welcome-item welcome-item-hidden">
|
|
30
32
|
{{ longestContent }}
|
|
@@ -195,13 +197,18 @@ export default {
|
|
|
195
197
|
color: #1c66e5;
|
|
196
198
|
gap: 10px;
|
|
197
199
|
box-sizing: border-box;
|
|
198
|
-
.item-
|
|
200
|
+
.item-container {
|
|
199
201
|
text-align: center;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
max-width: 100%;
|
|
203
|
+
.item-content {
|
|
204
|
+
display: inline-block;
|
|
205
|
+
text-align: left;
|
|
206
|
+
overflow-wrap: break-word;
|
|
207
|
+
word-break: normal;
|
|
208
|
+
width: 100%;
|
|
209
|
+
}
|
|
204
210
|
}
|
|
211
|
+
|
|
205
212
|
}
|
|
206
213
|
|
|
207
214
|
.welcome-item:hover {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<span
|
|
4
4
|
v-for="(item, index) in textMessageData.text"
|
|
5
5
|
:key="index"
|
|
6
|
-
>
|
|
6
|
+
>
|
|
7
7
|
<span v-if="item.name === 'text' && enableURLDetection === 1"
|
|
8
8
|
class="text"
|
|
9
9
|
v-html="item.text"
|
|
@@ -64,7 +64,8 @@ const textMessageData = computed(() => {
|
|
|
64
64
|
+ CUSTOM_BASIC_EMOJI_URL_MAPPING[item.emojiKey];
|
|
65
65
|
}
|
|
66
66
|
} else if (item.name === 'text' && enableURLDetection.value) {
|
|
67
|
-
|
|
67
|
+
// 开启 url 识别时先移除 html 标签,避免 xss 漏洞
|
|
68
|
+
item.text = item.text.replace(/<[^>]+>/g, '').replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (url) => {
|
|
68
69
|
return `<a href="${url}" target="_blank" rel="noopener noreferrer" class="message-text-link" style="color: ${linkColor.value}; text-decoration: underline;">${url}</a>`;
|
|
69
70
|
}) || '';
|
|
70
71
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="isScrollButtonVisible"
|
|
4
|
-
class="scroll-button"
|
|
4
|
+
:class="['scroll-button', isPC ? 'scroll-button-pc' : '']"
|
|
5
5
|
@click="scrollToMessageListBottom"
|
|
6
6
|
>
|
|
7
7
|
<Icon
|
|
8
|
-
width="
|
|
9
|
-
height="
|
|
10
|
-
:file="
|
|
8
|
+
width="15px"
|
|
9
|
+
height="15px"
|
|
10
|
+
:file="isPC ? arrowDownIconWhite : arrowDownIcon"
|
|
11
11
|
/>
|
|
12
|
-
<div class="scroll-button-text">
|
|
12
|
+
<div v-if="scrollButtonContent" :class="isPC ? 'scroll-button-text-pc' : 'scroll-button-text'">
|
|
13
13
|
{{ scrollButtonContent }}
|
|
14
14
|
</div>
|
|
15
15
|
</div>
|
|
@@ -26,10 +26,11 @@ import {
|
|
|
26
26
|
TUITranslateService,
|
|
27
27
|
} from '@tencentcloud/chat-uikit-engine';
|
|
28
28
|
import Icon from '../../../common/Icon.vue';
|
|
29
|
-
import
|
|
29
|
+
import arrowDownIcon from '../../../../assets/arrow_down_icon.svg';
|
|
30
|
+
import arrowDownIconWhite from '../../../../assets/arrow_down_icon_white.svg';
|
|
30
31
|
import { getBoundingClientRect } from '@tencentcloud/universal-api';
|
|
31
32
|
import { JSONToObject } from '../../../../utils';
|
|
32
|
-
|
|
33
|
+
import { isPC } from '../../../../utils/env';
|
|
33
34
|
|
|
34
35
|
interface IEmits {
|
|
35
36
|
(key: 'scrollToLatestMessage'): void;
|
|
@@ -197,7 +198,6 @@ defineExpose({
|
|
|
197
198
|
bottom: 10px;
|
|
198
199
|
right: 10px;
|
|
199
200
|
width: auto;
|
|
200
|
-
height: 28px;
|
|
201
201
|
background: #fff;
|
|
202
202
|
border: 1px solid #e0e0e0;
|
|
203
203
|
box-shadow: 0 4px 12px -5px rgba(0, 0, 0, 0.1);
|
|
@@ -205,7 +205,8 @@ defineExpose({
|
|
|
205
205
|
flex-direction: row;
|
|
206
206
|
align-items: center;
|
|
207
207
|
justify-content: center;
|
|
208
|
-
border-radius:
|
|
208
|
+
border-radius: 20px;
|
|
209
|
+
padding: 8px;
|
|
209
210
|
cursor: pointer;
|
|
210
211
|
-webkit-tap-highlight-color: transparent;
|
|
211
212
|
|
|
@@ -216,4 +217,11 @@ defineExpose({
|
|
|
216
217
|
margin-right: 3px;
|
|
217
218
|
}
|
|
218
219
|
}
|
|
220
|
+
.scroll-button-pc {
|
|
221
|
+
background: #1c66e5;
|
|
222
|
+
}
|
|
223
|
+
.scroll-button-text-pc {
|
|
224
|
+
color: #ffffff;
|
|
225
|
+
font-size: 10px;
|
|
226
|
+
}
|
|
219
227
|
</style>
|
|
@@ -5,7 +5,7 @@ import TOAST_TYPE from './type';
|
|
|
5
5
|
import MessageConstructor from './index-web.vue';
|
|
6
6
|
//@ts-ignore
|
|
7
7
|
import { vueVersion } from '../../../adapter-vue-web';
|
|
8
|
-
import { VNode } from 'vue';
|
|
8
|
+
import { VNode, ref } from 'vue';
|
|
9
9
|
//@ts-ignore
|
|
10
10
|
const { createVNode, render } = vue;
|
|
11
11
|
|
|
@@ -39,6 +39,7 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
39
39
|
zIndex: 20 + seed,
|
|
40
40
|
offset: verticalOffset,
|
|
41
41
|
id,
|
|
42
|
+
visible: true,
|
|
42
43
|
...options,
|
|
43
44
|
onClose: () => {
|
|
44
45
|
Toast.close(id, userOnClose);
|
|
@@ -66,8 +67,20 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
66
67
|
},
|
|
67
68
|
};
|
|
68
69
|
case 3:
|
|
70
|
+
let visible = ref(true);
|
|
69
71
|
// @ts-ignore
|
|
70
|
-
vm = createVNode(MessageConstructor,
|
|
72
|
+
vm = createVNode(MessageConstructor, {
|
|
73
|
+
...props,
|
|
74
|
+
'onUpdate:visible': (val: boolean) => {
|
|
75
|
+
visible.value = val;
|
|
76
|
+
if (!val) {
|
|
77
|
+
render(null, container);
|
|
78
|
+
if (container.parentNode) {
|
|
79
|
+
container.parentNode.removeChild(container);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
});
|
|
71
84
|
container = document.createElement('div');
|
|
72
85
|
vm?.props
|
|
73
86
|
&& (vm.props!.onDestroy = () => {
|
|
@@ -83,7 +96,7 @@ const Toast = function (options: IToast): IToastReturnType {
|
|
|
83
96
|
appendTo.appendChild(container.firstElementChild!);
|
|
84
97
|
return {
|
|
85
98
|
close: () => {
|
|
86
|
-
vm?.component?.
|
|
99
|
+
vm?.component?.emit('update:visible', false);
|
|
87
100
|
},
|
|
88
101
|
};
|
|
89
102
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
@after-leave="$emit('destroy')"
|
|
5
5
|
>
|
|
6
6
|
<div
|
|
7
|
-
v-show="
|
|
7
|
+
v-show="toastVisible"
|
|
8
8
|
class="message"
|
|
9
9
|
:class="[handleStyle(type), isH5 && 'message-h5']"
|
|
10
10
|
:style="customStyle"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import vue from '../../../adapter-vue';
|
|
21
21
|
import { isH5 } from '../../../utils/env';
|
|
22
22
|
import TOAST_TYPE from './type';
|
|
23
|
-
const { computed, onMounted, ref, watch } = vue;
|
|
23
|
+
const { computed, onMounted, ref, watch, onUnmounted } = vue;
|
|
24
24
|
|
|
25
25
|
const props = defineProps({
|
|
26
26
|
message: {
|
|
@@ -55,14 +55,19 @@ const props = defineProps({
|
|
|
55
55
|
type: String,
|
|
56
56
|
default: '',
|
|
57
57
|
},
|
|
58
|
+
visible: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
default: false,
|
|
61
|
+
},
|
|
58
62
|
});
|
|
59
|
-
const
|
|
63
|
+
const emit = defineEmits(['update:visible']);
|
|
64
|
+
const toastVisible = ref(props.visible);
|
|
60
65
|
let timer: any;
|
|
61
66
|
|
|
62
67
|
const startTimer = () => {
|
|
63
68
|
if (props.duration > 0) {
|
|
64
69
|
timer = setTimeout(() => {
|
|
65
|
-
if (
|
|
70
|
+
if (toastVisible.value) {
|
|
66
71
|
close();
|
|
67
72
|
}
|
|
68
73
|
}, props.duration);
|
|
@@ -74,7 +79,7 @@ const clearTimer = () => {
|
|
|
74
79
|
};
|
|
75
80
|
|
|
76
81
|
const close = () => {
|
|
77
|
-
visible
|
|
82
|
+
emit('update:visible', false);
|
|
78
83
|
if (typeof props.onClose === 'function') {
|
|
79
84
|
props.onClose();
|
|
80
85
|
}
|
|
@@ -95,7 +100,12 @@ const customStyle = computed<CSSProperties>(() => ({
|
|
|
95
100
|
|
|
96
101
|
onMounted(() => {
|
|
97
102
|
startTimer();
|
|
98
|
-
|
|
103
|
+
toastVisible.value = true;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
onUnmounted(() => {
|
|
107
|
+
clearTimer();
|
|
108
|
+
toastVisible.value = false;
|
|
99
109
|
});
|
|
100
110
|
|
|
101
111
|
const handleStyle = (type?: string) => {
|
package/constant.ts
CHANGED
package/locales/en/TUIChat.ts
CHANGED
|
@@ -20,7 +20,7 @@ const TUIChat = {
|
|
|
20
20
|
'关闭阅读状态': 'Read status closed',
|
|
21
21
|
'管理员开启全员禁言': 'The admin enables Mute All',
|
|
22
22
|
'欢迎使用TUICallKit': 'Welcome to TUICallKit',
|
|
23
|
-
'回到最新位置': '
|
|
23
|
+
'回到最新位置': '',
|
|
24
24
|
'回复': 'Reply',
|
|
25
25
|
'回复详情': 'Replies',
|
|
26
26
|
'集成TUICallKit': ' Integrate TUICallKit ',
|
|
@@ -105,8 +105,12 @@ const TUIChat = {
|
|
|
105
105
|
'空': 'Empty',
|
|
106
106
|
'文本包含本地审核拦截词': 'Text contains local moderation blocking words',
|
|
107
107
|
'按住说话': 'Hold to speak',
|
|
108
|
-
'
|
|
109
|
-
'
|
|
108
|
+
'松开发送': 'Release to send',
|
|
109
|
+
'松手取消': 'Release to cancel',
|
|
110
|
+
'录音结束提醒': 'Recording will stop in',
|
|
111
|
+
'语音播放失败': 'Voice playback failed',
|
|
112
|
+
'请检查麦克风访问权限': 'Please check microphone access permissions',
|
|
113
|
+
'按压时间过短,请按压超过1秒': 'Press time too short, please hold for more than 1 second',
|
|
110
114
|
'正在录音': 'Recording',
|
|
111
115
|
'继续上滑可取消': 'Continue to swipe to cancel',
|
|
112
116
|
'松开手指 取消发送': 'Release to cancel',
|
package/locales/en/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Submit",
|
|
8
8
|
"查看内容": "View content",
|
|
9
9
|
"请填写必填项": "Please fill in the required fields",
|
|
10
|
-
"Hi,我是": "Hi, I'm ",
|
|
11
10
|
"请输入内容":"Please enter the content",
|
|
12
11
|
"如果满意请给好评哦~":"If you're satisfied, please give a good review~",
|
|
13
12
|
"请对本次服务进行评价": "Please rate this service",
|
package/locales/fil/TUIChat.ts
CHANGED
|
@@ -42,7 +42,7 @@ const TUIChat = {
|
|
|
42
42
|
'该消息不存在': 'Ang mensaheng ito ay hindi umiiral',
|
|
43
43
|
'无法定位到原消息': 'Hindi mahanap ang orihinal na mensahe',
|
|
44
44
|
'对方正在输入': 'Ang kabilang panig ay nagta-type...',
|
|
45
|
-
'回到最新位置': '
|
|
45
|
+
'回到最新位置': '',
|
|
46
46
|
'条新消息': 'bagong mensahe',
|
|
47
47
|
'点此投诉': 'I-click dito para magreklamo',
|
|
48
48
|
'语音通话': 'Voice Call',
|
|
@@ -106,8 +106,12 @@ const TUIChat = {
|
|
|
106
106
|
'空': 'Walang laman',
|
|
107
107
|
'文本包含本地审核拦截词': 'May mga salitang sinusuri sa lokal na pagbabawal sa teksto',
|
|
108
108
|
'按住说话': 'Pindutin at magsalita',
|
|
109
|
-
'
|
|
110
|
-
'
|
|
109
|
+
'松开发送': 'Ibaba at ipadala',
|
|
110
|
+
'松手取消': 'Ibaba at kanselahin',
|
|
111
|
+
'录音结束提醒': 'Magtatapos ang pag-record sa loob ng',
|
|
112
|
+
'语音播放失败': 'Nabigo ang pag-play ng boses',
|
|
113
|
+
'请检查麦克风访问权限': 'Mangyaring suriin ang mga pahintulot sa access ng mikropono',
|
|
114
|
+
'按压时间过短,请按压超过1秒': 'Masyadong maikli ang pagpindot, pindutin nang higit sa 1 segundo',
|
|
111
115
|
'正在录音': 'Nagre-record',
|
|
112
116
|
'继续上滑可取消': 'Magpatuloy sa pag-swipe pataas para kanselahin',
|
|
113
117
|
'松开手指 取消发送': 'Bitawan ang daliri para kanselahin',
|
package/locales/fil/aidesk.ts
CHANGED
|
@@ -7,7 +7,6 @@ const AIDesk = {
|
|
|
7
7
|
"提交": "Isumite",
|
|
8
8
|
"查看内容": "Tingnan ang Nilalaman",
|
|
9
9
|
"请填写必填项": "Mangyaring punan ang mga kinakailangang field",
|
|
10
|
-
"Hi,我是": "Hi, ako ",
|
|
11
10
|
"请输入内容":"Pakilagay ang nilalaman",
|
|
12
11
|
"如果满意请给好评哦~":"Kung nasiyahan ka, mangyaring magbigay ng magandang pagsusuri~",
|
|
13
12
|
"请对本次服务进行评价": "Mangyaring suriin ang serbisyong ito",
|