@zhin.js/adapter-dingtalk 1.0.40 → 1.0.41
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 +9 -0
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +1 -6
- package/lib/adapter.js.map +1 -1
- package/package.json +9 -5
- package/skills/dingtalk/SKILL.md +18 -0
- package/src/adapter.ts +293 -0
- package/src/bot.ts +593 -0
- package/src/index.ts +38 -0
- package/src/types.ts +56 -0
package/CHANGELOG.md
CHANGED
package/lib/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,EACP,MAAM,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,EACP,MAAM,EAGP,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,qBAAa,eAAgB,SAAQ,OAAO,CAAC,WAAW,CAAC;;gBAG3C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAKvC,SAAS,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW;IAI3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B,OAAO,CAAC,6BAA6B;CAgPtC"}
|
package/lib/adapter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 钉钉适配器
|
|
3
3
|
*/
|
|
4
|
-
import { Adapter, createGroupManagementTools,
|
|
4
|
+
import { Adapter, createGroupManagementTools, } from "zhin.js";
|
|
5
5
|
import { DingTalkBot } from "./bot.js";
|
|
6
6
|
export class DingTalkAdapter extends Adapter {
|
|
7
7
|
#router;
|
|
@@ -34,11 +34,6 @@ export class DingTalkAdapter extends Adapter {
|
|
|
34
34
|
this.registerDingTalkPlatformTools();
|
|
35
35
|
const groupTools = createGroupManagementTools(this, this.name);
|
|
36
36
|
groupTools.forEach((t) => this.addTool(t));
|
|
37
|
-
this.declareSkill({
|
|
38
|
-
description: "钉钉群管理:踢人、禁言、设管理员、改群名、查成员等。仅有昵称时请先 list_members 获取 user_id 再操作。",
|
|
39
|
-
keywords: GROUP_MANAGEMENT_SKILL_KEYWORDS,
|
|
40
|
-
tags: GROUP_MANAGEMENT_SKILL_TAGS,
|
|
41
|
-
});
|
|
42
37
|
await super.start();
|
|
43
38
|
}
|
|
44
39
|
registerDingTalkPlatformTools() {
|
package/lib/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,EAEP,0BAA0B,
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-dingtalk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.41",
|
|
4
4
|
"description": "Zhin.js adapter for DingTalk (钉钉)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"typescript": "^5.3.0",
|
|
35
35
|
"@types/node": "^22.9.0",
|
|
36
36
|
"@types/koa": "^2.15.0",
|
|
37
|
-
"zhin.js": "1.0.
|
|
37
|
+
"zhin.js": "1.0.52"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"zhin.js": "1.0.
|
|
41
|
-
"@zhin.js/http": "1.0.
|
|
40
|
+
"zhin.js": "1.0.52",
|
|
41
|
+
"@zhin.js/http": "1.0.46"
|
|
42
42
|
},
|
|
43
43
|
"peerDependenciesMeta": {
|
|
44
44
|
"@zhin.js/http": {
|
|
@@ -46,9 +46,13 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"files": [
|
|
49
|
+
"src",
|
|
49
50
|
"lib",
|
|
50
|
-
"
|
|
51
|
+
"client",
|
|
52
|
+
"dist",
|
|
53
|
+
"skills",
|
|
51
54
|
"README.md",
|
|
55
|
+
"node",
|
|
52
56
|
"CHANGELOG.md"
|
|
53
57
|
],
|
|
54
58
|
"publishConfig": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dingtalk
|
|
3
|
+
description: 钉钉群管理:踢人、禁言、设管理员、改群名、查成员等。仅有昵称时请先 list_members 获取 user_id 再操作。
|
|
4
|
+
keywords:
|
|
5
|
+
- dingtalk
|
|
6
|
+
- 钉钉
|
|
7
|
+
- adapter:dingtalk
|
|
8
|
+
- 群管理
|
|
9
|
+
- list_members
|
|
10
|
+
tags:
|
|
11
|
+
- group
|
|
12
|
+
- management
|
|
13
|
+
tools: []
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 执行规则
|
|
17
|
+
|
|
18
|
+
- 使用 `dingtalk_*` 工具;先 list_members。
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 钉钉适配器
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
Adapter,
|
|
6
|
+
Plugin,
|
|
7
|
+
createGroupManagementTools,
|
|
8
|
+
type IGroupManagement,
|
|
9
|
+
} from "zhin.js";
|
|
10
|
+
import { DingTalkBot } from "./bot.js";
|
|
11
|
+
import type { DingTalkBotConfig } from "./types.js";
|
|
12
|
+
|
|
13
|
+
export class DingTalkAdapter extends Adapter<DingTalkBot> {
|
|
14
|
+
#router: any;
|
|
15
|
+
|
|
16
|
+
constructor(plugin: Plugin, router: any) {
|
|
17
|
+
super(plugin, "dingtalk", []);
|
|
18
|
+
this.#router = router;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
createBot(config: DingTalkBotConfig): DingTalkBot {
|
|
22
|
+
return new DingTalkBot(this, this.#router, config);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async kickMember(botId: string, sceneId: string, userId: string) {
|
|
26
|
+
const bot = this.bots.get(botId);
|
|
27
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
28
|
+
return bot.updateChat(sceneId, { del_useridlist: [userId] });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async setGroupName(botId: string, sceneId: string, name: string) {
|
|
32
|
+
const bot = this.bots.get(botId);
|
|
33
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
34
|
+
return bot.updateChat(sceneId, { name });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async getGroupInfo(botId: string, sceneId: string) {
|
|
38
|
+
const bot = this.bots.get(botId);
|
|
39
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
40
|
+
return bot.getChatInfo(sceneId);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async start(): Promise<void> {
|
|
44
|
+
this.registerDingTalkPlatformTools();
|
|
45
|
+
const groupTools = createGroupManagementTools(
|
|
46
|
+
this as unknown as IGroupManagement,
|
|
47
|
+
this.name
|
|
48
|
+
);
|
|
49
|
+
groupTools.forEach((t) => this.addTool(t));
|
|
50
|
+
await super.start();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private registerDingTalkPlatformTools(): void {
|
|
54
|
+
this.addTool({
|
|
55
|
+
name: "dingtalk_get_user",
|
|
56
|
+
description: "获取钉钉用户信息",
|
|
57
|
+
parameters: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
61
|
+
user_id: { type: "string", description: "用户 ID" },
|
|
62
|
+
},
|
|
63
|
+
required: ["bot", "user_id"],
|
|
64
|
+
},
|
|
65
|
+
platforms: ["dingtalk"],
|
|
66
|
+
scopes: ["group", "private"],
|
|
67
|
+
permissionLevel: "user",
|
|
68
|
+
execute: async (args) => {
|
|
69
|
+
const { bot: botId, user_id } = args;
|
|
70
|
+
const bot = this.bots.get(botId);
|
|
71
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
72
|
+
return await bot.getUserInfo(user_id);
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.addTool({
|
|
77
|
+
name: "dingtalk_get_dept_users",
|
|
78
|
+
description: "获取钉钉部门用户列表",
|
|
79
|
+
parameters: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
83
|
+
dept_id: { type: "number", description: "部门 ID" },
|
|
84
|
+
},
|
|
85
|
+
required: ["bot", "dept_id"],
|
|
86
|
+
},
|
|
87
|
+
platforms: ["dingtalk"],
|
|
88
|
+
scopes: ["group", "private"],
|
|
89
|
+
permissionLevel: "user",
|
|
90
|
+
execute: async (args) => {
|
|
91
|
+
const { bot: botId, dept_id } = args;
|
|
92
|
+
const bot = this.bots.get(botId);
|
|
93
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
94
|
+
const users = await bot.getDepartmentUsers(dept_id);
|
|
95
|
+
return { users, count: users.length };
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.addTool({
|
|
100
|
+
name: "dingtalk_list_departments",
|
|
101
|
+
description: "获取钉钉部门列表",
|
|
102
|
+
parameters: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
106
|
+
dept_id: { type: "number", description: "父部门 ID,默认 1(根部门)" },
|
|
107
|
+
},
|
|
108
|
+
required: ["bot"],
|
|
109
|
+
},
|
|
110
|
+
platforms: ["dingtalk"],
|
|
111
|
+
scopes: ["group", "private"],
|
|
112
|
+
permissionLevel: "user",
|
|
113
|
+
execute: async (args) => {
|
|
114
|
+
const { bot: botId, dept_id = 1 } = args;
|
|
115
|
+
const bot = this.bots.get(botId);
|
|
116
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
117
|
+
const departments = await bot.getDepartmentList(dept_id);
|
|
118
|
+
return { departments, count: departments.length };
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this.addTool({
|
|
123
|
+
name: "dingtalk_send_work_notice",
|
|
124
|
+
description: "向指定用户发送钉钉工作通知",
|
|
125
|
+
parameters: {
|
|
126
|
+
type: "object",
|
|
127
|
+
properties: {
|
|
128
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
129
|
+
user_ids: {
|
|
130
|
+
type: "array",
|
|
131
|
+
items: { type: "string" },
|
|
132
|
+
description: "用户 ID 列表",
|
|
133
|
+
},
|
|
134
|
+
content: { type: "string", description: "通知内容" },
|
|
135
|
+
},
|
|
136
|
+
required: ["bot", "user_ids", "content"],
|
|
137
|
+
},
|
|
138
|
+
platforms: ["dingtalk"],
|
|
139
|
+
scopes: ["group", "private"],
|
|
140
|
+
permissionLevel: "group_admin",
|
|
141
|
+
execute: async (args) => {
|
|
142
|
+
const { bot: botId, user_ids, content } = args;
|
|
143
|
+
const bot = this.bots.get(botId);
|
|
144
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
145
|
+
const msgContent = { msgtype: "text", text: { content } };
|
|
146
|
+
const success = await bot.sendWorkNotice(user_ids, msgContent);
|
|
147
|
+
return {
|
|
148
|
+
success,
|
|
149
|
+
message: success ? "工作通知已发送" : "发送失败",
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
this.addTool({
|
|
155
|
+
name: "dingtalk_create_chat",
|
|
156
|
+
description: "创建钉钉群聊",
|
|
157
|
+
parameters: {
|
|
158
|
+
type: "object",
|
|
159
|
+
properties: {
|
|
160
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
161
|
+
name: { type: "string", description: "群名" },
|
|
162
|
+
owner: { type: "string", description: "群主用户 ID" },
|
|
163
|
+
members: {
|
|
164
|
+
type: "array",
|
|
165
|
+
items: { type: "string" },
|
|
166
|
+
description: "成员用户 ID 列表",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
required: ["bot", "name", "owner", "members"],
|
|
170
|
+
},
|
|
171
|
+
platforms: ["dingtalk"],
|
|
172
|
+
scopes: ["group", "private"],
|
|
173
|
+
permissionLevel: "group_admin",
|
|
174
|
+
execute: async (args) => {
|
|
175
|
+
const { bot: botId, name, owner, members } = args;
|
|
176
|
+
const bot = this.bots.get(botId);
|
|
177
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
178
|
+
const chatId = await bot.createChat(name, owner, members);
|
|
179
|
+
return {
|
|
180
|
+
success: !!chatId,
|
|
181
|
+
chat_id: chatId,
|
|
182
|
+
message: chatId ? `群聊创建成功: ${chatId}` : "创建失败",
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
this.addTool({
|
|
188
|
+
name: "dingtalk_add_chat_members",
|
|
189
|
+
description: "向钉钉群聊添加成员",
|
|
190
|
+
parameters: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
194
|
+
chat_id: { type: "string", description: "群聊 ID" },
|
|
195
|
+
user_ids: {
|
|
196
|
+
type: "array",
|
|
197
|
+
items: { type: "string" },
|
|
198
|
+
description: "要添加的用户 ID 列表",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
required: ["bot", "chat_id", "user_ids"],
|
|
202
|
+
},
|
|
203
|
+
platforms: ["dingtalk"],
|
|
204
|
+
scopes: ["group"],
|
|
205
|
+
permissionLevel: "group_admin",
|
|
206
|
+
execute: async (args) => {
|
|
207
|
+
const { bot: botId, chat_id, user_ids } = args;
|
|
208
|
+
const bot = this.bots.get(botId);
|
|
209
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
210
|
+
const success = await bot.updateChat(chat_id, {
|
|
211
|
+
add_useridlist: user_ids,
|
|
212
|
+
});
|
|
213
|
+
return { success, message: success ? "成员添加成功" : "添加失败" };
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
this.addTool({
|
|
218
|
+
name: "dingtalk_dept_info",
|
|
219
|
+
description: "获取钉钉部门详细信息",
|
|
220
|
+
parameters: {
|
|
221
|
+
type: "object",
|
|
222
|
+
properties: {
|
|
223
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
224
|
+
dept_id: { type: "string", description: "部门 ID" },
|
|
225
|
+
},
|
|
226
|
+
required: ["bot", "dept_id"],
|
|
227
|
+
},
|
|
228
|
+
platforms: ["dingtalk"],
|
|
229
|
+
scopes: ["group", "private"],
|
|
230
|
+
permissionLevel: "user",
|
|
231
|
+
execute: async (args) => {
|
|
232
|
+
const { bot: botId, dept_id } = args;
|
|
233
|
+
const bot = this.bots.get(botId);
|
|
234
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
235
|
+
const info = await bot.getDepartmentInfo(Number(dept_id));
|
|
236
|
+
return info;
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
this.addTool({
|
|
241
|
+
name: "dingtalk_update_chat",
|
|
242
|
+
description: "更新钉钉群聊设置(改名、换群主、增减成员)",
|
|
243
|
+
parameters: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
bot: { type: "string", description: "Bot 名称" },
|
|
247
|
+
chat_id: { type: "string", description: "群聊 ID" },
|
|
248
|
+
name: { type: "string", description: "新群名(可选)" },
|
|
249
|
+
owner: { type: "string", description: "新群主 userId(可选)" },
|
|
250
|
+
add_members: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "要添加的成员 userId,逗号分隔(可选)",
|
|
253
|
+
},
|
|
254
|
+
remove_members: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "要移除的成员 userId,逗号分隔(可选)",
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
required: ["bot", "chat_id"],
|
|
260
|
+
},
|
|
261
|
+
platforms: ["dingtalk"],
|
|
262
|
+
scopes: ["group"],
|
|
263
|
+
permissionLevel: "group_admin",
|
|
264
|
+
execute: async (args) => {
|
|
265
|
+
const {
|
|
266
|
+
bot: botId,
|
|
267
|
+
chat_id,
|
|
268
|
+
name,
|
|
269
|
+
owner,
|
|
270
|
+
add_members,
|
|
271
|
+
remove_members,
|
|
272
|
+
} = args;
|
|
273
|
+
const bot = this.bots.get(botId);
|
|
274
|
+
if (!bot) throw new Error(`Bot ${botId} 不存在`);
|
|
275
|
+
const options: any = {};
|
|
276
|
+
if (name) options.name = name;
|
|
277
|
+
if (owner) options.owner = owner;
|
|
278
|
+
if (add_members)
|
|
279
|
+
options.add_useridlist = add_members
|
|
280
|
+
.split(",")
|
|
281
|
+
.map((s: string) => s.trim());
|
|
282
|
+
if (remove_members)
|
|
283
|
+
options.del_useridlist = remove_members
|
|
284
|
+
.split(",")
|
|
285
|
+
.map((s: string) => s.trim());
|
|
286
|
+
await bot.updateChat(chat_id, options);
|
|
287
|
+
return { success: true, message: "群聊设置已更新" };
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
this.plugin.logger.debug("已注册钉钉平台管理工具");
|
|
292
|
+
}
|
|
293
|
+
}
|
package/src/bot.ts
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 钉钉 Bot 实现
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
Bot,
|
|
6
|
+
Message,
|
|
7
|
+
SendOptions,
|
|
8
|
+
SendContent,
|
|
9
|
+
MessageSegment,
|
|
10
|
+
segment,
|
|
11
|
+
} from "zhin.js";
|
|
12
|
+
import type { Context } from "koa";
|
|
13
|
+
import { createHmac } from "crypto";
|
|
14
|
+
import type {
|
|
15
|
+
DingTalkBotConfig,
|
|
16
|
+
DingTalkMessage,
|
|
17
|
+
DingTalkEvent,
|
|
18
|
+
AccessToken,
|
|
19
|
+
} from "./types.js";
|
|
20
|
+
import type { DingTalkAdapter } from "./adapter.js";
|
|
21
|
+
|
|
22
|
+
export class DingTalkBot implements Bot<DingTalkBotConfig, DingTalkMessage> {
|
|
23
|
+
$connected: boolean;
|
|
24
|
+
private router: any;
|
|
25
|
+
private accessToken: AccessToken;
|
|
26
|
+
private baseURL: string;
|
|
27
|
+
private sessionWebhooks: Map<string, string> = new Map();
|
|
28
|
+
|
|
29
|
+
get $id() {
|
|
30
|
+
return this.$config.name;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get logger() {
|
|
34
|
+
return this.adapter.plugin.logger;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
public adapter: DingTalkAdapter,
|
|
39
|
+
router: any,
|
|
40
|
+
public $config: DingTalkBotConfig
|
|
41
|
+
) {
|
|
42
|
+
this.router = router;
|
|
43
|
+
this.$connected = false;
|
|
44
|
+
this.accessToken = { token: "", expires_in: 0, timestamp: 0 };
|
|
45
|
+
this.baseURL = $config.apiBaseUrl || "https://oapi.dingtalk.com";
|
|
46
|
+
this.setupWebhookRoute();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private async request(
|
|
50
|
+
path: string,
|
|
51
|
+
options: {
|
|
52
|
+
method?: "GET" | "POST";
|
|
53
|
+
params?: Record<string, any>;
|
|
54
|
+
body?: any;
|
|
55
|
+
} = {}
|
|
56
|
+
): Promise<any> {
|
|
57
|
+
await this.ensureAccessToken();
|
|
58
|
+
const { method = "GET", params = {}, body } = options;
|
|
59
|
+
const urlParams = new URLSearchParams({
|
|
60
|
+
...params,
|
|
61
|
+
access_token: this.accessToken.token,
|
|
62
|
+
});
|
|
63
|
+
const url = `${this.baseURL}${path}?${urlParams.toString()}`;
|
|
64
|
+
const fetchOptions: RequestInit = {
|
|
65
|
+
method,
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
if (body && method === "POST") {
|
|
71
|
+
fetchOptions.body = JSON.stringify(body);
|
|
72
|
+
}
|
|
73
|
+
const response = await fetch(url, fetchOptions);
|
|
74
|
+
return await response.json();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private setupWebhookRoute(): void {
|
|
78
|
+
this.router.post(this.$config.webhookPath, (ctx: Context) => {
|
|
79
|
+
this.handleWebhook(ctx);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async handleWebhook(ctx: Context): Promise<void> {
|
|
84
|
+
try {
|
|
85
|
+
const body = (ctx.request as any).body;
|
|
86
|
+
const headers = ctx.request.headers;
|
|
87
|
+
const timestamp = headers["timestamp"] as string;
|
|
88
|
+
const sign = headers["sign"] as string;
|
|
89
|
+
if (timestamp && sign) {
|
|
90
|
+
if (!this.verifySignature(timestamp, sign)) {
|
|
91
|
+
this.logger.warn("Invalid signature in webhook");
|
|
92
|
+
ctx.status = 403;
|
|
93
|
+
ctx.body = { code: -1, msg: "Forbidden" };
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const event: DingTalkEvent = body;
|
|
98
|
+
if (event.msgtype) {
|
|
99
|
+
await this.handleEvent(event);
|
|
100
|
+
}
|
|
101
|
+
ctx.status = 200;
|
|
102
|
+
ctx.body = { code: 0, msg: "success" };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
this.logger.error("Webhook error:", error);
|
|
105
|
+
ctx.status = 500;
|
|
106
|
+
ctx.body = { code: -1, msg: "Internal Server Error" };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private verifySignature(timestamp: string, sign: string): boolean {
|
|
111
|
+
try {
|
|
112
|
+
const stringToSign = `${timestamp}\n${this.$config.appSecret}`;
|
|
113
|
+
const hmac = createHmac("sha256", this.$config.appSecret);
|
|
114
|
+
hmac.update(stringToSign);
|
|
115
|
+
const calculatedSign = hmac.digest("base64");
|
|
116
|
+
return calculatedSign === sign;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
this.logger.error("Signature verification error:", error);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private async handleEvent(event: DingTalkEvent): Promise<void> {
|
|
124
|
+
if (event.sessionWebhook && event.conversationId) {
|
|
125
|
+
this.sessionWebhooks.set(event.conversationId, event.sessionWebhook);
|
|
126
|
+
}
|
|
127
|
+
const message = this.$formatMessage(event as any);
|
|
128
|
+
this.adapter.emit("message.receive", message);
|
|
129
|
+
this.logger.info(
|
|
130
|
+
`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private async ensureAccessToken(): Promise<void> {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
if (
|
|
137
|
+
this.accessToken.token &&
|
|
138
|
+
now <
|
|
139
|
+
this.accessToken.timestamp +
|
|
140
|
+
(this.accessToken.expires_in - 300) * 1000
|
|
141
|
+
) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
await this.refreshAccessToken();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private async refreshAccessToken(): Promise<void> {
|
|
148
|
+
try {
|
|
149
|
+
const baseURL =
|
|
150
|
+
this.$config.apiBaseUrl || "https://oapi.dingtalk.com";
|
|
151
|
+
const params = new URLSearchParams({
|
|
152
|
+
appkey: this.$config.appKey,
|
|
153
|
+
appsecret: this.$config.appSecret,
|
|
154
|
+
});
|
|
155
|
+
const url = `${baseURL}/gettoken?${params.toString()}`;
|
|
156
|
+
const response = await fetch(url);
|
|
157
|
+
const data = await response.json();
|
|
158
|
+
if (data.errcode === 0) {
|
|
159
|
+
this.accessToken = {
|
|
160
|
+
token: data.access_token,
|
|
161
|
+
expires_in: data.expires_in,
|
|
162
|
+
timestamp: Date.now(),
|
|
163
|
+
};
|
|
164
|
+
this.logger.debug("Access token refreshed successfully");
|
|
165
|
+
} else {
|
|
166
|
+
throw new Error(`Failed to get access token: ${data.errmsg}`);
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
this.logger.error("Failed to refresh access token:", error);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
$formatMessage(msg: DingTalkMessage): Message<DingTalkMessage> {
|
|
175
|
+
const content = this.parseMessageContent(msg);
|
|
176
|
+
const chatType = msg.conversationType === "2" ? "group" : "private";
|
|
177
|
+
return Message.from(msg, {
|
|
178
|
+
$id: msg.msgId || Date.now().toString(),
|
|
179
|
+
$adapter: "dingtalk",
|
|
180
|
+
$bot: this.$config.name,
|
|
181
|
+
$sender: {
|
|
182
|
+
id: msg.senderId || msg.senderStaffId || "unknown",
|
|
183
|
+
name: msg.senderNick || msg.senderId || "Unknown User",
|
|
184
|
+
},
|
|
185
|
+
$channel: {
|
|
186
|
+
id: msg.conversationId || "unknown",
|
|
187
|
+
type: chatType as any,
|
|
188
|
+
},
|
|
189
|
+
$content: content,
|
|
190
|
+
$raw: JSON.stringify(msg),
|
|
191
|
+
$timestamp: msg.createAt || Date.now(),
|
|
192
|
+
$recall: async () => {
|
|
193
|
+
await this.$recallMessage(msg.msgId || "");
|
|
194
|
+
},
|
|
195
|
+
$reply: async (content: SendContent): Promise<string> => {
|
|
196
|
+
return await this.adapter.sendMessage({
|
|
197
|
+
context: "dingtalk",
|
|
198
|
+
bot: this.$config.name,
|
|
199
|
+
id: msg.conversationId || msg.senderId || "unknown",
|
|
200
|
+
type: chatType,
|
|
201
|
+
content: content,
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private parseMessageContent(msg: DingTalkMessage): MessageSegment[] {
|
|
208
|
+
const content: MessageSegment[] = [];
|
|
209
|
+
if (!msg.msgtype) return content;
|
|
210
|
+
try {
|
|
211
|
+
switch (msg.msgtype) {
|
|
212
|
+
case "text":
|
|
213
|
+
if (msg.text?.content) {
|
|
214
|
+
content.push(segment("text", { content: msg.text.content }));
|
|
215
|
+
if (msg.atUsers && msg.atUsers.length > 0) {
|
|
216
|
+
for (const atUser of msg.atUsers) {
|
|
217
|
+
content.push(
|
|
218
|
+
segment("at", {
|
|
219
|
+
id: atUser.dingtalkId || atUser.staffId,
|
|
220
|
+
name: atUser.dingtalkId || atUser.staffId,
|
|
221
|
+
})
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
case "picture":
|
|
228
|
+
if (msg.content) {
|
|
229
|
+
content.push(
|
|
230
|
+
segment("image", {
|
|
231
|
+
url:
|
|
232
|
+
msg.content.downloadCode ||
|
|
233
|
+
msg.content.pictureDownloadCode,
|
|
234
|
+
file:
|
|
235
|
+
msg.content.downloadCode ||
|
|
236
|
+
msg.content.pictureDownloadCode,
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
break;
|
|
241
|
+
case "file":
|
|
242
|
+
if (msg.content) {
|
|
243
|
+
content.push(
|
|
244
|
+
segment("file", {
|
|
245
|
+
file: msg.content.downloadCode,
|
|
246
|
+
name: msg.content.fileName,
|
|
247
|
+
size: msg.content.fileSize,
|
|
248
|
+
})
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
case "audio":
|
|
253
|
+
if (msg.content) {
|
|
254
|
+
content.push(
|
|
255
|
+
segment("audio", {
|
|
256
|
+
file: msg.content.downloadCode,
|
|
257
|
+
duration: msg.content.duration,
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case "video":
|
|
263
|
+
if (msg.content) {
|
|
264
|
+
content.push(
|
|
265
|
+
segment("video", {
|
|
266
|
+
file: msg.content.downloadCode,
|
|
267
|
+
duration: msg.content.duration,
|
|
268
|
+
size: msg.content.videoSize,
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
break;
|
|
273
|
+
case "richText":
|
|
274
|
+
if (msg.content?.richText) {
|
|
275
|
+
for (const item of msg.content.richText) {
|
|
276
|
+
if (item.text) {
|
|
277
|
+
content.push(segment("text", { content: item.text }));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
break;
|
|
282
|
+
case "markdown":
|
|
283
|
+
if (msg.content?.text) {
|
|
284
|
+
content.push(
|
|
285
|
+
segment("markdown", {
|
|
286
|
+
content: msg.content.text,
|
|
287
|
+
title: msg.content.title,
|
|
288
|
+
})
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
content.push(
|
|
294
|
+
segment("text", {
|
|
295
|
+
content: `[不支持的消息类型: ${msg.msgtype}]`,
|
|
296
|
+
})
|
|
297
|
+
);
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
this.logger.error("Failed to parse message content:", error);
|
|
302
|
+
content.push(segment("text", { content: "[消息解析失败]" }));
|
|
303
|
+
}
|
|
304
|
+
return content;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async $sendMessage(options: SendOptions): Promise<string> {
|
|
308
|
+
const conversationId = options.id;
|
|
309
|
+
const content = this.formatSendContent(options.content);
|
|
310
|
+
try {
|
|
311
|
+
const sessionWebhook = this.sessionWebhooks.get(conversationId);
|
|
312
|
+
if (sessionWebhook) {
|
|
313
|
+
const response = await fetch(sessionWebhook, {
|
|
314
|
+
method: "POST",
|
|
315
|
+
headers: {
|
|
316
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
317
|
+
},
|
|
318
|
+
body: JSON.stringify(content),
|
|
319
|
+
});
|
|
320
|
+
const data = await response.json();
|
|
321
|
+
if (data.errcode !== 0) {
|
|
322
|
+
throw new Error(
|
|
323
|
+
`Failed to send message via session webhook: ${data.errmsg}`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
this.logger.debug("Message sent via session webhook");
|
|
327
|
+
return data.msgId || Date.now().toString();
|
|
328
|
+
}
|
|
329
|
+
const data = await this.request("/robot/send", {
|
|
330
|
+
method: "POST",
|
|
331
|
+
body: {
|
|
332
|
+
...content,
|
|
333
|
+
robotCode: this.$config.robotCode,
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
if (data.errcode !== 0) {
|
|
337
|
+
throw new Error(`Failed to send message: ${data.errmsg}`);
|
|
338
|
+
}
|
|
339
|
+
this.logger.debug("Message sent successfully");
|
|
340
|
+
return data.msgId || Date.now().toString();
|
|
341
|
+
} catch (error) {
|
|
342
|
+
this.logger.error("Failed to send message:", error);
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
async $recallMessage(id: string): Promise<void> {
|
|
348
|
+
this.logger.warn("DingTalk robot does not support message recall");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
private formatSendContent(content: SendContent): any {
|
|
352
|
+
if (typeof content === "string") {
|
|
353
|
+
return { msgtype: "text", text: { content } };
|
|
354
|
+
}
|
|
355
|
+
if (Array.isArray(content)) {
|
|
356
|
+
const textParts: string[] = [];
|
|
357
|
+
const atUserIds: string[] = [];
|
|
358
|
+
let hasMedia = false;
|
|
359
|
+
let mediaContent: any = null;
|
|
360
|
+
for (const item of content) {
|
|
361
|
+
if (typeof item === "string") {
|
|
362
|
+
textParts.push(item);
|
|
363
|
+
} else {
|
|
364
|
+
const seg = item as MessageSegment;
|
|
365
|
+
switch (seg.type) {
|
|
366
|
+
case "text":
|
|
367
|
+
textParts.push(seg.data.content || seg.data.text || "");
|
|
368
|
+
break;
|
|
369
|
+
case "at":
|
|
370
|
+
const userId = seg.data.id || seg.data.userId;
|
|
371
|
+
if (userId) {
|
|
372
|
+
atUserIds.push(userId);
|
|
373
|
+
textParts.push(`@${seg.data.name || userId} `);
|
|
374
|
+
}
|
|
375
|
+
break;
|
|
376
|
+
case "image":
|
|
377
|
+
if (!hasMedia) {
|
|
378
|
+
hasMedia = true;
|
|
379
|
+
mediaContent = {
|
|
380
|
+
msgtype: "picture",
|
|
381
|
+
picture: {
|
|
382
|
+
picURL: seg.data.url || seg.data.file,
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
break;
|
|
387
|
+
case "markdown":
|
|
388
|
+
if (!hasMedia) {
|
|
389
|
+
hasMedia = true;
|
|
390
|
+
mediaContent = {
|
|
391
|
+
msgtype: "markdown",
|
|
392
|
+
markdown: {
|
|
393
|
+
title: seg.data.title || "消息",
|
|
394
|
+
text: seg.data.content || seg.data.text,
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
399
|
+
case "link":
|
|
400
|
+
if (!hasMedia) {
|
|
401
|
+
hasMedia = true;
|
|
402
|
+
mediaContent = {
|
|
403
|
+
msgtype: "link",
|
|
404
|
+
link: {
|
|
405
|
+
title: seg.data.title || "链接",
|
|
406
|
+
text: seg.data.text || seg.data.content || "",
|
|
407
|
+
messageUrl: seg.data.url,
|
|
408
|
+
picUrl: seg.data.picUrl,
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (hasMedia && mediaContent) return mediaContent;
|
|
417
|
+
const result: any = {
|
|
418
|
+
msgtype: "text",
|
|
419
|
+
text: { content: textParts.join("") },
|
|
420
|
+
};
|
|
421
|
+
if (atUserIds.length > 0) {
|
|
422
|
+
result.at = { atUserIds, isAtAll: false };
|
|
423
|
+
}
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
return { msgtype: "text", text: { content: String(content) } };
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async $connect(): Promise<void> {
|
|
430
|
+
try {
|
|
431
|
+
await this.refreshAccessToken();
|
|
432
|
+
this.$connected = true;
|
|
433
|
+
this.logger.info(`DingTalk bot connected: ${this.$config.name}`);
|
|
434
|
+
this.logger.info(`Webhook URL: ${this.$config.webhookPath}`);
|
|
435
|
+
} catch (error) {
|
|
436
|
+
this.logger.error("Failed to connect DingTalk bot:", error);
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async $disconnect(): Promise<void> {
|
|
442
|
+
try {
|
|
443
|
+
this.$connected = false;
|
|
444
|
+
this.logger.info("DingTalk bot disconnected");
|
|
445
|
+
} catch (error) {
|
|
446
|
+
this.logger.error("Error disconnecting DingTalk bot:", error);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
async getUserInfo(userId: string): Promise<any> {
|
|
451
|
+
try {
|
|
452
|
+
const data = await this.request("/topapi/v2/user/get", {
|
|
453
|
+
method: "POST",
|
|
454
|
+
body: { userid: userId },
|
|
455
|
+
});
|
|
456
|
+
if (data.errcode === 0) return data.result;
|
|
457
|
+
throw new Error(`Failed to get user info: ${data.errmsg}`);
|
|
458
|
+
} catch (error) {
|
|
459
|
+
this.logger.error("Failed to get user info:", error);
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async getDepartmentUsers(deptId: number): Promise<any[]> {
|
|
465
|
+
try {
|
|
466
|
+
const data = await this.request("/topapi/user/listid", {
|
|
467
|
+
method: "POST",
|
|
468
|
+
body: { dept_id: deptId },
|
|
469
|
+
});
|
|
470
|
+
if (data.errcode === 0) return data.result.userid_list || [];
|
|
471
|
+
throw new Error(`Failed to get department users: ${data.errmsg}`);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
this.logger.error("Failed to get department users:", error);
|
|
474
|
+
return [];
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async sendWorkNotice(userIdList: string[], content: any): Promise<boolean> {
|
|
479
|
+
try {
|
|
480
|
+
const data = await this.request(
|
|
481
|
+
"/topapi/message/corpconversation/asyncsend_v2",
|
|
482
|
+
{
|
|
483
|
+
method: "POST",
|
|
484
|
+
body: {
|
|
485
|
+
agent_id: this.$config.robotCode,
|
|
486
|
+
userid_list: userIdList.join(","),
|
|
487
|
+
msg: content,
|
|
488
|
+
},
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
if (data.errcode === 0) {
|
|
492
|
+
this.logger.debug("Work notice sent successfully");
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
throw new Error(`Failed to send work notice: ${data.errmsg}`);
|
|
496
|
+
} catch (error) {
|
|
497
|
+
this.logger.error("Failed to send work notice:", error);
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async getDepartmentList(deptId: number = 1): Promise<any[]> {
|
|
503
|
+
try {
|
|
504
|
+
const data = await this.request("/topapi/v2/department/listsub", {
|
|
505
|
+
method: "POST",
|
|
506
|
+
body: { dept_id: deptId },
|
|
507
|
+
});
|
|
508
|
+
if (data.errcode === 0) return data.result || [];
|
|
509
|
+
throw new Error(`Failed to get department list: ${data.errmsg}`);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
this.logger.error("Failed to get department list:", error);
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async getDepartmentInfo(deptId: number): Promise<any> {
|
|
517
|
+
try {
|
|
518
|
+
const data = await this.request("/topapi/v2/department/get", {
|
|
519
|
+
method: "POST",
|
|
520
|
+
body: { dept_id: deptId },
|
|
521
|
+
});
|
|
522
|
+
if (data.errcode === 0) return data.result;
|
|
523
|
+
throw new Error(`Failed to get department info: ${data.errmsg}`);
|
|
524
|
+
} catch (error) {
|
|
525
|
+
this.logger.error("Failed to get department info:", error);
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async createChat(
|
|
531
|
+
name: string,
|
|
532
|
+
ownerUserId: string,
|
|
533
|
+
userIdList: string[]
|
|
534
|
+
): Promise<string | null> {
|
|
535
|
+
try {
|
|
536
|
+
const data = await this.request("/topapi/chat/create", {
|
|
537
|
+
method: "POST",
|
|
538
|
+
body: {
|
|
539
|
+
name,
|
|
540
|
+
owner: ownerUserId,
|
|
541
|
+
useridlist: userIdList,
|
|
542
|
+
},
|
|
543
|
+
});
|
|
544
|
+
if (data.errcode === 0) {
|
|
545
|
+
this.logger.info(`创建群聊成功: ${data.chatid}`);
|
|
546
|
+
return data.chatid;
|
|
547
|
+
}
|
|
548
|
+
throw new Error(`Failed to create chat: ${data.errmsg}`);
|
|
549
|
+
} catch (error) {
|
|
550
|
+
this.logger.error("Failed to create chat:", error);
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async getChatInfo(chatId: string): Promise<any> {
|
|
556
|
+
try {
|
|
557
|
+
const data = await this.request("/topapi/chat/get", {
|
|
558
|
+
method: "POST",
|
|
559
|
+
body: { chatid: chatId },
|
|
560
|
+
});
|
|
561
|
+
if (data.errcode === 0) return data.chat_info;
|
|
562
|
+
throw new Error(`Failed to get chat info: ${data.errmsg}`);
|
|
563
|
+
} catch (error) {
|
|
564
|
+
this.logger.error("Failed to get chat info:", error);
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
async updateChat(
|
|
570
|
+
chatId: string,
|
|
571
|
+
options: {
|
|
572
|
+
name?: string;
|
|
573
|
+
owner?: string;
|
|
574
|
+
add_useridlist?: string[];
|
|
575
|
+
del_useridlist?: string[];
|
|
576
|
+
}
|
|
577
|
+
): Promise<boolean> {
|
|
578
|
+
try {
|
|
579
|
+
const data = await this.request("/topapi/chat/update", {
|
|
580
|
+
method: "POST",
|
|
581
|
+
body: { chatid: chatId, ...options },
|
|
582
|
+
});
|
|
583
|
+
if (data.errcode === 0) {
|
|
584
|
+
this.logger.info(`更新群聊成功: ${chatId}`);
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
throw new Error(`Failed to update chat: ${data.errmsg}`);
|
|
588
|
+
} catch (error) {
|
|
589
|
+
this.logger.error("Failed to update chat:", error);
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 钉钉适配器入口:类型扩展、导出、注册
|
|
3
|
+
*/
|
|
4
|
+
import { usePlugin, type Plugin } from "zhin.js";
|
|
5
|
+
import { DingTalkAdapter } from "./adapter.js";
|
|
6
|
+
|
|
7
|
+
declare module "zhin.js" {
|
|
8
|
+
namespace Plugin {
|
|
9
|
+
interface Contexts {
|
|
10
|
+
router: import("@zhin.js/http").Router;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
interface Adapters {
|
|
14
|
+
dingtalk: DingTalkAdapter;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export * from "./types.js";
|
|
19
|
+
export { DingTalkBot } from "./bot.js";
|
|
20
|
+
export { DingTalkAdapter } from "./adapter.js";
|
|
21
|
+
|
|
22
|
+
const plugin = usePlugin();
|
|
23
|
+
const { provide, useContext } = plugin;
|
|
24
|
+
|
|
25
|
+
useContext("router", (router: any) => {
|
|
26
|
+
provide({
|
|
27
|
+
name: "dingtalk",
|
|
28
|
+
description: "DingTalk Bot Adapter",
|
|
29
|
+
mounted: async (p: Plugin) => {
|
|
30
|
+
const adapter = new DingTalkAdapter(p, router);
|
|
31
|
+
await adapter.start();
|
|
32
|
+
return adapter;
|
|
33
|
+
},
|
|
34
|
+
dispose: async (adapter: DingTalkAdapter) => {
|
|
35
|
+
await adapter.stop();
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 钉钉适配器类型定义
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface DingTalkBotConfig {
|
|
6
|
+
context: "dingtalk";
|
|
7
|
+
name: string;
|
|
8
|
+
appKey: string;
|
|
9
|
+
appSecret: string;
|
|
10
|
+
webhookPath: string;
|
|
11
|
+
robotCode?: string;
|
|
12
|
+
apiBaseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DingTalkMessage {
|
|
16
|
+
msgtype?: string;
|
|
17
|
+
text?: { content?: string };
|
|
18
|
+
msgId?: string;
|
|
19
|
+
createAt?: number;
|
|
20
|
+
conversationType?: string;
|
|
21
|
+
conversationId?: string;
|
|
22
|
+
senderId?: string;
|
|
23
|
+
senderNick?: string;
|
|
24
|
+
senderCorpId?: string;
|
|
25
|
+
sessionWebhook?: string;
|
|
26
|
+
chatbotCorpId?: string;
|
|
27
|
+
chatbotUserId?: string;
|
|
28
|
+
isAdmin?: boolean;
|
|
29
|
+
senderStaffId?: string;
|
|
30
|
+
atUsers?: Array<{ dingtalkId?: string; staffId?: string }>;
|
|
31
|
+
content?: any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface DingTalkEvent {
|
|
35
|
+
msgtype?: string;
|
|
36
|
+
text?: any;
|
|
37
|
+
conversationId?: string;
|
|
38
|
+
atUsers?: any[];
|
|
39
|
+
chatbotUserId?: string;
|
|
40
|
+
msgId?: string;
|
|
41
|
+
senderNick?: string;
|
|
42
|
+
isAdmin?: boolean;
|
|
43
|
+
senderStaffId?: string;
|
|
44
|
+
sessionWebhook?: string;
|
|
45
|
+
createAt?: number;
|
|
46
|
+
senderCorpId?: string;
|
|
47
|
+
conversationType?: string;
|
|
48
|
+
senderId?: string;
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface AccessToken {
|
|
53
|
+
token: string;
|
|
54
|
+
expires_in: number;
|
|
55
|
+
timestamp: number;
|
|
56
|
+
}
|