@lixiongwei/n8n-nodes-feishu 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/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # n8n-nodes-feishu
2
+
3
+ > 飞书/Lark 集成节点,免费功能 + Pro License。附带 5 个即用工作流模板。
4
+
5
+ ---
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install n8n-nodes-feishu
11
+ ```
12
+
13
+ n8n 自托管版直接在 n8n 所在目录执行。云版不支持社区节点。
14
+
15
+ ---
16
+
17
+ ## 免费功能 🆓
18
+
19
+ | 功能 | 说明 |
20
+ |------|------|
21
+ | **发送文本消息** | 给用户/群发文本消息 |
22
+ | **消息触发器** | 接收飞书事件回调 |
23
+
24
+ ---
25
+
26
+ ## Pro 功能 ⭐ (需 License Key)
27
+
28
+ | 功能 | 说明 |
29
+ |------|------|
30
+ | **发送卡片消息** | 富文本卡片模板 + Markdown |
31
+ | **读取多维表格** | 按字段读取 Bitable 数据 |
32
+ | **写入多维表格** | 写入新行到 Bitable |
33
+ | **获取待审批列表** | 查询审批实例 |
34
+
35
+ ---
36
+
37
+ ## 获取 License Key
38
+
39
+ 👉 **[在 Gumroad 购买](https://gumroad.com/l/feishu-pro)** — $49 一次性,永久使用。
40
+
41
+ 购买后在凭证管理里填入 Key,Pro 功能即刻解锁。
42
+
43
+ ---
44
+
45
+ ## 附带工作流模板
46
+
47
+ 在 `workflows/` 目录下,导入即用:
48
+
49
+ | 模板 | 场景 |
50
+ |------|------|
51
+ | `template-01-send-message.json` | Webhook → 飞书消息 |
52
+ | `template-02-cron-reminder.json` | 定时 → 飞书提醒 |
53
+ | `template-03-website-monitor.json` | 网站监控 → 飞书告警 |
54
+ | `template-04-form-notify.json` | 表单提交 → 卡片通知 |
55
+ | `template-05-api-to-feishu.json` | API 数据 → 飞书推送 |
56
+
57
+ ---
58
+
59
+ ## 飞书应用配置
60
+
61
+ 1. 飞书开发者后台创建 **企业自建应用**
62
+ 2. 开启 **机器人** 能力
63
+ 3. 权限管理开通:`im:message:send_as_bot`
64
+ 4. 发布应用
65
+ 5. 在 n8n 凭证中填入 App ID + App Secret + License Key
66
+
67
+ ---
68
+
69
+ ## 版本
70
+
71
+ - n8n 版本要求:1.x+
72
+ - 飞书 API 版本:v3
@@ -0,0 +1,7 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class FeishuApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeishuApi = void 0;
4
+ class FeishuApi {
5
+ constructor() {
6
+ this.name = 'feishuApi';
7
+ this.displayName = '飞书 Feishu API';
8
+ this.documentationUrl = 'https://open.feishu.cn/document/home/getting-started';
9
+ this.properties = [
10
+ {
11
+ displayName: 'App ID',
12
+ name: 'appId',
13
+ type: 'string',
14
+ default: '',
15
+ description: '飞书应用的 App ID(从开发者后台-凭证与基础信息获取)',
16
+ required: true,
17
+ },
18
+ {
19
+ displayName: 'App Secret',
20
+ name: 'appSecret',
21
+ type: 'string',
22
+ typeOptions: { password: true },
23
+ default: '',
24
+ description: '飞书应用的 App Secret',
25
+ required: true,
26
+ },
27
+ {
28
+ displayName: 'License Key',
29
+ name: 'licenseKey',
30
+ type: 'string',
31
+ default: '',
32
+ description: 'Pro License Key — 从 Gumroad 购买获取。留空则仅使用免费功能',
33
+ required: false,
34
+ },
35
+ ];
36
+ }
37
+ }
38
+ exports.FeishuApi = FeishuApi;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Feishu implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Feishu = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const license_1 = require("./license");
6
+ // --- Operation definitions ---
7
+ const FREE_OPERATIONS = ['sendTextMessage'];
8
+ const PRO_OPERATIONS = ['sendCardMessage', 'readBitable', 'writeBitable', 'getApprovals'];
9
+ // --- Token cache (in-memory, per-node lifetime) ---
10
+ let cachedToken = null;
11
+ let tokenExpiry = 0;
12
+ async function getFeishuToken(appId, appSecret) {
13
+ if (cachedToken && Date.now() < tokenExpiry) {
14
+ return cachedToken;
15
+ }
16
+ const response = await this.helpers.request({
17
+ method: 'POST',
18
+ url: 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
19
+ headers: { 'Content-Type': 'application/json' },
20
+ body: { app_id: appId, app_secret: appSecret },
21
+ json: true,
22
+ });
23
+ if (response.code !== 0) {
24
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `飞书 Token 获取失败:${response.msg} (code: ${response.code})`);
25
+ }
26
+ cachedToken = response.tenant_access_token;
27
+ tokenExpiry = Date.now() + (response.expire - 300) * 1000;
28
+ return cachedToken;
29
+ }
30
+ // --- Node Description ---
31
+ class Feishu {
32
+ constructor() {
33
+ this.description = {
34
+ displayName: '飞书 Feishu',
35
+ name: 'feishu',
36
+ icon: 'file:feishu.svg',
37
+ group: ['transform'],
38
+ version: 1,
39
+ subtitle: '={{ $parameter["operation"] }}',
40
+ description: '飞书集成:发消息、读多维表格、处理审批',
41
+ defaults: { name: '飞书 Feishu' },
42
+ inputs: ["main"],
43
+ outputs: ["main"],
44
+ credentials: [{ name: 'feishuApi', required: true }],
45
+ properties: [
46
+ // --- Operation selector ---
47
+ {
48
+ displayName: '操作 Operation',
49
+ name: 'operation',
50
+ type: 'options',
51
+ noDataExpression: true,
52
+ options: [
53
+ { name: '🆓 发送文本消息 (免费)', value: 'sendTextMessage' },
54
+ { name: '⭐ 发送卡片消息 (Pro)', value: 'sendCardMessage' },
55
+ { name: '⭐ 读取多维表格 (Pro)', value: 'readBitable' },
56
+ { name: '⭐ 写入多维表格 (Pro)', value: 'writeBitable' },
57
+ { name: '⭐ 获取待审批列表 (Pro)', value: 'getApprovals' },
58
+ ],
59
+ default: 'sendTextMessage',
60
+ description: 'Pro 功能需要 License Key',
61
+ },
62
+ // --- Send Text Message (Free) ---
63
+ {
64
+ displayName: '接收人 ID 类型',
65
+ name: 'receiveIdType',
66
+ type: 'options',
67
+ options: [
68
+ { name: '用户 Open ID', value: 'open_id' },
69
+ { name: '用户 User ID', value: 'user_id' },
70
+ { name: '邮箱', value: 'email' },
71
+ { name: '群 Chat ID', value: 'chat_id' },
72
+ ],
73
+ default: 'open_id',
74
+ displayOptions: { show: { operation: ['sendTextMessage', 'sendCardMessage'] } },
75
+ },
76
+ {
77
+ displayName: '接收人',
78
+ name: 'receiveId',
79
+ type: 'string',
80
+ default: '',
81
+ required: true,
82
+ displayOptions: { show: { operation: ['sendTextMessage', 'sendCardMessage'] } },
83
+ placeholder: 'ou_xxx 或 chat_xxx 或 email',
84
+ description: '接收人的 open_id、user_id、邮箱或群的 chat_id',
85
+ },
86
+ {
87
+ displayName: '消息内容',
88
+ name: 'textContent',
89
+ type: 'string',
90
+ typeOptions: { rows: 4 },
91
+ default: '',
92
+ required: true,
93
+ displayOptions: { show: { operation: ['sendTextMessage'] } },
94
+ placeholder: '输入要发送的消息...',
95
+ },
96
+ // --- Send Card Message (Pro) ---
97
+ {
98
+ displayName: '卡片标题',
99
+ name: 'cardTitle',
100
+ type: 'string',
101
+ default: '📢 通知',
102
+ displayOptions: { show: { operation: ['sendCardMessage'] } },
103
+ },
104
+ {
105
+ displayName: '卡片内容 (支持 Markdown)',
106
+ name: 'cardContent',
107
+ type: 'string',
108
+ typeOptions: { rows: 6 },
109
+ default: '',
110
+ required: true,
111
+ displayOptions: { show: { operation: ['sendCardMessage'] } },
112
+ placeholder: '**标题**\n内容...',
113
+ },
114
+ // --- Read Bitable (Pro) ---
115
+ {
116
+ displayName: '多维表格 App Token',
117
+ name: 'bitableAppToken',
118
+ type: 'string',
119
+ default: '',
120
+ required: true,
121
+ displayOptions: { show: { operation: ['readBitable', 'writeBitable'] } },
122
+ description: '多维表格 URL 中的 app token,如 /base/XXX 的 XXX 部分',
123
+ },
124
+ {
125
+ displayName: '表 ID',
126
+ name: 'tableId',
127
+ type: 'string',
128
+ default: '',
129
+ required: true,
130
+ displayOptions: { show: { operation: ['readBitable', 'writeBitable'] } },
131
+ placeholder: 'tblXXXXXXXXXXXXX',
132
+ },
133
+ // --- Write Bitable (Pro) ---
134
+ {
135
+ displayName: '写入数据 (JSON)',
136
+ name: 'bitableFields',
137
+ type: 'json',
138
+ default: '{"字段名": "值"}',
139
+ required: true,
140
+ displayOptions: { show: { operation: ['writeBitable'] } },
141
+ description: '要写入的字段和值,JSON 格式',
142
+ },
143
+ ],
144
+ };
145
+ }
146
+ // --- Execute ---
147
+ async execute() {
148
+ const items = this.getInputData();
149
+ const returnData = [];
150
+ // Get credentials
151
+ const credentials = await this.getCredentials('feishuApi');
152
+ const appId = credentials.appId;
153
+ const appSecret = credentials.appSecret;
154
+ const licenseKey = credentials.licenseKey || '';
155
+ for (let i = 0; i < items.length; i++) {
156
+ try {
157
+ const operation = this.getNodeParameter('operation', i);
158
+ // --- License check for Pro operations ---
159
+ if (PRO_OPERATIONS.includes(operation)) {
160
+ if (!licenseKey) {
161
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), '⭐ 这是 Pro 功能。请在凭证中填写 License Key。\n' +
162
+ '👉 购买 License Key:https://gumroad.com/l/feishu-pro\n' +
163
+ '👉 获取免费 Key 试用 7 天:https://gumroad.com/l/feishu-pro');
164
+ }
165
+ const validation = await license_1.validateLicense.call(this, licenseKey, appId);
166
+ if (!validation.valid) {
167
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `License Key 无效或已过期:${validation.reason}`);
168
+ }
169
+ }
170
+ // Get token
171
+ const token = await getFeishuToken.call(this, appId, appSecret);
172
+ // Execute operation
173
+ switch (operation) {
174
+ case 'sendTextMessage': {
175
+ const receiveIdType = this.getNodeParameter('receiveIdType', i);
176
+ const receiveId = this.getNodeParameter('receiveId', i);
177
+ const textContent = this.getNodeParameter('textContent', i);
178
+ const response = await this.helpers.request({
179
+ method: 'POST',
180
+ url: `https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`,
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ Authorization: `Bearer ${token}`,
184
+ },
185
+ body: {
186
+ receive_id: receiveId,
187
+ msg_type: 'text',
188
+ content: JSON.stringify({ text: textContent }),
189
+ },
190
+ json: true,
191
+ });
192
+ returnData.push({ json: response });
193
+ break;
194
+ }
195
+ case 'sendCardMessage': {
196
+ const receiveIdType = this.getNodeParameter('receiveIdType', i);
197
+ const receiveId = this.getNodeParameter('receiveId', i);
198
+ const cardTitle = this.getNodeParameter('cardTitle', i);
199
+ const cardContent = this.getNodeParameter('cardContent', i);
200
+ const response = await this.helpers.request({
201
+ method: 'POST',
202
+ url: `https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${receiveIdType}`,
203
+ headers: {
204
+ 'Content-Type': 'application/json',
205
+ Authorization: `Bearer ${token}`,
206
+ },
207
+ body: {
208
+ receive_id: receiveId,
209
+ msg_type: 'interactive',
210
+ content: JSON.stringify({
211
+ config: { wide_screen_mode: true },
212
+ header: {
213
+ title: { tag: 'plain_text', content: cardTitle },
214
+ },
215
+ elements: [
216
+ {
217
+ tag: 'div',
218
+ text: { tag: 'lark_md', content: cardContent },
219
+ },
220
+ ],
221
+ }),
222
+ },
223
+ json: true,
224
+ });
225
+ returnData.push({ json: response });
226
+ break;
227
+ }
228
+ case 'readBitable': {
229
+ const appToken = this.getNodeParameter('bitableAppToken', i);
230
+ const tableId = this.getNodeParameter('tableId', i);
231
+ const response = await this.helpers.request({
232
+ method: 'GET',
233
+ url: `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records?page_size=100`,
234
+ headers: { Authorization: `Bearer ${token}` },
235
+ json: true,
236
+ });
237
+ const records = (response.data?.items || []).map((item) => item.fields);
238
+ returnData.push({ json: { total: response.data?.total || 0, records } });
239
+ break;
240
+ }
241
+ case 'writeBitable': {
242
+ const appToken = this.getNodeParameter('bitableAppToken', i);
243
+ const tableId = this.getNodeParameter('tableId', i);
244
+ const fields = this.getNodeParameter('bitableFields', i);
245
+ const response = await this.helpers.request({
246
+ method: 'POST',
247
+ url: `https://open.feishu.cn/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records`,
248
+ headers: {
249
+ 'Content-Type': 'application/json',
250
+ Authorization: `Bearer ${token}`,
251
+ },
252
+ body: { fields: typeof fields === 'string' ? JSON.parse(fields) : fields },
253
+ json: true,
254
+ });
255
+ returnData.push({ json: response });
256
+ break;
257
+ }
258
+ case 'getApprovals': {
259
+ const response = await this.helpers.request({
260
+ method: 'GET',
261
+ url: 'https://open.feishu.cn/open-apis/approval/v4/instances?page_size=20&status=PENDING',
262
+ headers: { Authorization: `Bearer ${token}` },
263
+ json: true,
264
+ });
265
+ const instances = (response.data?.instance_list || []).map((inst) => ({
266
+ instanceCode: inst.instance_code,
267
+ approvalName: inst.approval_name,
268
+ startTime: inst.start_time,
269
+ status: inst.status,
270
+ }));
271
+ returnData.push({ json: { pending: instances.length, instances } });
272
+ break;
273
+ }
274
+ }
275
+ }
276
+ catch (error) {
277
+ if (error instanceof n8n_workflow_1.NodeOperationError) {
278
+ returnData.push({ json: { error: error.message }, error });
279
+ }
280
+ else {
281
+ returnData.push({
282
+ json: { error: error.message || 'Unknown error' },
283
+ });
284
+ }
285
+ }
286
+ }
287
+ return [returnData];
288
+ }
289
+ }
290
+ exports.Feishu = Feishu;
@@ -0,0 +1,5 @@
1
+ import { IWebhookFunctions, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
2
+ export declare class FeishuTrigger implements INodeType {
3
+ description: INodeTypeDescription;
4
+ webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
5
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FeishuTrigger = void 0;
4
+ class FeishuTrigger {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: '飞书触发器 Feishu Trigger',
8
+ name: 'feishuTrigger',
9
+ icon: 'file:feishu.svg',
10
+ group: ['trigger'],
11
+ version: 1,
12
+ subtitle: '={{ $parameter["event"] }}',
13
+ description: '监听飞书事件:消息接收、审批状态变化',
14
+ defaults: { name: '飞书 Trigger' },
15
+ inputs: [],
16
+ outputs: ["main"],
17
+ credentials: [{ name: 'feishuApi', required: true }],
18
+ webhooks: [
19
+ {
20
+ name: 'default',
21
+ httpMethod: 'POST',
22
+ responseMode: 'onReceived',
23
+ path: 'feishu-webhook',
24
+ },
25
+ ],
26
+ properties: [
27
+ {
28
+ displayName: '事件类型',
29
+ name: 'event',
30
+ type: 'options',
31
+ options: [
32
+ { name: '🆓 消息接收 (免费)', value: 'message_receive' },
33
+ { name: '⭐ 审批状态变化 (Pro)', value: 'approval_change' },
34
+ ],
35
+ default: 'message_receive',
36
+ description: 'Pro 功能需要 License Key',
37
+ },
38
+ {
39
+ displayName: '验证 Token',
40
+ name: 'verificationToken',
41
+ type: 'string',
42
+ default: '',
43
+ description: '飞书事件订阅的 Verification Token,用于验证回调来源',
44
+ },
45
+ ],
46
+ };
47
+ }
48
+ async webhook() {
49
+ const req = this.getRequestObject();
50
+ const body = req.body;
51
+ // Handle Feishu URL verification challenge
52
+ if (body?.type === 'url_verification') {
53
+ return {
54
+ webhookResponse: { challenge: body.challenge },
55
+ workflowData: [],
56
+ };
57
+ }
58
+ // Handle event
59
+ const event = body?.event || {};
60
+ const header = body?.header || {};
61
+ return {
62
+ webhookResponse: { code: 0, msg: 'ok' },
63
+ workflowData: [
64
+ [
65
+ {
66
+ json: {
67
+ eventType: header.event_type || 'unknown',
68
+ eventId: header.event_id || '',
69
+ appId: header.app_id || '',
70
+ tenantKey: header.tenant_key || '',
71
+ senderOpenId: event.sender?.sender_id?.open_id || '',
72
+ messageType: event.message?.msg_type || '',
73
+ messageContent: event.message?.content || '',
74
+ sourceData: event,
75
+ },
76
+ },
77
+ ],
78
+ ],
79
+ };
80
+ }
81
+ }
82
+ exports.FeishuTrigger = FeishuTrigger;
@@ -0,0 +1,14 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ interface ValidationResult {
3
+ valid: boolean;
4
+ reason?: string;
5
+ plan?: string;
6
+ expiry?: string;
7
+ }
8
+ /**
9
+ * Offline-first license validation.
10
+ * When VALIDATION_URL is set, also tries remote validation.
11
+ * When empty (default), uses built-in key verification.
12
+ */
13
+ export declare function validateLicense(this: IExecuteFunctions, licenseKey: string, _appId: string): Promise<ValidationResult>;
14
+ export {};
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateLicense = validateLicense;
4
+ // Optional: remote validation URL. Set to '' to use offline-only mode.
5
+ const VALIDATION_URL = '';
6
+ // In-memory cache
7
+ const cache = new Map();
8
+ /**
9
+ * Offline-first license validation.
10
+ * When VALIDATION_URL is set, also tries remote validation.
11
+ * When empty (default), uses built-in key verification.
12
+ */
13
+ async function validateLicense(licenseKey, _appId) {
14
+ const cached = cache.get(licenseKey);
15
+ if (cached && Date.now() - cached.ts < 86400000) {
16
+ return cached.result;
17
+ }
18
+ // --- Local validation ---
19
+ const result = validateLocal(licenseKey);
20
+ // --- Optional: try remote validation ---
21
+ if (VALIDATION_URL) {
22
+ try {
23
+ const response = await this.helpers.request({
24
+ method: 'POST',
25
+ url: VALIDATION_URL,
26
+ headers: { 'Content-Type': 'application/json' },
27
+ body: { key: licenseKey },
28
+ json: true,
29
+ timeout: 5000,
30
+ });
31
+ const remoteResult = response;
32
+ cache.set(licenseKey, { result: remoteResult, ts: Date.now() });
33
+ return remoteResult;
34
+ }
35
+ catch {
36
+ // Network fail — fall back to local result
37
+ }
38
+ }
39
+ cache.set(licenseKey, { result, ts: Date.now() });
40
+ return result;
41
+ }
42
+ /**
43
+ * Local key validation.
44
+ * Format: FLS-XXXX-XXXX-XXXX
45
+ * - TRIAL prefix ⇒ 7-day trial
46
+ * - PRO prefix ⇒ lifetime
47
+ * - Matches known test keys
48
+ */
49
+ function validateLocal(key) {
50
+ const cleaned = key.trim().toUpperCase();
51
+ // Test keys (hardcoded for MVP)
52
+ const TEST_KEYS = {
53
+ 'FLS-TEST-PRO-KEY1': { plan: 'pro' },
54
+ 'FLS-TEST-TRIAL-KEY': { plan: 'trial' },
55
+ };
56
+ if (TEST_KEYS[cleaned]) {
57
+ return {
58
+ valid: true,
59
+ plan: TEST_KEYS[cleaned].plan,
60
+ expiry: TEST_KEYS[cleaned].plan === 'trial' ? '7 days' : 'lifetime',
61
+ };
62
+ }
63
+ // Pattern-based: valid if matches FLS-PRO-XXXXXXXX format
64
+ if (/^FLS-PRO-[A-Z0-9]{4,}$/.test(cleaned)) {
65
+ return { valid: true, plan: 'pro', expiry: 'lifetime' };
66
+ }
67
+ if (/^FLS-(TRIAL|TEST)-/.test(cleaned)) {
68
+ return { valid: true, plan: 'trial', expiry: '7 days' };
69
+ }
70
+ return { valid: false, reason: '无效的 License Key' };
71
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@lixiongwei/n8n-nodes-feishu",
3
+ "version": "1.0.0",
4
+ "description": "飞书/Lark nodes for n8n — send messages, manage bitables, process approvals. Free tier + Pro license.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "dev": "tsc --watch",
9
+ "prepublishOnly": "npm run build"
10
+ },
11
+ "keywords": [
12
+ "n8n-community-node-package",
13
+ "n8n",
14
+ "feishu",
15
+ "lark",
16
+ "飞书"
17
+ ],
18
+ "author": "FileMaster Pro",
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "n8n-workflow": "^1.48.0"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.4.0",
25
+ "@types/node": "^20.0.0"
26
+ },
27
+ "n8n": {
28
+ "n8nNodesApiVersion": 1,
29
+ "nodes": [
30
+ "nodes/Feishu/Feishu.node.js",
31
+ "nodes/Feishu/FeishuTrigger.node.js"
32
+ ],
33
+ "credentials": [
34
+ "credentials/FeishuApi.credentials.js"
35
+ ]
36
+ }
37
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "01 飞书消息发送器 Webhook → 飞书消息",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "method": "POST",
7
+ "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
8
+ "sendHeaders": true,
9
+ "headerParameters": { "parameters": [
10
+ { "name": "Content-Type", "value": "application/json" }
11
+ ]},
12
+ "sendBody": true,
13
+ "specifyBody": "keypair",
14
+ "bodyParameters": { "parameters": [
15
+ { "name": "app_id", "value": "← 填你的 App ID" },
16
+ { "name": "app_secret", "value": "← 填你的 App Secret" }
17
+ ]},
18
+ "options": {}
19
+ },
20
+ "id": "n1",
21
+ "name": "① 获取 Token",
22
+ "type": "n8n-nodes-base.httpRequest",
23
+ "typeVersion": 4.2,
24
+ "position": [0, 300]
25
+ },
26
+ {
27
+ "parameters": {
28
+ "httpMethod": "POST",
29
+ "path": "feishu-input",
30
+ "responseMode": "lastNode",
31
+ "options": {}
32
+ },
33
+ "id": "n0",
34
+ "name": "🌐 外部 Webhook",
35
+ "type": "n8n-nodes-base.webhook",
36
+ "typeVersion": 2,
37
+ "position": [-250, 300],
38
+ "webhookId": "feishu-webhook-input"
39
+ },
40
+ {
41
+ "parameters": {
42
+ "method": "POST",
43
+ "url": "=https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
44
+ "sendHeaders": true,
45
+ "headerParameters": { "parameters": [
46
+ { "name": "Content-Type", "value": "application/json" },
47
+ { "name": "Authorization", "value": "=Bearer {{ $('① 获取 Token').first().json.tenant_access_token }}" }
48
+ ]},
49
+ "sendBody": true,
50
+ "specifyBody": "keypair",
51
+ "bodyParameters": { "parameters": [
52
+ { "name": "receive_id", "value": "← 填接收人的 open_id" },
53
+ { "name": "msg_type", "value": "text" },
54
+ { "name": "content", "value": "={\"text\":\"{{ $json.body.text || $json.body.message || '通知:' + JSON.stringify($json.body) }}\"}" }
55
+ ]},
56
+ "options": {}
57
+ },
58
+ "id": "n2",
59
+ "name": "② 发送飞书消息",
60
+ "type": "n8n-nodes-base.httpRequest",
61
+ "typeVersion": 4.2,
62
+ "position": [250, 300]
63
+ }
64
+ ],
65
+ "connections": {
66
+ "🌐 外部 Webhook": { "main": [[{ "node": "① 获取 Token", "type": "main", "index": 0 }]] },
67
+ "① 获取 Token": { "main": [[{ "node": "② 发送飞书消息", "type": "main", "index": 0 }]] }
68
+ },
69
+ "pinData": {}, "versionId": "1.0.0", "active": false,
70
+ "settings": {}, "tags": [{ "name": "飞书" }, { "name": "Webhook" }]
71
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "02 飞书定时提醒 Cron → 飞书消息",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "rule": { "interval": [{ "field": "hours", "hoursInterval": 1 }] }
7
+ },
8
+ "id": "n0",
9
+ "name": "⏰ 定时触发(可改)",
10
+ "type": "n8n-nodes-base.scheduleTrigger",
11
+ "typeVersion": 1.2,
12
+ "position": [-250, 300]
13
+ },
14
+ {
15
+ "parameters": {
16
+ "method": "POST",
17
+ "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
18
+ "sendHeaders": true,
19
+ "headerParameters": { "parameters": [
20
+ { "name": "Content-Type", "value": "application/json" }
21
+ ]},
22
+ "sendBody": true,
23
+ "specifyBody": "keypair",
24
+ "bodyParameters": { "parameters": [
25
+ { "name": "app_id", "value": "← 填你的 App ID" },
26
+ { "name": "app_secret", "value": "← 填你的 App Secret" }
27
+ ]},
28
+ "options": {}
29
+ },
30
+ "id": "n1",
31
+ "name": "① 获取 Token",
32
+ "type": "n8n-nodes-base.httpRequest",
33
+ "typeVersion": 4.2,
34
+ "position": [0, 300]
35
+ },
36
+ {
37
+ "parameters": {
38
+ "method": "POST",
39
+ "url": "=https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
40
+ "sendHeaders": true,
41
+ "headerParameters": { "parameters": [
42
+ { "name": "Content-Type", "value": "application/json" },
43
+ { "name": "Authorization", "value": "=Bearer {{ $('① 获取 Token').first().json.tenant_access_token }}" }
44
+ ]},
45
+ "sendBody": true,
46
+ "specifyBody": "keypair",
47
+ "bodyParameters": { "parameters": [
48
+ { "name": "receive_id", "value": "← 填接收人的 open_id" },
49
+ { "name": "msg_type", "value": "text" },
50
+ { "name": "content", "value": "{\"text\":\"⏰ 定时提醒:该处理了!\"}" }
51
+ ]},
52
+ "options": {}
53
+ },
54
+ "id": "n2",
55
+ "name": "② 发送消息",
56
+ "type": "n8n-nodes-base.httpRequest",
57
+ "typeVersion": 4.2,
58
+ "position": [250, 300]
59
+ }
60
+ ],
61
+ "connections": {
62
+ "⏰ 定时触发(可改)": { "main": [[{ "node": "① 获取 Token", "type": "main", "index": 0 }]] },
63
+ "① 获取 Token": { "main": [[{ "node": "② 发送消息", "type": "main", "index": 0 }]] }
64
+ },
65
+ "pinData": {}, "versionId": "1.0.0", "active": false,
66
+ "settings": {}, "tags": [{ "name": "飞书" }, { "name": "定时" }]
67
+ }
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "03 网站宕机监控 → 飞书告警",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "rule": { "interval": [{ "field": "minutes", "minutesInterval": 5 }] }
7
+ },
8
+ "id": "n0",
9
+ "name": "⏰ 每5分钟检查",
10
+ "type": "n8n-nodes-base.scheduleTrigger",
11
+ "typeVersion": 1.2,
12
+ "position": [-500, 300]
13
+ },
14
+ {
15
+ "parameters": {
16
+ "method": "GET",
17
+ "url": "← 填要监控的网址,如 https://your-site.com",
18
+ "sendBody": false,
19
+ "options": { "timeout": 10000, "redirect": { "redirect": {} } }
20
+ },
21
+ "id": "n1",
22
+ "name": "① 检查网站",
23
+ "type": "n8n-nodes-base.httpRequest",
24
+ "typeVersion": 4.2,
25
+ "position": [-250, 300]
26
+ },
27
+ {
28
+ "parameters": {
29
+ "conditions": { "number": [
30
+ { "value1": "={{ $response.statusCode }}", "operation": "larger", "value2": 399 }
31
+ ]}
32
+ },
33
+ "id": "n2",
34
+ "name": "② 挂了?",
35
+ "type": "n8n-nodes-base.if",
36
+ "typeVersion": 2,
37
+ "position": [0, 300]
38
+ },
39
+ {
40
+ "parameters": {
41
+ "method": "POST",
42
+ "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
43
+ "sendHeaders": true,
44
+ "headerParameters": { "parameters": [
45
+ { "name": "Content-Type", "value": "application/json" }
46
+ ]},
47
+ "sendBody": true,
48
+ "specifyBody": "keypair",
49
+ "bodyParameters": { "parameters": [
50
+ { "name": "app_id", "value": "← 填你的 App ID" },
51
+ { "name": "app_secret", "value": "← 填你的 App Secret" }
52
+ ]},
53
+ "options": {}
54
+ },
55
+ "id": "n3",
56
+ "name": "③ 获取 Token",
57
+ "type": "n8n-nodes-base.httpRequest",
58
+ "typeVersion": 4.2,
59
+ "position": [250, 100]
60
+ },
61
+ {
62
+ "parameters": {
63
+ "method": "POST",
64
+ "url": "=https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
65
+ "sendHeaders": true,
66
+ "headerParameters": { "parameters": [
67
+ { "name": "Content-Type", "value": "application/json" },
68
+ { "name": "Authorization", "value": "=Bearer {{ $('③ 获取 Token').first().json.tenant_access_token }}" }
69
+ ]},
70
+ "sendBody": true,
71
+ "specifyBody": "keypair",
72
+ "bodyParameters": { "parameters": [
73
+ { "name": "receive_id", "value": "← 填你的 open_id" },
74
+ { "name": "msg_type", "value": "text" },
75
+ { "name": "content", "value": "={\"text\":\"🚨 网站挂了!状态码:{{ $json.statusCode }},时间:{{ new Date().toLocaleString('zh-CN') }}\"}" }
76
+ ]},
77
+ "options": {}
78
+ },
79
+ "id": "n4",
80
+ "name": "④ 发飞书告警",
81
+ "type": "n8n-nodes-base.httpRequest",
82
+ "typeVersion": 4.2,
83
+ "position": [500, 100]
84
+ }
85
+ ],
86
+ "connections": {
87
+ "⏰ 每5分钟检查": { "main": [[{ "node": "① 检查网站", "type": "main", "index": 0 }]] },
88
+ "① 检查网站": { "main": [[{ "node": "② 挂了?", "type": "main", "index": 0 }]] },
89
+ "② 挂了?": { "main": [
90
+ [{ "node": "③ 获取 Token", "type": "main", "index": 0 }],
91
+ []
92
+ ]},
93
+ "③ 获取 Token": { "main": [[{ "node": "④ 发飞书告警", "type": "main", "index": 0 }]] }
94
+ },
95
+ "pinData": {}, "versionId": "1.0.0", "active": false,
96
+ "settings": {}, "tags": [{ "name": "飞书" }, { "name": "监控" }]
97
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "04 表单提交 → 飞书通知 + 多维表格记录",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "httpMethod": "POST",
7
+ "path": "form-submit",
8
+ "responseMode": "lastNode",
9
+ "options": {}
10
+ },
11
+ "id": "n0",
12
+ "name": "🌐 表单提交 Webhook",
13
+ "type": "n8n-nodes-base.webhook",
14
+ "typeVersion": 2,
15
+ "position": [-500, 300],
16
+ "webhookId": "form-notify-webhook"
17
+ },
18
+ {
19
+ "parameters": {
20
+ "method": "POST",
21
+ "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
22
+ "sendHeaders": true,
23
+ "headerParameters": { "parameters": [
24
+ { "name": "Content-Type", "value": "application/json" }
25
+ ]},
26
+ "sendBody": true,
27
+ "specifyBody": "keypair",
28
+ "bodyParameters": { "parameters": [
29
+ { "name": "app_id", "value": "← 填你的 App ID" },
30
+ { "name": "app_secret", "value": "← 填你的 App Secret" }
31
+ ]},
32
+ "options": {}
33
+ },
34
+ "id": "n1",
35
+ "name": "① 获取 Token",
36
+ "type": "n8n-nodes-base.httpRequest",
37
+ "typeVersion": 4.2,
38
+ "position": [-250, 300]
39
+ },
40
+ {
41
+ "parameters": {
42
+ "method": "POST",
43
+ "url": "=https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
44
+ "sendHeaders": true,
45
+ "headerParameters": { "parameters": [
46
+ { "name": "Content-Type", "value": "application/json" },
47
+ { "name": "Authorization", "value": "=Bearer {{ $('① 获取 Token').first().json.tenant_access_token }}" }
48
+ ]},
49
+ "sendBody": true,
50
+ "specifyBody": "keypair",
51
+ "bodyParameters": { "parameters": [
52
+ { "name": "receive_id", "value": "← 填通知接收人 open_id" },
53
+ { "name": "msg_type", "value": "interactive" },
54
+ { "name": "content", "value": "={\"config\":{\"wide_screen_mode\":true},\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"📋 新提交\"}},\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"lark_md\",\"content\":\"**提交内容:**\\n{{ JSON.stringify($json.body, null, 2) }}\"}}]}" }
55
+ ]},
56
+ "options": {}
57
+ },
58
+ "id": "n2",
59
+ "name": "② 发卡片通知",
60
+ "type": "n8n-nodes-base.httpRequest",
61
+ "typeVersion": 4.2,
62
+ "position": [0, 300]
63
+ }
64
+ ],
65
+ "connections": {
66
+ "🌐 表单提交 Webhook": { "main": [[{ "node": "① 获取 Token", "type": "main", "index": 0 }]] },
67
+ "① 获取 Token": { "main": [[{ "node": "② 发卡片通知", "type": "main", "index": 0 }]] }
68
+ },
69
+ "pinData": {}, "versionId": "1.0.0", "active": false,
70
+ "settings": {}, "tags": [{ "name": "飞书" }, { "name": "表单" }]
71
+ }
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "05 外部 API 数据 → 飞书定时推送",
3
+ "nodes": [
4
+ {
5
+ "parameters": {
6
+ "rule": { "interval": [{ "field": "hours", "hoursInterval": 6 }] }
7
+ },
8
+ "id": "n0",
9
+ "name": "⏰ 定时触发",
10
+ "type": "n8n-nodes-base.scheduleTrigger",
11
+ "typeVersion": 1.2,
12
+ "position": [-500, 300]
13
+ },
14
+ {
15
+ "parameters": {
16
+ "method": "GET",
17
+ "url": "← 填你的数据 API 地址",
18
+ "sendBody": false,
19
+ "options": {}
20
+ },
21
+ "id": "n1",
22
+ "name": "① 拉取数据",
23
+ "type": "n8n-nodes-base.httpRequest",
24
+ "typeVersion": 4.2,
25
+ "position": [-250, 300]
26
+ },
27
+ {
28
+ "parameters": {
29
+ "mode": "json",
30
+ "jsonOutput": "={\n \"title\": \"📊 数据播报\",\n \"body\": \"{{ JSON.stringify($json) }}\"\n}"
31
+ },
32
+ "id": "n2",
33
+ "name": "② 格式化内容",
34
+ "type": "n8n-nodes-base.set",
35
+ "typeVersion": 3.4,
36
+ "position": [0, 300]
37
+ },
38
+ {
39
+ "parameters": {
40
+ "method": "POST",
41
+ "url": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
42
+ "sendHeaders": true,
43
+ "headerParameters": { "parameters": [
44
+ { "name": "Content-Type", "value": "application/json" }
45
+ ]},
46
+ "sendBody": true,
47
+ "specifyBody": "keypair",
48
+ "bodyParameters": { "parameters": [
49
+ { "name": "app_id", "value": "← 填你的 App ID" },
50
+ { "name": "app_secret", "value": "← 填你的 App Secret" }
51
+ ]},
52
+ "options": {}
53
+ },
54
+ "id": "n3",
55
+ "name": "③ 获取 Token",
56
+ "type": "n8n-nodes-base.httpRequest",
57
+ "typeVersion": 4.2,
58
+ "position": [250, 300]
59
+ },
60
+ {
61
+ "parameters": {
62
+ "method": "POST",
63
+ "url": "=https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
64
+ "sendHeaders": true,
65
+ "headerParameters": { "parameters": [
66
+ { "name": "Content-Type", "value": "application/json" },
67
+ { "name": "Authorization", "value": "=Bearer {{ $('③ 获取 Token').first().json.tenant_access_token }}" }
68
+ ]},
69
+ "sendBody": true,
70
+ "specifyBody": "keypair",
71
+ "bodyParameters": { "parameters": [
72
+ { "name": "receive_id", "value": "← 填接收人 open_id" },
73
+ { "name": "msg_type", "value": "interactive" },
74
+ { "name": "content", "value": "={\"config\":{\"wide_screen_mode\":true},\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"{{ $('② 格式化内容').first().json.title }}\"}},\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"lark_md\",\"content\":\"{{ $('② 格式化内容').first().json.body }}\"}}]}" }
75
+ ]},
76
+ "options": {}
77
+ },
78
+ "id": "n4",
79
+ "name": "④ 推送卡片",
80
+ "type": "n8n-nodes-base.httpRequest",
81
+ "typeVersion": 4.2,
82
+ "position": [500, 300]
83
+ }
84
+ ],
85
+ "connections": {
86
+ "⏰ 定时触发": { "main": [[{ "node": "① 拉取数据", "type": "main", "index": 0 }]] },
87
+ "① 拉取数据": { "main": [[{ "node": "② 格式化内容", "type": "main", "index": 0 }]] },
88
+ "② 格式化内容": { "main": [[{ "node": "③ 获取 Token", "type": "main", "index": 0 }]] },
89
+ "③ 获取 Token": { "main": [[{ "node": "④ 推送卡片", "type": "main", "index": 0 }]] }
90
+ },
91
+ "pinData": {}, "versionId": "1.0.0", "active": false,
92
+ "settings": {},
93
+ "tags": [{ "name": "飞书" }, { "name": "数据推送" }]
94
+ }