修复消息订阅
This commit is contained in:
+20
-20
@@ -2,45 +2,45 @@
|
||||
PORT=3000
|
||||
NODE_ENV=production
|
||||
# 管理后台密码(首次部署务必修改)
|
||||
ADMIN_PASSWORD=change-me-to-strong-password
|
||||
ADMIN_PASSWORD=:e7P6ZaxwU9Uv8R
|
||||
|
||||
# ===== 飞书配置 =====
|
||||
# 在飞书开放平台创建企业自建应用后获取
|
||||
FEISHU_APP_ID=cli_xxxxxxxxxxxx
|
||||
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
FEISHU_APP_ID=cli_aae9a27533e2dbed
|
||||
FEISHU_APP_SECRET=iZhaalG01oqkVDZsmdmOFdMzGtfFGzsD
|
||||
# 事件订阅的 Verification Token 和 Encrypt Key
|
||||
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxx
|
||||
FEISHU_VERIFICATION_TOKEN=jPBz4l4fdCS25H95fSlQWeanmMzohUBm
|
||||
FEISHU_ENCRYPT_KEY=
|
||||
# 办理人的 open_id(程序以此身份完成办理任务)
|
||||
# 获取方式:飞书开放平台 API调试台 → 搜索"获取用户信息" → 用手机号查自己的 open_id
|
||||
FEISHU_HANDLER_USER_ID=ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
FEISHU_HANDLER_USER_ID=ou_195f9c5d3d382732af4a665d7675fbfe
|
||||
# 飞书审批定义code(飞书管理后台 → 审批管理 → 打开对应表单 → URL中的 approvalCode 参数)
|
||||
FEISHU_APPROVAL_FILE_IN=你的文件传入审批code
|
||||
FEISHU_APPROVAL_FILE_OUT=你的文件传出审批code
|
||||
FEISHU_APPROVAL_GROUP_PERM=你的红区组权限审批code
|
||||
FEISHU_APPROVAL_FILE_IN=CC9211DE-851A-4E22-9A2B-337134F20F0E
|
||||
FEISHU_APPROVAL_FILE_OUT=60650A89-AEDE-43AD-BEC3-5BB569B6F12F
|
||||
FEISHU_APPROVAL_GROUP_PERM=935A65D1-3173-48F2-A8A1-B61318E31CAF
|
||||
# 告警通知群 webhook(群机器人)
|
||||
FEISHU_ALERT_WEBHOOK=https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx
|
||||
FEISHU_ALERT_WEBHOOK=https://open.feishu.cn/open-apis/bot/v2/hook/0e9ca0de-54e2-4bff-8621-32ccdbfa5623
|
||||
|
||||
# ===== 群晖 NAS 配置 =====
|
||||
SYNOLOGY_HOST=https://你的NAS_IP:5001
|
||||
SYNOLOGY_USERNAME=你的NAS账号
|
||||
SYNOLOGY_PASSWORD=你的NAS密码
|
||||
SYNOLOGY_HOST=https://10.2.3.40:5001
|
||||
SYNOLOGY_USERNAME=qwq
|
||||
SYNOLOGY_PASSWORD=:e7P6ZaxwU9Uv8R
|
||||
# 是否跳过TLS证书验证(自签证书时设为true)
|
||||
SYNOLOGY_SKIP_TLS=true
|
||||
|
||||
# ===== JumpServer 配置 =====
|
||||
JUMPSERVER_HOST=http://你的JumpServer地址
|
||||
JUMPSERVER_KEY_ID=你的API-Key-ID
|
||||
JUMPSERVER_KEY_SECRET=你的API-Key-Secret
|
||||
# ic1 资产的 asset_id(在JumpServer控制台 → 资产管理 → 点击ic1 → URL中的UUID)
|
||||
JUMPSERVER_ASSET_IC1=你的ic1资产UUID
|
||||
JUMPSERVER_HOST=http://10.2.3.41
|
||||
JUMPSERVER_KEY_ID=912c725a-145b-4ee9-8eb8-4dc33913349b
|
||||
JUMPSERVER_KEY_SECRET=O4XnRa6ustUV7A4sU6KWaH8yAs3TXtxzLcTa
|
||||
# ic1 资产的 asset_id(在JumpServer控制台查看)
|
||||
JUMPSERVER_ASSET_IC1=c37d2b6d-3c4f-4d24-8792-40f3db2be54e
|
||||
# 系统用户(用于连接ic1的账号)
|
||||
JUMPSERVER_SYSTEM_USER=root
|
||||
|
||||
# ===== Nextcloud 配置 =====
|
||||
NEXTCLOUD_HOST=http://你的Nextcloud地址
|
||||
NEXTCLOUD_USERNAME=你的Nextcloud账号
|
||||
NEXTCLOUD_PASSWORD=你的Nextcloud密码
|
||||
NEXTCLOUD_HOST=http://10.2.3.137:28080
|
||||
NEXTCLOUD_USERNAME=qwq
|
||||
NEXTCLOUD_PASSWORD=03451420
|
||||
# 共享默认权限(1=读, 15=读写删, 17=读+分享)
|
||||
NEXTCLOUD_SHARE_PERMISSIONS=1
|
||||
|
||||
|
||||
+51
-16
@@ -42,31 +42,50 @@ router.post('/event', async (req, res) => {
|
||||
});
|
||||
|
||||
/**
|
||||
* 处理飞书事件
|
||||
* 处理飞书事件(支持 approval_instance 和 approval_task 两种)
|
||||
*/
|
||||
async function processEvent(body) {
|
||||
// 飞书事件订阅 v2 格式
|
||||
const header = body.header || {};
|
||||
const event = body.event || {};
|
||||
const eventType = header.event_type;
|
||||
|
||||
// 只处理审批实例状态变更事件
|
||||
if (eventType !== 'approval_instance') return;
|
||||
logger.info(`[飞书事件] 收到事件类型: ${eventType}, 数据: ${JSON.stringify(event).substring(0, 300)}`);
|
||||
|
||||
const instanceCode = event.instance_code;
|
||||
const approvalCode = event.approval_code;
|
||||
const status = event.status; // APPROVED / REJECTED / PENDING
|
||||
let instanceCode, approvalCode;
|
||||
|
||||
// 只处理进行中的审批(办理任务到达时 instance 仍为 PENDING)
|
||||
if (status !== 'PENDING' && status !== 'APPROVED') return;
|
||||
if (eventType === 'approval_task') {
|
||||
// 审批任务事件:上级审批通过后,办理任务被创建时触发
|
||||
// 数据结构可能是 event.object 或 event 本身
|
||||
const taskObj = event.object || event;
|
||||
instanceCode = taskObj.instance_code || taskObj.instance_id;
|
||||
approvalCode = taskObj.approval_code;
|
||||
const taskStatus = taskObj.status;
|
||||
const taskUserId = taskObj.user_id;
|
||||
|
||||
// 防重复处理
|
||||
if (isApprovalProcessed(instanceCode)) {
|
||||
logger.info(`[飞书事件] 审批已处理过,跳过: ${instanceCode}`);
|
||||
logger.info(`[飞书事件][task] instance=${instanceCode}, approval=${approvalCode}, status=${taskStatus}, user=${taskUserId}`);
|
||||
|
||||
// 只处理 PENDING 状态的任务(新到达的待办)
|
||||
if (taskStatus !== 'PENDING') {
|
||||
logger.info(`[飞书事件][task] 非PENDING状态,跳过: ${taskStatus}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查当前 PENDING 任务是否分配给办理人(过滤掉上级审批阶段)
|
||||
// 检查是否分配给配置的办理人
|
||||
const handlerId = config.feishu.handlerUserId;
|
||||
if (handlerId && taskUserId && taskUserId !== handlerId) {
|
||||
logger.info(`[飞书事件][task] 任务非本办理人,跳过: task_user=${taskUserId}, handler=${handlerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (eventType === 'approval_instance') {
|
||||
// 审批实例事件:整个审批单状态变化
|
||||
instanceCode = event.instance_code;
|
||||
approvalCode = event.approval_code;
|
||||
const status = event.status;
|
||||
|
||||
if (status !== 'PENDING' && status !== 'APPROVED') return;
|
||||
|
||||
// 检查当前 PENDING 任务是否分配给办理人
|
||||
const handlerId = config.feishu.handlerUserId;
|
||||
if (handlerId) {
|
||||
try {
|
||||
@@ -74,15 +93,31 @@ async function processEvent(body) {
|
||||
const taskList = instance.task_list || [];
|
||||
const pendingTask = taskList.find(t => t.status === 'PENDING');
|
||||
if (!pendingTask || pendingTask.user_id !== handlerId) {
|
||||
logger.info(`[飞书事件] 当前待办非本程序办理任务,跳过: instance=${instanceCode}`);
|
||||
logger.info(`[飞书事件][instance] 当前待办非本程序办理任务,跳过`);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn(`[飞书事件] 获取实例详情失败,继续处理: ${e.message}`);
|
||||
logger.warn(`[飞书事件][instance] 获取实例详情失败: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`[飞书事件] 办理任务到达: code=${approvalCode}, instance=${instanceCode}`);
|
||||
} else {
|
||||
// 非目标事件
|
||||
return;
|
||||
}
|
||||
|
||||
if (!instanceCode || !approvalCode) {
|
||||
logger.warn(`[飞书事件] 缺少 instanceCode 或 approvalCode,跳过`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 防重复处理
|
||||
if (isApprovalProcessed(instanceCode)) {
|
||||
logger.info(`[飞书事件] 审批已处理过,跳过: ${instanceCode}`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`[飞书事件] 办理任务确认: code=${approvalCode}, instance=${instanceCode}`);
|
||||
|
||||
// 根据审批定义 code 路由到不同工作流
|
||||
if (approvalCode === config.feishu.approvalCodes.fileIn) {
|
||||
|
||||
@@ -16,13 +16,14 @@ function startWsClient() {
|
||||
const wsClient = new lark.WSClient({
|
||||
appId: config.feishu.appId,
|
||||
appSecret: config.feishu.appSecret,
|
||||
loggerLevel: lark.LoggerLevel.info,
|
||||
loggerLevel: lark.LoggerLevel.debug, // 调试阶段用 debug,稳定后改回 info
|
||||
});
|
||||
|
||||
wsClient.start({
|
||||
eventDispatcher: new lark.EventDispatcher({}).register({
|
||||
// 审批实例状态变更(整个审批单的状态变化)
|
||||
'approval_instance': async (data) => {
|
||||
logger.info('[飞书WS] 收到审批事件:', JSON.stringify(data).substring(0, 200));
|
||||
logger.info('[飞书WS][approval_instance] 收到事件:', JSON.stringify(data).substring(0, 500));
|
||||
if (eventHandler) {
|
||||
try {
|
||||
await eventHandler({
|
||||
@@ -30,14 +31,29 @@ function startWsClient() {
|
||||
event: data,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`[飞书WS] 事件处理失败: ${err.message}`);
|
||||
logger.error(`[飞书WS] approval_instance 处理失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 审批任务状态变更(办理任务到达时会触发这个)
|
||||
'approval_task': async (data) => {
|
||||
logger.info('[飞书WS][approval_task] 收到事件:', JSON.stringify(data).substring(0, 500));
|
||||
if (eventHandler) {
|
||||
try {
|
||||
await eventHandler({
|
||||
header: { event_type: 'approval_task' },
|
||||
event: data,
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`[飞书WS] approval_task 处理失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
logger.info('[飞书WS] 长连接已启动,等待审批事件...');
|
||||
logger.info('[飞书WS] 长连接已启动,监听 approval_instance + approval_task 事件');
|
||||
}
|
||||
|
||||
module.exports = { startWsClient, setEventHandler };
|
||||
|
||||
Reference in New Issue
Block a user