diff --git a/dev/architecture.md b/dev/architecture.md index e67ba9d..16b4a18 100644 --- a/dev/architecture.md +++ b/dev/architecture.md @@ -13,7 +13,7 @@ | 对象映射 | MapStruct 1.6.3 | | 账单解析 | EasyExcel(xlsx)/ Apache POI(xls)+ commons-csv + PDFBox + Zip4j | | AI | DeepSeek(OpenAI 兼容接口,Spring RestClient) | -| 通知 | Jakarta Mail(SMTP / IMAP)+ Server 酱 | +| 通知 | Jakarta Mail(SMTP / IMAP)+ Server 酱 + 飞书自定义机器人 | | API 文档 | Knife4j(OpenAPI 3) | ## 后端分层 diff --git a/dev/notifications.md b/dev/notifications.md index 0cc0cca..1f1abd2 100644 --- a/dev/notifications.md +++ b/dev/notifications.md @@ -17,13 +17,14 @@ |---|---| | `EMAIL` | 邮箱 SMTP(如 QQ 邮箱),动态构建 `JavaMailSenderImpl`,默认 `smtp.qq.com:465` + SSL | | `SERVERCHAN` | Server 酱 Turbo,推送到个人微信,校验返回 `code == 0` | +| `FEISHU` | 飞书自定义机器人 Webhook,post 富文本(标题保留为卡片标题、正文按行分段),可选加签(`timestamp` + HMAC-SHA256),校验 `code` / `StatusCode` | 发送器采用工厂模式:`NotificationSender` 接口 + `NotificationSenderFactory` 按类型分发,`AbstractHttpNotificationSender` 封装 JSON/表单 POST。 ## 配置与日志 - `t_notification_config`:启用开关、周期、每月日期、每周星期、提醒时间、最近发送时间。 -- `t_notification_channel`:类型、名称、启用、配置 JSON(SMTP 账号或 SendKey)。邮箱密码留空表示不修改,返回时脱敏。 +- `t_notification_channel`:类型、名称、启用、配置 JSON(SMTP 账号、Server 酱 SendKey 或飞书 `webhookUrl` / `secret`)。邮箱密码与飞书密钥留空表示不修改,返回时脱敏,`NotificationChannelVO` 以 `hasPassword` / `hasSecret` 标记是否已配置。 - `t_notification_log`:每次发送的结果(成功/失败、渠道类型、说明),面板展示最近 20 条。 ## 接口 diff --git a/guide/introduction.md b/guide/introduction.md index 13ccfad..3978db1 100644 --- a/guide/introduction.md +++ b/guide/introduction.md @@ -25,7 +25,7 @@ | 自定义规则 | 关键词/收支类型/金额区间组合,优先级排序、启用停用,导入时自动应用;支持 AI 生成规则、搜索、分页与批量删除 | | AI 能力 | 分类标签与渠道建议、自然语言查询、智能查数(自然语言转只读 SQL)、文字/多图图片记账、AI 统计搜索、AI 生成规则、分类/标签/渠道生成、关系命名、Emoji/颜色推荐、用量统计 | | 邮箱账单 | 多邮箱 IMAP IDLE 监听、发件人规则识别账单类型、待处理列表先预览再导入 | -| 定时通知 | 每天/每周/每月提醒,邮箱 SMTP 与 Server 酱渠道,发送日志 | +| 定时通知 | 每天/每周/每月提醒,邮箱 SMTP、Server 酱与飞书渠道,发送日志 | | 日志 | 访问日志、登录日志、运行日志在线查看,运行日志实时推送,自动清理 | | 账号与多语言 | JWT 登录、注册开关、运行时数据库配置(SQLite/MySQL)、中/英/日三语 | @@ -40,7 +40,7 @@ | 对象映射 | MapStruct 1.6.3 | | 账单解析 | EasyExcel 4.0.3 + PDFBox 3.0.3 + Zip4j 2.11.5 | | AI 能力 | DeepSeek | -| 通知渠道 | 邮箱 SMTP / Server 酱 | +| 通知渠道 | 邮箱 SMTP / Server 酱 / 飞书 | | 多语言 | 中文 / 英文 / 日文(vue-i18n) | | API 文档 | Knife4j(OpenAPI 3) | diff --git a/guide/notifications.md b/guide/notifications.md index 6c6499b..53437fd 100644 --- a/guide/notifications.md +++ b/guide/notifications.md @@ -1,6 +1,6 @@ # 定时提醒与通知 -系统可按周期提醒你导入新账单,并通过邮箱或 Server 酱推送通知。配置入口为「设置 → 定时通知」。 +系统可按周期提醒你导入新账单,并通过邮箱、Server 酱或飞书推送通知。配置入口为「设置 → 定时通知」。 ![设置](https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/settings.png) @@ -13,15 +13,20 @@ ## 推送渠道 -点击「添加渠道」新增,支持两种类型: +点击「添加渠道」新增,支持三种类型: | 渠道 | 配置项 | |---|---| | Server 酱 | SendKey(在 sct.ftqq.com 获取),可推送到个人微信 | | 邮箱 | SMTP 服务器、端口、邮箱账号、授权码、收件人、是否使用 SSL | +| 飞书 | Webhook 完整地址(飞书群「设置 → 群机器人 → 添加机器人 → 自定义机器人」获取);若机器人开启了「签名校验」,再填写签名密钥,可推送到飞书群 | ![添加渠道弹窗](https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/elements/add-channel.png) +飞书渠道配置示例(类型选择「飞书」,填写 Webhook 地址与可选的签名密钥): + +![飞书渠道配置](https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/elements/add-channel-feishu.png) + 每个渠道可单独「测试」「编辑」「删除」,并可通过启用开关控制是否参与发送。 面板右上角的「立即发送」可向所有启用渠道立即发送一次提醒,用于验证配置。 diff --git a/guide/settings.md b/guide/settings.md index 9c0105c..99fd523 100644 --- a/guide/settings.md +++ b/guide/settings.md @@ -103,7 +103,7 @@ ![定时通知面板](https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/elements/panel-notification.png) -配置账单导入提醒的周期、时间与推送渠道(Server 酱 / 邮箱),并可查看发送日志。详见[定时提醒与通知](/guide/notifications)。 +配置账单导入提醒的周期、时间与推送渠道(Server 酱 / 邮箱 / 飞书),并可查看发送日志。详见[定时提醒与通知](/guide/notifications)。 ## 相关 diff --git a/index.md b/index.md index 22ee246..e634ead 100644 --- a/index.md +++ b/index.md @@ -37,7 +37,7 @@ features: - title: 统计与图表 details: 月度收支汇总、分类占比、收支趋势、交易渠道占比,支持多维度筛选与自定义时间范围,图表可点击下钻明细。 - title: 定时提醒与通知 - details: 按每天/每周/每月周期提醒导入新账单,支持邮箱 SMTP 与 Server 酱多渠道推送。 + details: 按每天/每周/每月周期提醒导入新账单,支持邮箱 SMTP、Server 酱与飞书多渠道推送。 - title: 邮箱账单自动拉取 details: 通过 IMAP IDLE 监听邮箱,新账单邮件到达后自动拉取附件,先预览再确认导入。 - title: 日志 diff --git a/scripts/ts/capture-elements.ts b/scripts/ts/capture-elements.ts index 3412dbd..d69a3bc 100644 --- a/scripts/ts/capture-elements.ts +++ b/scripts/ts/capture-elements.ts @@ -86,6 +86,38 @@ export async function captureModals(page: Page, only?: string[]): Promise } } +/** + * 截取「添加渠道」弹窗的飞书配置表单(elements/add-channel-feishu.png)。 + * + * 打开设置页的添加渠道弹窗后,将「渠道类型」切换为飞书,展示 Webhook 地址与签名密钥表单项。 + * + * @param page Page 实例 + */ +export async function captureChannelFeishu(page: Page): Promise { + try { + await page.setViewportSize({ width: 1440, height: 1000 }) + await page.goto(BASE_URL + '/settings') + await waitPage(page, { selector: PAGE_READY }) + if (!(await clickText(page, '添加渠道'))) throw new Error('未找到「添加渠道」按钮') + const modal = page.locator('.n-modal').first() + try { + await modal.waitFor({ state: 'visible', timeout: 8000 }) + } catch { + // 首次点击可能未生效(页面状态未就绪),重试一次 + await clickText(page, '添加渠道') + await modal.waitFor({ state: 'visible', timeout: 15000 }) + } + // 弹窗内首个下拉为「渠道类型」,切换为飞书以展示 Webhook 与签名密钥表单 + await modal.locator('.n-base-selection').first().click() + await page.getByText('飞书', { exact: true }).last().click() + await page.waitForTimeout(600) + await modal.screenshot({ path: resolve(ELEM_DIR, 'add-channel-feishu.png') }) + console.log('[OK] modal/add-channel-feishu') + } catch (err) { + console.log(`[FAIL] add-channel-feishu: ${err}`) + } +} + /** * 截取新增记录弹窗(elements/add-record.png)。 * @@ -605,6 +637,7 @@ async function main(): Promise { await captureCalendarDetail(page) await captureAddRecord(page) await captureModals(page) + await captureChannelFeishu(page) await captureEditRecord(page) await captureInlineCreate(page) await captureAiRule(page)