@tencentcloud/ai-desk-customer-vue 1.5.0 → 1.5.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 +13 -0
- package/components/CustomerServiceChat/index-web.vue +16 -4
- package/components/CustomerServiceChat/message-input-toolbar/file-upload/index.vue +14 -1
- package/components/CustomerServiceChat/message-input-toolbar/image-upload/index.vue +26 -2
- package/components/CustomerServiceChat/message-input-toolbar/video-upload/index.vue +14 -1
- package/components/CustomerServiceChat/message-list/bottom-quick-order/index.vue +201 -0
- package/components/CustomerServiceChat/message-list/index-web.vue +46 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +6 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-ivr-form/index.vue +2 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-product-card.vue +140 -87
- package/components/CustomerServiceChat/style/h5.scss +1 -0
- package/constant.ts +3 -3
- package/interface.ts +15 -1
- package/locales/en/aidesk.ts +4 -1
- package/locales/fil/aidesk.ts +3 -0
- package/locales/id/aidesk.ts +3 -0
- package/locales/ja/aidesk.ts +3 -0
- package/locales/ms/aidesk.ts +3 -0
- package/locales/ru/aidesk.ts +3 -0
- package/locales/th/aidesk.ts +3 -0
- package/locales/vi/aidesk.ts +3 -0
- package/locales/zh_cn/aidesk.ts +3 -0
- package/locales/zh_tw/aidesk.ts +3 -0
- package/package.json +1 -1
- package/utils/utils.ts +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -17,9 +17,12 @@
|
|
|
17
17
|
:class="['tui-chat-message-list', !isPC && 'tui-chat-h5-message-list']"
|
|
18
18
|
@handleEditor="handleEditor"
|
|
19
19
|
@closeInputToolBar="() => changeToolbarDisplayType('none')"
|
|
20
|
+
:bottomQuickOrder="props.bottomQuickOrder"
|
|
21
|
+
:showBottomQuickOrder="showBottomQuickOrder"
|
|
22
|
+
@closeBottomQuickOrder="closeBottomQuickOrder"
|
|
20
23
|
/>
|
|
21
24
|
<MessageToolbarButton
|
|
22
|
-
v-if="!
|
|
25
|
+
v-if="!isH5 || (!Boolean(quoteMessage) && !showBottomQuickOrder)"
|
|
23
26
|
:toolbarButtonList="props.toolbarButtonList"
|
|
24
27
|
/>
|
|
25
28
|
<MessageInputToolbar
|
|
@@ -95,16 +98,16 @@ import MessageInput from './message-input/index-web.vue';
|
|
|
95
98
|
import MessageInputToolbar from './message-input-toolbar/index-web.vue';
|
|
96
99
|
import EmojiDialog from './message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue';
|
|
97
100
|
import { isH5, isPC } from '../../utils/env';
|
|
98
|
-
import { ToolbarButtonModel, ToolbarDisplayType, InputToolbarModel } from '../../interface';
|
|
101
|
+
import { ToolbarButtonModel, ToolbarDisplayType, InputToolbarModel, QuickOrderModel } from '../../interface';
|
|
99
102
|
import { isSupportedLang } from '../../utils/';
|
|
100
103
|
import Log from '../../utils/logger';
|
|
101
104
|
import MessageToolbarButton from './message-toolbar-button/index.vue';
|
|
102
105
|
import TUILocales from '../../locales';
|
|
103
106
|
import { Toast, TOAST_TYPE } from '../common/Toast/index-web';
|
|
104
107
|
import state from '../../utils/state.js';
|
|
105
|
-
import { switchReadStatus } from '../../utils/utils';
|
|
108
|
+
import { switchReadStatus,isNonEmptyObject } from '../../utils/utils';
|
|
106
109
|
|
|
107
|
-
const { ref, onMounted, onUnmounted, computed
|
|
110
|
+
const { ref, onMounted, onUnmounted, computed } = vue;
|
|
108
111
|
|
|
109
112
|
interface IProps {
|
|
110
113
|
canCloseChat?: boolean;
|
|
@@ -125,6 +128,7 @@ interface IProps {
|
|
|
125
128
|
inputToolbarList?: InputToolbarModel[];
|
|
126
129
|
showReadStatus?: number;
|
|
127
130
|
showTyping?: number;
|
|
131
|
+
bottomQuickOrder?: QuickOrderModel;
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
const emits = defineEmits(['closeChat']);
|
|
@@ -139,6 +143,7 @@ const emojiOpen = ref(false);
|
|
|
139
143
|
const toolShowH5 = ref(false);
|
|
140
144
|
const languages = Object.keys(TUILocales);
|
|
141
145
|
const quoteMessage = ref<IMessageModel>();
|
|
146
|
+
const showBottomQuickOrder = ref(false);
|
|
142
147
|
const props = withDefaults(defineProps<IProps>(), {
|
|
143
148
|
canCloseChat: true,
|
|
144
149
|
SDKAppID: 0,
|
|
@@ -247,6 +252,9 @@ try {
|
|
|
247
252
|
setAvatarNickName();
|
|
248
253
|
setShowReadStatus();
|
|
249
254
|
setShowTyping();
|
|
255
|
+
if (isNonEmptyObject(props.bottomQuickOrder)) {
|
|
256
|
+
showBottomQuickOrder.value = true;
|
|
257
|
+
}
|
|
250
258
|
} catch (e) {
|
|
251
259
|
console.log(e)
|
|
252
260
|
}
|
|
@@ -389,6 +397,10 @@ function onQuoteMessageUpdated(options?: {
|
|
|
389
397
|
quoteMessage.value = undefined;
|
|
390
398
|
}
|
|
391
399
|
}
|
|
400
|
+
|
|
401
|
+
function closeBottomQuickOrder() {
|
|
402
|
+
showBottomQuickOrder.value = false;
|
|
403
|
+
}
|
|
392
404
|
</script>
|
|
393
405
|
|
|
394
406
|
<style scoped lang="scss" src="./style/index.scss">
|
|
@@ -35,6 +35,8 @@ import fileIcon from '../../../../assets/files.svg';
|
|
|
35
35
|
import fileIconH5 from '../../../../assets/file-h5.png';
|
|
36
36
|
import { isPC, isH5 } from '../../../../utils/env';
|
|
37
37
|
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../../utils/utils';
|
|
38
|
+
import Log from '../../../../utils/logger';
|
|
39
|
+
import { Toast, TOAST_TYPE } from '../../../common/Toast/index-web';
|
|
38
40
|
const { ref } = vue;
|
|
39
41
|
|
|
40
42
|
const inputRef = ref();
|
|
@@ -63,7 +65,18 @@ const sendFileMessage = (e: any) => {
|
|
|
63
65
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
64
66
|
} as SendMessageParams;
|
|
65
67
|
const sendMessageOptions: SendMessageOptions = {};
|
|
66
|
-
TUIChatService.sendFileMessage(options, sendMessageOptions)
|
|
68
|
+
TUIChatService.sendFileMessage(options, sendMessageOptions)
|
|
69
|
+
.catch((err) => {
|
|
70
|
+
Toast({
|
|
71
|
+
message:
|
|
72
|
+
err.code === 2402 ?
|
|
73
|
+
TUITranslateService.t('AIDesk.file 大小超过 100MB,无法发送')
|
|
74
|
+
: err.message,
|
|
75
|
+
type: TOAST_TYPE.ERROR,
|
|
76
|
+
duration: 5000,
|
|
77
|
+
});
|
|
78
|
+
Log.l(`Send File Failed:${err.code} ${err.message}`);
|
|
79
|
+
});
|
|
67
80
|
e.target.value = '';
|
|
68
81
|
};
|
|
69
82
|
</script>
|
|
@@ -38,6 +38,8 @@ import ToolbarItemContainer from '../toolbar-item-container/index.vue';
|
|
|
38
38
|
import imageIcon from '../../../../assets/image.svg';
|
|
39
39
|
import imageUniIcon from '../../../../assets/image-uni.png';
|
|
40
40
|
import { getTo, isEnabledMessageReadReceiptGlobal } from '../../../../utils/utils';
|
|
41
|
+
import Log from '../../../../utils/logger';
|
|
42
|
+
import { Toast, TOAST_TYPE } from '../../../common/Toast/index-web';
|
|
41
43
|
const { ref, computed } = vue;
|
|
42
44
|
|
|
43
45
|
const props = defineProps({
|
|
@@ -119,7 +121,18 @@ const sendImageMessage = (files: any) => {
|
|
|
119
121
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
120
122
|
} as SendMessageParams;
|
|
121
123
|
const sendMessageOptions: SendMessageOptions = {};
|
|
122
|
-
TUIChatService.sendImageMessage(options, sendMessageOptions)
|
|
124
|
+
TUIChatService.sendImageMessage(options, sendMessageOptions)
|
|
125
|
+
.catch((err) => {
|
|
126
|
+
Toast({
|
|
127
|
+
message:
|
|
128
|
+
err.code === 2253 ?
|
|
129
|
+
TUITranslateService.t('AIDesk.image 大小超过 20MB,无法发送')
|
|
130
|
+
: err.message,
|
|
131
|
+
type: TOAST_TYPE.ERROR,
|
|
132
|
+
duration: 5000,
|
|
133
|
+
});
|
|
134
|
+
Log.l(`Send Image Failed:${err.code} ${err.message}`);
|
|
135
|
+
});
|
|
123
136
|
};
|
|
124
137
|
const sendVideoMessage = (file: any) => {
|
|
125
138
|
if (!file) {
|
|
@@ -134,7 +147,18 @@ const sendVideoMessage = (file: any) => {
|
|
|
134
147
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
135
148
|
} as SendMessageParams;
|
|
136
149
|
const sendMessageOptions: SendMessageOptions = {};
|
|
137
|
-
TUIChatService.sendVideoMessage(options, sendMessageOptions)
|
|
150
|
+
TUIChatService.sendVideoMessage(options, sendMessageOptions)
|
|
151
|
+
.catch((err) => {
|
|
152
|
+
Toast({
|
|
153
|
+
message:
|
|
154
|
+
err.code === 2351 ?
|
|
155
|
+
TUITranslateService.t('AIDesk.video 大小超过 100MB,无法发送')
|
|
156
|
+
: err.message,
|
|
157
|
+
type: TOAST_TYPE.ERROR,
|
|
158
|
+
duration: 5000,
|
|
159
|
+
});
|
|
160
|
+
Log.l(`Send Video Failed:${err.code} ${err.message}`);
|
|
161
|
+
});
|
|
138
162
|
};
|
|
139
163
|
</script>
|
|
140
164
|
|
|
@@ -35,6 +35,8 @@ import ToolbarItemContainer from '../toolbar-item-container/index.vue';
|
|
|
35
35
|
import videoIcon from '../../../../assets/video.svg';
|
|
36
36
|
import videoIconH5 from '../../../../assets/video_h5.svg'
|
|
37
37
|
import { isEnabledMessageReadReceiptGlobal, getTo } from '../../../../utils/utils';
|
|
38
|
+
import Log from '../../../../utils/logger';
|
|
39
|
+
import { Toast, TOAST_TYPE } from '../../../common/Toast/index-web';
|
|
38
40
|
const { ref } = vue;
|
|
39
41
|
|
|
40
42
|
const props = defineProps({
|
|
@@ -89,7 +91,18 @@ const sendVideoMessage = (file: any) => {
|
|
|
89
91
|
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
90
92
|
} as SendMessageParams;
|
|
91
93
|
const sendMessageOptions: SendMessageOptions = {};
|
|
92
|
-
TUIChatService.sendVideoMessage(options, sendMessageOptions)
|
|
94
|
+
TUIChatService.sendVideoMessage(options, sendMessageOptions)
|
|
95
|
+
.catch((err) => {
|
|
96
|
+
Toast({
|
|
97
|
+
message:
|
|
98
|
+
err.code === 2351 ?
|
|
99
|
+
TUITranslateService.t('AIDesk.video 大小超过 100MB,无法发送')
|
|
100
|
+
: err.message,
|
|
101
|
+
type: TOAST_TYPE.ERROR,
|
|
102
|
+
duration: 5000,
|
|
103
|
+
});
|
|
104
|
+
Log.l(`Send Video Failed:${err.code} ${err.message}`);
|
|
105
|
+
});
|
|
93
106
|
};
|
|
94
107
|
</script>
|
|
95
108
|
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="isPC ? 'bottom-quick-order-line':''">
|
|
3
|
+
<div :class="['bottom-quick-order-container',isPC && 'bottom-quick-order-container-pc']">
|
|
4
|
+
<div @click="closeOrder">
|
|
5
|
+
<Icon class="close-icon" :file="cardToolbarCloseIcon" width="12px" height="12px"/>
|
|
6
|
+
</div>
|
|
7
|
+
<div v-for="(item,index) in topCustomField" :key="index" class="quick-order-custom-field">
|
|
8
|
+
<div class="custom-field-line">
|
|
9
|
+
<div v-if="item.name" class="order-name">
|
|
10
|
+
{{ item.name }}:
|
|
11
|
+
</div>
|
|
12
|
+
<div class="order-value">
|
|
13
|
+
{{ item.value }}
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="quick-order-main">
|
|
18
|
+
<img
|
|
19
|
+
v-if="props.bottomQuickOrder.pic"
|
|
20
|
+
class="quick-order-img"
|
|
21
|
+
:src="props.bottomQuickOrder.pic"
|
|
22
|
+
>
|
|
23
|
+
<div class="quick-order-information">
|
|
24
|
+
<div class="quick-order-title">
|
|
25
|
+
{{ props.bottomQuickOrder.header }}
|
|
26
|
+
</div>
|
|
27
|
+
<div class="quick-order-description-block">
|
|
28
|
+
<div class="quick-order-description">
|
|
29
|
+
{{ props.bottomQuickOrder.desc }}
|
|
30
|
+
</div>
|
|
31
|
+
<div v-if="bottomCustomField.length === 0" class="quick-order-link" @click="sendOrder">
|
|
32
|
+
{{ TUITranslateService.t("发送") }}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div v-for="(item,index) in bottomCustomField" :key="index" class="quick-order-custom-field">
|
|
38
|
+
<div class="custom-field-line">
|
|
39
|
+
<div v-if="item.name" class="order-name">
|
|
40
|
+
{{ item.name }}:
|
|
41
|
+
</div>
|
|
42
|
+
<div class="order-value">
|
|
43
|
+
{{ item.value }}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div v-if="bottomCustomField.length !== 0" class="quick-order-link" @click="sendOrder">
|
|
48
|
+
{{ TUITranslateService.t("发送") }}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
<script lang="ts" setup>
|
|
54
|
+
import vue from '../../../../adapter-vue';
|
|
55
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
56
|
+
import cardToolbarCloseIcon from '../../../../assets/dialog-close.png';
|
|
57
|
+
import Icon from '../../../common/Icon.vue';
|
|
58
|
+
import { QuickOrderModel } from '../../../../interface';
|
|
59
|
+
import { isPC } from '../../../../utils/env';
|
|
60
|
+
const { computed } = vue;
|
|
61
|
+
interface IProps {
|
|
62
|
+
bottomQuickOrder: QuickOrderModel;
|
|
63
|
+
}
|
|
64
|
+
const emits = defineEmits(['closeOrder','sendOrder']);
|
|
65
|
+
|
|
66
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
67
|
+
bottomQuickOrder: () => ({} as QuickOrderModel),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const customField = computed(() => {
|
|
71
|
+
return Array.isArray(props.bottomQuickOrder?.customField) ? props.bottomQuickOrder.customField : [];
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const topCustomField = computed(() => {
|
|
75
|
+
return customField.value.filter((item) => item.position === 'top');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const bottomCustomField = computed(() => {
|
|
79
|
+
return customField.value.filter((item) => item.position !== 'top');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const sendOrder = () => {
|
|
83
|
+
emits('sendOrder');
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const closeOrder = () => {
|
|
87
|
+
emits('closeOrder');
|
|
88
|
+
};
|
|
89
|
+
</script>
|
|
90
|
+
<style scoped lang="scss">
|
|
91
|
+
.bottom-quick-order-line {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: flex-end;
|
|
94
|
+
}
|
|
95
|
+
.bottom-quick-order-container {
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-direction: column;
|
|
98
|
+
background: #fff;
|
|
99
|
+
padding: 10px 30px 10px 10px;
|
|
100
|
+
border-radius: 8px;
|
|
101
|
+
margin: 0 10px 0 10px;
|
|
102
|
+
position: relative;
|
|
103
|
+
font-family: PingFangSC-Regular;
|
|
104
|
+
}
|
|
105
|
+
.bottom-quick-order-container-pc {
|
|
106
|
+
width: 300px;
|
|
107
|
+
box-shadow: rgb(204, 204, 204) 0px 0px 10px;
|
|
108
|
+
margin-bottom: 5px;
|
|
109
|
+
}
|
|
110
|
+
.quick-order-custom-field {
|
|
111
|
+
font-size: 12px;
|
|
112
|
+
max-width: 100%;
|
|
113
|
+
overflow: hidden;
|
|
114
|
+
}
|
|
115
|
+
.custom-field-line {
|
|
116
|
+
display: flex;
|
|
117
|
+
gap: 5px;
|
|
118
|
+
font-size: 12px;
|
|
119
|
+
line-height: 22px;
|
|
120
|
+
}
|
|
121
|
+
.order-name {
|
|
122
|
+
color: #878787;
|
|
123
|
+
margin-right: 3px;
|
|
124
|
+
white-space: nowrap;
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
}
|
|
127
|
+
.order-value {
|
|
128
|
+
flex: 1;
|
|
129
|
+
min-width: 0;
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
text-overflow: ellipsis;
|
|
133
|
+
}
|
|
134
|
+
.quick-order-main {
|
|
135
|
+
display: flex;
|
|
136
|
+
margin: 10px 0 10px 0;
|
|
137
|
+
}
|
|
138
|
+
.quick-order-img {
|
|
139
|
+
width: 60px;
|
|
140
|
+
height: 60px;
|
|
141
|
+
border-radius: 10px;
|
|
142
|
+
margin-right: 15px;
|
|
143
|
+
flex-shrink: 0;
|
|
144
|
+
object-fit: cover;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.quick-order-information {
|
|
148
|
+
width: 100%;
|
|
149
|
+
margin-right: 5px;
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
justify-content: space-between;
|
|
153
|
+
|
|
154
|
+
.quick-order-title {
|
|
155
|
+
color: #000000;
|
|
156
|
+
font-size: 14px;
|
|
157
|
+
display: -webkit-box;
|
|
158
|
+
overflow: hidden;
|
|
159
|
+
text-overflow: ellipsis;
|
|
160
|
+
-webkit-line-clamp: 2;
|
|
161
|
+
-webkit-box-orient: vertical;
|
|
162
|
+
word-break: break-word;
|
|
163
|
+
overflow-wrap: anywhere;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.quick-order-description-block {
|
|
167
|
+
display: flex;
|
|
168
|
+
justify-content: space-between;
|
|
169
|
+
align-items: center;
|
|
170
|
+
gap: 5px;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.quick-order-description {
|
|
174
|
+
font-size: 16px;
|
|
175
|
+
max-width: 120px;
|
|
176
|
+
color: #1C66E5;
|
|
177
|
+
overflow: hidden;
|
|
178
|
+
text-overflow: ellipsis;
|
|
179
|
+
white-space: nowrap;
|
|
180
|
+
font-weight: 500;
|
|
181
|
+
flex: 0 1 120px;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
.quick-order-link {
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
background-color: #1c66e5;
|
|
187
|
+
color: #ffffff;
|
|
188
|
+
font-size: 12px;
|
|
189
|
+
padding: 2px 18px;
|
|
190
|
+
line-height: 22px;
|
|
191
|
+
border-radius: 23px;
|
|
192
|
+
flex: 0 0 auto;
|
|
193
|
+
margin-left: auto;
|
|
194
|
+
}
|
|
195
|
+
.close-icon {
|
|
196
|
+
position: absolute;
|
|
197
|
+
right: 10px;
|
|
198
|
+
top: 10px;
|
|
199
|
+
cursor: pointer;
|
|
200
|
+
}
|
|
201
|
+
</style>
|
|
@@ -172,6 +172,13 @@
|
|
|
172
172
|
:imageList="imageMessageList"
|
|
173
173
|
@close="onImagePreviewerClose"
|
|
174
174
|
/>
|
|
175
|
+
<BottomQuickOrder
|
|
176
|
+
class="bottom-quick-order"
|
|
177
|
+
v-if="isNonEmptyObject(props.bottomQuickOrder) && props.showBottomQuickOrder"
|
|
178
|
+
:bottomQuickOrder="props.bottomQuickOrder"
|
|
179
|
+
@closeOrder="closeBottomQuickOrder"
|
|
180
|
+
@sendOrder="sendBottomQuickOrder"
|
|
181
|
+
/>
|
|
175
182
|
</div>
|
|
176
183
|
</div>
|
|
177
184
|
</template>
|
|
@@ -208,6 +215,7 @@ import MessageRevoked from './message-tool/message-revoked.vue';
|
|
|
208
215
|
import MessagePlugin from '../message-list/message-elements/message-desk/message-plugin-web.vue';
|
|
209
216
|
import MessageThinking from './message-elements/message-thinking.vue';
|
|
210
217
|
import ScrollButton from './scroll-button/index.vue';
|
|
218
|
+
import BottomQuickOrder from './bottom-quick-order/index.vue';
|
|
211
219
|
import { isPluginMessage } from './message-elements/message-desk/index';
|
|
212
220
|
import Dialog from '../../common/Dialog/index.vue';
|
|
213
221
|
import ImagePreviewer from '../../common/ImagePreviewer/index-web.vue';
|
|
@@ -217,10 +225,12 @@ import chatStorage from '../../../utils/chatStorage';
|
|
|
217
225
|
import {
|
|
218
226
|
isEnabledMessageReadReceiptGlobal,
|
|
219
227
|
deepCopy,
|
|
228
|
+
isNonEmptyObject,
|
|
220
229
|
} from '../../../utils/utils';
|
|
221
230
|
import { isMessageInvisible, isThinkingMessage, isThinkingMessageOverTime, JSONToObject } from '../../../utils/index';
|
|
222
231
|
import { isCustomerConversation } from '../../../index';
|
|
223
232
|
import { CUSTOM_MESSAGE_SRC } from '../../../constant';
|
|
233
|
+
import { QuickOrderModel } from '../../../interface';
|
|
224
234
|
|
|
225
235
|
interface ScrollConfig {
|
|
226
236
|
scrollToMessage?: IMessageModel;
|
|
@@ -231,9 +241,18 @@ interface ScrollConfig {
|
|
|
231
241
|
};
|
|
232
242
|
}
|
|
233
243
|
|
|
244
|
+
interface IProps {
|
|
245
|
+
bottomQuickOrder?: QuickOrderModel;
|
|
246
|
+
showBottomQuickOrder: boolean;
|
|
247
|
+
}
|
|
248
|
+
const props = withDefaults(defineProps<IProps>(), {
|
|
249
|
+
showBottomQuickOrder: false,
|
|
250
|
+
});
|
|
251
|
+
|
|
234
252
|
interface IEmits {
|
|
235
253
|
(key: 'closeInputToolBar'): void;
|
|
236
254
|
(key: 'handleEditor', message: IMessageModel, type: string): void;
|
|
255
|
+
(key: 'closeBottomQuickOrder'): void;
|
|
237
256
|
}
|
|
238
257
|
|
|
239
258
|
const emits = defineEmits<IEmits>();
|
|
@@ -742,6 +761,26 @@ function setAudioPlayed(messageID: string) {
|
|
|
742
761
|
};
|
|
743
762
|
}
|
|
744
763
|
|
|
764
|
+
function closeBottomQuickOrder() {
|
|
765
|
+
emits('closeBottomQuickOrder');
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function sendBottomQuickOrder() {
|
|
769
|
+
TUIChatService.sendCustomMessage({
|
|
770
|
+
to: currentConversationID.value.replace('C2C', ''),
|
|
771
|
+
conversationType: 'C2C',
|
|
772
|
+
payload: {
|
|
773
|
+
data: JSON.stringify({
|
|
774
|
+
src: CUSTOM_MESSAGE_SRC.PRODUCT_CARD,
|
|
775
|
+
content: props.bottomQuickOrder,
|
|
776
|
+
customerServicePlugin: 0,
|
|
777
|
+
}),
|
|
778
|
+
},
|
|
779
|
+
needReadReceipt: isEnabledMessageReadReceiptGlobal(),
|
|
780
|
+
});
|
|
781
|
+
closeBottomQuickOrder();
|
|
782
|
+
}
|
|
783
|
+
|
|
745
784
|
defineExpose({
|
|
746
785
|
scrollToLatestMessage,
|
|
747
786
|
});
|
|
@@ -752,4 +791,11 @@ defineExpose({
|
|
|
752
791
|
.row-reverse {
|
|
753
792
|
flex-direction: row-reverse;
|
|
754
793
|
}
|
|
794
|
+
.bottom-quick-order {
|
|
795
|
+
position: absolute;
|
|
796
|
+
bottom: 0;
|
|
797
|
+
right: 0;
|
|
798
|
+
z-index: 1000;
|
|
799
|
+
width: 100%;
|
|
800
|
+
}
|
|
755
801
|
</style>
|
|
@@ -19,7 +19,12 @@ export const marked = new Marked(
|
|
|
19
19
|
if (href) {
|
|
20
20
|
// 匹配以 http:// 或 https:// 开头,所有 URL 主体字符,遇到第一个非主体字符(如中文括号、空格、表情符号等)时停止
|
|
21
21
|
let ret = href.replace(/https?:\/\/[\w\-./?=&:#]+(?=[^\w\-./?=&:#]|$)/g, (matchedUrl) => {
|
|
22
|
-
|
|
22
|
+
let isURLInText = false;
|
|
23
|
+
if (matchedUrl !== href) {
|
|
24
|
+
// 如果 text 里包含 url,我们就用 matchedUrl 作为 a 标签的值;否则用 text 作为值
|
|
25
|
+
isURLInText = true;
|
|
26
|
+
}
|
|
27
|
+
return `<a target="_blank" rel="noreferrer noopenner" class="message-marked_link" href="${matchedUrl || ''}" title="${title}">${isURLInText ? matchedUrl : text}</a>`;
|
|
23
28
|
});
|
|
24
29
|
if (ret === href) {
|
|
25
30
|
Log.w(`Unable to extract url, href:${href}`);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<FormBranch
|
|
8
8
|
:title="content.header"
|
|
9
9
|
:list="content.items"
|
|
10
|
-
:selectedContent="content.selected
|
|
10
|
+
:selectedContent="content.selected && content.selected.content"
|
|
11
11
|
@input-click="handleContentListItemClick"
|
|
12
12
|
/>
|
|
13
13
|
</div>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
>
|
|
19
19
|
<FormInput
|
|
20
20
|
:title="content.header"
|
|
21
|
-
:selectedContent="content.selected
|
|
21
|
+
:selectedContent="content.selected && content.selected.content"
|
|
22
22
|
@input-submit="handleFormSaveInputSubmit"
|
|
23
23
|
/>
|
|
24
24
|
</div>
|
|
@@ -2,38 +2,58 @@
|
|
|
2
2
|
<div
|
|
3
3
|
class="message-product-card"
|
|
4
4
|
>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
:src="props.payload.content.pic"
|
|
14
|
-
>
|
|
15
|
-
<div class="product-card-information">
|
|
16
|
-
<div class="product-card-title">
|
|
17
|
-
{{ props.payload.content.header }}
|
|
5
|
+
<div v-for="(item,index) in topCustomField" :key="index" class="product-card-custom-field">
|
|
6
|
+
<div class="custom-field-line">
|
|
7
|
+
<div v-if="item.name" class="order-name">
|
|
8
|
+
{{ item.name }}:
|
|
9
|
+
</div>
|
|
10
|
+
<div class="order-value">
|
|
11
|
+
{{ item.value }}
|
|
12
|
+
</div>
|
|
18
13
|
</div>
|
|
19
|
-
|
|
14
|
+
</div>
|
|
15
|
+
<div class="product-card-main">
|
|
16
|
+
<img
|
|
17
|
+
v-if="props.payload.content.pic"
|
|
18
|
+
class="product-img"
|
|
19
|
+
:src="props.payload.content.pic"
|
|
20
|
+
>
|
|
21
|
+
<div class="product-card-information">
|
|
22
|
+
<div class="product-card-title">
|
|
23
|
+
{{ props.payload.content.header }}
|
|
24
|
+
</div>
|
|
25
|
+
<div class="product-card-description-block">
|
|
20
26
|
<div class="product-card-description">
|
|
21
|
-
|
|
27
|
+
{{ props.payload.content.desc }}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div v-for="(item,index) in bottomCustomField" :key="index" class="product-card-custom-field">
|
|
34
|
+
<div class="custom-field-line">
|
|
35
|
+
<div v-if="item.name" class="order-name">
|
|
36
|
+
{{ item.name }}:
|
|
37
|
+
</div>
|
|
38
|
+
<div class="order-value">
|
|
39
|
+
{{ item.value }}
|
|
22
40
|
</div>
|
|
23
|
-
<div class="product-card-link" @click="jumpProductCard">
|
|
24
|
-
{{TUITranslateService.t("AIDesk.跳转")}}
|
|
25
|
-
</div>
|
|
26
41
|
</div>
|
|
27
42
|
</div>
|
|
43
|
+
<div class="product-card-link" @click="jumpProductCard">
|
|
44
|
+
{{ TUITranslateService.t("AIDesk.跳转") }}
|
|
45
|
+
</div>
|
|
28
46
|
</div>
|
|
29
47
|
</template>
|
|
30
48
|
|
|
31
49
|
<script lang="ts">
|
|
50
|
+
import vue from '../../../../../../adapter-vue';
|
|
32
51
|
import { customerServicePayloadType } from '../../../../../../interface';
|
|
33
52
|
import { isApp } from '../../../../../../utils/env';
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
import { openSafeUrl } from '../../../../../../utils/utils';
|
|
54
|
+
import { TUITranslateService } from '@tencentcloud/chat-uikit-engine';
|
|
55
|
+
import Log from '../../../../../../utils/logger';
|
|
56
|
+
const { computed } = vue;
|
|
37
57
|
|
|
38
58
|
interface Props {
|
|
39
59
|
payload: customerServicePayloadType;
|
|
@@ -49,92 +69,125 @@ export default {
|
|
|
49
69
|
emits: ['sendMessage'],
|
|
50
70
|
setup(props: Props) {
|
|
51
71
|
const jumpProductCard = () => {
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
const { url } = props.payload.content;
|
|
73
|
+
if (url) {
|
|
74
|
+
openSafeUrl(props.payload.content.url);
|
|
54
75
|
} else {
|
|
55
|
-
|
|
56
|
-
// #ifdef APP-PLUS
|
|
57
|
-
// @ts-ignore
|
|
58
|
-
plus.runtime.openURL(props.payload.content.url);
|
|
59
|
-
// #endif
|
|
60
|
-
// #ifdef H5
|
|
61
|
-
// @ts-ignore
|
|
62
|
-
window.open(props.payload.content.url);
|
|
63
|
-
// #endif
|
|
76
|
+
Log.w('Missing required url');
|
|
64
77
|
}
|
|
65
78
|
};
|
|
79
|
+
const customField = computed(() => {
|
|
80
|
+
return Array.isArray(props.payload.content.customField) ? props.payload.content.customField : [];
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const topCustomField = computed(() => {
|
|
84
|
+
return customField.value.filter((item) => item.position === 'top');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const bottomCustomField = computed(() => {
|
|
88
|
+
return customField.value.filter((item) => item.position !== 'top');
|
|
89
|
+
});
|
|
66
90
|
return {
|
|
67
91
|
props,
|
|
68
92
|
isApp,
|
|
69
93
|
jumpProductCard,
|
|
70
|
-
TUITranslateService
|
|
94
|
+
TUITranslateService,
|
|
95
|
+
topCustomField,
|
|
96
|
+
bottomCustomField,
|
|
71
97
|
};
|
|
72
98
|
},
|
|
73
99
|
};
|
|
74
100
|
</script>
|
|
75
101
|
<style lang="scss" scoped>
|
|
76
102
|
.message-product-card {
|
|
77
|
-
min-width:
|
|
103
|
+
min-width: 100%;
|
|
78
104
|
max-width: 400px;
|
|
105
|
+
margin-top: 2px;
|
|
106
|
+
font-family: PingFangSC-Regular;
|
|
79
107
|
display: flex;
|
|
80
|
-
|
|
81
|
-
.product-
|
|
82
|
-
width: 75px;
|
|
83
|
-
height: 75px;
|
|
84
|
-
border-radius: 10px;
|
|
85
|
-
flex-shrink: 0;
|
|
86
|
-
object-fit: cover;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.product-card-information {
|
|
90
|
-
width:100%;
|
|
91
|
-
margin-left: 15px;
|
|
92
|
-
margin-right:5px;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
.product-card-main {
|
|
93
110
|
display: flex;
|
|
94
|
-
|
|
95
|
-
|
|
111
|
+
margin: 10px 0 10px 0;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
.product-img {
|
|
115
|
+
width: 60px;
|
|
116
|
+
height: 60px;
|
|
117
|
+
border-radius: 10px;
|
|
118
|
+
flex-shrink: 0;
|
|
119
|
+
object-fit: cover;
|
|
120
|
+
margin-right: 15px;
|
|
121
|
+
align-self: center;
|
|
122
|
+
}
|
|
96
123
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
overflow: hidden;
|
|
104
|
-
text-overflow: ellipsis;
|
|
105
|
-
-webkit-line-clamp: 2;
|
|
106
|
-
-webkit-box-orient: vertical;
|
|
107
|
-
overflow-wrap: break-word;
|
|
108
|
-
word-break: normal;
|
|
109
|
-
}
|
|
124
|
+
.product-card-information {
|
|
125
|
+
width:100%;
|
|
126
|
+
margin-right: 5px;
|
|
127
|
+
display: flex;
|
|
128
|
+
flex-direction: column;
|
|
129
|
+
justify-content: space-between;
|
|
110
130
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
.product-card-title {
|
|
132
|
+
color: #000000;
|
|
133
|
+
font-size: 12px;
|
|
134
|
+
display: -webkit-box;
|
|
135
|
+
overflow: hidden;
|
|
136
|
+
text-overflow: ellipsis;
|
|
137
|
+
-webkit-line-clamp: 2;
|
|
138
|
+
-webkit-box-orient: vertical;
|
|
139
|
+
word-break: break-word;
|
|
140
|
+
overflow-wrap: anywhere;
|
|
141
|
+
}
|
|
117
142
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
white-space: nowrap;
|
|
125
|
-
font-weight: 600;
|
|
126
|
-
flex: 0 1 60px;
|
|
127
|
-
}
|
|
143
|
+
.product-card-description-block {
|
|
144
|
+
display:flex;
|
|
145
|
+
justify-content: space-between;
|
|
146
|
+
align-items: center;
|
|
147
|
+
gap: 5px;
|
|
148
|
+
}
|
|
128
149
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
.product-card-description {
|
|
151
|
+
font-size: 14px;
|
|
152
|
+
max-width: 100px;
|
|
153
|
+
color: #1C66E5;
|
|
154
|
+
overflow: hidden;
|
|
155
|
+
text-overflow: ellipsis;
|
|
156
|
+
white-space: nowrap;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
flex: 0 1 100px;
|
|
138
159
|
}
|
|
139
160
|
}
|
|
161
|
+
.product-card-custom-field {
|
|
162
|
+
color: #000;
|
|
163
|
+
margin: 0 0 5px 0;
|
|
164
|
+
}
|
|
165
|
+
.custom-field-line {
|
|
166
|
+
display: flex;
|
|
167
|
+
font-size: 12px;
|
|
168
|
+
gap: 5px;
|
|
169
|
+
overflow: hidden;
|
|
170
|
+
.order-name {
|
|
171
|
+
color: #878787;
|
|
172
|
+
margin-right: 3px;
|
|
173
|
+
white-space: nowrap;
|
|
174
|
+
flex-shrink: 0;
|
|
175
|
+
}
|
|
176
|
+
.order-value {
|
|
177
|
+
overflow: hidden;
|
|
178
|
+
text-overflow: ellipsis;
|
|
179
|
+
white-space: nowrap;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
.product-card-link {
|
|
183
|
+
cursor: pointer;
|
|
184
|
+
background-color: #1c66e5;
|
|
185
|
+
color: #ffffff;
|
|
186
|
+
padding: 2px 18px;
|
|
187
|
+
border-radius: 23px;
|
|
188
|
+
font-size: 12px;
|
|
189
|
+
line-height: 22px;
|
|
190
|
+
flex: 0 0 auto;
|
|
191
|
+
margin-left: auto;
|
|
192
|
+
}
|
|
140
193
|
</style>
|
package/constant.ts
CHANGED
|
@@ -148,14 +148,14 @@ export const TOOLBAR_BUTTON_TYPE = {
|
|
|
148
148
|
HUMAN_SERVICE: 'humanService',
|
|
149
149
|
SERVICE_RATING: 'serviceRating',
|
|
150
150
|
END_HUMAN_SERVICE: 'endHumanService',
|
|
151
|
-
}
|
|
151
|
+
};
|
|
152
152
|
export const INPUT_TOOLBAR_TYPE = {
|
|
153
153
|
EMOJI: 'emoji',
|
|
154
154
|
IMAGE: 'image',
|
|
155
155
|
FILE: 'file',
|
|
156
156
|
VIDEO: 'video',
|
|
157
157
|
RATING: 'rating',
|
|
158
|
-
}
|
|
158
|
+
};
|
|
159
159
|
|
|
160
160
|
export const USER_DEFAULT_AVATAR = 'https://web.sdk.qcloud.com/im/desk/assets/user_default_avatar.png';
|
|
161
161
|
|
|
@@ -165,4 +165,4 @@ export enum ReadState {
|
|
|
165
165
|
AllRead,
|
|
166
166
|
NotShow,
|
|
167
167
|
PartiallyRead,
|
|
168
|
-
}
|
|
168
|
+
};
|
package/interface.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TOOLBAR_BUTTON_TYPE,INPUT_TOOLBAR_TYPE } from './constant';
|
|
1
|
+
import { TOOLBAR_BUTTON_TYPE, INPUT_TOOLBAR_TYPE } from './constant';
|
|
2
2
|
export interface customerServicePayloadType {
|
|
3
3
|
chatbotPlugin?: number | string;
|
|
4
4
|
customerServicePlugin?: number | string;
|
|
@@ -211,4 +211,18 @@ export interface InputToolbarModel {
|
|
|
211
211
|
isEnabled?: number, // 是否显示
|
|
212
212
|
renderCondition?: () => {},// [UIKit] 是否显示
|
|
213
213
|
clickEvent?: () => void,// [UIKit] 点击事件
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface QuickOrderCustomFieldModel {
|
|
217
|
+
name?: string,
|
|
218
|
+
value: string,
|
|
219
|
+
position: string,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface QuickOrderModel {
|
|
223
|
+
header: string,
|
|
224
|
+
desc: string,
|
|
225
|
+
pic?: string,
|
|
226
|
+
url: string,
|
|
227
|
+
customField?: QuickOrderCustomFieldModel[],
|
|
214
228
|
}
|
package/locales/en/aidesk.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const AIDesk = {
|
|
2
2
|
"结束人工会话": "End human service",
|
|
3
3
|
"转人工服务": "Human service",
|
|
4
|
-
"跳转": "
|
|
4
|
+
"跳转": "Open",
|
|
5
5
|
"立即填写": "Fill now",
|
|
6
6
|
"已提交": "Submitted",
|
|
7
7
|
"提交": "Submit",
|
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Context misunderstanding",
|
|
28
28
|
"格式不规范":"Improper format",
|
|
29
29
|
"内容不完整":"Incomplete content",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Unable to send the file as it exceeds 100 MB",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Unable to send the image as it exceeds 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Unable to send the video as it exceeds 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/fil/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Maling pag-unawa sa konteksto",
|
|
28
28
|
"格式不规范":"Hindi tamang pormat",
|
|
29
29
|
"内容不完整":"Hindi kumpletong nilalaman",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Lampas sa 100MB ang file, hindi maipadala",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Hindi maipadala ang larawan dahil lampas ito sa 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Hindi maipadala ang video dahil lampas ito sa 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/id/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Kesalahan pemahaman konteks",
|
|
28
28
|
"格式不规范":"Format tidak standar",
|
|
29
29
|
"内容不完整":"Konten tidak lengkap",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Ukuran file melebihi 100MB, tidak dapat dikirim",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Tidak dapat mengirim gambar karena melebihi 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Tidak dapat mengirim video karena melebihi 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/ja/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"文脈の理解誤り",
|
|
28
28
|
"格式不规范":"形式が不適切",
|
|
29
29
|
"内容不完整":"内容が不完全",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"ファイルサイズが100MBを超えているため送信できません",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"画像のサイズが20MBを超えているため送信できません",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"動画のサイズが100MBを超えているため送信できません",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/ms/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Kesilapan pemahaman konteks",
|
|
28
28
|
"格式不规范":"Format tidak standard",
|
|
29
29
|
"内容不完整":"Kandungan tidak lengkap",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Saiz fail melebihi 100MB, tidak boleh dihantar",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Tidak dapat menghantar gambar kerana melebihi 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Tidak dapat menghantar video kerana melebihi 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/ru/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Ошибка понимания контекста",
|
|
28
28
|
"格式不规范":"Нестандартный формат",
|
|
29
29
|
"内容不完整":"Неполное содержание",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Размер файла превышает 100MB, отправка невозможна",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Невозможно отправить изображение, так как оно превышает 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Невозможно отправить видео, так как оно превышает 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/th/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"ความเข้าใจบริบทผิดพลาด",
|
|
28
28
|
"格式不规范":"รูปแบบไม่ถูกต้อง",
|
|
29
29
|
"内容不完整":"เนื้อหาไม่สมบูรณ์",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"ขนาดไฟล์เกิน 100MB ไม่สามารถส่งได้",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"ไม่สามารถส่งรูปภาพได้เนื่องจากขนาดเกิน 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"ไม่สามารถส่งวิดีโอได้เนื่องจากขนาดเกิน 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/vi/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"Hiểu sai ngữ cảnh",
|
|
28
28
|
"格式不规范":"Định dạng không chuẩn",
|
|
29
29
|
"内容不完整":"Nội dung không đầy đủ",
|
|
30
|
+
"file 大小超过 100MB,无法发送":"Kích thước tệp vượt quá 100MB, không thể gửi",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"Không thể gửi hình ảnh do vượt quá 20 MB",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"Không thể gửi video do vượt quá 100 MB",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/zh_cn/aidesk.ts
CHANGED
|
@@ -27,5 +27,8 @@ const AIDesk = {
|
|
|
27
27
|
"上下文理解错误":"上下文理解错误",
|
|
28
28
|
"格式不规范":"格式不规范",
|
|
29
29
|
"内容不完整":"内容不完整",
|
|
30
|
+
"file 大小超过 100MB,无法发送": "file 大小超过 100MB,无法发送",
|
|
31
|
+
"image 大小超过 20MB,无法发送":"image 大小超过 20MB,无法发送",
|
|
32
|
+
"video 大小超过 100MB,无法发送":"video 大小超过 100MB,无法发送",
|
|
30
33
|
}
|
|
31
34
|
export default AIDesk;
|
package/locales/zh_tw/aidesk.ts
CHANGED
package/package.json
CHANGED
package/utils/utils.ts
CHANGED
|
@@ -206,3 +206,10 @@ export function switchReadStatus(value: number) {
|
|
|
206
206
|
export function getTo(conversation: IConversationModel): string {
|
|
207
207
|
return conversation?.groupProfile?.groupID || conversation?.userProfile?.userID;
|
|
208
208
|
}
|
|
209
|
+
|
|
210
|
+
export function isNonEmptyObject(obj: any): boolean {
|
|
211
|
+
if (obj && Object.getPrototypeOf(obj) === Object.prototype && Object.keys(obj).length > 0) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
}
|