@tencentcloud/ai-desk-customer-vue 0.2.0 → 0.3.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/README.md +23 -25
- package/components/CustomerServiceChat/index-web.vue +16 -3
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +6 -14
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +5 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-file.vue +6 -80
- package/package.json +4 -5
- package/server.ts +13 -7
- package/utils/console.js +28 -0
- package/utils/index.ts +12 -0
- package/utils/logger.js +178 -0
- package/utils/time.js +15 -0
package/README.md
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
## 介绍
|
|
2
2
|
|
|
3
|
-
智能客服用户端 Web UIKit。使用此 UIKit,您可以在一天内将智能客服的能力集成到您的 Web 或 Hybrid 项目。极简接入,用 AI
|
|
4
|
-
|
|
5
|
-

|
|
6
|
-
|
|
3
|
+
智能客服用户端 Web UIKit。使用此 UIKit,您可以在一天内将智能客服的能力集成到您的 Web 或 Hybrid 项目。极简接入,用 AI 为您的产品增收提效。
|
|
7
4
|
|
|
8
5
|
## 效果展示
|
|
9
6
|
|
|
@@ -107,13 +104,25 @@ npm install
|
|
|
107
104
|
npm i -D sass sass-loader
|
|
108
105
|
```
|
|
109
106
|
|
|
110
|
-
|
|
111
|
-
>
|
|
107
|
+
清除项目默认的样式,避免样式问题:
|
|
112
108
|
|
|
113
|
-
> 请删除 **src/style.css** 内的项目默认样式,避免样式问题。
|
|
114
|
-
>
|
|
115
109
|
|
|
116
110
|
|
|
111
|
+
【macOS 端】
|
|
112
|
+
``` bash
|
|
113
|
+
echo -n > src/style.css
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
【Windows 端(PowerShell)】
|
|
117
|
+
``` bash
|
|
118
|
+
Clear-Content -Path src/style.css
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
【Windows 端(CMD)】
|
|
122
|
+
``` bash
|
|
123
|
+
echo. > src\style.css
|
|
124
|
+
```
|
|
125
|
+
|
|
117
126
|
### 步骤2:下载 UI 组件
|
|
118
127
|
|
|
119
128
|
通过 npm 方式下载 UI 组件,并将 UI 组件复制到自己工程的 src 目录下:
|
|
@@ -170,7 +179,7 @@ xcopy .\node_modules\@tencentcloud\ai-desk-customer-vue .\src\ai-desk-customer-v
|
|
|
170
179
|
:SDKAppID=""
|
|
171
180
|
userID=""
|
|
172
181
|
userSig=""
|
|
173
|
-
:style="{ width: '600px', height: '
|
|
182
|
+
:style="{ width: '600px', height: '80vh', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
|
|
174
183
|
/>
|
|
175
184
|
</template>
|
|
176
185
|
<script setup lang="ts">
|
|
@@ -188,7 +197,7 @@ xcopy .\node_modules\@tencentcloud\ai-desk-customer-vue .\src\ai-desk-customer-v
|
|
|
188
197
|
:SDKAppID=""
|
|
189
198
|
userID=""
|
|
190
199
|
userSig=""
|
|
191
|
-
:style="{ width: '600px', height: '
|
|
200
|
+
:style="{ width: '600px', height: '80vh', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
|
|
192
201
|
/>
|
|
193
202
|
</div>
|
|
194
203
|
</template>
|
|
@@ -210,7 +219,7 @@ body {
|
|
|
210
219
|
:SDKAppID=""
|
|
211
220
|
userID=""
|
|
212
221
|
userSig=""
|
|
213
|
-
:style="{ width: '600px', height: '
|
|
222
|
+
:style="{ width: '600px', height: '80vh', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
|
|
214
223
|
/>
|
|
215
224
|
</div>
|
|
216
225
|
</template>
|
|
@@ -223,18 +232,13 @@ body {
|
|
|
223
232
|
}
|
|
224
233
|
</style>
|
|
225
234
|
```
|
|
226
|
-
1.
|
|
227
|
-
|
|
228
|
-
``` javascript
|
|
229
|
-
npm i @vue/composition-api unplugin-vue2-script-setup vue@2.6.14 vue-template-compiler@2.6.14
|
|
230
|
-
```
|
|
231
|
-
2. 在 `main.ts/mian.js `中引入 VueCompositionAPI。
|
|
235
|
+
1. 在 `main.ts/mian.js `中引入 VueCompositionAPI。
|
|
232
236
|
|
|
233
237
|
``` javascript
|
|
234
238
|
import VueCompositionAPI from "@vue/composition-api";
|
|
235
239
|
Vue.use(VueCompositionAPI);
|
|
236
240
|
```
|
|
237
|
-
|
|
241
|
+
2. 在 `vue.config.js `中增加,若没有该文件请新建。
|
|
238
242
|
|
|
239
243
|
``` javascript
|
|
240
244
|
const ScriptSetup = require("unplugin-vue2-script-setup/webpack").default;
|
|
@@ -253,7 +257,7 @@ module.exports = {
|
|
|
253
257
|
},
|
|
254
258
|
};
|
|
255
259
|
```
|
|
256
|
-
|
|
260
|
+
3. 在 `src/ai-desk-customer-vue/adapter-vue-web.ts` 文件最后, 替换导出源:
|
|
257
261
|
|
|
258
262
|
``` javascript
|
|
259
263
|
// 初始写法
|
|
@@ -317,12 +321,6 @@ export * from "@vue/composition-api";
|
|
|
317
321
|
> 在 tsconfig.json 中关闭 ai-desk-customer-vue 的ts检测。
|
|
318
322
|
>
|
|
319
323
|
> `{`
|
|
320
|
-
> ` "compilerOptions": {`
|
|
321
|
-
> ` ...`
|
|
322
|
-
> ` "preserveValueImports": false,`
|
|
323
|
-
> ` "importsNotUsedAsValues": "preserve",`
|
|
324
|
-
> ` "noImplicitAny": false,`
|
|
325
|
-
> ` },`
|
|
326
324
|
> ` "exclude": [`
|
|
327
325
|
> ` "node_modules",`
|
|
328
326
|
> ` "src/ai-desk-customer-vue",`
|
|
@@ -88,7 +88,8 @@ import MessageInputToolbar from './message-input-toolbar/index-web.vue';
|
|
|
88
88
|
import EmojiDialog from './message-input-toolbar/emoji-dialog-mobile/emoji-dialog-mobile.vue';
|
|
89
89
|
import { isPC, isH5} from '../../utils/env';
|
|
90
90
|
import { ToolbarDisplayType } from '../../interface';
|
|
91
|
-
|
|
91
|
+
import { isSupportedLang } from '../../utils/';
|
|
92
|
+
import Log from '../../utils/logger';
|
|
92
93
|
|
|
93
94
|
const { ref, onMounted, onUnmounted, computed } = vue;
|
|
94
95
|
|
|
@@ -97,6 +98,7 @@ interface IProps {
|
|
|
97
98
|
SDKAppID?:number;
|
|
98
99
|
userID?:string;
|
|
99
100
|
userSig?:string;
|
|
101
|
+
robotLang?:string;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
const emits = defineEmits(['closeChat']);
|
|
@@ -112,6 +114,7 @@ const props = withDefaults(defineProps<IProps>(), {
|
|
|
112
114
|
SDKAppID: 0,
|
|
113
115
|
userID: '',
|
|
114
116
|
userSig: '',
|
|
117
|
+
robotLang: '',
|
|
115
118
|
});
|
|
116
119
|
|
|
117
120
|
const loginCustomerUIKit = () => {
|
|
@@ -121,7 +124,7 @@ const loginCustomerUIKit = () => {
|
|
|
121
124
|
userSig: props.userSig,
|
|
122
125
|
useUploadPlugin: true,
|
|
123
126
|
}).then(() => {
|
|
124
|
-
|
|
127
|
+
Log.i(`login success, robotLang:${props.robotLang}`);
|
|
125
128
|
let conversationID = 'C2C@customer_service_account';
|
|
126
129
|
TUIConversationService.switchConversation(conversationID);
|
|
127
130
|
TUIChatEngine.chat.callExperimentalAPI('isFeatureEnabledForStat', Math.pow(2, 42));
|
|
@@ -134,6 +137,9 @@ try {
|
|
|
134
137
|
const userContext = TUILogin.getContext();
|
|
135
138
|
if(userContext.userID == '' && props.SDKAppID!==0 && props.userID!=='' && props.userSig!==''){
|
|
136
139
|
loginCustomerUIKit();
|
|
140
|
+
if (props.robotLang && !isSupportedLang(props.robotLang)) {
|
|
141
|
+
Log.w(`robotLang:${props.robotLang} is not supported`);
|
|
142
|
+
}
|
|
137
143
|
}
|
|
138
144
|
} catch (e) {
|
|
139
145
|
console.log(e)
|
|
@@ -200,6 +206,10 @@ function scrollToLatestMessage() {
|
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
function onCurrentConversationIDUpdate(conversationID: string) {
|
|
209
|
+
if (!conversationID) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
203
213
|
if (currentConversationID.value === conversationID) {
|
|
204
214
|
return;
|
|
205
215
|
}
|
|
@@ -210,7 +220,10 @@ function onCurrentConversationIDUpdate(conversationID: string) {
|
|
|
210
220
|
TUICore.callService({
|
|
211
221
|
serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
|
|
212
222
|
method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
|
|
213
|
-
params: {
|
|
223
|
+
params: {
|
|
224
|
+
conversationID: conversationID,
|
|
225
|
+
robotLang: props.robotLang && isSupportedLang(props.robotLang) ? props.robotLang : undefined,
|
|
226
|
+
},
|
|
214
227
|
});
|
|
215
228
|
}
|
|
216
229
|
|
|
@@ -13,7 +13,7 @@ import vue from '../../../../../../adapter-vue';
|
|
|
13
13
|
import { customerServicePayloadType } from '../../../../../../interface';
|
|
14
14
|
import { parseMarkdown } from './marked'
|
|
15
15
|
|
|
16
|
-
const { ref, watchEffect,
|
|
16
|
+
const { ref, watchEffect, onMounted } = vue;
|
|
17
17
|
|
|
18
18
|
interface Props {
|
|
19
19
|
payload: customerServicePayloadType;
|
|
@@ -27,14 +27,12 @@ export default {
|
|
|
27
27
|
},
|
|
28
28
|
},
|
|
29
29
|
setup(props: Props) {
|
|
30
|
-
const content = ref<string>('');
|
|
31
30
|
const displayedContent = ref<string>('');
|
|
32
31
|
const isFinished = ref<boolean>(false);
|
|
33
32
|
let currentIndex = 0;
|
|
34
33
|
|
|
35
34
|
onMounted(() => {
|
|
36
|
-
|
|
37
|
-
displayedContent.value = parseMarkdown(content.value);
|
|
35
|
+
displayedContent.value = parseMarkdown(props?.payload?.chunks?.join('') ?? '');
|
|
38
36
|
currentIndex = displayedContent.value.length;
|
|
39
37
|
});
|
|
40
38
|
|
|
@@ -43,6 +41,7 @@ export default {
|
|
|
43
41
|
const parsedContent = parseMarkdown(newContent);
|
|
44
42
|
if (parsedContent.length > currentIndex) {
|
|
45
43
|
displayedContent.value = parsedContent;
|
|
44
|
+
currentIndex = parsedContent.length;
|
|
46
45
|
}
|
|
47
46
|
});
|
|
48
47
|
|
|
@@ -51,7 +50,6 @@ export default {
|
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
return {
|
|
54
|
-
content,
|
|
55
53
|
props,
|
|
56
54
|
isFinished,
|
|
57
55
|
displayedContent,
|
|
@@ -69,21 +67,15 @@ export default {
|
|
|
69
67
|
.blinking-cursor {
|
|
70
68
|
display: inline-block;
|
|
71
69
|
width: 1px;
|
|
72
|
-
height:
|
|
70
|
+
height: 1em;
|
|
73
71
|
background-color: black;
|
|
74
72
|
animation: blink 1s step-end infinite;
|
|
75
73
|
vertical-align: sub;
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
@keyframes blink {
|
|
79
|
-
0%,
|
|
80
|
-
|
|
81
|
-
background-color: transparent;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
50% {
|
|
85
|
-
background-color: black;
|
|
86
|
-
}
|
|
77
|
+
0%, 100% { opacity: 1; }
|
|
78
|
+
50% { opacity: 0; }
|
|
87
79
|
}
|
|
88
80
|
}
|
|
89
81
|
</style>
|
|
@@ -124,6 +124,7 @@
|
|
|
124
124
|
justify-content: flex-start;
|
|
125
125
|
margin: 0;
|
|
126
126
|
padding: 0;
|
|
127
|
+
font-family: PingFangSC-Regular;
|
|
127
128
|
|
|
128
129
|
.message-marked_code-container {
|
|
129
130
|
display: flex;
|
|
@@ -176,3 +177,7 @@
|
|
|
176
177
|
cursor: pointer;
|
|
177
178
|
}
|
|
178
179
|
}
|
|
180
|
+
|
|
181
|
+
.message-marked >*:last-child {
|
|
182
|
+
margin-bottom: 0;
|
|
183
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
:class="['file-message-
|
|
3
|
+
:class="['file-message-container']"
|
|
4
4
|
:title="TUITranslateService.t('TUIChat.单击下载')"
|
|
5
5
|
@click="download"
|
|
6
6
|
>
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from '@tencentcloud/chat-uikit-engine';
|
|
24
24
|
import Icon from '../../../common/Icon.vue';
|
|
25
25
|
import files from '../../../../assets/files.png';
|
|
26
|
-
import { isUniFrameWork
|
|
26
|
+
import { isUniFrameWork } from '../../../../utils/env';
|
|
27
27
|
import type { IFileMessageContent } from '../../../../interface';
|
|
28
28
|
const { withDefaults } = vue;
|
|
29
29
|
|
|
@@ -39,10 +39,10 @@ const props = withDefaults(
|
|
|
39
39
|
);
|
|
40
40
|
|
|
41
41
|
const download = () => {
|
|
42
|
-
if (props.messageItem.hasRiskContent
|
|
42
|
+
if (props.messageItem.hasRiskContent) {
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
// If the browser supports fetch, use blob to download, so as to avoid the browser clicking the a tag and jumping to the preview of the new page
|
|
47
47
|
if (!isUniFrameWork && (window as any)?.fetch) {
|
|
48
48
|
const option = {
|
|
@@ -60,89 +60,15 @@ const download = () => {
|
|
|
60
60
|
a.download = props.content.name;
|
|
61
61
|
a.click();
|
|
62
62
|
});
|
|
63
|
-
} else if(isWeChat){
|
|
64
|
-
console.log("isWechat",props.content.url)
|
|
65
|
-
|
|
66
|
-
wx.downloadFile({
|
|
67
|
-
url: props.content.url,
|
|
68
|
-
filePath: wx.env.USER_DATA_PATH + '/' + props.content.name,
|
|
69
|
-
success: function (res) {
|
|
70
|
-
var filePath = res.filePath;
|
|
71
|
-
const lastIndex = filePath.lastIndexOf('.');
|
|
72
|
-
const fileType = filePath.substring(lastIndex + 1);
|
|
73
|
-
console.log(fileType)
|
|
74
|
-
wx.openDocument({
|
|
75
|
-
filePath: filePath,
|
|
76
|
-
showMenu:true,
|
|
77
|
-
fileType:fileType,
|
|
78
|
-
success: function (res) {
|
|
79
|
-
console.log('打开文档成功');
|
|
80
|
-
},
|
|
81
|
-
fail:function(){
|
|
82
|
-
console.log("fail")
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}else if(isUniFrameWork){
|
|
88
|
-
const lastIndex = props.content.url.lastIndexOf('.');
|
|
89
|
-
const fileType = props.content.url.substring(lastIndex + 1);
|
|
90
|
-
uni.downloadFile({
|
|
91
|
-
url:props.content.url,
|
|
92
|
-
success:function(res){
|
|
93
|
-
if(res.statusCode == 200){
|
|
94
|
-
console.log(res)
|
|
95
|
-
const tempFilePaths = res.tempFilePath;
|
|
96
|
-
uni.showToast({
|
|
97
|
-
title: '下载成功'+tempFilePaths,
|
|
98
|
-
icon: 'success',
|
|
99
|
-
duration: 2000
|
|
100
|
-
});
|
|
101
|
-
console.log(tempFilePaths);
|
|
102
|
-
uni.openDocument({
|
|
103
|
-
filePath: tempFilePaths,
|
|
104
|
-
fileType: fileType,
|
|
105
|
-
success: function () {
|
|
106
|
-
console.log('打开文档成功');
|
|
107
|
-
},
|
|
108
|
-
fail: function () {
|
|
109
|
-
console.log('打开文档失败');
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
// uni.openDocument({
|
|
116
|
-
// filePath: tempFilePaths[0],
|
|
117
|
-
// fileType: 'pdf',
|
|
118
|
-
// success: function () {
|
|
119
|
-
// console.log('打开文档成功');
|
|
120
|
-
// },
|
|
121
|
-
// fail: function () {
|
|
122
|
-
// console.log('打开文档失败');
|
|
123
|
-
// }
|
|
124
|
-
// });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
else {
|
|
128
|
-
console.log("no window here")
|
|
129
|
-
const a = document.createElement('a');
|
|
130
|
-
a.href = props.content.url;
|
|
131
|
-
a.target = '_blank';
|
|
132
|
-
a.download = props.content.name;
|
|
133
|
-
a.click();
|
|
134
63
|
}
|
|
135
64
|
};
|
|
136
65
|
</script>
|
|
137
66
|
<style lang="scss" scoped>
|
|
138
67
|
@import "../../style/common";
|
|
139
|
-
.file-
|
|
140
|
-
cursor: pointer;
|
|
141
|
-
}
|
|
142
|
-
.file-message-montainer {
|
|
68
|
+
.file-message-container {
|
|
143
69
|
display: flex;
|
|
144
70
|
flex-direction: row;
|
|
145
|
-
|
|
71
|
+
cursor: pointer;
|
|
146
72
|
|
|
147
73
|
.file-icon {
|
|
148
74
|
margin: auto 8px;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tencentcloud/ai-desk-customer-vue",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "chat uikit ai-desk-customer",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "chat uikit ai-desk-customer web-mui-uikit",
|
|
5
5
|
"main": "index",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"customer service",
|
|
@@ -9,10 +9,9 @@
|
|
|
9
9
|
"chatbot",
|
|
10
10
|
"vue",
|
|
11
11
|
"tencentcloud",
|
|
12
|
-
"客服",
|
|
13
12
|
"智能客服",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"智能机器人",
|
|
14
|
+
"deepseek"
|
|
16
15
|
],
|
|
17
16
|
"scripts": {
|
|
18
17
|
"sync": "node ./script/fileCopy.js",
|
package/server.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import TUICore, { TUIConstants
|
|
1
|
+
import TUICore, { TUIConstants } from '@tencentcloud/tui-core';
|
|
2
2
|
import {
|
|
3
3
|
isCustomerServiceMessage,
|
|
4
4
|
isMessageInvisible,
|
|
5
5
|
} from './utils/index';
|
|
6
6
|
import TUIChatEngine, { TUIChatService, TUIConversationService,IMessageModel } from '@tencentcloud/chat-uikit-engine';
|
|
7
|
+
import Log from './utils/logger';
|
|
7
8
|
|
|
8
9
|
export default class TUICustomerServer {
|
|
9
10
|
static isInitialized: boolean;
|
|
10
11
|
static instance: TUICustomerServer;
|
|
11
12
|
private customerServiceAccounts: any[];
|
|
12
13
|
constructor() {
|
|
13
|
-
console.log('TUICustomerServer.init ok');
|
|
14
14
|
TUICore.registerService(TUIConstants.TUICustomerServicePlugin.SERVICE.NAME, this);
|
|
15
15
|
TUICore.registerExtension(TUIConstants.TUIContact.EXTENSION.CONTACT_LIST.EXT_ID, this);
|
|
16
16
|
this.customerServiceAccounts = ['@customer_service_account'];
|
|
17
|
+
Log.i('TUICustomerServer.init ok');
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
static getInstance(): TUICustomerServer {
|
|
@@ -30,12 +31,12 @@ export default class TUICustomerServer {
|
|
|
30
31
|
userSig,
|
|
31
32
|
useUploadPlugin: true,
|
|
32
33
|
}).then(() => {
|
|
33
|
-
|
|
34
|
+
Log.i("login success");
|
|
34
35
|
TUIConversationService.switchConversation('C2C@customer_service_account');
|
|
35
36
|
TUIChatEngine.chat.callExperimentalAPI('isFeatureEnabledForStat', Math.pow(2, 42));
|
|
36
37
|
})
|
|
37
38
|
.catch((error) => {
|
|
38
|
-
|
|
39
|
+
Log.l(error);
|
|
39
40
|
})
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -73,7 +74,7 @@ export default class TUICustomerServer {
|
|
|
73
74
|
{
|
|
74
75
|
weight: 0,
|
|
75
76
|
icon: '',
|
|
76
|
-
text: '
|
|
77
|
+
text: '智能客服',
|
|
77
78
|
data: {
|
|
78
79
|
name: 'customer',
|
|
79
80
|
accountList: this.customerServiceAccounts,
|
|
@@ -84,16 +85,21 @@ export default class TUICustomerServer {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
public onCall(method: string, params: any) {
|
|
88
|
+
Log.l(`TUICustomerServer.onCall method:${method} params:`, params);
|
|
87
89
|
if (method === TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION) {
|
|
88
90
|
if (this.isCustomerConversation(params.conversationID)) {
|
|
89
91
|
TUIChatService.sendCustomMessage({
|
|
90
92
|
to: params.conversationID.slice(3),
|
|
91
93
|
conversationType: TUIChatEngine.TYPES.CONV_C2C,
|
|
92
94
|
payload: {
|
|
93
|
-
data: JSON.stringify({
|
|
95
|
+
data: JSON.stringify({
|
|
96
|
+
src: '7',
|
|
97
|
+
customerServicePlugin: 0,
|
|
98
|
+
triggeredContent: typeof params.robotLang === 'undefined' ? undefined : { language: params.robotLang }
|
|
99
|
+
}),
|
|
94
100
|
},
|
|
95
101
|
}, { onlineUserOnly: true});
|
|
96
102
|
}
|
|
97
103
|
}
|
|
98
104
|
}
|
|
99
|
-
}
|
|
105
|
+
}
|
package/utils/console.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
let _console; let method;
|
|
2
|
+
if (typeof console !== 'undefined') {
|
|
3
|
+
_console = console;
|
|
4
|
+
} else if (typeof global !== 'undefined' && global.console) {
|
|
5
|
+
_console = global.console;
|
|
6
|
+
} else if (typeof window !== 'undefined' && window.console) {
|
|
7
|
+
_console = window.console;
|
|
8
|
+
} else {
|
|
9
|
+
_console = {};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const noop = function() {};
|
|
13
|
+
const methods = [
|
|
14
|
+
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'group',
|
|
15
|
+
'groupCollapsed', 'groupEnd', 'info', 'log', 'profile', 'profileEnd',
|
|
16
|
+
'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn',
|
|
17
|
+
];
|
|
18
|
+
let length = methods.length;
|
|
19
|
+
|
|
20
|
+
while (length--) {
|
|
21
|
+
method = methods[length];
|
|
22
|
+
|
|
23
|
+
if (!console[method]) {
|
|
24
|
+
_console[method] = noop;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default _console;
|
package/utils/index.ts
CHANGED
|
@@ -58,3 +58,15 @@ export const isMessageInvisible = (message: IMessageModel): boolean => {
|
|
|
58
58
|
const isRobot = customerServicePayload?.src === CUSTOM_MESSAGE_SRC.ROBOT && robotCommandArray.indexOf(customerServicePayload?.content?.command) !== -1;
|
|
59
59
|
return isCustomerMessage && (isCustomerInvisible || isRobot || isMultiFormMessage);
|
|
60
60
|
};
|
|
61
|
+
|
|
62
|
+
export const isSupportedLang = (lang: string): boolean => {
|
|
63
|
+
return [
|
|
64
|
+
'zh', // Simplified Chinese中文简体:zh
|
|
65
|
+
'zh-TW', // Traditional Chinese中文繁体:zh-TW
|
|
66
|
+
'en', // English英语:en
|
|
67
|
+
'id', // Indonesian印度尼西亚语:id
|
|
68
|
+
'vi', // Vietnamese越南语:vi
|
|
69
|
+
'ja', // Japanese日语:ja
|
|
70
|
+
'fil' // Filipino菲律宾语:fil
|
|
71
|
+
].indexOf(lang) !== -1;
|
|
72
|
+
}
|
package/utils/logger.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import console from './console';
|
|
2
|
+
import { getDate } from './time';
|
|
3
|
+
|
|
4
|
+
const USER_AGENT = window && window.navigator && window.navigator.userAgent || '';
|
|
5
|
+
const IS_IE = /MSIE/.test(USER_AGENT) || (USER_AGENT.indexOf('Trident') > -1 && USER_AGENT.indexOf('rv:11.0') > -1);
|
|
6
|
+
|
|
7
|
+
const canIUseConsoleStyle = function() {
|
|
8
|
+
// ie 浏览器不支持 console css style
|
|
9
|
+
// 小程序仅部分支持 console css style (console.warn/console.error 不支持)
|
|
10
|
+
return !IS_IE;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const getType = function(input) {
|
|
14
|
+
return Object.prototype.toString
|
|
15
|
+
.call(input)
|
|
16
|
+
.match(/^\[object (.*)\]$/)[1]
|
|
17
|
+
.toLowerCase();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const isArray = function(input) {
|
|
21
|
+
if (typeof Array.isArray === 'function') {
|
|
22
|
+
return Array.isArray(input);
|
|
23
|
+
}
|
|
24
|
+
return getType(input) === 'array';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const isObject = function(input) {
|
|
28
|
+
// null is object, hence the extra check
|
|
29
|
+
return input !== null && typeof input === 'object';
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 检测input是否为Error的实例
|
|
34
|
+
* @param {*} input 任意类型的输入
|
|
35
|
+
* @returns {Boolean} true->input is an instance of Error
|
|
36
|
+
*/
|
|
37
|
+
const isInstanceOfError = function(input) {
|
|
38
|
+
return (input instanceof Error);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 检测input类型是否为数组或者object
|
|
43
|
+
* @param {*} input 任意类型的输入
|
|
44
|
+
* @returns {Boolean} true->input is an array or an object
|
|
45
|
+
*/
|
|
46
|
+
const isArrayOrObject = function(input) {
|
|
47
|
+
return isArray(input) || isObject(input);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 对齐毫秒字符串
|
|
52
|
+
* @param {*} ms 毫秒
|
|
53
|
+
* @returns {String} 对齐后的毫秒时间字符串
|
|
54
|
+
*/
|
|
55
|
+
function padMs(ms) {
|
|
56
|
+
const len = ms.toString().length;
|
|
57
|
+
let ret;
|
|
58
|
+
switch (len) {
|
|
59
|
+
case 1:
|
|
60
|
+
ret = '00' + ms;
|
|
61
|
+
break;
|
|
62
|
+
case 2:
|
|
63
|
+
ret = '0' + ms;
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
ret = ms;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return ret;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* log前缀
|
|
75
|
+
* @returns {String} 日志前缀
|
|
76
|
+
*/
|
|
77
|
+
function getPrefix() {
|
|
78
|
+
if (!canIUseConsoleStyle()) {
|
|
79
|
+
return 'ai-desk-customer';
|
|
80
|
+
}
|
|
81
|
+
return '%c ai-desk-customer %c';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getPrefixStyle() {
|
|
85
|
+
return 'background:#0052d9; padding:1px; border-radius:3px; color: #fff';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getBgStyle() {
|
|
89
|
+
return 'background:transparent';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getTime() {
|
|
93
|
+
const date = getDate();
|
|
94
|
+
return date.toLocaleTimeString('en-US', { hour12: false }) + '.' + padMs(date.getMilliseconds());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const Log = {
|
|
98
|
+
// 将函数参数拼成字符串
|
|
99
|
+
arguments2String(args) {
|
|
100
|
+
let s = '';
|
|
101
|
+
if (args.length === 1) {
|
|
102
|
+
s = args[0];
|
|
103
|
+
} else {
|
|
104
|
+
for (let i = 0, length = args.length; i < length; i++) {
|
|
105
|
+
if (isArrayOrObject(args[i])) {
|
|
106
|
+
try {
|
|
107
|
+
s += isInstanceOfError(args[i]) ? JSON.stringify(args[i], ['message', 'code']) : JSON.stringify(args[i]);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
s += error ? error.message : '';
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
s += args[i];
|
|
114
|
+
}
|
|
115
|
+
s += ' ';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return s;
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
_exec(api, log) {
|
|
122
|
+
if (!canIUseConsoleStyle()) {
|
|
123
|
+
console[api](`${getPrefix()} ${getTime()} ${log}`);
|
|
124
|
+
} else {
|
|
125
|
+
console[api](getPrefix(), getPrefixStyle(), getBgStyle(), getTime(), log);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 打印调试日志
|
|
131
|
+
*/
|
|
132
|
+
d: function() {
|
|
133
|
+
const s = this.arguments2String(arguments);
|
|
134
|
+
this._exec('debug', s);
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 打印普通日志
|
|
139
|
+
*/
|
|
140
|
+
l: function() {
|
|
141
|
+
const s = this.arguments2String(arguments);
|
|
142
|
+
this._exec('log', s);
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 打印普通日志,等同于 Log.i,为了兼容低版本的本地审核插件(其内部调用了 Logger.log)
|
|
147
|
+
*/
|
|
148
|
+
log: function() {
|
|
149
|
+
const s = this.arguments2String(arguments);
|
|
150
|
+
this._exec('log', s);
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 打印release日志
|
|
155
|
+
*/
|
|
156
|
+
i: function() {
|
|
157
|
+
const s = this.arguments2String(arguments);
|
|
158
|
+
this._exec('info', s);
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 打印告警日志
|
|
163
|
+
*/
|
|
164
|
+
w: function() {
|
|
165
|
+
const s = this.arguments2String(arguments);
|
|
166
|
+
this._exec('warn', s);
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 打印错误日志
|
|
171
|
+
*/
|
|
172
|
+
e: function() {
|
|
173
|
+
const s = this.arguments2String(arguments);
|
|
174
|
+
this._exec('error', s);
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export default Log;
|
package/utils/time.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// user system clock may be inaccurate, so we need to adjust the timestamp
|
|
2
|
+
// based on the baseTime received from login server
|
|
3
|
+
|
|
4
|
+
let _offset = 0;
|
|
5
|
+
|
|
6
|
+
export const getTimestamp = function() {
|
|
7
|
+
return new Date().getTime() + _offset;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getDate = function() {
|
|
11
|
+
const now = new Date();
|
|
12
|
+
now.setTime(getTimestamp());
|
|
13
|
+
return now;
|
|
14
|
+
};
|
|
15
|
+
|