@quantabit/group-sdk 1.0.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/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/index.cjs +816 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +795 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +90 -0
- package/types/index.d.ts +82 -0
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback, useContext, createContext } from 'react';
|
|
2
|
+
import { BaseApiClient } from '@quantabit/sdk-config';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Group SDK - API 客户端
|
|
6
|
+
* 群组系统后端接口封装
|
|
7
|
+
*
|
|
8
|
+
* 使用 BaseApiClient 基类简化代码
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 群组 API 客户端
|
|
14
|
+
*/
|
|
15
|
+
class GroupApiClient extends BaseApiClient {
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
super('/group', config);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ============ 群组查询 ============
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 获取我的群组
|
|
24
|
+
* @param {Object} params - 查询参数
|
|
25
|
+
*/
|
|
26
|
+
async getMyGroups(params = {}) {
|
|
27
|
+
return this.get('/my', params);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 获取群组详情
|
|
32
|
+
* @param {string} groupId - 群组 ID
|
|
33
|
+
*/
|
|
34
|
+
async getGroup(groupId) {
|
|
35
|
+
return this.get(`/${groupId}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 搜索群组
|
|
40
|
+
* @param {string} keyword - 关键词
|
|
41
|
+
* @param {Object} params - 查询参数
|
|
42
|
+
*/
|
|
43
|
+
async searchGroups(keyword, params = {}) {
|
|
44
|
+
return this.get('/search', {
|
|
45
|
+
keyword,
|
|
46
|
+
...params
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获取推荐群组
|
|
52
|
+
* @param {number} limit - 返回数量
|
|
53
|
+
*/
|
|
54
|
+
async getRecommendedGroups(limit = 10) {
|
|
55
|
+
return this.get('/recommended', {
|
|
56
|
+
limit
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ============ 群组创建/管理 ============
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 创建群组
|
|
64
|
+
* @param {Object} data - 群组数据
|
|
65
|
+
*/
|
|
66
|
+
async createGroup(data) {
|
|
67
|
+
return this.post('/', data);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 更新群组信息
|
|
72
|
+
* @param {string} groupId - 群组 ID
|
|
73
|
+
* @param {Object} updates - 更新数据
|
|
74
|
+
*/
|
|
75
|
+
async updateGroup(groupId, updates) {
|
|
76
|
+
return this.put(`/${groupId}`, updates);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 解散群组
|
|
81
|
+
* @param {string} groupId - 群组 ID
|
|
82
|
+
*/
|
|
83
|
+
async dissolveGroup(groupId) {
|
|
84
|
+
return this.delete(`/${groupId}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 转让群主
|
|
89
|
+
* @param {string} groupId - 群组 ID
|
|
90
|
+
* @param {string} newOwnerId - 新群主 ID
|
|
91
|
+
*/
|
|
92
|
+
async transferOwnership(groupId, newOwnerId) {
|
|
93
|
+
return this.post(`/${groupId}/transfer`, {
|
|
94
|
+
new_owner_id: newOwnerId
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ============ 成员管理 ============
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 获取群成员
|
|
102
|
+
* @param {string} groupId - 群组 ID
|
|
103
|
+
* @param {Object} params - 查询参数
|
|
104
|
+
*/
|
|
105
|
+
async getMembers(groupId, params = {}) {
|
|
106
|
+
return this.get(`/${groupId}/members`, params);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 邀请成员
|
|
111
|
+
* @param {string} groupId - 群组 ID
|
|
112
|
+
* @param {string[]} userIds - 用户 ID 列表
|
|
113
|
+
*/
|
|
114
|
+
async inviteMembers(groupId, userIds) {
|
|
115
|
+
return this.post(`/${groupId}/invite`, {
|
|
116
|
+
user_ids: userIds
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 移除成员
|
|
122
|
+
* @param {string} groupId - 群组 ID
|
|
123
|
+
* @param {string} memberId - 成员 ID
|
|
124
|
+
*/
|
|
125
|
+
async removeMember(groupId, memberId) {
|
|
126
|
+
return this.delete(`/${groupId}/members/${memberId}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 设置管理员
|
|
131
|
+
* @param {string} groupId - 群组 ID
|
|
132
|
+
* @param {string} memberId - 成员 ID
|
|
133
|
+
* @param {boolean} isAdmin - 是否设为管理员
|
|
134
|
+
*/
|
|
135
|
+
async setAdmin(groupId, memberId, isAdmin) {
|
|
136
|
+
return this.put(`/${groupId}/members/${memberId}/admin`, {
|
|
137
|
+
is_admin: isAdmin
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 禁言成员
|
|
143
|
+
* @param {string} groupId - 群组 ID
|
|
144
|
+
* @param {string} memberId - 成员 ID
|
|
145
|
+
* @param {number} duration - 禁言时长(秒)
|
|
146
|
+
*/
|
|
147
|
+
async muteMember(groupId, memberId, duration) {
|
|
148
|
+
return this.post(`/${groupId}/members/${memberId}/mute`, {
|
|
149
|
+
duration
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ============ 加入/退出 ============
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 申请加入群组
|
|
157
|
+
* @param {string} groupId - 群组 ID
|
|
158
|
+
* @param {string} message - 申请消息
|
|
159
|
+
*/
|
|
160
|
+
async applyToJoin(groupId, message = '') {
|
|
161
|
+
return this.post(`/${groupId}/apply`, {
|
|
162
|
+
message
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 获取入群申请(管理员)
|
|
168
|
+
* @param {string} groupId - 群组 ID
|
|
169
|
+
*/
|
|
170
|
+
async getApplications(groupId) {
|
|
171
|
+
return this.get(`/${groupId}/applications`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 处理入群申请(管理员)
|
|
176
|
+
* @param {string} groupId - 群组 ID
|
|
177
|
+
* @param {string} applicationId - 申请 ID
|
|
178
|
+
* @param {boolean} approved - 是否批准
|
|
179
|
+
*/
|
|
180
|
+
async handleApplication(groupId, applicationId, approved) {
|
|
181
|
+
return this.post(`/${groupId}/applications/${applicationId}`, {
|
|
182
|
+
approved
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 退出群组
|
|
188
|
+
* @param {string} groupId - 群组 ID
|
|
189
|
+
*/
|
|
190
|
+
async leaveGroup(groupId) {
|
|
191
|
+
return this.post(`/${groupId}/leave`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ============ 群组设置 ============
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 获取群组设置
|
|
198
|
+
* @param {string} groupId - 群组 ID
|
|
199
|
+
*/
|
|
200
|
+
async getSettings(groupId) {
|
|
201
|
+
return this.get(`/${groupId}/settings`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 更新群组设置(管理员)
|
|
206
|
+
* @param {string} groupId - 群组 ID
|
|
207
|
+
* @param {Object} settings - 设置数据
|
|
208
|
+
*/
|
|
209
|
+
async updateSettings(groupId, settings) {
|
|
210
|
+
return this.put(`/${groupId}/settings`, settings);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 获取个人群设置
|
|
215
|
+
* @param {string} groupId - 群组 ID
|
|
216
|
+
*/
|
|
217
|
+
async getMySettings(groupId) {
|
|
218
|
+
return this.get(`/${groupId}/my/settings`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 更新个人群设置
|
|
223
|
+
* @param {string} groupId - 群组 ID
|
|
224
|
+
* @param {Object} settings - 设置数据
|
|
225
|
+
*/
|
|
226
|
+
async updateMySettings(groupId, settings) {
|
|
227
|
+
return this.put(`/${groupId}/my/settings`, settings);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ============ 群公告 ============
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* 获取群公告
|
|
234
|
+
* @param {string} groupId - 群组 ID
|
|
235
|
+
*/
|
|
236
|
+
async getAnnouncements(groupId) {
|
|
237
|
+
return this.get(`/${groupId}/announcements`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 发布群公告(管理员)
|
|
242
|
+
* @param {string} groupId - 群组 ID
|
|
243
|
+
* @param {Object} announcement - 公告数据
|
|
244
|
+
*/
|
|
245
|
+
async postAnnouncement(groupId, announcement) {
|
|
246
|
+
return this.post(`/${groupId}/announcements`, announcement);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 创建默认实例
|
|
251
|
+
const groupApi = new GroupApiClient();
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Group SDK - 国际化 i18n
|
|
255
|
+
*/
|
|
256
|
+
|
|
257
|
+
const SUPPORTED_LANGUAGES = ['en', 'zh', 'ja', 'ko'];
|
|
258
|
+
const messages = {
|
|
259
|
+
zh: {
|
|
260
|
+
loading: '加载中...',
|
|
261
|
+
group: '群组',
|
|
262
|
+
groups: '群组列表',
|
|
263
|
+
community: '社区',
|
|
264
|
+
guild: '公会',
|
|
265
|
+
myGroups: '我的群组',
|
|
266
|
+
createGroup: '创建群组',
|
|
267
|
+
joinGroup: '加入群组',
|
|
268
|
+
leaveGroup: '退出群组',
|
|
269
|
+
// 群组信息
|
|
270
|
+
groupName: '群组名称',
|
|
271
|
+
groupDesc: '群组简介',
|
|
272
|
+
groupAvatar: '群组头像',
|
|
273
|
+
groupCover: '群组封面',
|
|
274
|
+
memberCount: '成员数量',
|
|
275
|
+
postCount: '帖子数量',
|
|
276
|
+
// 类型
|
|
277
|
+
typePublic: '公开群组',
|
|
278
|
+
typePrivate: '私密群组',
|
|
279
|
+
typeSecret: '隐藏群组',
|
|
280
|
+
// 角色
|
|
281
|
+
roleOwner: '群主',
|
|
282
|
+
roleAdmin: '管理员',
|
|
283
|
+
roleModerator: '版主',
|
|
284
|
+
roleMember: '成员',
|
|
285
|
+
// 成员管理
|
|
286
|
+
members: '成员',
|
|
287
|
+
memberList: '成员列表',
|
|
288
|
+
inviteMember: '邀请成员',
|
|
289
|
+
removeMember: '移除成员',
|
|
290
|
+
setAdmin: '设为管理员',
|
|
291
|
+
removeAdmin: '取消管理员',
|
|
292
|
+
transferOwner: '转让群主',
|
|
293
|
+
// 公告
|
|
294
|
+
announcement: '公告',
|
|
295
|
+
announcements: '群公告',
|
|
296
|
+
postAnnouncement: '发布公告',
|
|
297
|
+
// 帖子
|
|
298
|
+
posts: '帖子',
|
|
299
|
+
createPost: '发帖',
|
|
300
|
+
pinPost: '置顶',
|
|
301
|
+
unpinPost: '取消置顶',
|
|
302
|
+
// 操作
|
|
303
|
+
edit: '编辑',
|
|
304
|
+
delete: '删除',
|
|
305
|
+
disband: '解散群组',
|
|
306
|
+
report: '举报',
|
|
307
|
+
settings: '设置',
|
|
308
|
+
// 状态
|
|
309
|
+
joined: '已加入',
|
|
310
|
+
pending: '待审核',
|
|
311
|
+
rejected: '已拒绝',
|
|
312
|
+
// 提示
|
|
313
|
+
noGroups: '暂无群组',
|
|
314
|
+
joinSuccess: '加入成功',
|
|
315
|
+
leaveSuccess: '退出成功',
|
|
316
|
+
createSuccess: '创建成功',
|
|
317
|
+
confirmLeave: '确定退出该群组?',
|
|
318
|
+
confirmDisband: '确定解散该群组?此操作不可恢复。',
|
|
319
|
+
needApproval: '需要管理员审核'
|
|
320
|
+
},
|
|
321
|
+
en: {
|
|
322
|
+
loading: 'Loading...',
|
|
323
|
+
group: 'Group',
|
|
324
|
+
groups: 'Groups',
|
|
325
|
+
community: 'Community',
|
|
326
|
+
guild: 'Guild',
|
|
327
|
+
myGroups: 'My Groups',
|
|
328
|
+
createGroup: 'Create Group',
|
|
329
|
+
joinGroup: 'Join',
|
|
330
|
+
leaveGroup: 'Leave',
|
|
331
|
+
groupName: 'Group Name',
|
|
332
|
+
groupDesc: 'Description',
|
|
333
|
+
groupAvatar: 'Avatar',
|
|
334
|
+
groupCover: 'Cover',
|
|
335
|
+
memberCount: 'Members',
|
|
336
|
+
postCount: 'Posts',
|
|
337
|
+
typePublic: 'Public',
|
|
338
|
+
typePrivate: 'Private',
|
|
339
|
+
typeSecret: 'Secret',
|
|
340
|
+
roleOwner: 'Owner',
|
|
341
|
+
roleAdmin: 'Admin',
|
|
342
|
+
roleModerator: 'Moderator',
|
|
343
|
+
roleMember: 'Member',
|
|
344
|
+
members: 'Members',
|
|
345
|
+
memberList: 'Member List',
|
|
346
|
+
inviteMember: 'Invite',
|
|
347
|
+
removeMember: 'Remove',
|
|
348
|
+
setAdmin: 'Set Admin',
|
|
349
|
+
removeAdmin: 'Remove Admin',
|
|
350
|
+
transferOwner: 'Transfer Ownership',
|
|
351
|
+
announcement: 'Announcement',
|
|
352
|
+
announcements: 'Announcements',
|
|
353
|
+
postAnnouncement: 'Post Announcement',
|
|
354
|
+
posts: 'Posts',
|
|
355
|
+
createPost: 'Create Post',
|
|
356
|
+
pinPost: 'Pin',
|
|
357
|
+
unpinPost: 'Unpin',
|
|
358
|
+
edit: 'Edit',
|
|
359
|
+
delete: 'Delete',
|
|
360
|
+
disband: 'Disband',
|
|
361
|
+
report: 'Report',
|
|
362
|
+
settings: 'Settings',
|
|
363
|
+
joined: 'Joined',
|
|
364
|
+
pending: 'Pending',
|
|
365
|
+
rejected: 'Rejected',
|
|
366
|
+
noGroups: 'No groups',
|
|
367
|
+
joinSuccess: 'Joined successfully',
|
|
368
|
+
leaveSuccess: 'Left successfully',
|
|
369
|
+
createSuccess: 'Created successfully',
|
|
370
|
+
confirmLeave: 'Are you sure to leave this group?',
|
|
371
|
+
confirmDisband: 'Are you sure to disband? This cannot be undone.',
|
|
372
|
+
needApproval: 'Requires approval'
|
|
373
|
+
},
|
|
374
|
+
ja: {
|
|
375
|
+
loading: '読み込み中...',
|
|
376
|
+
group: 'グループ',
|
|
377
|
+
groups: 'グループ一覧',
|
|
378
|
+
community: 'コミュニティ',
|
|
379
|
+
guild: 'ギルド',
|
|
380
|
+
myGroups: 'マイグループ',
|
|
381
|
+
createGroup: 'グループを作成',
|
|
382
|
+
joinGroup: '参加する',
|
|
383
|
+
leaveGroup: '退出する',
|
|
384
|
+
groupName: 'グループ名',
|
|
385
|
+
groupDesc: '概要',
|
|
386
|
+
groupAvatar: 'アバター',
|
|
387
|
+
groupCover: 'カバー',
|
|
388
|
+
memberCount: 'メンバー数',
|
|
389
|
+
postCount: '投稿数',
|
|
390
|
+
typePublic: '公開グループ',
|
|
391
|
+
typePrivate: '非公開グループ',
|
|
392
|
+
typeSecret: '秘密のグループ',
|
|
393
|
+
roleOwner: 'オーナー',
|
|
394
|
+
roleAdmin: '管理者',
|
|
395
|
+
roleModerator: 'モデレーター',
|
|
396
|
+
roleMember: 'メンバー',
|
|
397
|
+
members: 'メンバー',
|
|
398
|
+
memberList: 'メンバー一覧',
|
|
399
|
+
inviteMember: '招待する',
|
|
400
|
+
removeMember: '削除する',
|
|
401
|
+
setAdmin: '管理者に設定',
|
|
402
|
+
removeAdmin: '管理者を解除',
|
|
403
|
+
transferOwner: 'オーナー権限を譲渡',
|
|
404
|
+
announcement: 'お知らせ',
|
|
405
|
+
announcements: 'グループのお知らせ',
|
|
406
|
+
postAnnouncement: 'お知らせを投稿',
|
|
407
|
+
posts: '投稿',
|
|
408
|
+
createPost: '投稿を作成',
|
|
409
|
+
pinPost: 'ピン留め',
|
|
410
|
+
unpinPost: 'ピン留め解除',
|
|
411
|
+
edit: '編集',
|
|
412
|
+
delete: '削除',
|
|
413
|
+
disband: '解散する',
|
|
414
|
+
report: '通報',
|
|
415
|
+
settings: '設定',
|
|
416
|
+
joined: '参加済み',
|
|
417
|
+
pending: '承認待ち',
|
|
418
|
+
rejected: '拒否されました',
|
|
419
|
+
noGroups: 'グループはありません',
|
|
420
|
+
joinSuccess: '参加しました',
|
|
421
|
+
leaveSuccess: '退出しました',
|
|
422
|
+
createSuccess: '作成に成功しました',
|
|
423
|
+
confirmLeave: 'このグループから退出してもよろしいですか?',
|
|
424
|
+
confirmDisband: 'グループを解散してもよろしいですか?この操作は元に戻せません。',
|
|
425
|
+
needApproval: '管理者の承認が必要です'
|
|
426
|
+
},
|
|
427
|
+
ko: {
|
|
428
|
+
loading: '로딩 중...',
|
|
429
|
+
group: '그룹',
|
|
430
|
+
groups: '그룹 목록',
|
|
431
|
+
community: '커뮤니티',
|
|
432
|
+
guild: '길드',
|
|
433
|
+
myGroups: '내 그룹',
|
|
434
|
+
createGroup: '그룹 만들기',
|
|
435
|
+
joinGroup: '가입하기',
|
|
436
|
+
leaveGroup: '탈퇴하기',
|
|
437
|
+
groupName: '그룹 이름',
|
|
438
|
+
groupDesc: '그룹 소개',
|
|
439
|
+
groupAvatar: '아바타',
|
|
440
|
+
groupCover: '커버',
|
|
441
|
+
memberCount: '회원 수',
|
|
442
|
+
postCount: '게시물 수',
|
|
443
|
+
typePublic: '공개 그룹',
|
|
444
|
+
typePrivate: '비공개 그룹',
|
|
445
|
+
typeSecret: '비밀 그룹',
|
|
446
|
+
roleOwner: '소유자',
|
|
447
|
+
roleAdmin: '관리자',
|
|
448
|
+
roleModerator: '모더레이터',
|
|
449
|
+
roleMember: '멤버',
|
|
450
|
+
members: '멤버',
|
|
451
|
+
memberList: '멤버 목록',
|
|
452
|
+
inviteMember: '초대하기',
|
|
453
|
+
removeMember: '제거하기',
|
|
454
|
+
setAdmin: '관리자로 설정',
|
|
455
|
+
removeAdmin: '관리자 해제',
|
|
456
|
+
transferOwner: '소유권 양도',
|
|
457
|
+
announcement: '공지사항',
|
|
458
|
+
announcements: '그룹 공지사항',
|
|
459
|
+
postAnnouncement: '공지사항 작성',
|
|
460
|
+
posts: '게시물',
|
|
461
|
+
createPost: '게시물 작성',
|
|
462
|
+
pinPost: '고정하기',
|
|
463
|
+
unpinPost: '고정 해제',
|
|
464
|
+
edit: '편집',
|
|
465
|
+
delete: '삭제',
|
|
466
|
+
disband: '해산하기',
|
|
467
|
+
report: '신고',
|
|
468
|
+
settings: '설정',
|
|
469
|
+
joined: '가입됨',
|
|
470
|
+
pending: '승인 대기 중',
|
|
471
|
+
rejected: '거절됨',
|
|
472
|
+
noGroups: '그룹이 없습니다',
|
|
473
|
+
joinSuccess: '가입 성공',
|
|
474
|
+
leaveSuccess: '탈퇴 성공',
|
|
475
|
+
createSuccess: '생성 성공',
|
|
476
|
+
confirmLeave: '이 그룹에서 탈퇴하시겠습니까?',
|
|
477
|
+
confirmDisband: '이 그룹을 해산하시겠습니까? 이 작업은 취소할 수 없습니다.',
|
|
478
|
+
needApproval: '관리자 승인이 필요합니다'
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
let currentLanguage = 'zh';
|
|
482
|
+
function setLanguage(lang) {
|
|
483
|
+
if (SUPPORTED_LANGUAGES.includes(lang)) {
|
|
484
|
+
currentLanguage = lang;
|
|
485
|
+
if (typeof window !== 'undefined') {
|
|
486
|
+
localStorage.setItem('qbit_did_group_language', lang);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function getLanguage() {
|
|
491
|
+
if (typeof window !== 'undefined') {
|
|
492
|
+
const saved = localStorage.getItem('qbit_did_group_language');
|
|
493
|
+
if (saved && SUPPORTED_LANGUAGES.includes(saved)) {
|
|
494
|
+
currentLanguage = saved;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return currentLanguage;
|
|
498
|
+
}
|
|
499
|
+
function t(key, params) {
|
|
500
|
+
const msgs = messages[getLanguage()] || messages.zh;
|
|
501
|
+
let text = msgs[key] || key;
|
|
502
|
+
if (params) {
|
|
503
|
+
Object.keys(params).forEach(k => {
|
|
504
|
+
text = text.replace(new RegExp(`\\{${k}\\}`, 'g'), params[k]);
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return text;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Group SDK - Context Provider
|
|
512
|
+
*/
|
|
513
|
+
|
|
514
|
+
const GroupContext = /*#__PURE__*/createContext(null);
|
|
515
|
+
function GroupProvider({
|
|
516
|
+
children,
|
|
517
|
+
apiUrl,
|
|
518
|
+
token,
|
|
519
|
+
language = 'zh',
|
|
520
|
+
onJoin,
|
|
521
|
+
onLeave,
|
|
522
|
+
onError
|
|
523
|
+
}) {
|
|
524
|
+
const [groups, setGroups] = useState([]);
|
|
525
|
+
const [myGroups, setMyGroups] = useState([]);
|
|
526
|
+
const [currentGroup, setCurrentGroup] = useState(null);
|
|
527
|
+
const [members, setMembers] = useState([]);
|
|
528
|
+
const [loading, setLoading] = useState(false);
|
|
529
|
+
const [error, setError] = useState(null);
|
|
530
|
+
useEffect(() => {
|
|
531
|
+
setLanguage(language);
|
|
532
|
+
}, [language]);
|
|
533
|
+
const handleError = useCallback(err => {
|
|
534
|
+
setError(err);
|
|
535
|
+
onError?.(err);
|
|
536
|
+
}, [onError]);
|
|
537
|
+
const loadGroups = useCallback(async (params = {}) => {
|
|
538
|
+
try {
|
|
539
|
+
const result = await groupApi.getGroups(params);
|
|
540
|
+
const items = result.items || result.data || result || [];
|
|
541
|
+
setGroups(items);
|
|
542
|
+
return items;
|
|
543
|
+
} catch (err) {
|
|
544
|
+
handleError(err);
|
|
545
|
+
throw err;
|
|
546
|
+
}
|
|
547
|
+
}, [handleError]);
|
|
548
|
+
const loadMyGroups = useCallback(async () => {
|
|
549
|
+
try {
|
|
550
|
+
const result = await groupApi.getMyGroups();
|
|
551
|
+
const items = result.items || result.data || result || [];
|
|
552
|
+
setMyGroups(items);
|
|
553
|
+
return items;
|
|
554
|
+
} catch (err) {
|
|
555
|
+
handleError(err);
|
|
556
|
+
throw err;
|
|
557
|
+
}
|
|
558
|
+
}, [handleError]);
|
|
559
|
+
const loadGroup = useCallback(async groupId => {
|
|
560
|
+
setLoading(true);
|
|
561
|
+
try {
|
|
562
|
+
const result = await groupApi.getGroup(groupId);
|
|
563
|
+
setCurrentGroup(result);
|
|
564
|
+
return result;
|
|
565
|
+
} catch (err) {
|
|
566
|
+
handleError(err);
|
|
567
|
+
throw err;
|
|
568
|
+
} finally {
|
|
569
|
+
setLoading(false);
|
|
570
|
+
}
|
|
571
|
+
}, [handleError]);
|
|
572
|
+
const loadMembers = useCallback(async (groupId, params = {}) => {
|
|
573
|
+
try {
|
|
574
|
+
const result = await groupApi.getMembers(groupId, params);
|
|
575
|
+
const items = result.items || result.data || result || [];
|
|
576
|
+
setMembers(items);
|
|
577
|
+
return items;
|
|
578
|
+
} catch (err) {
|
|
579
|
+
handleError(err);
|
|
580
|
+
throw err;
|
|
581
|
+
}
|
|
582
|
+
}, [handleError]);
|
|
583
|
+
|
|
584
|
+
// ============ 群组操作 ============
|
|
585
|
+
|
|
586
|
+
const createGroup = useCallback(async data => {
|
|
587
|
+
setLoading(true);
|
|
588
|
+
try {
|
|
589
|
+
const result = await groupApi.createGroup(data);
|
|
590
|
+
await loadMyGroups();
|
|
591
|
+
return result;
|
|
592
|
+
} catch (err) {
|
|
593
|
+
handleError(err);
|
|
594
|
+
throw err;
|
|
595
|
+
} finally {
|
|
596
|
+
setLoading(false);
|
|
597
|
+
}
|
|
598
|
+
}, [loadMyGroups, handleError]);
|
|
599
|
+
const joinGroup = useCallback(async (groupId, message) => {
|
|
600
|
+
setLoading(true);
|
|
601
|
+
try {
|
|
602
|
+
const result = await groupApi.joinGroup(groupId, message);
|
|
603
|
+
await loadMyGroups();
|
|
604
|
+
onJoin?.(result);
|
|
605
|
+
return result;
|
|
606
|
+
} catch (err) {
|
|
607
|
+
handleError(err);
|
|
608
|
+
throw err;
|
|
609
|
+
} finally {
|
|
610
|
+
setLoading(false);
|
|
611
|
+
}
|
|
612
|
+
}, [loadMyGroups, onJoin, handleError]);
|
|
613
|
+
const leaveGroup = useCallback(async groupId => {
|
|
614
|
+
setLoading(true);
|
|
615
|
+
try {
|
|
616
|
+
await groupApi.leaveGroup(groupId);
|
|
617
|
+
await loadMyGroups();
|
|
618
|
+
onLeave?.(groupId);
|
|
619
|
+
} catch (err) {
|
|
620
|
+
handleError(err);
|
|
621
|
+
throw err;
|
|
622
|
+
} finally {
|
|
623
|
+
setLoading(false);
|
|
624
|
+
}
|
|
625
|
+
}, [loadMyGroups, onLeave, handleError]);
|
|
626
|
+
const value = {
|
|
627
|
+
groups,
|
|
628
|
+
myGroups,
|
|
629
|
+
currentGroup,
|
|
630
|
+
members,
|
|
631
|
+
loading,
|
|
632
|
+
error,
|
|
633
|
+
loadGroups,
|
|
634
|
+
loadMyGroups,
|
|
635
|
+
loadGroup,
|
|
636
|
+
loadMembers,
|
|
637
|
+
createGroup,
|
|
638
|
+
joinGroup,
|
|
639
|
+
leaveGroup,
|
|
640
|
+
api: groupApi
|
|
641
|
+
};
|
|
642
|
+
return /*#__PURE__*/React.createElement(GroupContext.Provider, {
|
|
643
|
+
value: value
|
|
644
|
+
}, children);
|
|
645
|
+
}
|
|
646
|
+
function useGroup() {
|
|
647
|
+
const context = useContext(GroupContext);
|
|
648
|
+
if (!context) {
|
|
649
|
+
throw new Error('useGroup must be used within a GroupProvider');
|
|
650
|
+
}
|
|
651
|
+
return context;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function GroupCard() {
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function MemberList() {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Group SDK - 类型定义
|
|
664
|
+
*/
|
|
665
|
+
|
|
666
|
+
// 群组类型
|
|
667
|
+
const GroupType = {
|
|
668
|
+
PUBLIC: 'public',
|
|
669
|
+
// 公开群组
|
|
670
|
+
PRIVATE: 'private',
|
|
671
|
+
// 私密群组(需审核)
|
|
672
|
+
SECRET: 'secret' // 隐藏群组(仅邀请)
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// 成员角色
|
|
676
|
+
const MemberRole = {
|
|
677
|
+
OWNER: 'owner',
|
|
678
|
+
// 群主
|
|
679
|
+
ADMIN: 'admin',
|
|
680
|
+
// 管理员
|
|
681
|
+
MODERATOR: 'moderator',
|
|
682
|
+
// 版主
|
|
683
|
+
MEMBER: 'member' // 普通成员
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// 成员状态
|
|
687
|
+
const MemberStatus = {
|
|
688
|
+
ACTIVE: 'active',
|
|
689
|
+
// 正常
|
|
690
|
+
PENDING: 'pending',
|
|
691
|
+
// 待审核
|
|
692
|
+
MUTED: 'muted',
|
|
693
|
+
// 禁言
|
|
694
|
+
BANNED: 'banned' // 封禁
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* 创建默认群组
|
|
699
|
+
*/
|
|
700
|
+
function createDefaultGroup(overrides = {}) {
|
|
701
|
+
return {
|
|
702
|
+
id: null,
|
|
703
|
+
name: '',
|
|
704
|
+
description: '',
|
|
705
|
+
avatar_url: null,
|
|
706
|
+
cover_url: null,
|
|
707
|
+
type: GroupType.PUBLIC,
|
|
708
|
+
owner_did: null,
|
|
709
|
+
member_count: 0,
|
|
710
|
+
post_count: 0,
|
|
711
|
+
max_members: null,
|
|
712
|
+
tags: [],
|
|
713
|
+
is_verified: false,
|
|
714
|
+
settings: {},
|
|
715
|
+
created_at: null,
|
|
716
|
+
...overrides
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* 创建默认成员
|
|
722
|
+
*/
|
|
723
|
+
function createDefaultMember(overrides = {}) {
|
|
724
|
+
return {
|
|
725
|
+
id: null,
|
|
726
|
+
group_id: null,
|
|
727
|
+
user_did: null,
|
|
728
|
+
nickname: null,
|
|
729
|
+
avatar_url: null,
|
|
730
|
+
role: MemberRole.MEMBER,
|
|
731
|
+
status: MemberStatus.ACTIVE,
|
|
732
|
+
joined_at: null,
|
|
733
|
+
...overrides
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* 创建默认公告
|
|
739
|
+
*/
|
|
740
|
+
function createDefaultAnnouncement(overrides = {}) {
|
|
741
|
+
return {
|
|
742
|
+
id: null,
|
|
743
|
+
group_id: null,
|
|
744
|
+
title: '',
|
|
745
|
+
content: '',
|
|
746
|
+
author_did: null,
|
|
747
|
+
is_pinned: false,
|
|
748
|
+
created_at: null,
|
|
749
|
+
...overrides
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* 检查是否有管理权限
|
|
755
|
+
*/
|
|
756
|
+
function hasAdminPermission(role) {
|
|
757
|
+
return [MemberRole.OWNER, MemberRole.ADMIN].includes(role);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* 检查是否可以管理成员
|
|
762
|
+
*/
|
|
763
|
+
function canManageMember(operatorRole, targetRole) {
|
|
764
|
+
const roleLevel = {
|
|
765
|
+
[MemberRole.OWNER]: 4,
|
|
766
|
+
[MemberRole.ADMIN]: 3,
|
|
767
|
+
[MemberRole.MODERATOR]: 2,
|
|
768
|
+
[MemberRole.MEMBER]: 1
|
|
769
|
+
};
|
|
770
|
+
return roleLevel[operatorRole] > roleLevel[targetRole];
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* 获取角色显示名称
|
|
775
|
+
*/
|
|
776
|
+
function getRoleName(role, language = 'zh') {
|
|
777
|
+
const names = {
|
|
778
|
+
zh: {
|
|
779
|
+
[MemberRole.OWNER]: '群主',
|
|
780
|
+
[MemberRole.ADMIN]: '管理员',
|
|
781
|
+
[MemberRole.MODERATOR]: '版主',
|
|
782
|
+
[MemberRole.MEMBER]: '成员'
|
|
783
|
+
},
|
|
784
|
+
en: {
|
|
785
|
+
[MemberRole.OWNER]: 'Owner',
|
|
786
|
+
[MemberRole.ADMIN]: 'Admin',
|
|
787
|
+
[MemberRole.MODERATOR]: 'Mod',
|
|
788
|
+
[MemberRole.MEMBER]: 'Member'
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
return names[language]?.[role] || role;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
export { GroupApiClient, GroupCard, GroupProvider, GroupType, MemberList, MemberRole, MemberStatus, SUPPORTED_LANGUAGES, canManageMember, createDefaultAnnouncement, createDefaultGroup, createDefaultMember, getLanguage, getRoleName, groupApi, hasAdminPermission, messages, setLanguage, t, useGroup };
|
|
795
|
+
//# sourceMappingURL=index.esm.js.map
|