@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 CHANGED
@@ -1,9 +1,6 @@
1
1
  ## 介绍
2
2
 
3
- 智能客服用户端 Web UIKit。使用此 UIKit,您可以在一天内将智能客服的能力集成到您的 Web 或 Hybrid 项目。极简接入,用 AI 为您的产品降本增效。其流程如下图所示:
4
-
5
- ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100027960326/7de563a1f4cf11efa8355254001c06ec.png)
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: '970px', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
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: '970px', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
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: '970px', margin: '10px auto', boxShadow: '0 11px 20px #ccc' }"
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. 安装支持 composition-api 以及 script setup 的相关依赖,以及 vue2.6 相关依赖。
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
- 3. 在 `vue.config.js `中增加,若没有该文件请新建。
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
- 4. 在 `src/ai-desk-customer-vue/adapter-vue.ts` 文件最后, 替换导出源:
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
- console.log("ai-desk-customer login success");
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: { conversationID: conversationID },
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, onBeforeUnmount, onMounted } = vue;
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
- content.value = props?.payload?.chunks?.join('') ?? '';
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: 16px;
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
- 100% {
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-montainer',messageItem.flow === 'in'?'file-in' :'']"
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,isWeChat } from '../../../../utils/env';
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 || props.messageItem.flow === 'out') {
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-in{
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.2.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, TUILogin } from '@tencentcloud/tui-core';
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
- console.log("login success");
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
- console.log(error);
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({src: '7', customerServicePlugin: 0}),
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
+ }
@@ -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
+ }
@@ -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
+