@warriorteam/redai-zalo-sdk 1.18.0 → 1.20.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/CHANGELOG.md +156 -0
- package/README.md +33 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/services/broadcast.service.d.ts +90 -0
- package/dist/services/broadcast.service.d.ts.map +1 -0
- package/dist/services/broadcast.service.js +211 -0
- package/dist/services/broadcast.service.js.map +1 -0
- package/dist/services/group-message.service.d.ts +200 -0
- package/dist/services/group-message.service.d.ts.map +1 -1
- package/dist/services/group-message.service.js +331 -0
- package/dist/services/group-message.service.js.map +1 -1
- package/dist/types/broadcast.d.ts +244 -0
- package/dist/types/broadcast.d.ts.map +1 -0
- package/dist/types/broadcast.js +114 -0
- package/dist/types/broadcast.js.map +1 -0
- package/dist/zalo-sdk.d.ts +2 -0
- package/dist/zalo-sdk.d.ts.map +1 -1
- package/dist/zalo-sdk.js +2 -0
- package/dist/zalo-sdk.js.map +1 -1
- package/docs/API_REFERENCE.md +53 -0
- package/docs/BROADCAST_SERVICE.md +276 -0
- package/docs/group-message-list-api.md +332 -0
- package/examples/broadcast-example.ts +144 -0
- package/examples/group-message-list.ts +288 -0
- package/package.json +11 -3
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# RedAI Zalo SDK - Broadcast Service Guide
|
|
2
|
+
|
|
3
|
+
## Tổng quan
|
|
4
|
+
|
|
5
|
+
BroadcastService cho phép gửi tin truyền thông broadcast đến nhiều người dùng cùng lúc dựa trên các tiêu chí targeting như tuổi, giới tính, địa điểm, và platform.
|
|
6
|
+
|
|
7
|
+
## API Endpoint
|
|
8
|
+
|
|
9
|
+
- **URL**: `https://openapi.zalo.me/v2.0/oa/message`
|
|
10
|
+
- **Method**: POST
|
|
11
|
+
- **Content-Type**: application/json
|
|
12
|
+
- **Header**: `access_token: <your_access_token>`
|
|
13
|
+
|
|
14
|
+
## Khởi tạo Service
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";
|
|
18
|
+
|
|
19
|
+
const zalo = new ZaloSDK({
|
|
20
|
+
appId: "your-app-id",
|
|
21
|
+
appSecret: "your-app-secret"
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Access broadcast service
|
|
25
|
+
const broadcastService = zalo.broadcast;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Các Phương Thức Chính
|
|
29
|
+
|
|
30
|
+
### 1. Gửi Broadcast Message
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Gửi broadcast đến người dùng ở Hồ Chí Minh
|
|
34
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
35
|
+
cities: ["Hồ Chí Minh"]
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
39
|
+
accessToken,
|
|
40
|
+
{ target },
|
|
41
|
+
"article-attachment-id"
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
console.log("Message ID:", result.data.message_id);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Tạo Targeting Criteria
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Targeting phức tạp
|
|
51
|
+
const complexTarget = zalo.broadcast.createBroadcastTarget({
|
|
52
|
+
gender: "FEMALE", // Nữ giới
|
|
53
|
+
ages: ["18-24", "25-34"], // Tuổi 18-34
|
|
54
|
+
cities: ["Hà Nội", "Đà Nẵng"], // Hà Nội và Đà Nẵng
|
|
55
|
+
platform: ["ANDROID", "IOS"] // Android và iOS
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Targeting Criteria
|
|
60
|
+
|
|
61
|
+
### 1. Nhóm Tuổi (Ages)
|
|
62
|
+
|
|
63
|
+
| Nhóm tuổi | Mã | Mô tả |
|
|
64
|
+
|-----------|----|----|
|
|
65
|
+
| `"0-12"` | `"0"` | Tuổi từ 0-12 |
|
|
66
|
+
| `"13-17"` | `"1"` | Tuổi từ 13-17 |
|
|
67
|
+
| `"18-24"` | `"2"` | Tuổi từ 18-24 |
|
|
68
|
+
| `"25-34"` | `"3"` | Tuổi từ 25-34 |
|
|
69
|
+
| `"35-44"` | `"4"` | Tuổi từ 35-44 |
|
|
70
|
+
| `"45-54"` | `"5"` | Tuổi từ 45-54 |
|
|
71
|
+
| `"55-64"` | `"6"` | Tuổi từ 55-64 |
|
|
72
|
+
| `"65+"` | `"7"` | Tuổi từ 65 trở lên |
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
76
|
+
ages: ["18-24", "25-34"] // Targeting 18-34 tuổi
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2. Giới Tính (Gender)
|
|
81
|
+
|
|
82
|
+
| Giới tính | Mã | Mô tả |
|
|
83
|
+
|-----------|----|----|
|
|
84
|
+
| `"ALL"` | `"0"` | Tất cả giới tính |
|
|
85
|
+
| `"MALE"` | `"1"` | Nam |
|
|
86
|
+
| `"FEMALE"` | `"2"` | Nữ |
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
90
|
+
gender: "MALE" // Chỉ targeting nam giới
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Tỉnh Thành (Cities)
|
|
95
|
+
|
|
96
|
+
Hỗ trợ 63 tỉnh thành Việt Nam:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
100
|
+
cities: ["Hồ Chí Minh", "Hà Nội", "Đà Nẵng"]
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Xem tất cả mã tỉnh thành
|
|
104
|
+
const cityCodes = zalo.broadcast.getCityCodes();
|
|
105
|
+
console.log(cityCodes);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 4. Miền (Locations)
|
|
109
|
+
|
|
110
|
+
| Miền | Mã | Mô tả |
|
|
111
|
+
|------|----|----|
|
|
112
|
+
| `"NORTH"` | `"0"` | Miền Bắc |
|
|
113
|
+
| `"CENTRAL"` | `"1"` | Miền Trung |
|
|
114
|
+
| `"SOUTH"` | `"2"` | Miền Nam |
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
118
|
+
locations: ["SOUTH"] // Chỉ miền Nam
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 5. Platform
|
|
123
|
+
|
|
124
|
+
| Platform | Mã | Mô tả |
|
|
125
|
+
|----------|----|----|
|
|
126
|
+
| `"IOS"` | `"1"` | iOS |
|
|
127
|
+
| `"ANDROID"` | `"2"` | Android |
|
|
128
|
+
| `"WINDOWS_PHONE"` | `"3"` | Windows Phone |
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
132
|
+
platforms: ["IOS", "ANDROID"] // iOS và Android
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Ví Dụ Sử Dụng
|
|
137
|
+
|
|
138
|
+
### 1. Broadcast Đơn Giản
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// Gửi đến tất cả người dùng ở Hồ Chí Minh
|
|
142
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
143
|
+
cities: ["Hồ Chí Minh"]
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
147
|
+
accessToken,
|
|
148
|
+
{ target },
|
|
149
|
+
"bd5ea46bb32e5a0033f"
|
|
150
|
+
);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 2. Targeting Theo Nhân Khẩu Học
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// Nữ giới 25-34 tuổi
|
|
157
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
158
|
+
gender: "FEMALE",
|
|
159
|
+
ages: ["25-34"]
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
163
|
+
accessToken,
|
|
164
|
+
{ target },
|
|
165
|
+
"article-id"
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 3. Targeting Phức Tạp
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Nam giới 18-34 tuổi, dùng iOS, ở miền Nam
|
|
173
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
174
|
+
gender: "MALE",
|
|
175
|
+
ages: ["18-24", "25-34"],
|
|
176
|
+
platforms: ["IOS"],
|
|
177
|
+
locations: ["SOUTH"]
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
181
|
+
accessToken,
|
|
182
|
+
{ target },
|
|
183
|
+
"article-id"
|
|
184
|
+
);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Error Handling
|
|
188
|
+
|
|
189
|
+
### Các Lỗi Thường Gặp
|
|
190
|
+
|
|
191
|
+
| Mã lỗi | Mô tả | Giải pháp |
|
|
192
|
+
|--------|-------|-----------|
|
|
193
|
+
| `3001` | Không có quyền broadcast | Liên hệ Zalo để được cấp quyền |
|
|
194
|
+
| `3002` | Article không tồn tại | Kiểm tra attachment_id |
|
|
195
|
+
| `3003` | Targeting không hợp lệ | Kiểm tra các tham số targeting |
|
|
196
|
+
| `3004` | Vượt quota broadcast | Chờ reset quota hoặc nâng cấp |
|
|
197
|
+
| `3005` | Vi phạm chính sách | Kiểm tra nội dung article |
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
try {
|
|
201
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
202
|
+
accessToken,
|
|
203
|
+
{ target },
|
|
204
|
+
articleId
|
|
205
|
+
);
|
|
206
|
+
console.log("Success:", result.data.message_id);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
switch (error.code) {
|
|
209
|
+
case 3001:
|
|
210
|
+
console.error("Không có quyền broadcast");
|
|
211
|
+
break;
|
|
212
|
+
case 3002:
|
|
213
|
+
console.error("Article không tồn tại");
|
|
214
|
+
break;
|
|
215
|
+
default:
|
|
216
|
+
console.error("Lỗi khác:", error.message);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Yêu Cầu và Giới Hạn
|
|
222
|
+
|
|
223
|
+
### 1. Quyền Broadcast
|
|
224
|
+
- OA phải được Zalo cấp quyền gửi broadcast
|
|
225
|
+
- Cần tuân thủ chính sách về spam và nội dung
|
|
226
|
+
|
|
227
|
+
### 2. Article Attachment
|
|
228
|
+
- Chỉ hỗ trợ template type `"media"` với `media_type: "article"`
|
|
229
|
+
- Article phải được tạo trước và có attachment_id hợp lệ
|
|
230
|
+
|
|
231
|
+
### 3. Targeting
|
|
232
|
+
- Phải có ít nhất 1 tiêu chí targeting
|
|
233
|
+
- Có thể kết hợp nhiều tiêu chí cùng lúc
|
|
234
|
+
|
|
235
|
+
### 4. Rate Limiting
|
|
236
|
+
- Tuân thủ giới hạn số lượng broadcast theo gói dịch vụ
|
|
237
|
+
- Tránh gửi quá nhiều broadcast trong thời gian ngắn
|
|
238
|
+
|
|
239
|
+
## Best Practices
|
|
240
|
+
|
|
241
|
+
### 1. Targeting Hiệu Quả
|
|
242
|
+
```typescript
|
|
243
|
+
// Tốt: Targeting cụ thể
|
|
244
|
+
const target = zalo.broadcast.createBroadcastTarget({
|
|
245
|
+
gender: "FEMALE",
|
|
246
|
+
ages: ["25-34"],
|
|
247
|
+
cities: ["Hồ Chí Minh"]
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Tránh: Targeting quá rộng
|
|
251
|
+
const broadTarget = zalo.broadcast.createBroadcastTarget({
|
|
252
|
+
gender: "ALL" // Quá rộng, có thể bị spam
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 2. Nội Dung Chất Lượng
|
|
257
|
+
- Sử dụng article có nội dung hữu ích
|
|
258
|
+
- Tránh nội dung spam hoặc quảng cáo quá mức
|
|
259
|
+
- Tuân thủ chính sách của Zalo
|
|
260
|
+
|
|
261
|
+
### 3. Monitoring và Analytics
|
|
262
|
+
```typescript
|
|
263
|
+
// Lưu message_id để tracking
|
|
264
|
+
const result = await zalo.broadcast.sendBroadcastMessage(
|
|
265
|
+
accessToken,
|
|
266
|
+
{ target },
|
|
267
|
+
articleId
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// Lưu vào database để theo dõi
|
|
271
|
+
await saveBroadcastLog({
|
|
272
|
+
messageId: result.data.message_id,
|
|
273
|
+
targetCriteria: target,
|
|
274
|
+
sentAt: new Date()
|
|
275
|
+
});
|
|
276
|
+
```
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# API Gửi Danh Sách Tin Nhắn Group
|
|
2
|
+
|
|
3
|
+
API mở rộng cho phép gửi danh sách tin nhắn tới groups với callback tracking real-time.
|
|
4
|
+
|
|
5
|
+
## Tính năng
|
|
6
|
+
|
|
7
|
+
- ✅ Gửi danh sách tin nhắn tới 1 group
|
|
8
|
+
- ✅ Gửi danh sách tin nhắn tới nhiều groups cùng lúc
|
|
9
|
+
- ✅ Hỗ trợ đầy đủ 5 loại tin nhắn: text, image, file, sticker, mention
|
|
10
|
+
- ✅ Callback tracking real-time cho từng tin nhắn/group
|
|
11
|
+
- ✅ Delay tùy chỉnh giữa tin nhắn và giữa groups
|
|
12
|
+
- ✅ Thống kê chi tiết thành công/thất bại
|
|
13
|
+
- ✅ Error isolation - lỗi 1 tin nhắn/group không ảnh hưởng phần còn lại
|
|
14
|
+
|
|
15
|
+
## Cách sử dụng
|
|
16
|
+
|
|
17
|
+
### 1. Import các interface và service
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import {
|
|
21
|
+
GroupMessageService,
|
|
22
|
+
GroupMessageItem,
|
|
23
|
+
SendMessageListToGroupRequest,
|
|
24
|
+
SendMessageListToMultipleGroupsRequest
|
|
25
|
+
} from "../src/services/group-message.service";
|
|
26
|
+
import { ZaloClient } from "../src/clients/zalo-client";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Khởi tạo service
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const zaloClient = new ZaloClient();
|
|
33
|
+
const groupMessageService = new GroupMessageService(zaloClient);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. Định nghĩa danh sách tin nhắn
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const messages: GroupMessageItem[] = [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: "📢 Thông báo quan trọng!",
|
|
43
|
+
delay: 2000, // Delay 2 giây sau tin nhắn này
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "image",
|
|
47
|
+
imageUrl: "https://example.com/image.jpg",
|
|
48
|
+
caption: "Hình ảnh minh họa",
|
|
49
|
+
delay: 1500,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
type: "mention",
|
|
53
|
+
text: "@Admin Vui lòng xem thông báo",
|
|
54
|
+
mentions: [
|
|
55
|
+
{ user_id: "ADMIN_ID", offset: 0, length: 6 }
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 4. Gửi tới 1 group
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const result = await groupMessageService.sendMessageListToGroup({
|
|
65
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
66
|
+
groupId: "GROUP_ID",
|
|
67
|
+
messages,
|
|
68
|
+
defaultDelay: 1000,
|
|
69
|
+
onProgress: (progress) => {
|
|
70
|
+
console.log(`${progress.status}: Message ${progress.messageIndex + 1}/${progress.totalMessages}`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
console.log(`Thành công: ${result.successfulMessages}/${result.totalMessages} tin nhắn`);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 5. Gửi tới nhiều groups
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const result = await groupMessageService.sendMessageListToMultipleGroups({
|
|
81
|
+
accessToken: "YOUR_ACCESS_TOKEN",
|
|
82
|
+
groupIds: ["GROUP_1", "GROUP_2", "GROUP_3"],
|
|
83
|
+
messages,
|
|
84
|
+
defaultDelay: 1000,
|
|
85
|
+
delayBetweenGroups: 3000, // Delay 3s giữa các groups
|
|
86
|
+
onProgress: (progress) => {
|
|
87
|
+
console.log(`${progress.status}: Group ${progress.groupIndex + 1}/${progress.totalGroups}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(`Thành công: ${result.successfulGroups}/${result.totalGroups} groups`);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Các loại tin nhắn được hỗ trợ
|
|
95
|
+
|
|
96
|
+
### 1. Text Message
|
|
97
|
+
```typescript
|
|
98
|
+
{
|
|
99
|
+
type: "text",
|
|
100
|
+
text: "Nội dung tin nhắn",
|
|
101
|
+
delay: 1000, // Optional
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. Image Message
|
|
106
|
+
```typescript
|
|
107
|
+
// Sử dụng URL
|
|
108
|
+
{
|
|
109
|
+
type: "image",
|
|
110
|
+
imageUrl: "https://example.com/image.jpg",
|
|
111
|
+
caption: "Caption cho ảnh", // Optional, max 2000 ký tự
|
|
112
|
+
delay: 1500,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Hoặc sử dụng attachment ID
|
|
116
|
+
{
|
|
117
|
+
type: "image",
|
|
118
|
+
attachmentId: "ATTACHMENT_ID",
|
|
119
|
+
caption: "Caption cho ảnh",
|
|
120
|
+
delay: 1500,
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 3. File Message
|
|
125
|
+
```typescript
|
|
126
|
+
{
|
|
127
|
+
type: "file",
|
|
128
|
+
fileToken: "FILE_TOKEN_FROM_UPLOAD_API", // Bắt buộc
|
|
129
|
+
fileName: "document.pdf", // Optional
|
|
130
|
+
delay: 1000,
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 4. Sticker Message
|
|
135
|
+
```typescript
|
|
136
|
+
{
|
|
137
|
+
type: "sticker",
|
|
138
|
+
stickerId: "STICKER_ID", // Bắt buộc
|
|
139
|
+
delay: 500,
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 5. Mention Message
|
|
144
|
+
```typescript
|
|
145
|
+
{
|
|
146
|
+
type: "mention",
|
|
147
|
+
text: "@Admin @User Vui lòng xem thông báo", // Bắt buộc
|
|
148
|
+
mentions: [ // Bắt buộc
|
|
149
|
+
{ user_id: "ADMIN_ID", offset: 0, length: 6 },
|
|
150
|
+
{ user_id: "USER_ID", offset: 7, length: 5 }
|
|
151
|
+
],
|
|
152
|
+
delay: 2000,
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Interface chi tiết
|
|
157
|
+
|
|
158
|
+
### GroupMessageItem
|
|
159
|
+
```typescript
|
|
160
|
+
interface GroupMessageItem {
|
|
161
|
+
type: "text" | "image" | "file" | "sticker" | "mention";
|
|
162
|
+
text?: string;
|
|
163
|
+
imageUrl?: string;
|
|
164
|
+
attachmentId?: string;
|
|
165
|
+
caption?: string;
|
|
166
|
+
fileToken?: string;
|
|
167
|
+
fileName?: string;
|
|
168
|
+
stickerId?: string;
|
|
169
|
+
mentions?: Array<{
|
|
170
|
+
user_id: string;
|
|
171
|
+
offset: number;
|
|
172
|
+
length: number;
|
|
173
|
+
}>;
|
|
174
|
+
delay?: number; // milliseconds
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### SendMessageListToGroupRequest
|
|
179
|
+
```typescript
|
|
180
|
+
interface SendMessageListToGroupRequest {
|
|
181
|
+
accessToken: string;
|
|
182
|
+
groupId: string;
|
|
183
|
+
messages: GroupMessageItem[];
|
|
184
|
+
defaultDelay?: number; // milliseconds
|
|
185
|
+
onProgress?: (progress: GroupMessageProgressInfo) => void;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### SendMessageListToMultipleGroupsRequest
|
|
190
|
+
```typescript
|
|
191
|
+
interface SendMessageListToMultipleGroupsRequest {
|
|
192
|
+
accessToken: string;
|
|
193
|
+
groupIds: string[];
|
|
194
|
+
messages: GroupMessageItem[];
|
|
195
|
+
defaultDelay?: number; // milliseconds
|
|
196
|
+
delayBetweenGroups?: number; // milliseconds
|
|
197
|
+
onProgress?: (progress: MultipleGroupsProgressInfo) => void;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Ví dụ thực tế
|
|
202
|
+
|
|
203
|
+
### Thông báo bảo trì hệ thống
|
|
204
|
+
```typescript
|
|
205
|
+
const maintenanceMessages: GroupMessageItem[] = [
|
|
206
|
+
{
|
|
207
|
+
type: "text",
|
|
208
|
+
text: "🔧 THÔNG BÁO BẢO TRÌ HỆ THỐNG",
|
|
209
|
+
delay: 2000,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: "text",
|
|
213
|
+
text: "⏰ Thời gian: 2:00 - 4:00 sáng ngày mai\n⚠️ Các dịch vụ sẽ tạm ngưng",
|
|
214
|
+
delay: 1500,
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: "image",
|
|
218
|
+
imageUrl: "https://company.com/maintenance-schedule.jpg",
|
|
219
|
+
caption: "Lịch trình bảo trì chi tiết",
|
|
220
|
+
delay: 2000,
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: "📞 Hotline hỗ trợ: 1900-xxxx",
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
const result = await groupMessageService.sendMessageListToMultipleGroups({
|
|
229
|
+
accessToken: "TOKEN",
|
|
230
|
+
groupIds: ["TECH_GROUP", "SUPPORT_GROUP", "ADMIN_GROUP"],
|
|
231
|
+
messages: maintenanceMessages,
|
|
232
|
+
delayBetweenGroups: 2000,
|
|
233
|
+
onProgress: (progress) => {
|
|
234
|
+
if (progress.status === 'completed') {
|
|
235
|
+
console.log(`✅ Đã thông báo tới group ${progress.groupIndex + 1}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Marketing Campaign
|
|
242
|
+
```typescript
|
|
243
|
+
const campaignMessages: GroupMessageItem[] = [
|
|
244
|
+
{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: "🎉 FLASH SALE 24H - GIẢM GIÁ SỐC!",
|
|
247
|
+
delay: 2000,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
type: "image",
|
|
251
|
+
imageUrl: "https://shop.com/flash-sale-banner.jpg",
|
|
252
|
+
caption: "🔥 Giảm tới 70% + Freeship",
|
|
253
|
+
delay: 3000,
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
type: "text",
|
|
257
|
+
text: "⏰ Chỉ còn 12 giờ!\n🛒 Mua ngay: https://shop.com/sale",
|
|
258
|
+
delay: 1500,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: "sticker",
|
|
262
|
+
stickerId: "SALE_STICKER_ID",
|
|
263
|
+
},
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
const customerGroups = ["VIP_CUSTOMERS", "REGULAR_CUSTOMERS", "NEW_CUSTOMERS"];
|
|
267
|
+
|
|
268
|
+
const result = await groupMessageService.sendMessageListToMultipleGroups({
|
|
269
|
+
accessToken: "TOKEN",
|
|
270
|
+
groupIds: customerGroups,
|
|
271
|
+
messages: campaignMessages,
|
|
272
|
+
defaultDelay: 1000,
|
|
273
|
+
delayBetweenGroups: 5000, // 5s delay để tránh spam
|
|
274
|
+
onProgress: (progress) => {
|
|
275
|
+
console.log(`📤 Campaign progress: ${progress.groupIndex + 1}/${progress.totalGroups}`);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
console.log(`🎯 Campaign hoàn thành: ${result.successfulGroups} groups nhận được tin nhắn`);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Meeting Notification với Mention
|
|
283
|
+
```typescript
|
|
284
|
+
const meetingMessages: GroupMessageItem[] = [
|
|
285
|
+
{
|
|
286
|
+
type: "text",
|
|
287
|
+
text: "📅 THÔNG BÁO CUỘC HỌP",
|
|
288
|
+
delay: 1000,
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
type: "mention",
|
|
292
|
+
text: "@TeamLead @Developer @Designer Cuộc họp dự án lúc 14:00 hôm nay",
|
|
293
|
+
mentions: [
|
|
294
|
+
{ user_id: "LEAD_ID", offset: 0, length: 9 },
|
|
295
|
+
{ user_id: "DEV_ID", offset: 10, length: 10 },
|
|
296
|
+
{ user_id: "DESIGN_ID", offset: 21, length: 9 }
|
|
297
|
+
],
|
|
298
|
+
delay: 2000,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
type: "text",
|
|
302
|
+
text: "📋 Agenda:\n1. Sprint review\n2. Planning\n3. Q&A",
|
|
303
|
+
},
|
|
304
|
+
];
|
|
305
|
+
|
|
306
|
+
const result = await groupMessageService.sendMessageListToGroup({
|
|
307
|
+
accessToken: "TOKEN",
|
|
308
|
+
groupId: "PROJECT_TEAM_GROUP",
|
|
309
|
+
messages: meetingMessages,
|
|
310
|
+
defaultDelay: 1500,
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## So sánh với API cũ
|
|
315
|
+
|
|
316
|
+
| Tính năng | API cũ | API mới |
|
|
317
|
+
|-----------|--------|---------|
|
|
318
|
+
| Số lượng tin nhắn | 1 tin nhắn | Nhiều tin nhắn |
|
|
319
|
+
| Số lượng groups | 1 group | 1 hoặc nhiều groups |
|
|
320
|
+
| Callback tracking | ❌ | ✅ Real-time |
|
|
321
|
+
| Delay control | ❌ | ✅ Tùy chỉnh |
|
|
322
|
+
| Error handling | Dừng khi lỗi | Tiếp tục với tin nhắn/group khác |
|
|
323
|
+
| Statistics | ❌ | ✅ Chi tiết |
|
|
324
|
+
| Use case | Tin nhắn đơn lẻ | Campaigns, notifications |
|
|
325
|
+
|
|
326
|
+
## Lưu ý quan trọng
|
|
327
|
+
|
|
328
|
+
1. **Rate Limiting**: Sử dụng `delayBetweenGroups` để tránh hit rate limit
|
|
329
|
+
2. **Group Permissions**: OA phải có quyền gửi tin nhắn trong group
|
|
330
|
+
3. **Message Limits**: Tuân thủ giới hạn của từng loại tin nhắn (text: 2000 ký tự, etc.)
|
|
331
|
+
4. **Error Isolation**: Lỗi của 1 tin nhắn/group không ảnh hưởng phần còn lại
|
|
332
|
+
5. **Callback Performance**: Callback không nên thực hiện operations nặng
|