joytalk 0.0.21 → 0.0.23
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 +236 -287
- package/dist/apis/request.d.ts +1 -1
- package/dist/index.cjs.js +6 -6
- package/dist/index.es.js +375 -360
- package/dist/index.umd.js +6 -6
- package/dist/lib/index.d.ts +2 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/request.d.ts +0 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ pnpm add joytalk
|
|
|
29
29
|
## API 方法
|
|
30
30
|
|
|
31
31
|
### 初始化
|
|
32
|
+
|
|
32
33
|
初始化 SDK,传入 token 等配置。**使用前必须调用一次。**
|
|
33
34
|
|
|
34
35
|
**参数说明:**
|
|
@@ -39,8 +40,10 @@ pnpm add joytalk
|
|
|
39
40
|
| `reconnectInterval` | 重连间隔(毫秒) | 否 | 3000 |
|
|
40
41
|
| `maxReconnectAttempts` | 最大重连次数 | 否 | 5 |
|
|
41
42
|
| `responseTimeout` | 响应消息超时时间(毫秒) | 否 | 10000 |
|
|
43
|
+
| `env` | 环境(development, prodtest, production) | 否 | production |
|
|
42
44
|
|
|
43
45
|
**示例:**
|
|
46
|
+
|
|
44
47
|
```typescript
|
|
45
48
|
import JoyTalk, { EventType, ChatType, MessageCode } from 'joytalk';
|
|
46
49
|
|
|
@@ -48,16 +51,19 @@ import JoyTalk, { EventType, ChatType, MessageCode } from 'joytalk';
|
|
|
48
51
|
const JTalk = new JoyTalk();
|
|
49
52
|
|
|
50
53
|
// 初始化:传入 token 等配置(必须在使用前调用)
|
|
51
|
-
|
|
54
|
+
JTalk.init({
|
|
52
55
|
token: 'your-token',
|
|
53
56
|
});
|
|
54
57
|
```
|
|
55
58
|
|
|
59
|
+
---
|
|
60
|
+
|
|
56
61
|
### 获取咨询列表
|
|
57
|
-
通过 `getConsultationList` 方法,传入入口ID,获取咨询列表。
|
|
58
62
|
|
|
63
|
+
通过 `getConsultationList` 方法,传入入口 ID,获取咨询列表。
|
|
59
64
|
|
|
60
65
|
**示例:**
|
|
66
|
+
|
|
61
67
|
```typescript
|
|
62
68
|
const entranceId = '123456';
|
|
63
69
|
// 获取咨询列表
|
|
@@ -79,20 +85,22 @@ console.log(result);
|
|
|
79
85
|
|
|
80
86
|
**ConsultationItem 类型定义:**
|
|
81
87
|
|
|
82
|
-
| 参数
|
|
83
|
-
|
|
84
|
-
| `id`
|
|
85
|
-
| `customerGroupId` | 客服组 ID
|
|
86
|
-
| `guideText`
|
|
87
|
-
| `name`
|
|
88
|
-
| `isDefault`
|
|
88
|
+
| 参数 | 说明 |
|
|
89
|
+
| ----------------- | ------------ |
|
|
90
|
+
| `id` | 咨询类型 ID |
|
|
91
|
+
| `customerGroupId` | 客服组 ID |
|
|
92
|
+
| `guideText` | 引导文案 |
|
|
93
|
+
| `name` | 咨询类型名称 |
|
|
94
|
+
| `isDefault` | 是否默认 |
|
|
89
95
|
|
|
90
96
|
---
|
|
91
97
|
|
|
92
98
|
### 获取用户信息
|
|
99
|
+
|
|
93
100
|
通过 `getUserInfo` 方法,获取用户信息。
|
|
94
101
|
|
|
95
102
|
**示例:**
|
|
103
|
+
|
|
96
104
|
```typescript
|
|
97
105
|
// 获取用户信息
|
|
98
106
|
const userInfo = await JTalk.getUserInfo();
|
|
@@ -102,21 +110,23 @@ console.log(userInfo);
|
|
|
102
110
|
**返回值说明:**
|
|
103
111
|
| 参数 | 说明 |
|
|
104
112
|
|------|------|
|
|
105
|
-
| `uuid` | 用户ID |
|
|
106
|
-
| `merchantId` | 商户ID |
|
|
113
|
+
| `uuid` | 用户 ID |
|
|
114
|
+
| `merchantId` | 商户 ID |
|
|
107
115
|
| `nickname` | 用户昵称 |
|
|
108
116
|
| `avatar` | 用户头像 |
|
|
109
117
|
| `userSource` | 用户来源 |
|
|
110
|
-
| `externalUserId` | 外部用户ID |
|
|
111
|
-
| `userIp` | 用户IP |
|
|
118
|
+
| `externalUserId` | 外部用户 ID |
|
|
119
|
+
| `userIp` | 用户 IP |
|
|
112
120
|
| `isAnonymous` | 是否匿名 |
|
|
113
121
|
|
|
114
122
|
---
|
|
115
123
|
|
|
116
124
|
### 连接到服务器
|
|
125
|
+
|
|
117
126
|
通过 `connect` 方法,连接到服务器。
|
|
118
127
|
|
|
119
128
|
**示例:**
|
|
129
|
+
|
|
120
130
|
```typescript
|
|
121
131
|
const consultationTypeId = '123456';
|
|
122
132
|
// 连接到服务器
|
|
@@ -130,10 +140,12 @@ JTalk.connect(consultationTypeId);
|
|
|
130
140
|
|
|
131
141
|
---
|
|
132
142
|
|
|
133
|
-
###
|
|
143
|
+
### 监听WebSocket事件
|
|
144
|
+
|
|
134
145
|
通过 `on` 方法,监听消息事件。
|
|
135
146
|
|
|
136
147
|
**示例:**
|
|
148
|
+
|
|
137
149
|
```typescript
|
|
138
150
|
// 监听连接事件
|
|
139
151
|
JTalk.on(EventType.CONNECTED, () => {
|
|
@@ -143,7 +155,7 @@ JTalk.on(EventType.CONNECTED, () => {
|
|
|
143
155
|
// 监听消息事件
|
|
144
156
|
JTalk.on(EventType.MESSAGE, (message) => {
|
|
145
157
|
console.log('收到消息:', message);
|
|
146
|
-
|
|
158
|
+
|
|
147
159
|
// 根据消息类型处理
|
|
148
160
|
switch (message.code) {
|
|
149
161
|
case MessageCode.SEND_SUCCESS:
|
|
@@ -166,6 +178,16 @@ JTalk.on(EventType.STATUS_CHANGE, (status) => {
|
|
|
166
178
|
console.log('连接状态变化:', status);
|
|
167
179
|
});
|
|
168
180
|
|
|
181
|
+
// 监听心跳超时事件
|
|
182
|
+
JTalk.on(EventType.HEARTBEAT_TIMEOUT, () => {
|
|
183
|
+
console.log('心跳超时');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// 监听连接断开事件
|
|
187
|
+
JTalk.on(EventType.DISCONNECTED, () => {
|
|
188
|
+
console.log('连接断开');
|
|
189
|
+
});
|
|
190
|
+
|
|
169
191
|
```
|
|
170
192
|
|
|
171
193
|
**参数说明:**
|
|
@@ -175,6 +197,7 @@ JTalk.on(EventType.STATUS_CHANGE, (status) => {
|
|
|
175
197
|
| `callback` | 回调函数 | 是 | - |
|
|
176
198
|
|
|
177
199
|
**EventType 枚举:**
|
|
200
|
+
|
|
178
201
|
- `EventType.CONNECTED` - 连接成功
|
|
179
202
|
- `EventType.DISCONNECTED` - 连接断开
|
|
180
203
|
- `EventType.ERROR` - 发生错误
|
|
@@ -182,27 +205,123 @@ JTalk.on(EventType.STATUS_CHANGE, (status) => {
|
|
|
182
205
|
- `EventType.STATUS_CHANGE` - 连接状态变化
|
|
183
206
|
- `EventType.HEARTBEAT_TIMEOUT` - 心跳超时
|
|
184
207
|
|
|
208
|
+
---
|
|
209
|
+
### 消息处理示例
|
|
210
|
+
|
|
211
|
+
通过监听 `EventType.MESSAGE`,根据 `message.code` 区分消息类型并处理。
|
|
212
|
+
|
|
213
|
+
**示例:**
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
JTalk.on(EventType.MESSAGE, (message) => {
|
|
217
|
+
const msgData = message.data
|
|
218
|
+
// 根据消息类型处理
|
|
219
|
+
switch (message.code) {
|
|
220
|
+
case MessageCode.MATCH_INFO:
|
|
221
|
+
case MessageCode.MATCH_SUCCESS:
|
|
222
|
+
case MessageCode.TRANSFER_USER_SUCCESS:
|
|
223
|
+
case MessageCode.REMATCH:
|
|
224
|
+
// 匹配成功/分配成功/转接成功/重新匹配,msgData 为 SessionData 类型
|
|
225
|
+
sessionData.value = msgData
|
|
226
|
+
if (message.code === MessageCode.MATCH_INFO || message.code === MessageCode.MATCH_SUCCESS) {
|
|
227
|
+
// 匹配成功/分配成功,获取聊天记录
|
|
228
|
+
getHistoryMessages()
|
|
229
|
+
}
|
|
230
|
+
break
|
|
231
|
+
case MessageCode.MATCH_FAIL:
|
|
232
|
+
console.error(message.msg || '匹配失败')
|
|
233
|
+
break
|
|
234
|
+
case MessageCode.SEND_SUCCESS:
|
|
235
|
+
case MessageCode.REPLY_SUCCESS:
|
|
236
|
+
// 发送成功/回复成功,msgData 为 MessageData 类型
|
|
237
|
+
console.log('收到回复消息', msgData)
|
|
238
|
+
break
|
|
239
|
+
case MessageCode.RETRACT:
|
|
240
|
+
// 撤回消息,msgData 为 MessageData 类型
|
|
241
|
+
console.log('收到撤回消息', msgData)
|
|
242
|
+
console.log('撤回消息的 messageId', messageId)
|
|
243
|
+
break
|
|
244
|
+
case MessageCode.EDIT:
|
|
245
|
+
// 编辑消息,msgData 为 MessageData 类型
|
|
246
|
+
console.log('收到编辑消息', msgData)
|
|
247
|
+
console.log('编辑消息的 messageId', messageId)
|
|
248
|
+
console.log('编辑后消息的内容', msgData.content)
|
|
249
|
+
break
|
|
250
|
+
default:
|
|
251
|
+
console.log('收到其他消息', msgData)
|
|
252
|
+
break
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
185
257
|
**MessageCode 枚举:**
|
|
258
|
+
|
|
186
259
|
- `MessageCode.CONNECT_SUCCESS` - 连接成功
|
|
187
260
|
- `MessageCode.CONNECT_FAILED` - 连接失败
|
|
188
|
-
- `MessageCode.
|
|
261
|
+
- `MessageCode.TRANSFER_CUSTOMER_SUCCESS` - 转接成功通知原客服
|
|
262
|
+
- `MessageCode.TRANSFER_TO_CUSTOMER_SUCCESS` - 转接成功通知转接客服
|
|
263
|
+
- `MessageCode.TRANSFER_USER_SUCCESS` - 转接成功通知用户
|
|
264
|
+
- `MessageCode.TRANSFER_FAIL` - 转接失败
|
|
189
265
|
- `MessageCode.MATCH_FAIL` - 匹配失败
|
|
190
|
-
- `MessageCode.
|
|
191
|
-
- `MessageCode.
|
|
266
|
+
- `MessageCode.MATCH_INFO` - 匹配成功,返回信息
|
|
267
|
+
- `MessageCode.MATCH_SUCCESS` - 分配成功
|
|
192
268
|
- `MessageCode.RETRACT` - 撤回
|
|
269
|
+
- `MessageCode.RETRACT_FAIL` - 撤回失败
|
|
193
270
|
- `MessageCode.EDIT` - 编辑
|
|
194
|
-
- `MessageCode.
|
|
271
|
+
- `MessageCode.EDIT_FAIL` - 编辑失败
|
|
195
272
|
- `MessageCode.COMMON_FAIL` - 通用错误
|
|
273
|
+
- `MessageCode.SEND_SUCCESS` - 发送成功
|
|
274
|
+
- `MessageCode.SEND_CALLBACK` - 发送回调
|
|
275
|
+
- `MessageCode.CHANGE_CHAT_STATUS` - 变更会话状态
|
|
276
|
+
- `MessageCode.REPLY_FAIL` - 回复消息失败
|
|
277
|
+
- `MessageCode.REPLY_SUCCESS` - 回复消息成功
|
|
278
|
+
- `MessageCode.UNBIND_SUCCESS` - 解绑成功
|
|
279
|
+
- `MessageCode.REMATCH` - 重新匹配
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### 获取聊天记录
|
|
285
|
+
|
|
286
|
+
通过 `getHistoryMessages` 方法,获取聊天记录。
|
|
287
|
+
**注意:该方法需在已匹配客服后调用。**
|
|
288
|
+
|
|
289
|
+
**示例:**
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
const getHistoryMessages = async (lastMsgId?: string) => {
|
|
293
|
+
const { list, hasMore } = await JTalk.getHistoryMessages({ lastMsgId, size: 50 });
|
|
294
|
+
console.log(list, hasMore);
|
|
295
|
+
return { list, hasMore };
|
|
296
|
+
};
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**参数说明:**
|
|
300
|
+
|
|
301
|
+
| 参数 | 说明 | 是否必填 | 默认值 |
|
|
302
|
+
| ----------- | --------------------- | -------- | ------ |
|
|
303
|
+
| `lastMsgId` | 上一页最后一条消息 ID | 否 | - |
|
|
304
|
+
| `size` | 每页条数 | 否 | 50 |
|
|
305
|
+
|
|
306
|
+
**返回值说明:**
|
|
307
|
+
|
|
308
|
+
| 返回值 | 说明 |
|
|
309
|
+
| --------- | -------------- |
|
|
310
|
+
| `list` | 消息列表 |
|
|
311
|
+
| `hasMore` | 是否有更多数据 |
|
|
196
312
|
|
|
197
313
|
---
|
|
198
314
|
|
|
199
315
|
### 发送文本消息
|
|
316
|
+
|
|
200
317
|
通过 `sendText` 方法,发送文本消息。
|
|
201
318
|
|
|
202
319
|
**示例:**
|
|
320
|
+
|
|
203
321
|
```typescript
|
|
204
|
-
const content = '
|
|
205
|
-
JTalk.sendText(content);
|
|
322
|
+
const content = '你好!';
|
|
323
|
+
const { messageId } = await JTalk.sendText(content);
|
|
324
|
+
console.log(messageId);
|
|
206
325
|
```
|
|
207
326
|
|
|
208
327
|
**参数说明:**
|
|
@@ -210,77 +329,101 @@ JTalk.sendText(content);
|
|
|
210
329
|
|------|------|----------|--------|
|
|
211
330
|
| `content` | 消息内容 | 是 | - |
|
|
212
331
|
|
|
213
|
-
|
|
214
|
-
|
|
332
|
+
**返回值说明:**
|
|
333
|
+
|
|
334
|
+
| 返回值 | 说明 |
|
|
335
|
+
| ----------- | ------- |
|
|
336
|
+
| `messageId` | 消息 ID |
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### 发送文件消息(图片 / 视频 / 文件)
|
|
341
|
+
|
|
342
|
+
通过 `sendFile` 方法,发送图片、视频或普通文件消息。
|
|
215
343
|
|
|
216
344
|
**示例:**
|
|
345
|
+
|
|
217
346
|
```typescript
|
|
218
347
|
// 发送图片
|
|
219
348
|
const file = document.querySelector('input[type="file"]').files?.[0];
|
|
220
349
|
if (file) {
|
|
221
|
-
await JTalk.sendFile({ file, chatType: ChatType.IMAGE });
|
|
350
|
+
const { messageId } = await JTalk.sendFile({ file, chatType: ChatType.IMAGE });
|
|
351
|
+
console.log(messageId);
|
|
222
352
|
}
|
|
223
|
-
// 发送文件
|
|
224
|
-
await JTalk.sendFile({ file: docFile, chatType: ChatType.FILE });
|
|
225
|
-
```
|
|
226
353
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
| 参数 | 说明 | 是否必填 | 默认值 |
|
|
230
|
-
|------|------|----------|--------|
|
|
231
|
-
| `file` | 文件对象 | 是 | - |
|
|
232
|
-
| `chatType` | 聊天类型:`ChatType.IMAGE` 或 `ChatType.FILE` | 是 | - |
|
|
233
|
-
|
|
234
|
-
### 发送视频消息
|
|
235
|
-
通过 `sendFile` 方法并传入 `ChatType.VIDEO`,发送视频消息。建议先用 `getVideoThumbnail` 生成缩略图再发送。
|
|
236
|
-
|
|
237
|
-
**示例:**
|
|
238
|
-
```typescript
|
|
354
|
+
// 发送视频
|
|
239
355
|
const videoFile = document.querySelector('input[type="file"]').files?.[0];
|
|
240
356
|
if (videoFile) {
|
|
357
|
+
// 获取视频缩略图
|
|
241
358
|
const thumbnailFile = await JTalk.getVideoThumbnail(videoFile);
|
|
242
|
-
await JTalk.sendFile({
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
359
|
+
const { messageId } = await JTalk.sendFile({ file: videoFile, thumbnailFile, chatType: ChatType.VIDEO });
|
|
360
|
+
console.log(messageId);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// 发送文件
|
|
364
|
+
const file = document.querySelector('input[type="file"]').files?.[0];
|
|
365
|
+
if (file) {
|
|
366
|
+
const { messageId } = await JTalk.sendFile({ file, chatType: ChatType.FILE });
|
|
367
|
+
console.log(messageId);
|
|
247
368
|
}
|
|
248
369
|
```
|
|
249
370
|
|
|
250
371
|
**参数说明:**
|
|
251
372
|
|
|
252
|
-
| 参数
|
|
253
|
-
|
|
254
|
-
| `file`
|
|
255
|
-
| `thumbnailFile` | 缩略图文件(可选,建议使用 getVideoThumbnail 生成)
|
|
256
|
-
| `chatType`
|
|
373
|
+
| 参数 | 说明 | 是否必填 | 默认值 |
|
|
374
|
+
| --------------- | ----------------------------------------------------------------- | -------- | ------ |
|
|
375
|
+
| `file` | 文件对象 | 是 | - |
|
|
376
|
+
| `thumbnailFile` | 缩略图文件(可选,建议使用 getVideoThumbnail 生成) | 否 | - |
|
|
377
|
+
| `chatType` | 聊天类型:`ChatType.IMAGE` 或 `ChatType.VIDEO` 或 `ChatType.FILE` | 是 | - |
|
|
257
378
|
|
|
258
|
-
|
|
259
|
-
|
|
379
|
+
**返回值说明:**
|
|
380
|
+
|
|
381
|
+
| 返回值 | 说明 |
|
|
382
|
+
| ----------- | ------- |
|
|
383
|
+
| `messageId` | 消息 ID |
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
### 发送 FAQ 消息
|
|
388
|
+
|
|
389
|
+
点击 FAQ 问题时,通过 `sendFaq` 方法,将该 FAQ 问题对象作为参数传入,SDK 会自动返回该 FAQ 问题的答案。
|
|
260
390
|
|
|
261
391
|
**示例:**
|
|
392
|
+
|
|
262
393
|
```typescript
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
394
|
+
const faqItem = {
|
|
395
|
+
faqId: 1,
|
|
396
|
+
faqItemId: 1,
|
|
397
|
+
id: 1,
|
|
398
|
+
imageUrl: ['https://example.com/image.jpg'],
|
|
399
|
+
question: '问题',
|
|
400
|
+
answer: '答案',
|
|
401
|
+
sortOrder: 1,
|
|
402
|
+
isMulti: false,
|
|
403
|
+
item: [],
|
|
404
|
+
};
|
|
405
|
+
await JTalk.sendFaq(faqItem);
|
|
269
406
|
```
|
|
270
407
|
|
|
271
408
|
**参数说明:**
|
|
272
409
|
|
|
273
|
-
| 参数
|
|
274
|
-
|
|
275
|
-
| `
|
|
276
|
-
| `size` | 每页条数 | 否 | 50 |
|
|
410
|
+
| 参数 | 说明 | 是否必填 | 默认值 |
|
|
411
|
+
| --------- | ------------ | -------- | ------ |
|
|
412
|
+
| `faqItem` | FAQ 问题对象 | 是 | - |
|
|
277
413
|
|
|
278
|
-
|
|
414
|
+
**FaqItem 类型定义:**
|
|
279
415
|
|
|
280
|
-
|
|
|
281
|
-
|
|
282
|
-
| `
|
|
283
|
-
| `
|
|
416
|
+
| 参数 | 说明 |
|
|
417
|
+
| ----------- | ------------- |
|
|
418
|
+
| `faqId` | FAQ ID |
|
|
419
|
+
| `faqItemId` | FAQ 项 ID |
|
|
420
|
+
| `id` | ID |
|
|
421
|
+
| `imageUrl` | 图片 URL 列表 |
|
|
422
|
+
| `question` | 问题 |
|
|
423
|
+
| `answer` | 答案 |
|
|
424
|
+
| `sortOrder` | 排序 |
|
|
425
|
+
| `isMulti` | 是否多选 |
|
|
426
|
+
| `item` | 子项 |
|
|
284
427
|
|
|
285
428
|
---
|
|
286
429
|
|
|
@@ -290,7 +433,6 @@ const next = await JTalk.getHistoryMessages({
|
|
|
290
433
|
- **`getStatus(): ConnectionStatus`** — 获取当前连接状态。
|
|
291
434
|
- **`isConnected(): boolean`** — 是否已连接。
|
|
292
435
|
- **`getVideoThumbnail(videoFile: File): Promise<File>`** — 获取视频首帧缩略图,发送视频时建议使用。
|
|
293
|
-
- **`sendFaq(faqItem: FaqItem): void`** — 发送 FAQ 消息。
|
|
294
436
|
- **`off(event, callback): void`** — 取消监听事件,需传入与 `on` 时相同的回调引用。
|
|
295
437
|
- **公共属性:** `OBS_URL`(OBS 存储地址)、`userInfo`(当前用户信息,只读)。
|
|
296
438
|
|
|
@@ -366,252 +508,59 @@ const handleFileChange = async (e: Event) => {
|
|
|
366
508
|
</html>
|
|
367
509
|
```
|
|
368
510
|
|
|
369
|
-
#### 完整示例
|
|
370
|
-
|
|
371
|
-
```html
|
|
372
|
-
<!DOCTYPE html>
|
|
373
|
-
<html lang="zh-CN">
|
|
374
|
-
<head>
|
|
375
|
-
<meta charset="UTF-8">
|
|
376
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
377
|
-
<title>客服 SDK 示例</title>
|
|
378
|
-
<!-- 引入 SDK -->
|
|
379
|
-
<script src="https://your-cdn.com/joytalk/dist/index.umd.js"></script>
|
|
380
|
-
</head>
|
|
381
|
-
<body>
|
|
382
|
-
<div id="app">
|
|
383
|
-
<button id="connectBtn">连接</button>
|
|
384
|
-
<button id="sendBtn">发送消息</button>
|
|
385
|
-
<input type="file" id="fileInput" accept="image/*,video/*" />
|
|
386
|
-
</div>
|
|
387
|
-
|
|
388
|
-
<script>
|
|
389
|
-
(async function () {
|
|
390
|
-
const JoyTalk = window.JoyTalk.default;
|
|
391
|
-
const { EventType, ChatType, MessageCode, ConnectionStatus, MessageType } = window.JoyTalk;
|
|
392
|
-
|
|
393
|
-
const sdk = new JoyTalk();
|
|
394
|
-
|
|
395
|
-
await sdk.init({
|
|
396
|
-
token: 'your-token',
|
|
397
|
-
autoReconnect: true,
|
|
398
|
-
reconnectInterval: 3000,
|
|
399
|
-
maxReconnectAttempts: 5,
|
|
400
|
-
responseTimeout: 10000,
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
sdk.on(EventType.CONNECTED, () => {
|
|
404
|
-
console.log('已连接到服务器');
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
// 监听消息事件
|
|
408
|
-
sdk.on(EventType.MESSAGE, (message) => {
|
|
409
|
-
console.log('收到消息:', message);
|
|
410
|
-
|
|
411
|
-
// 根据消息类型处理
|
|
412
|
-
switch (message.code) {
|
|
413
|
-
case MessageCode.SEND_SUCCESS:
|
|
414
|
-
console.log('消息发送成功:', message.data);
|
|
415
|
-
break;
|
|
416
|
-
case MessageCode.MATCH_SUCCESS:
|
|
417
|
-
console.log('匹配成功:', message.data);
|
|
418
|
-
break;
|
|
419
|
-
// ... 其他消息类型
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// 监听错误事件
|
|
424
|
-
sdk.on(EventType.ERROR, (error) => {
|
|
425
|
-
console.error('发生错误:', error);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
// 监听状态变化
|
|
429
|
-
sdk.on(EventType.STATUS_CHANGE, (status) => {
|
|
430
|
-
console.log('连接状态变化:', status);
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
// 连接按钮
|
|
434
|
-
document.getElementById('connectBtn').addEventListener('click', async () => {
|
|
435
|
-
try {
|
|
436
|
-
await sdk.connect('customer-group-id');
|
|
437
|
-
console.log('连接成功');
|
|
438
|
-
} catch (error) {
|
|
439
|
-
console.error('连接失败:', error);
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
// 发送消息按钮
|
|
444
|
-
document.getElementById('sendBtn').addEventListener('click', async () => {
|
|
445
|
-
try {
|
|
446
|
-
await sdk.sendText('你好,我需要帮助');
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.error('发送失败:', error);
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
// 文件上传
|
|
453
|
-
document.getElementById('fileInput').addEventListener('change', async (e) => {
|
|
454
|
-
const file = e.target.files[0];
|
|
455
|
-
if (!file) return;
|
|
456
|
-
|
|
457
|
-
try {
|
|
458
|
-
if (file.type.startsWith('image/')) {
|
|
459
|
-
// 发送图片
|
|
460
|
-
await sdk.sendFile({
|
|
461
|
-
file: file,
|
|
462
|
-
chatType: ChatType.IMAGE,
|
|
463
|
-
});
|
|
464
|
-
} else if (file.type.startsWith('video/')) {
|
|
465
|
-
// 发送视频(自动生成缩略图)
|
|
466
|
-
const thumbnailFile = await sdk.getVideoThumbnail(file);
|
|
467
|
-
await sdk.sendFile({
|
|
468
|
-
file: file,
|
|
469
|
-
thumbnailFile: thumbnailFile,
|
|
470
|
-
chatType: ChatType.VIDEO,
|
|
471
|
-
});
|
|
472
|
-
} else {
|
|
473
|
-
// 发送文件
|
|
474
|
-
await sdk.sendFile({
|
|
475
|
-
file: file,
|
|
476
|
-
chatType: ChatType.FILE,
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
console.log('文件发送成功');
|
|
480
|
-
} catch (error) {
|
|
481
|
-
console.error('文件发送失败:', error);
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
// 获取用户信息示例
|
|
486
|
-
async function loadUserInfo() {
|
|
487
|
-
try {
|
|
488
|
-
const userInfo = await sdk.getUserInfo();
|
|
489
|
-
console.log('用户信息:', userInfo);
|
|
490
|
-
// 可以在页面上显示用户信息
|
|
491
|
-
// document.getElementById('userName').textContent = userInfo.nickname;
|
|
492
|
-
} catch (error) {
|
|
493
|
-
console.error('获取用户信息失败:', error);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// 获取咨询列表示例
|
|
498
|
-
async function loadConsultationList(entranceId) {
|
|
499
|
-
try {
|
|
500
|
-
const result = await sdk.getConsultationList(entranceId);
|
|
501
|
-
console.log('咨询列表:', result.data.list);
|
|
502
|
-
// 可以在页面上显示咨询列表
|
|
503
|
-
} catch (error) {
|
|
504
|
-
console.error('获取咨询列表失败:', error);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// 页面加载完成后可以调用
|
|
509
|
-
// loadUserInfo();
|
|
510
|
-
// loadConsultationList(123);
|
|
511
|
-
})();
|
|
512
|
-
</script>
|
|
513
|
-
</body>
|
|
514
|
-
</html>
|
|
515
|
-
```
|
|
516
|
-
|
|
517
511
|
**CDN 地址说明:**
|
|
512
|
+
|
|
518
513
|
- 将 `https://your-cdn.com/joytalk/dist/index.umd.js` 替换为实际的 CDN 地址
|
|
519
514
|
- 如果使用本地构建文件,可以使用相对路径:`<script src="./dist/index.umd.js"></script>`
|
|
520
515
|
- 建议使用版本号锁定,如:`https://cdn.example.com/joytalk@0.0.1/dist/index.umd.js`
|
|
521
516
|
|
|
522
517
|
**注意事项:**
|
|
518
|
+
|
|
523
519
|
- CDN 引入后,SDK 会挂载到 `window.JoyTalk` 全局对象上
|
|
524
520
|
- 默认导出(`default`)是 `JoyTalk` 类,通过 `window.JoyTalk.default` 访问
|
|
525
521
|
- 所有枚举和类型都可以从 `window.JoyTalk` 中获取,如 `EventType`、`ChatType`、`MessageCode`、`ConnectionStatus`、`MessageType` 等
|
|
526
522
|
- 确保 CDN 地址可访问,并且版本正确
|
|
527
523
|
- 如果页面中已经使用了模块化构建工具(如 Webpack、Vite),建议使用 NPM 安装方式而不是 CDN
|
|
528
524
|
|
|
529
|
-
### 配置选项(SDKConfig)
|
|
530
525
|
|
|
531
|
-
初始化时通过 `init(config)` 传入的配置项。参数说明见上方「初始化」表格。
|
|
532
526
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
## 类型定义
|
|
530
|
+
|
|
531
|
+
SDK 提供完整的 TypeScript 类型定义,可从 `joytalk` 按需导入。
|
|
532
|
+
|
|
533
|
+
| 类型名 | 说明 |
|
|
534
|
+
| ----------------------- | -------------------- |
|
|
535
|
+
| `MessageData` | 消息数据(联合类型) |
|
|
536
|
+
| `TextMessageData` | 文本消息数据 |
|
|
537
|
+
| `FileMessageData` | 文件消息数据 |
|
|
538
|
+
| `FaqMessageData` | FAQ 消息数据 |
|
|
539
|
+
| `SessionData` | 会话数据 |
|
|
540
|
+
| `UserInfo` | 用户信息 |
|
|
541
|
+
| `ChatType` | 聊天类型枚举 |
|
|
542
|
+
| `MessageType` | 消息类型枚举 |
|
|
543
|
+
| `EventType` | 事件类型枚举 |
|
|
544
|
+
| `ConnectionStatus` | 连接状态枚举 |
|
|
545
|
+
| `MessageCode` | 消息代码枚举 |
|
|
546
|
+
| `MatchStatus` | 匹配状态枚举 |
|
|
547
|
+
| `HistoryMessagesParams` | 聊天记录查询参数 |
|
|
548
|
+
| `RequestResponse<T>` | 接口响应包装 |
|
|
540
549
|
|
|
541
550
|
**消息类型(ChatType):**
|
|
551
|
+
|
|
542
552
|
- `ChatType.TEXT` - 文本消息
|
|
543
553
|
- `ChatType.IMAGE` - 图片消息
|
|
544
554
|
- `ChatType.VIDEO` - 视频消息
|
|
545
555
|
- `ChatType.FILE` - 文件消息
|
|
546
556
|
- `ChatType.FAQ` - FAQ 消息
|
|
547
557
|
|
|
548
|
-
|
|
549
|
-
- `ConnectionStatus.DISCONNECTED` - 未连接
|
|
550
|
-
- `ConnectionStatus.CONNECTING` - 连接中
|
|
551
|
-
- `ConnectionStatus.CONNECTED` - 已连接
|
|
552
|
-
- `ConnectionStatus.RECONNECTING` - 重连中
|
|
553
|
-
- `ConnectionStatus.ERROR` - 错误
|
|
558
|
+
|
|
554
559
|
|
|
555
560
|
**匹配状态(MatchStatus):**
|
|
561
|
+
|
|
556
562
|
- `MatchStatus.UNMATCHED` - 未匹配
|
|
557
563
|
- `MatchStatus.MATCHING` - 匹配中
|
|
558
564
|
- `MatchStatus.MATCHED` - 已匹配
|
|
559
565
|
- `MatchStatus.UNBIND` - 已解绑
|
|
560
566
|
|
|
561
|
-
**线路测速与 Base URL:** 首次发起 API 请求时,SDK 会调用 `ListLines` 获取线路列表,并对 API 线路请求 `TestLineLatency`、对下载线路请求 `/pub/logo.png`,取最先成功的地址作为后续请求的 baseURL。
|
|
562
|
-
|
|
563
|
-
**环境变量(构建时):** `VITE_BASE_API_URL` 拉取 ListLines 的初始 API 地址(必填);`VITE_OBS_URL` 下载线路测速失败时的下载地址兜底(可选)。
|
|
564
|
-
|
|
565
|
-
## 类型定义
|
|
566
|
-
|
|
567
|
-
SDK 提供完整的 TypeScript 类型定义,可从 `joytalk` 按需导入。
|
|
568
|
-
|
|
569
|
-
| 类型名 | 说明 |
|
|
570
|
-
|--------|------|
|
|
571
|
-
| `MessageData` | 消息数据(联合类型) |
|
|
572
|
-
| `TextMessageData` | 文本消息数据 |
|
|
573
|
-
| `FileMessageData` | 文件消息数据 |
|
|
574
|
-
| `FaqMessageData` | FAQ 消息数据 |
|
|
575
|
-
| `SessionData` | 会话数据 |
|
|
576
|
-
| `UserInfo` | 用户信息 |
|
|
577
|
-
| `ChatType` | 聊天类型枚举 |
|
|
578
|
-
| `MessageType` | 消息类型枚举 |
|
|
579
|
-
| `EventType` | 事件类型枚举 |
|
|
580
|
-
| `ConnectionStatus` | 连接状态枚举 |
|
|
581
|
-
| `MessageCode` | 消息代码枚举 |
|
|
582
|
-
| `MatchStatus` | 匹配状态枚举 |
|
|
583
|
-
| `HistoryMessagesParams` | 聊天记录查询参数 |
|
|
584
|
-
| `RequestResponse<T>` | 接口响应包装 |
|
|
585
|
-
|
|
586
|
-
## 消息处理示例
|
|
587
|
-
|
|
588
|
-
通过监听 `EventType.MESSAGE`,根据 `message.code` 区分消息类型并处理。
|
|
589
|
-
|
|
590
|
-
**示例:**
|
|
591
|
-
```typescript
|
|
592
|
-
import JoyTalk, { EventType, MessageCode, ChatType } from 'joytalk';
|
|
593
|
-
|
|
594
|
-
const JTalk = new JoyTalk();
|
|
595
|
-
await JTalk.init({ token: 'your-token' });
|
|
596
|
-
|
|
597
|
-
JTalk.on(EventType.MESSAGE, (message) => {
|
|
598
|
-
switch (message.code) {
|
|
599
|
-
case MessageCode.SEND_SUCCESS:
|
|
600
|
-
const messageData = message.data;
|
|
601
|
-
if (messageData.contentType === ChatType.TEXT) {
|
|
602
|
-
console.log('文本消息:', messageData.content);
|
|
603
|
-
} else if (messageData.contentType === ChatType.IMAGE) {
|
|
604
|
-
console.log('图片消息:', messageData.content.fileUrl);
|
|
605
|
-
}
|
|
606
|
-
break;
|
|
607
|
-
case MessageCode.MATCH_SUCCESS:
|
|
608
|
-
const sessionData = message.data;
|
|
609
|
-
console.log('会话ID:', sessionData.sessionId);
|
|
610
|
-
break;
|
|
611
|
-
case MessageCode.CONNECT_SUCCESS:
|
|
612
|
-
console.log('连接成功');
|
|
613
|
-
break;
|
|
614
|
-
// ... 其他消息类型
|
|
615
|
-
}
|
|
616
|
-
});
|
|
617
|
-
```
|