diff --git a/src/server/feishu.ts b/src/server/feishu.ts new file mode 100644 index 0000000..d1e58d7 --- /dev/null +++ b/src/server/feishu.ts @@ -0,0 +1,102 @@ +/** + * 飞书消息发送模块 + * 通过飞书自定义机器人Webhook发送项目通知 + */ + +const FEISHU_WEBHOOK = 'https://open.feishu.cn/open-apis/bot/v2/hook/58321c74-5881-4f41-bcd4-85f4d7c5b3c1'; +const FEISHU_SECRET = 'UgCdzrcci4s9YS1GSAHt4e'; + +import { createHmac } from 'crypto'; + +/** + * 生成飞书签名 + */ +function generateSign(timestamp: number, secret: string): string { + const stringToSign = `${timestamp}\n${secret}`; + const hmac = createHmac('sha256', stringToSign); + return hmac.digest('base64'); +} + +export interface FeishuMessageOptions { + /** 消息内容 */ + text: string; + /** 是否使用签名校验 */ + sign?: boolean; +} + +/** + * 发送飞书文本消息 + */ +export async function sendFeishuMessage(options: FeishuMessageOptions): Promise<{ ok: boolean; code: number; msg: string }> { + const { text, sign = true } = options; + const timestamp = Math.floor(Date.now() / 1000); + + const body: Record = { + msg_type: 'text', + content: { text }, + }; + + if (sign) { + body.timestamp = String(timestamp); + body.sign = generateSign(timestamp, FEISHU_SECRET); + } + + try { + const response = await fetch(FEISHU_WEBHOOK, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }); + + const result = await response.json(); + return { + ok: result.code === 0 || result.StatusCode === 0, + code: result.code ?? result.StatusCode ?? -1, + msg: result.msg ?? result.StatusMessage ?? '', + }; + } catch (error) { + return { + ok: false, + code: -1, + msg: error instanceof Error ? error.message : 'Unknown error', + }; + } +} + +/** + * 发送项目创建通知 + */ +export async function notifyProjectCreated(projectName: string, goal: string): Promise { + await sendFeishuMessage({ + text: `🚀 新项目已创建\n\n项目:${projectName}\n目标:${goal}\n\n请及时查看并确认项目章程。`, + }); +} + +/** + * 发送里程碑提醒 + */ +export async function notifyMilestoneReminder(milestoneName: string, targetDate: string): Promise { + await sendFeishuMessage({ + text: `⏰ 里程碑提醒\n\n里程碑「${milestoneName}」即将到期\n目标日期:${targetDate}\n\n请确认进度是否正常。`, + }); +} + +/** + * 发送风险预警 + */ +export async function notifyRiskAlert(riskDesc: string, priority: number): Promise { + const level = priority >= 15 ? '🔴 高' : priority >= 10 ? '🟡 中' : '🟢 低'; + await sendFeishuMessage({ + text: `⚠️ 风险预警\n\n风险:${riskDesc}\n优先级:${level}(${priority}分)\n\n请评估并制定应对措施。`, + }); +} + +/** + * 发送决策请求 + */ +export async function notifyDecisionRequired(title: string, options: string[]): Promise { + const optionList = options.map((o, i) => ` ${i + 1}. ${o}`).join('\n'); + await sendFeishuMessage({ + text: `🔑 需要您的决策\n\n${title}\n\n选项:\n${optionList}\n\n请回复选项编号。`, + }); +}