{"id":"06d53a8f-b77f-4773-9097-2dd6e16ee513","entityType":"agent","slug":"clawhub-naeemtc-feishu-accounting","name":"飞书个人记账(含面板app)","canonicalUrl":"https://www.xpersona.co/agent/clawhub-naeemtc-feishu-accounting","canonicalPath":"/agent/clawhub-naeemtc-feishu-accounting","generatedAt":"2026-10-10T13:43:21.982Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":null},"description":"飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入... Skill: 飞书个人记账(含面板app) Owner: naeemtc Summary: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入... Tags: accounting:2.0.0, bitable:2.0.0, feishu:2.0.0, latest:2.1.0, setup:2.0.0 Version history: v2.1.0 | 2026-05-22T06:15:09.367Z | user v2.1.0: 饼图右侧图例, 删除逻辑修复(先飞书再本地), 单选框字段匹配修复, SKILL.md权限19个scope补全, 清理踩坑说明 v2.0","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.5K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s170vht2yz7teynje6m1q699xh84rgyr:feishu-accounting","sourceUrl":"https://clawhub.ai/naeemtc/feishu-accounting","homepage":"https://clawhub.ai/naeemtc/skills/feishu-accounting","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/naeemtc/feishu-accounting","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/naeemtc/skills/feishu-accounting","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":64,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":null},"stars":null,"forks":null,"downloads":1507,"packageName":null,"latestVersion":"2.1.0","tractionLabel":"1.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T10:04:13.007Z","lastCrawledAt":"2026-10-10T10:04:13.007Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T10:04:13.007Z","lastVerifiedAt":null,"highlights":[{"version":"2.1.0","createdAt":"2026-05-22T06:15:09.367Z","changelog":"v2.1.0: 饼图右侧图例, 删除逻辑修复(先飞书再本地), 单选框字段匹配修复, SKILL.md权限19个scope补全, 清理踩坑说明","fileCount":11,"zipByteSize":26545},{"version":"2.0.0","createdAt":"2026-05-22T02:55:13.078Z","changelog":"大版本更新，保持与 GitHub 1.3.4 同步","fileCount":10,"zipByteSize":23910},{"version":"1.3.4","createdAt":"2026-05-21T09:29:29.902Z","changelog":"fix: 收入分类写飞书时保留原名（工资/奖金/兼职/投资），不再归入「其它」","fileCount":12,"zipByteSize":30436},{"version":"1.3.3","createdAt":"2026-05-21T09:06:37.342Z","changelog":"v1.3.3 — 修复字段索引错位：修复API返回字段数组顺序与代码硬编码索引不匹配导致的\"所有图表/卡片空白\"问题（FI.text=1, FI.month=5），修复keystore密码硬编码隐私泄露 v1.3.2 — 修复收入混入支出图表、检查更新超时保护、SKILL.md移除错误发版指引 v1.3.1 — 修复JS加载崩溃：解决ALL_CATS声明顺序导致脚本加载期TypeError v1.3.0 — 单表重构：合并汇总表与明细表，新增收入饼图/分类tab，UI润色（按钮统一scale反馈、弹窗背景关闭、页面过渡动画、颜色CSS变量化）","fileCount":12,"zipByteSize":29273},{"version":"1.2.4","createdAt":"2026-05-21T02:33:39.704Z","changelog":"修复 feishu-cli 下载链接（404 + 超时），纯 GitHub 官方链接无代理","fileCount":5,"zipByteSize":13330},{"version":"1.2.3","createdAt":"2026-05-20T09:54:26.495Z","changelog":"fix: 去掉第三方代理和 sudo 依赖，改为 GitHub 直连 + 用户目录安装","fileCount":4,"zipByteSize":12979},{"version":"1.2.2","createdAt":"2026-05-20T08:23:23.934Z","changelog":"v1.2.2: APK 下载链接改为 latest 永不过期格式（releases/latest/download/app-release.apk），以后发版无需改文档","fileCount":4,"zipByteSize":12419},{"version":"1.2.1","createdAt":"2026-05-20T02:47:33.516Z","changelog":"修复SKILL.md中APK下载链接为v1.2.0","fileCount":4,"zipByteSize":12938}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s170vht2yz7teynje6m1q699xh84rgyr:feishu-accounting","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T13:43:21.977Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-naeemtc-feishu-accounting/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":null},"readme":"Skill: 飞书个人记账(含面板app)\n\nOwner: naeemtc\n\nSummary: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入...\n\nTags: accounting:2.0.0, bitable:2.0.0, feishu:2.0.0, latest:2.1.0, setup:2.0.0\n\nVersion history:\n\nv2.1.0 | 2026-05-22T06:15:09.367Z | user\n\nv2.1.0: 饼图右侧图例, 删除逻辑修复(先飞书再本地), 单选框字段匹配修复, SKILL.md权限19个scope补全, 清理踩坑说明\n\nv2.0.0 | 2026-05-22T02:55:13.078Z | user\n\n大版本更新，保持与 GitHub 1.3.4 同步\n\nv1.3.4 | 2026-05-21T09:29:29.902Z | user\n\nfix: 收入分类写飞书时保留原名（工资/奖金/兼职/投资），不再归入「其它」\n\nv1.3.3 | 2026-05-21T09:06:37.342Z | user\n\nv1.3.3 — 修复字段索引错位：修复API返回字段数组顺序与代码硬编码索引不匹配导致的\"所有图表/卡片空白\"问题（FI.text=1, FI.month=5），修复keystore密码硬编码隐私泄露\nv1.3.2 — 修复收入混入支出图表、检查更新超时保护、SKILL.md移除错误发版指引\nv1.3.1 — 修复JS加载崩溃：解决ALL_CATS声明顺序导致脚本加载期TypeError\nv1.3.0 — 单表重构：合并汇总表与明细表，新增收入饼图/分类tab，UI润色（按钮统一scale反馈、弹窗背景关闭、页面过渡动画、颜色CSS变量化）\n\nv1.2.4 | 2026-05-21T02:33:39.704Z | user\n\n修复 feishu-cli 下载链接（404 + 超时），纯 GitHub 官方链接无代理\n\nv1.2.3 | 2026-05-20T09:54:26.495Z | user\n\nfix: 去掉第三方代理和 sudo 依赖，改为 GitHub 直连 + 用户目录安装\n\nv1.2.2 | 2026-05-20T08:23:23.934Z | user\n\nv1.2.2: APK 下载链接改为 latest 永不过期格式（releases/latest/download/app-release.apk），以后发版无需改文档\n\nv1.2.1 | 2026-05-20T02:47:33.516Z | user\n\n修复SKILL.md中APK下载链接为v1.2.0\n\nv1.2.0 | 2026-05-20T02:46:03.072Z | user\n\n分类扩展至13个（+服饰/生活/数码/运动/宠物），新增设置弹窗（分类勾选+检查更新+关于），弹窗淡入缩放动画，版本号统一为v1.2.0，keystore密码改为环境变量\n\nv1.1.0 | 2026-05-20T02:13:33.534Z | user\n\n分类扩展至13个（+服饰/生活/数码/运动/宠物），新增设置弹窗（分类勾选+检查更新），统一按钮尺寸，同步更新建表步骤和categories.md\n\nv1.0.4 | 2026-05-20T01:43:12.676Z | user\n\nfeat: 新增分类设置功能，13个分类可选，未勾选归入其他\n\nv1.0.3 | 2026-05-19T09:24:45.634Z | user\n\ndocs: 更新标题，标注含安卓仪表盘App\n\nv1.0.2 | 2026-05-19T07:43:09.659Z | user\n\nfix: APK 下载链接指向正确文件名\n\nv1.0.1 | 2026-05-19T06:21:12.678Z | user\n\nfix: 移除 SKILL.md 中的示例 base_token 防止凭证泄漏\n\nv1.0.0 | 2026-05-18T09:12:47.871Z | auto\n\nfeishu-accounting 1.0.0\n\n- 首次发布完整的飞书多维表格记账技能包。\n- 支持一键引导配置，包括飞书应用创建、表格搭建、权限开通及凭证收集。\n- 日常记账支持本地存储与飞书多维表格实时同步，自动写入明细表和汇总表。\n- 提供详细的setup、记账与查询命令说明，支持图片记账和多语句触发。\n- 附带环境变量和凭证管理说明，兼容 Android App 仪表盘查看数据。\n\nArchive index:\n\nArchive v2.1.0: 11 files, 26545 bytes\n\nFiles: references/apk-architecture.md (5053b), references/categories.md (2780b), references/feishu-base-api-pitfalls.md (2166b), references/feishu-permissions-api.md (2362b), scripts/apply_permissions.py (4621b), scripts/cleanup_bitable.py (4597b), scripts/record_bill.py (21368b), scripts/setup_bitable.py (6563b), skill-card.md (2643b), SKILL.md (10705b), _meta.json (136b)\n\nFile v2.1.0:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入明细表，通过「类型」字段区分支出和收入。**\nversion: 1.3.4\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup, permissions]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 引导创建飞书应用 → 一键搭建多维表格 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书明细表（单表模式） |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 2：一键开通权限（Agent 自动生成授权链接，用户只需点击确认）\n\n**AI 执行** `apply_permissions.py`（自动获取 Tenant Token、生成一键授权链接）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本输出一个 **一键授权链接**，AI 直接把脚本输出的完整链接原样发给用户\n\n> ⚠️ **AI 注意**：不要自己拼链接！必须运行 `apply_permissions.py`，取 stdout 里的链接，原样发给用户。链接里必须包含以下全部 19 个权限，一个不能少：\n>\n> `base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only,bitable:app:readonly,bitable:app`\n>\n> 用户点击链接 → 页面列出所有权限 → 全选后点击 **「确认开通权限」** → 完成。\n\n**然后 AI 调用** `scopes/apply` API 提交管理员审批申请。\n\n---\n\n### Step 3：一键搭建多维表格\n\n用户提供 App ID + App Secret 后，运行 `setup_bitable.py`（无需安装任何外部工具，直接调飞书 API）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本会自动完成：\n1. 获取 Tenant Token（永久有效）\n2. 创建多维表格「个人记账本」\n3. 创建一张明细表（单表模式，支出和收入共用）\n4. 创建所有字段（文本/月份/金额/分类/类型）+ 补充选项（18个分类 + 收支类型选项）\n\n输出 4 个凭证：App ID / App Secret / Base Token / 明细表 Table ID\n\n### Step 4：输出凭证给用户\n\n**AI 必须将以下 4 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 1 用户提供的值，Base Token / Table ID 来自 Step 3 脚本输出的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 4 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的全量账本数据）\n\n### Step 5：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF\n```\n\n### Step 6：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n\n> **⚠️ 单表模式**：支出和收入均写入同一张明细表，通过「类型」字段区分。App 端按类型字段分组聚合计算月度收支。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 数据管理（查看 / 删除记录）\n\n**查看记录：**\n```bash\n# 列出当日账单（含序号，用于定位要删除的记录）\npython3 scripts/record_bill.py --list\n\n# 列出指定日期账单\npython3 scripts/record_bill.py --list --date 2026-05-22\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n`--list` 输出中每条记录有一个 `index` 字段（1起算），用于删除定位。\n\n**删除记录：**\n```bash\n# 删除指定日期的第 N 条记录（同时从本地文件和飞书明细表移除）\npython3 scripts/record_bill.py --delete --date 2026-05-22 --index 2\n```\n\n> **注意**：删除操作会同时从本地 `bills/YYYY-MM-DD.md` 和飞书明细表移除记录，**不可撤销**，请先确认 index 序号正确。\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md` 和 `references/feishu-permissions-api.md`（飞书权限 API 模式），核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n| 支出 | 通讯 | 话费/流量/套餐 |\n| 支出 | 医疗 | 医院/药店/挂号/体检 |\n| 支出 | 住房 | 房租/水电/物业/宽带 |\n| 支出 | 教育 | 学费/课程/书/培训 |\n| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n| 收入 | 工资 | 工资/薪资/月薪 |\n| 收入 | 兼职 | 兼职/副业/接单 |\n| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个支出分类 + 5个收入分类（工资/奖金/兼职/投资/其他），在飞书明细表中均有对应选项，无需映射损耗。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md                   # 本文件\n├── scripts/\n│   ├── record_bill.py         # 记账核心脚本\n│   ├── setup_bitable.py       # 一键搭建多维表格脚本\n│   ├── cleanup_bitable.py     # 清空多维表格数据（重置/测试用）\n│   └── apply_permissions.py   # 一键权限申请——生成授权链接 + 调 scopes/apply\n└── references/\n    └── categories.md                # 分类关键词参考\n    └── feishu-base-api-pitfalls.md   # base/v3 API 踩坑记录（分页/字段/格式）\n    └── feishu-permissions-api.md     # 飞书权限一键授权 API 模式\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_APP_ID` | 飞书应用 App ID（必填） | `cli_xxxxxxxxxxxxxxxx` |\n| `FEISHU_APP_SECRET` | 飞书应用 App Secret（必填） | `xxxxxxxxxxxxxxxxxx` |\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID（单表，含类型字段区分收支） | `tblxxxxxxxxxxxxxxxx` |\n\n> **无需 User Access Token**：record_bill.py 使用永久有效的 Tenant Token（自动从 App ID + Secret 获取），不再有 7 天过期问题。\n\nFile v2.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"2.1.0\",\n  \"publishedAt\": 1779430509367\n}\n\nFile v2.1.0:references/apk-architecture.md\n\n# APK 仪表盘 App 内部架构\n\n本 App 是 Capacitor 项目，核心为单文件 `dist/index.html`（~1100 行）。Android 层只提供一个 WebView 壳子，所有 UI 和业务逻辑在 HTML 内。\n\n## 文件结构（dist 目录）\n\n```\ndist/\n└── index.html          # 唯一源码，内嵌 CSS + JS + ECharts\nandroid/\n└── app/\n    └── build.gradle    # versionCode + versionName + 签名配置\n```\n\n## 字段索引映射（FI）\n\nFeishu base v3 API 使用 `offset` 翻页时，记录以**位置数组**返回。`FI` 对象定义字段位置：\n\n```javascript\nvar FI = {text: 0, month: 1, amount: 2, category: 3, type: 4};\n```\n\n| 索引 | 字段名 | Feishu 类型 | JS 访问方式 | 示例值 |\n|------|--------|-------------|------------|--------|\n| 0 | 文本 | 文本 | `r[FI.text]` | `\"2026-05-21 12:30 午饭\"` |\n| 1 | 月份 | 文本 | `r[FI.month]` | `\"2026-05\"` |\n| 2 | 金额 | 数字 | `r[FI.amount]` | `23.50` |\n| 3 | 分类 | 单选 | `r[FI.category]` | `[\"餐饮\"]` |\n| 4 | 类型 | 单选 | `r[FI.type]` | `[\"支出\"]` |\n\n注意：单选/多选字段在数组中的值是 **数组**（`[\"餐饮\"]`），取第一个用 `arr[0]`。\n\n**FI 顺序由 setup_bitable.py 中 create_field 的调用顺序决定**，不能随意调整。\n\n## 业务逻辑流程\n\n### 数据生命周期\n\n1. **登录** → 输入 App ID / Secret / Base Token / Table ID → 存 localStorage\n2. **init()** → getToken() → fetchAll() → 拉取全部明细记录 → showApp() + render()\n3. **刷新** → doRefresh() → 重新 fetchAll → 渲染\n4. **月份切换** → 改变 curMonth → re-render（不复拉数据）\n5. **全部模式** → isTotalMode=true → render(month=null) → 聚合所有月份\n\n### 渲染链\n\n```\nrender()\n├── getMonthSummary(month)      → 遍历 detailRecords，按 type 字段区分收支\n├── renderSummary(inc, exp)     → 三张卡片 + 自适应字号（canvas measureText）\n├── renderPie(cats)             → 支出饼图（ECharts 环形图）\n├── renderIncPie(incCats)       → 收入饼图（仅在 showIncomePie=true 时）\n├── renderHBar(cats)            → 分类金额水平条形图\n├── renderBar()                 → 月度对比柱状图（从 detailRecords 按月份聚合）\n├── renderLine(month)           → 日支出趋势折线图\n└── renderDetails(month)        → 消费明细列表 + 分页\n```\n\n### 样式架构\n\n- 主题通过 `data-theme` 属性切换（dark / light）\n- 所有颜色通过 CSS 变量引用（`var(--bg)`, `var(--card)` 等）\n- ECharts 颜色通过 `CUR_THEME` 对象传递\n- 按钮反馈统一使用 `transform:scale`\n- 页面入场：`fadeUp` 动画\n\n## UI 约定速查\n\n| 组件 | CSS 类 | 按压反馈 | 禁用态 |\n|------|--------|----------|--------|\n| 导航按钮 | `.mbtn` | `scale(.88)` | `opacity:.35, cursor:not-allowed` |\n| 主操作按钮 | `.lbtn` | `scale(.97)` | (无禁用态) |\n| 弹窗按钮 | `.dbtn` | `scale(.95)` | (内联控制) |\n| 功能按钮按下态 | `.pressed` | 背景色变 accent，颜色变白 | — |\n| header 齿轮 | `.mbtn.sett:active` | `rotate(45deg)` | — |\n| header 刷新 | `.mbtn.refresh:active` | `rotate(180deg)` | — |\n\n## 弹窗系统\n\n所有弹窗使用同一套模式：\n\n1. 点击触发 → `lock-scroll` → 移除 overlay 的 `hidden` → 显示 `dialogIn` 动画\n2. 关闭 → `closeOverlay(id)` → 加 `.closing` 类触发 `dialogOut` 动画（150ms）→ 加 `.hidden` → 移除 `lock-scroll`\n3. 背景关闭 → 绑定 `click` 事件检查 `e.target === this`\n\n| 弹窗 | overlay ID | 关闭方式 |\n|------|-----------|----------|\n| 设置 | `sett-overlay` | 点击 ✕ / 背景 |\n| 分类设置 | `cat-overlay` | 点击 ✕ / 背景 |\n| 检查更新 | `upd-overlay` | 点击按钮 / 背景 |\n| 关于 | `abt-overlay` | 点击 ✕ / 背景 |\n| 刷新确认 | `refresh-overlay` | 点击按钮 / 背景 |\n| 通用错误 | `.dialog` | 点击按钮 |\n\n## 主题系统\n\n```javascript\nvar THEMES = {\n  dark:  { tooltipBg: '#1a1a2e', tooltipBorder: '#2a2a4a', ... },\n  light: { tooltipBg: '#ffffff', tooltipBorder: '#ddd6cc', ... }\n};\n```\n\n`applyTheme(theme)` 会：\n1. 设置 `data-theme` 属性 + `localStorage` 持久化\n2. 更新按钮图标（☀ / 🌙）\n3. 全部 dispose 已有 ECharts 实例\n4. 调用 `render()` 重绘\n5. 给每个图表容器加 `.chart-fade` 淡入类（300ms 后移除）\n\n## 版本号三处同步\n\n| 文件 | 变量 | 示例 |\n|------|------|------|\n| `dist/index.html` (JS) | `APP_VERSION` | `'1.3.0'` |\n| `android/app/build.gradle` | `versionCode`, `versionName` | `14`, `\"1.3.0\"` |\n| 仓库 `SKILL.md` | `version:` | `1.3.0` |\n\nversionCode 计算：主×10000 + 次×100 + 修订，每次 release +1。\n\n## 构建与发布\n\n```bash\nexport JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64\ncd /path/to/feishu-dashboard-app\nbash sync.sh\n# APK 输出到 android/app/build/outputs/apk/release/app-release.apk\n```\n\n发布流程：构建 → 用户测试 → git add + commit → git tag → GitHub Release（手动）\n\nFile v2.1.0:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nFile v2.1.0:references/feishu-base-api-pitfalls.md\n\n# 飞书 base/v3 API 踩坑记录\n\n## 1. Record 创建：不加 `fields` 包装\n\n```python\n# ✅ 正确（base/v3 API 直接平铺字段）\npayload = {\n    \"月份\": \"2026-05\",\n    \"分类\": \"餐饮\",\n    \"金额\": 23.40,\n    \"文本\": \"2026-05-15 13:11午饭\",\n}\n\n# ❌ 错误（这是其他飞书 API 的格式，base/v3 不支持）\npayload = {\n    \"fields\": {\n        \"月份\": \"2026-05\",\n        ...\n    }\n}\n```\n\n错误响应：`\"Record write payload must not be wrapped in 'fields'.\"`\n\n## 2. Tenant Token 分页上限只有 ~20 条\n\n`page_size=100` 参数在 Tenant Token 下实际只返回 20 条（实测验证），`has_more` 正常指示。\n\n**正确翻页写法：**\n\n```python\noffset = 0\nwhile True:\n    url = f\"/records?page_size=100&offset={offset}\"\n    # ... 请求 ...\n    records = data[\"data\"][\"data\"]\n    if not records:\n        break\n    for rec in records:\n        process(rec)\n    offset += len(records)  # 按实际返回数累加，而非固定步长\n```\n\n**错误写法（会漏数据）：**\n```python\noffset += 100  # ❌ 实际只返回 20 条，offset=100 跳过了 21-100\n```\n\n## 3. 字段创建后需等待缓存生效\n\n创建字段后立即更新选项（UPDATE field）需要加 `time.sleep(1)`，否则飞书返回 400。\n\n```python\ndef update_field_options(...):\n    time.sleep(1)  # 等待字段创建缓存生效\n    # 然后才能 PUT 更新选项\n```\n\n## 4. 地址恢复与字段映射\n\n```\n创建多维表格: data[\"base_token\"]        # 不是 data[\"base\"][\"token\"]\n创建数据表:   data[\"id\"]                # 不是 data[\"table_id\"]\n创建字段:     data[\"id\"]                # 不是 data[\"field\"][\"id\"]\n更新字段:     用 PUT                     # 不是 PATCH\n```\n\n每次写字段前，建议调 `GET /fields` 确认字段顺序和 ID，不要靠记忆写死 index。\n\n## 5. `.env` 加载：用直接赋值覆盖父 shell 变量\n\n```python\n# ❌ 错误：setdefault 不覆盖已存在的环境变量\n# 如果父 shell 已有 FEISHU_APP_ID（旧应用的），.env 的值会被忽略\nos.environ.setdefault(k.strip(), v.strip())\n\n# ✅ 正确：直接赋值，.env 始终优先\nos.environ[k.strip()] = v.strip()\n```\n\nFile v2.1.0:references/feishu-permissions-api.md\n\n# 飞书开放平台权限申请 API 模式\n\n## 问题\n\n飞书自建应用需要开通 API 权限才能调用接口。传统的控制台手动搜索勾选效率低、易遗漏。\n\n## 两个 API 工具\n\n### 1. 一键授权链接（推荐用于 Setup 阶段）\n\n飞书支持把权限 scope 打包在 URL 里，用户点一次确认即可批量开通。\n\n**格式：**\n```\nhttps://open.feishu.cn/app/{appId}/auth?q=scope1,scope2,...&op_from=openapi&token_type=tenant\n```\n\n**示例（记账系统）：**\n```\nhttps://open.feishu.cn/app/cli_xxx/auth?q=base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only&op_from=openapi&token_type=tenant\n```\n\n**用户操作：** 点击链接 → 确认开通 → 完成。\n\n### 2. scopes/apply API（用于触发审批）\n\n```http\nPOST https://open.feishu.cn/open-apis/application/v6/scopes/apply\nAuthorization: Bearer {tenant_access_token}\nContent-Type: application/json; charset=utf-8\n```\n\nBody 为空 JSON `{}`。不需要额外权限即可调用（Required Scopes: None）。\n\n**返回码：**\n| code | 含义 |\n|------|------|\n| 0 | 成功，已提交审批 |\n| 212002 | 所有权限已授权，无需审批 |\n| 212003 | 同版本申请超过 10 次限制 |\n| 212004 | 重复申请 |\n\n### 完整流程\n\n1. 用户创建飞书自建应用，提供 App ID + App Secret\n2. Agent 生成**一键授权链接**给用户\n3. 用户点击链接 → 确认开通所有权限 → **即时生效** ✅\n\n> ⚠️ 常见误区：**不需要创建版本和发布**。对于自建应用，管理员（也是应用创建者）点击确认后权限立即生效。发版流程是商店应用或需要管理员审核的企业应用场景，不适用于个人自建应用。\n\n### 注意事项\n\n- `scopes/apply` 同版本上限 10 次。确认权限后调用返回 212002（均已授权）是正常现象，无需重复调用\n- Tenant Token 需通过 `POST /open-apis/auth/v3/tenant_access_token/internal` 获取\n- 权限生效后仍需重试 API 调用（之前的 400/403 错误已经过去，需要重新请求）\n- 自建应用场景下，应用开发者和管理员同一人时，无额外审批节点\n\nFile v2.1.0:skill-card.md\n\n## Description:\n\n飞书多维表格记账系统完整技能包，帮助用户配置飞书自建应用和多维表格，并通过脚本记录、查询和同步个人收支。\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[naeemtc](https://clawhub.ai/user/naeemtc)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users use this skill to set up a Feishu Base personal accounting system, record income and expenses, query local bill files, and synchronize bookkeeping records to Feishu.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Broad Feishu Base permissions can expose or change more workspace data than intended.\n\nMitigation: Use a least-privilege Feishu app where possible and review the requested permission list before approving access.\n\nRisk: Long-lived App Secret handling can leak credentials through chat history, shell history, logs, or local files.\n\nMitigation: Avoid pasting secrets into shared channels, store credentials only on trusted local machines, and rotate any secret already used in an exposed workflow.\n\nRisk: The Android APK is distributed as a release artifact outside the skill package.\n\nMitigation: Verify the APK source or build it locally before installation.\n\nRisk: Receipt image parsing can record incorrect amounts or categories.\n\nMitigation: Manually confirm parsed receipt data before recording transactions.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/naeemtc/skills/feishu-accounting)\n- [Project homepage](https://github.com/NaeemTC/feishu-accounting-skill)\n- [Feishu Open Platform](https://open.feishu.cn)\n- [APK dashboard architecture](references/apk-architecture.md)\n- [Accounting categories reference](references/categories.md)\n- [Feishu Base API pitfalls](references/feishu-base-api-pitfalls.md)\n- [Feishu permissions API](references/feishu-permissions-api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, Files]\n\n**Output Format:** [Markdown guidance with shell commands and credential/configuration snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May create local .env and bills/YYYY-MM-DD.md files and synchronize records to Feishu Base when credentials are supplied.]\n\n## Skill Version(s):\n\n2.1.0 (source: server release evidence; artifact frontmatter states 1.3.4)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.0.0: 10 files, 23910 bytes\n\nFiles: references/apk-architecture.md (5053b), references/categories.md (2780b), references/feishu-base-api-pitfalls.md (2166b), references/feishu-permissions-api.md (2362b), scripts/apply_permissions.py (4574b), scripts/cleanup_bitable.py (4597b), scripts/record_bill.py (19016b), scripts/setup_bitable.py (6563b), SKILL.md (9649b), _meta.json (136b)\n\nFile v2.0.0:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入明细表，通过「类型」字段区分支出和收入。**\nversion: 1.3.4\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup, permissions]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 引导创建飞书应用 → 一键搭建多维表格 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书明细表（单表模式） |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 2：一键开通权限（Agent 自动生成授权链接，用户只需点击确认）\n\n**AI 执行** `apply_permissions.py`（自动获取 Tenant Token、生成一键授权链接）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本输出一个 **一键授权链接**，AI 直接把链接发给用户：\n\n> 点击下方链接，所有记账需要的权限已经预选好了，你只需确认一次：\n>\n> 🔗 `https://open.feishu.cn/app/{appId}/auth?q=base:app:read,base:app:update,...&op_from=openapi&token_type=tenant`\n>\n> 点击后 → 页面会列出所有需要的 base 权限 → 全选后点击 **「确认开通权限」** → 完成。\n\n**然后 AI 调用** `scopes/apply` API 提交管理员审批申请。\n\n---\n\n### Step 3：一键搭建多维表格\n\n用户提供 App ID + App Secret 后，运行 `setup_bitable.py`（无需安装任何外部工具，直接调飞书 API）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本会自动完成：\n1. 获取 Tenant Token（永久有效）\n2. 创建多维表格「个人记账本」\n3. 创建一张明细表（单表模式，支出和收入共用）\n4. 创建所有字段（文本/月份/金额/分类/类型）+ 补充选项（18个分类 + 收支类型选项）\n\n输出 4 个凭证：App ID / App Secret / Base Token / 明细表 Table ID\n\n### Step 4：输出凭证给用户\n\n**AI 必须将以下 4 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 1 用户提供的值，Base Token / Table ID 来自 Step 3 脚本输出的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 4 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的全量账本数据）\n\n### Step 5：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF\n```\n\n### Step 6：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 单表模式**：支出和收入均写入同一张明细表，通过「类型」字段区分。App 端按类型字段分组聚合计算月度收支。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md` 和 `references/feishu-permissions-api.md`（飞书权限 API 模式），核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n| 支出 | 通讯 | 话费/流量/套餐 |\n| 支出 | 医疗 | 医院/药店/挂号/体检 |\n| 支出 | 住房 | 房租/水电/物业/宽带 |\n| 支出 | 教育 | 学费/课程/书/培训 |\n| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n| 收入 | 工资 | 工资/薪资/月薪 |\n| 收入 | 兼职 | 兼职/副业/接单 |\n| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个支出分类 + 5个收入分类（工资/奖金/兼职/投资/其他），在飞书明细表中均有对应选项，无需映射损耗。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md                   # 本文件\n├── scripts/\n│   ├── record_bill.py         # 记账核心脚本\n│   ├── setup_bitable.py       # 一键搭建多维表格脚本\n│   ├── cleanup_bitable.py     # 清空多维表格数据（重置/测试用）\n│   └── apply_permissions.py   # 一键权限申请——生成授权链接 + 调 scopes/apply\n└── references/\n    └── categories.md                # 分类关键词参考\n    └── feishu-base-api-pitfalls.md   # base/v3 API 踩坑记录（分页/字段/格式）\n    └── feishu-permissions-api.md     # 飞书权限一键授权 API 模式\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_APP_ID` | 飞书应用 App ID（必填） | `cli_xxxxxxxxxxxxxxxx` |\n| `FEISHU_APP_SECRET` | 飞书应用 App Secret（必填） | `xxxxxxxxxxxxxxxxxx` |\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID（单表，含类型字段区分收支） | `tblxxxxxxxxxxxxxxxx` |\n\n> **无需 User Access Token**：record_bill.py 使用永久有效的 Tenant Token（自动从 App ID + Secret 获取），不再有 7 天过期问题。\n\n---\n\nFile v2.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"2.0.0\",\n  \"publishedAt\": 1779418513078\n}\n\nFile v2.0.0:references/apk-architecture.md\n\n# APK 仪表盘 App 内部架构\n\n本 App 是 Capacitor 项目，核心为单文件 `dist/index.html`（~1100 行）。Android 层只提供一个 WebView 壳子，所有 UI 和业务逻辑在 HTML 内。\n\n## 文件结构（dist 目录）\n\n```\ndist/\n└── index.html          # 唯一源码，内嵌 CSS + JS + ECharts\nandroid/\n└── app/\n    └── build.gradle    # versionCode + versionName + 签名配置\n```\n\n## 字段索引映射（FI）\n\nFeishu base v3 API 使用 `offset` 翻页时，记录以**位置数组**返回。`FI` 对象定义字段位置：\n\n```javascript\nvar FI = {text: 0, month: 1, amount: 2, category: 3, type: 4};\n```\n\n| 索引 | 字段名 | Feishu 类型 | JS 访问方式 | 示例值 |\n|------|--------|-------------|------------|--------|\n| 0 | 文本 | 文本 | `r[FI.text]` | `\"2026-05-21 12:30 午饭\"` |\n| 1 | 月份 | 文本 | `r[FI.month]` | `\"2026-05\"` |\n| 2 | 金额 | 数字 | `r[FI.amount]` | `23.50` |\n| 3 | 分类 | 单选 | `r[FI.category]` | `[\"餐饮\"]` |\n| 4 | 类型 | 单选 | `r[FI.type]` | `[\"支出\"]` |\n\n注意：单选/多选字段在数组中的值是 **数组**（`[\"餐饮\"]`），取第一个用 `arr[0]`。\n\n**FI 顺序由 setup_bitable.py 中 create_field 的调用顺序决定**，不能随意调整。\n\n## 业务逻辑流程\n\n### 数据生命周期\n\n1. **登录** → 输入 App ID / Secret / Base Token / Table ID → 存 localStorage\n2. **init()** → getToken() → fetchAll() → 拉取全部明细记录 → showApp() + render()\n3. **刷新** → doRefresh() → 重新 fetchAll → 渲染\n4. **月份切换** → 改变 curMonth → re-render（不复拉数据）\n5. **全部模式** → isTotalMode=true → render(month=null) → 聚合所有月份\n\n### 渲染链\n\n```\nrender()\n├── getMonthSummary(month)      → 遍历 detailRecords，按 type 字段区分收支\n├── renderSummary(inc, exp)     → 三张卡片 + 自适应字号（canvas measureText）\n├── renderPie(cats)             → 支出饼图（ECharts 环形图）\n├── renderIncPie(incCats)       → 收入饼图（仅在 showIncomePie=true 时）\n├── renderHBar(cats)            → 分类金额水平条形图\n├── renderBar()                 → 月度对比柱状图（从 detailRecords 按月份聚合）\n├── renderLine(month)           → 日支出趋势折线图\n└── renderDetails(month)        → 消费明细列表 + 分页\n```\n\n### 样式架构\n\n- 主题通过 `data-theme` 属性切换（dark / light）\n- 所有颜色通过 CSS 变量引用（`var(--bg)`, `var(--card)` 等）\n- ECharts 颜色通过 `CUR_THEME` 对象传递\n- 按钮反馈统一使用 `transform:scale`\n- 页面入场：`fadeUp` 动画\n\n## UI 约定速查\n\n| 组件 | CSS 类 | 按压反馈 | 禁用态 |\n|------|--------|----------|--------|\n| 导航按钮 | `.mbtn` | `scale(.88)` | `opacity:.35, cursor:not-allowed` |\n| 主操作按钮 | `.lbtn` | `scale(.97)` | (无禁用态) |\n| 弹窗按钮 | `.dbtn` | `scale(.95)` | (内联控制) |\n| 功能按钮按下态 | `.pressed` | 背景色变 accent，颜色变白 | — |\n| header 齿轮 | `.mbtn.sett:active` | `rotate(45deg)` | — |\n| header 刷新 | `.mbtn.refresh:active` | `rotate(180deg)` | — |\n\n## 弹窗系统\n\n所有弹窗使用同一套模式：\n\n1. 点击触发 → `lock-scroll` → 移除 overlay 的 `hidden` → 显示 `dialogIn` 动画\n2. 关闭 → `closeOverlay(id)` → 加 `.closing` 类触发 `dialogOut` 动画（150ms）→ 加 `.hidden` → 移除 `lock-scroll`\n3. 背景关闭 → 绑定 `click` 事件检查 `e.target === this`\n\n| 弹窗 | overlay ID | 关闭方式 |\n|------|-----------|----------|\n| 设置 | `sett-overlay` | 点击 ✕ / 背景 |\n| 分类设置 | `cat-overlay` | 点击 ✕ / 背景 |\n| 检查更新 | `upd-overlay` | 点击按钮 / 背景 |\n| 关于 | `abt-overlay` | 点击 ✕ / 背景 |\n| 刷新确认 | `refresh-overlay` | 点击按钮 / 背景 |\n| 通用错误 | `.dialog` | 点击按钮 |\n\n## 主题系统\n\n```javascript\nvar THEMES = {\n  dark:  { tooltipBg: '#1a1a2e', tooltipBorder: '#2a2a4a', ... },\n  light: { tooltipBg: '#ffffff', tooltipBorder: '#ddd6cc', ... }\n};\n```\n\n`applyTheme(theme)` 会：\n1. 设置 `data-theme` 属性 + `localStorage` 持久化\n2. 更新按钮图标（☀ / 🌙）\n3. 全部 dispose 已有 ECharts 实例\n4. 调用 `render()` 重绘\n5. 给每个图表容器加 `.chart-fade` 淡入类（300ms 后移除）\n\n## 版本号三处同步\n\n| 文件 | 变量 | 示例 |\n|------|------|------|\n| `dist/index.html` (JS) | `APP_VERSION` | `'1.3.0'` |\n| `android/app/build.gradle` | `versionCode`, `versionName` | `14`, `\"1.3.0\"` |\n| 仓库 `SKILL.md` | `version:` | `1.3.0` |\n\nversionCode 计算：主×10000 + 次×100 + 修订，每次 release +1。\n\n## 构建与发布\n\n```bash\nexport JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64\ncd /path/to/feishu-dashboard-app\nbash sync.sh\n# APK 输出到 android/app/build/outputs/apk/release/app-release.apk\n```\n\n发布流程：构建 → 用户测试 → git add + commit → git tag → GitHub Release（手动）\n\nFile v2.0.0:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nFile v2.0.0:references/feishu-base-api-pitfalls.md\n\n# 飞书 base/v3 API 踩坑记录\n\n## 1. Record 创建：不加 `fields` 包装\n\n```python\n# ✅ 正确（base/v3 API 直接平铺字段）\npayload = {\n    \"月份\": \"2026-05\",\n    \"分类\": \"餐饮\",\n    \"金额\": 23.40,\n    \"文本\": \"2026-05-15 13:11午饭\",\n}\n\n# ❌ 错误（这是其他飞书 API 的格式，base/v3 不支持）\npayload = {\n    \"fields\": {\n        \"月份\": \"2026-05\",\n        ...\n    }\n}\n```\n\n错误响应：`\"Record write payload must not be wrapped in 'fields'.\"`\n\n## 2. Tenant Token 分页上限只有 ~20 条\n\n`page_size=100` 参数在 Tenant Token 下实际只返回 20 条（实测验证），`has_more` 正常指示。\n\n**正确翻页写法：**\n\n```python\noffset = 0\nwhile True:\n    url = f\"/records?page_size=100&offset={offset}\"\n    # ... 请求 ...\n    records = data[\"data\"][\"data\"]\n    if not records:\n        break\n    for rec in records:\n        process(rec)\n    offset += len(records)  # 按实际返回数累加，而非固定步长\n```\n\n**错误写法（会漏数据）：**\n```python\noffset += 100  # ❌ 实际只返回 20 条，offset=100 跳过了 21-100\n```\n\n## 3. 字段创建后需等待缓存生效\n\n创建字段后立即更新选项（UPDATE field）需要加 `time.sleep(1)`，否则飞书返回 400。\n\n```python\ndef update_field_options(...):\n    time.sleep(1)  # 等待字段创建缓存生效\n    # 然后才能 PUT 更新选项\n```\n\n## 4. 地址恢复与字段映射\n\n```\n创建多维表格: data[\"base_token\"]        # 不是 data[\"base\"][\"token\"]\n创建数据表:   data[\"id\"]                # 不是 data[\"table_id\"]\n创建字段:     data[\"id\"]                # 不是 data[\"field\"][\"id\"]\n更新字段:     用 PUT                     # 不是 PATCH\n```\n\n每次写字段前，建议调 `GET /fields` 确认字段顺序和 ID，不要靠记忆写死 index。\n\n## 5. `.env` 加载：用直接赋值覆盖父 shell 变量\n\n```python\n# ❌ 错误：setdefault 不覆盖已存在的环境变量\n# 如果父 shell 已有 FEISHU_APP_ID（旧应用的），.env 的值会被忽略\nos.environ.setdefault(k.strip(), v.strip())\n\n# ✅ 正确：直接赋值，.env 始终优先\nos.environ[k.strip()] = v.strip()\n```\n\nFile v2.0.0:references/feishu-permissions-api.md\n\n# 飞书开放平台权限申请 API 模式\n\n## 问题\n\n飞书自建应用需要开通 API 权限才能调用接口。传统的控制台手动搜索勾选效率低、易遗漏。\n\n## 两个 API 工具\n\n### 1. 一键授权链接（推荐用于 Setup 阶段）\n\n飞书支持把权限 scope 打包在 URL 里，用户点一次确认即可批量开通。\n\n**格式：**\n```\nhttps://open.feishu.cn/app/{appId}/auth?q=scope1,scope2,...&op_from=openapi&token_type=tenant\n```\n\n**示例（记账系统）：**\n```\nhttps://open.feishu.cn/app/cli_xxx/auth?q=base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only&op_from=openapi&token_type=tenant\n```\n\n**用户操作：** 点击链接 → 确认开通 → 完成。\n\n### 2. scopes/apply API（用于触发审批）\n\n```http\nPOST https://open.feishu.cn/open-apis/application/v6/scopes/apply\nAuthorization: Bearer {tenant_access_token}\nContent-Type: application/json; charset=utf-8\n```\n\nBody 为空 JSON `{}`。不需要额外权限即可调用（Required Scopes: None）。\n\n**返回码：**\n| code | 含义 |\n|------|------|\n| 0 | 成功，已提交审批 |\n| 212002 | 所有权限已授权，无需审批 |\n| 212003 | 同版本申请超过 10 次限制 |\n| 212004 | 重复申请 |\n\n### 完整流程\n\n1. 用户创建飞书自建应用，提供 App ID + App Secret\n2. Agent 生成**一键授权链接**给用户\n3. 用户点击链接 → 确认开通所有权限 → **即时生效** ✅\n\n> ⚠️ 常见误区：**不需要创建版本和发布**。对于自建应用，管理员（也是应用创建者）点击确认后权限立即生效。发版流程是商店应用或需要管理员审核的企业应用场景，不适用于个人自建应用。\n\n### 注意事项\n\n- `scopes/apply` 同版本上限 10 次。确认权限后调用返回 212002（均已授权）是正常现象，无需重复调用\n- Tenant Token 需通过 `POST /open-apis/auth/v3/tenant_access_token/internal` 获取\n- 权限生效后仍需重试 API 调用（之前的 400/403 错误已经过去，需要重新请求）\n- 自建应用场景下，应用开发者和管理员同一人时，无额外审批节点\n\nArchive v1.3.4: 12 files, 30436 bytes\n\nFiles: bills/2026-05-21.md (291b), references/apk-architecture.md (5053b), references/apk-ui-polish-checklist.md (1273b), references/categories.md (2780b), references/feishu-base-api-pitfalls.md (4632b), references/feishu-permissions-api.md (2362b), scripts/apply_permissions.py (4574b), scripts/cleanup_bitable.py (4597b), scripts/record_bill.py (19016b), scripts/setup_bitable.py (6563b), SKILL.md (17643b), _meta.json (136b)\n\nFile v1.3.4:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入明细表，通过「类型」字段区分支出和收入。**\nversion: 1.3.4\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup, permissions]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 引导创建飞书应用 → 一键搭建多维表格 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书明细表（单表模式） |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 2：一键开通权限（Agent 自动生成授权链接，用户只需点击确认）\n\n**AI 执行** `apply_permissions.py`（自动获取 Tenant Token、生成一键授权链接）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本输出一个 **一键授权链接**，AI 直接把链接发给用户：\n\n> 点击下方链接，所有记账需要的权限已经预选好了，你只需确认一次：\n>\n> 🔗 `https://open.feishu.cn/app/{appId}/auth?q=base:app:read,base:app:update,...&op_from=openapi&token_type=tenant`\n>\n> 点击后 → 页面会列出所有需要的 base 权限 → 点击 **「确认开通权限」** → 完成。\n\n**然后 AI 调用** `scopes/apply` API 提交管理员审批申请。\n\n---\n\n### Step 3：一键搭建多维表格\n\n用户提供 App ID + App Secret 后，运行 `setup_bitable.py`（无需安装任何外部工具，直接调飞书 API）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本会自动完成：\n1. 获取 Tenant Token（永久有效）\n2. 创建多维表格「个人记账本」\n3. 创建一张明细表（单表模式，支出和收入共用）\n4. 创建所有字段（文本/月份/金额/分类/类型）+ 补充选项（18个分类 + 收支类型选项）\n\n输出 4 个凭证：App ID / App Secret / Base Token / 明细表 Table ID\n\n### Step 4：输出凭证给用户\n\n**AI 必须将以下 4 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 1 用户提供的值，Base Token / Table ID 来自 Step 3 脚本输出的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 4 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的全量账本数据）\n\n### Step 5：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF\n```\n\n### Step 6：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 单表模式**：支出和收入均写入同一张明细表，通过「类型」字段区分。App 端按类型字段分组聚合计算月度收支。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md` 和 `references/feishu-permissions-api.md`（飞书权限 API 模式），核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n| 支出 | 通讯 | 话费/流量/套餐 |\n| 支出 | 医疗 | 医院/药店/挂号/体检 |\n| 支出 | 住房 | 房租/水电/物业/宽带 |\n| 支出 | 教育 | 学费/课程/书/培训 |\n| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n| 收入 | 工资 | 工资/薪资/月薪 |\n| 收入 | 兼职 | 兼职/副业/接单 |\n| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个支出分类 + 5个收入分类（工资/奖金/兼职/投资/其他），在飞书明细表中均有对应选项，无需映射损耗。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md                   # 本文件\n├── scripts/\n│   ├── record_bill.py         # 记账核心脚本\n│   ├── setup_bitable.py       # 一键搭建多维表格脚本\n│   ├── cleanup_bitable.py     # 清空多维表格数据（重置/测试用）\n│   └── apply_permissions.py   # 一键权限申请——生成授权链接 + 调 scopes/apply\n└── references/\n    └── categories.md                # 分类关键词参考\n    └── feishu-base-api-pitfalls.md   # base/v3 API 踩坑记录（分页/字段/格式）\n    └── feishu-permissions-api.md     # 飞书权限一键授权 API 模式\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_APP_ID` | 飞书应用 App ID（必填） | `cli_xxxxxxxxxxxxxxxx` |\n| `FEISHU_APP_SECRET` | 飞书应用 App Secret（必填） | `xxxxxxxxxxxxxxxxxx` |\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID（单表，含类型字段区分收支） | `tblxxxxxxxxxxxxxxxx` |\n\n> **无需 User Access Token**：record_bill.py 使用永久有效的 Tenant Token（自动从 App ID + Secret 获取），不再有 7 天过期问题。\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 建表时 HTTP 400 Bad Request | 缺 `base:table:create` 权限 | 在开放平台单独开通此权限并重新发版 |\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 Tenant Token 调 `GET .../fields` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 ~20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset += len(records)` 动态累加（而非固定步长）。详见 `references/feishu-base-api-pitfalls.md` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 飞书同步失败 | 凭证未配置或权限不足 | 检查 .env 文件中的 4 个凭证，确认 `base:record:create` 权限已开通 |\n| `.env` 中 FEISHU_APP_ID 没生效，仍用了父 shell 的旧值 | `os.environ.setdefault()` 不覆盖已有变量 | `.env` 加载改用直接赋值 `os.environ[k] = v` |\n| **APK 端：收入记录混入支出图表/明细列表** | `catSummaryFromDetail()` 和 `getDashRecords()` 没按 FI.type 过滤收入 | 添加 `if(type==='收入')continue;`（参见 `incomeCatSummaryFromDetail` 的写法） |\n| **重装 skill 时把旧 .env 带了过去** | 备份恢复操作保留旧属性（如已不用的 SUMMARY_TABLE_ID） | 全新安装时不应备份旧 .env，让用户重新走 Setup 流程获取新凭证 |\n| **income 记录写飞书后分类变成「其它」** | `FEISHU_CATEGORY_MAP` 中 `工资/奖金/兼职/投资` 映射为 `\"其它\"`（双表时代残留，收入只写汇总表不需要细分类） | 单表下收入分类应映射自身：`\"工资\": \"工资\"`，同步更新 `setup_bitable.py` 确保分类字段包含这些选项 |\n| **APK 端收入分类「其他」匹配不上飞书「其它」** | 飞书分类字段选项名是 `\"其它\"`（⺮它），但 APK 的 `INCOME_CATS` / `INC_COLORS` / 回退逻辑用了 `\"其他\"`（⺮他）。姓不同，indexOf 返回 -1 全部归入「其他」 | 全部统一为 `\"其它\"`：`INCOME_CATS`、`INC_COLORS` 键名、`incomeCatSummaryFromDetail` 回退值，三处一起改 |\n\n## 🔧 APK 开发与维护\n\n### Git 工作流（重要）\n\n本技能涉及 GitHub 仓库 `NaeemTC/feishu-accounting-skill` 的代码维护。**所有 git 操作必须遵守以下规则：**\n\n> ⚠️ **数据源可控，不加防御代码**：`record_bill.py` 是唯一的数据写入入口，`amount` 字段类型固定为 number。APK 端无需加 `parseFloat` 防御，所有字段类型都由你控制的脚本确定，不会变。不要加无意义的防御代码。\n\n**有关数据源确定性的重要原则：** `record_bill.py` 是唯一写入飞书多维表格的脚本，因此 `amount` 字段的类型始终是 number（来自脚本中的 `amount: float` 参数），`文本`、`月份` 字段始终是 string，`分类`、`类型` 是 single-select（返回数组）。APK 端读取时无需对字段类型做冗余防御（如 `parseFloat`），因为数据管道是封闭、可控的。如需改变字段类型，改 `record_bill.py` 并同时更新 APK 端 `FI` 映射即可。\n\n**改动前必须先列清单让用户确认**：动手改任何代码之前，必须先列出要改的文件和具体改动（增/删/改哪里），让用户点头再动手。不能「先改再说」。这条规则在 commit/push/release 前同样适用。\n\n**只改根因文件，不改 collateral**：定位到一个 bug 后，只改导致 bug 的根因文件。不要顺手改其他文件中「看起来也对但跟这个 bug 无关」的代码。比如：`FEISHU_CATEGORY_MAP` 映射错了导致收入分类变「其它」，那就只改 `record_bill.py`。`dist/index.html` 的 `INCOME_CATS` / `INC_COLORS` 虽然跟分类相关，但在这个 bug 里不是根因，不动。\n\n1. **任何 commit / push / tag / release 操作前，必须先问用户确认**\n2. 用户说「改了 APK 要先发测试」→ 先 build APK 发给用户测，确认无误再推 git\n3. github-repo-management 的审计清单（token 泄漏、硬编码路径等）必须过一遍\n4. 版本号三处同步：`dist/index.html` 的 `APP_VERSION` + `android/app/build.gradle` 的 `versionName/versionCode` + `SKILL.md` 的 frontmatter\n5. Release 上传 APK 固定命名 `app-release.apk`，使 latest 链接永久有效\n6. **keystore 密码不得硬编码在 build.gradle 中** — 移入 `android/keystore.properties`，`.gitignore` 排除。提供 `keystore.properties.example` 模板。这一步在发布前必须检查\n7. **ClawHub 同步** — GitHub 发布后，`clawhub publish ~/.hermes/skills/feishu-accounting --slug feishu-accounting --name \"个人记账with仪表盘app\" --version X.Y.Z --changelog \"...\"`。ClawHub 和 GitHub 是独立的，不同步\n\n### 常见 APK 端 Bug 模式\n\n| Bug | 根因 | 修复 |\n|-----|------|------|\n| 收入记录出现在支出饼图/消费明细/日趋势图中 | `catSummaryFromDetail()` 和 `getDashRecords()` 遍历 detailRecords 时没按 `FI.type` 过滤 | 添加 `var type=r[FI.type]||''; if(Array.isArray(type))type=type[0]||''; if(type==='收入')continue;` |\n| 新安装 APK 提示「正在连接飞书...」无限转圈 | **① 旧版 localStorage 存了过期凭证** — 新应用 ID/Secret 不对应 | 错误页点「重新配置」按钮清除 localStorage，或手动填写新凭证 |\n| | **② JS 声明顺序崩溃（更致命）** — `var DEFAULT_CATS=ALL_CATS.slice()` 写在 `var ALL_CATS=[...]` 之前，`ALL_CATS` 未赋值导致 `undefined.slice()` 抛出 TypeError，脚本在加载期即中断，`init()` 永不执行，线上 spinner 永远转 | 确保 `ALL_CATS` 定义在 `DEFAULT_CATS` 之前。调试方法：用 `browser_console` 看是否有 `Uncaught TypeError`（脚本加载期错误不会被 Promise.catch 捕获） |\n| 检查更新按钮点了没反应/一直转 | **① fetch 回调没调 `.json()`** — 返回的是 Response 对象，`d.tag_name` 为 undefined，条件判断永不通过 | 加 `.then(r=>r.json())` 解析 JSON |\n| | **② 无超时保护** — 请求挂起时 spinner 无限转 | 加 `AbortController` + 10 秒超时，超时显示「检查更新失败，请稍后重试」 |\n| 主题切换后图表瞬间消失 | `applyTheme` 中 dispose/recreate 图表无过渡 | 已修复：render 后对 chart 容器加 `.chart-fade` 动画类 |\n| 所有图表/卡片按月查看全空，日趋势/明细永远「暂无数据」 | `var FI` 字段索引映射不对应飞书 API 返回的数组顺序。实际数组为 `[ID,文本,金额,分类,类型,月份]`（按 field_id 字母序），但代码写成了 `{text:0,month:1}`（实际 text 在 index 1，month 在 index 5） | 调 API 验证数组顺序，设 `FI={text:1,month:5,amount:2,category:3,type:4}`。注意自动编号字段占用 index 0，单选字段返回 `[值]` 数组。详见 `references/feishu-base-api-pitfalls.md` 第6节 |\n\n### UI 风格约定\n\n- 按钮反馈：所有可点击元素统一使用 `transform:scale(.88~.97)`，不用 `opacity`\n- 弹窗：必须支持点背景关闭（`if(e.target===this)hideXxx()`）\n- 禁态：`mbtn:disabled` 设 `opacity:.35;cursor:not-allowed;transform:none!important`\n- 过渡：页面切换加 `.fade-in`（`fadeUp` 动画），主题切换图表加 `.chart-fade`\n- 颜色：禁止硬编码 `#666`，必须用 `var(--dim)` 或 `CUR_THEME.axisLabel`\n\n---\n\nFile v1.3.4:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.3.4\",\n  \"publishedAt\": 1779355769902\n}\n\nFile v1.3.4:references/apk-architecture.md\n\n# APK 仪表盘 App 内部架构\n\n本 App 是 Capacitor 项目，核心为单文件 `dist/index.html`（~1100 行）。Android 层只提供一个 WebView 壳子，所有 UI 和业务逻辑在 HTML 内。\n\n## 文件结构（dist 目录）\n\n```\ndist/\n└── index.html          # 唯一源码，内嵌 CSS + JS + ECharts\nandroid/\n└── app/\n    └── build.gradle    # versionCode + versionName + 签名配置\n```\n\n## 字段索引映射（FI）\n\nFeishu base v3 API 使用 `offset` 翻页时，记录以**位置数组**返回。`FI` 对象定义字段位置：\n\n```javascript\nvar FI = {text: 0, month: 1, amount: 2, category: 3, type: 4};\n```\n\n| 索引 | 字段名 | Feishu 类型 | JS 访问方式 | 示例值 |\n|------|--------|-------------|------------|--------|\n| 0 | 文本 | 文本 | `r[FI.text]` | `\"2026-05-21 12:30 午饭\"` |\n| 1 | 月份 | 文本 | `r[FI.month]` | `\"2026-05\"` |\n| 2 | 金额 | 数字 | `r[FI.amount]` | `23.50` |\n| 3 | 分类 | 单选 | `r[FI.category]` | `[\"餐饮\"]` |\n| 4 | 类型 | 单选 | `r[FI.type]` | `[\"支出\"]` |\n\n注意：单选/多选字段在数组中的值是 **数组**（`[\"餐饮\"]`），取第一个用 `arr[0]`。\n\n**FI 顺序由 setup_bitable.py 中 create_field 的调用顺序决定**，不能随意调整。\n\n## 业务逻辑流程\n\n### 数据生命周期\n\n1. **登录** → 输入 App ID / Secret / Base Token / Table ID → 存 localStorage\n2. **init()** → getToken() → fetchAll() → 拉取全部明细记录 → showApp() + render()\n3. **刷新** → doRefresh() → 重新 fetchAll → 渲染\n4. **月份切换** → 改变 curMonth → re-render（不复拉数据）\n5. **全部模式** → isTotalMode=true → render(month=null) → 聚合所有月份\n\n### 渲染链\n\n```\nrender()\n├── getMonthSummary(month)      → 遍历 detailRecords，按 type 字段区分收支\n├── renderSummary(inc, exp)     → 三张卡片 + 自适应字号（canvas measureText）\n├── renderPie(cats)             → 支出饼图（ECharts 环形图）\n├── renderIncPie(incCats)       → 收入饼图（仅在 showIncomePie=true 时）\n├── renderHBar(cats)            → 分类金额水平条形图\n├── renderBar()                 → 月度对比柱状图（从 detailRecords 按月份聚合）\n├── renderLine(month)           → 日支出趋势折线图\n└── renderDetails(month)        → 消费明细列表 + 分页\n```\n\n### 样式架构\n\n- 主题通过 `data-theme` 属性切换（dark / light）\n- 所有颜色通过 CSS 变量引用（`var(--bg)`, `var(--card)` 等）\n- ECharts 颜色通过 `CUR_THEME` 对象传递\n- 按钮反馈统一使用 `transform:scale`\n- 页面入场：`fadeUp` 动画\n\n## UI 约定速查\n\n| 组件 | CSS 类 | 按压反馈 | 禁用态 |\n|------|--------|----------|--------|\n| 导航按钮 | `.mbtn` | `scale(.88)` | `opacity:.35, cursor:not-allowed` |\n| 主操作按钮 | `.lbtn` | `scale(.97)` | (无禁用态) |\n| 弹窗按钮 | `.dbtn` | `scale(.95)` | (内联控制) |\n| 功能按钮按下态 | `.pressed` | 背景色变 accent，颜色变白 | — |\n| header 齿轮 | `.mbtn.sett:active` | `rotate(45deg)` | — |\n| header 刷新 | `.mbtn.refresh:active` | `rotate(180deg)` | — |\n\n## 弹窗系统\n\n所有弹窗使用同一套模式：\n\n1. 点击触发 → `lock-scroll` → 移除 overlay 的 `hidden` → 显示 `dialogIn` 动画\n2. 关闭 → `closeOverlay(id)` → 加 `.closing` 类触发 `dialogOut` 动画（150ms）→ 加 `.hidden` → 移除 `lock-scroll`\n3. 背景关闭 → 绑定 `click` 事件检查 `e.target === this`\n\n| 弹窗 | overlay ID | 关闭方式 |\n|------|-----------|----------|\n| 设置 | `sett-overlay` | 点击 ✕ / 背景 |\n| 分类设置 | `cat-overlay` | 点击 ✕ / 背景 |\n| 检查更新 | `upd-overlay` | 点击按钮 / 背景 |\n| 关于 | `abt-overlay` | 点击 ✕ / 背景 |\n| 刷新确认 | `refresh-overlay` | 点击按钮 / 背景 |\n| 通用错误 | `.dialog` | 点击按钮 |\n\n## 主题系统\n\n```javascript\nvar THEMES = {\n  dark:  { tooltipBg: '#1a1a2e', tooltipBorder: '#2a2a4a', ... },\n  light: { tooltipBg: '#ffffff', tooltipBorder: '#ddd6cc', ... }\n};\n```\n\n`applyTheme(theme)` 会：\n1. 设置 `data-theme` 属性 + `localStorage` 持久化\n2. 更新按钮图标（☀ / 🌙）\n3. 全部 dispose 已有 ECharts 实例\n4. 调用 `render()` 重绘\n5. 给每个图表容器加 `.chart-fade` 淡入类（300ms 后移除）\n\n## 版本号三处同步\n\n| 文件 | 变量 | 示例 |\n|------|------|------|\n| `dist/index.html` (JS) | `APP_VERSION` | `'1.3.0'` |\n| `android/app/build.gradle` | `versionCode`, `versionName` | `14`, `\"1.3.0\"` |\n| 仓库 `SKILL.md` | `version:` | `1.3.0` |\n\nversionCode 计算：主×10000 + 次×100 + 修订，每次 release +1。\n\n## 构建与发布\n\n```bash\nexport JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64\ncd /path/to/feishu-dashboard-app\nbash sync.sh\n# APK 输出到 android/app/build/outputs/apk/release/app-release.apk\n```\n\n发布流程：构建 → 用户测试 → git add + commit → git tag → GitHub Release（手动）\n\nFile v1.3.4:references/apk-ui-polish-checklist.md\n\n# APK UI 润色检查清单\n\n执行 APK 全局 UI 审查时逐项检查：\n\n## 按钮反馈统一\n- [ ] `lbtn:active` → `transform:scale(.97)`\n- [ ] `dbtn:active` → `transform:scale(.95)`，所有 dbtn 统一 transition\n- [ ] `mbtn:active` → `transform:scale(.88)`\n- [ ] `mbtn:disabled` → `opacity:.35;cursor:not-allowed;transform:none!important`\n- [ ] 按钮类都有 `transition:transform .15s` 等平滑效果\n\n## 弹窗交互\n- [ ] 设置/分类/关于弹窗支持点背景关闭：`if(e.target===this)hideXxx()`\n- [ ] 弹窗关闭动画：`.closing` 类 + `dialogOut` 动画\n- [ ] 遮罩 `backdrop-filter:blur(8px)`\n\n## 颜色主题一致性\n- [ ] 无硬编码 `#666`（改用 `var(--dim)` 或 `CUR_THEME.axisLabel`）\n- [ ] 空状态文本使用主题色，非固定色值\n- [ ] CSS 变量全量覆盖：`--bg` `--card` `--text` `--dim` `--border` `--accent` 等\n\n## 动效\n- [ ] 页面切换有 `.fade-in` 入场动画（fadeUp）\n- [ ] 主题切换时图表有 `.chart-fade` 淡入\n- [ ] chart dispose 后重新 init 不应闪烁\n\n## 数据逻辑\n- [ ] 支出相关筛选（饼图/明细/日趋势）已加 `FI.type` 过滤，排除收入\n- [ ] 收入相关聚合也已加 `FI.type` 过滤，只包含收入\n- [ ] FI 索引与飞书表格字段顺序一致\n\nFile v1.3.4:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nFile v1.3.4:references/feishu-base-api-pitfalls.md\n\n# 飞书 base/v3 API 踩坑记录\n\n## 1. Record 创建：不加 `fields` 包装\n\n```python\n# ✅ 正确（base/v3 API 直接平铺字段）\npayload = {\n    \"月份\": \"2026-05\",\n    \"分类\": \"餐饮\",\n    \"金额\": 23.40,\n    \"文本\": \"2026-05-15 13:11午饭\",\n}\n\n# ❌ 错误（这是其他飞书 API 的格式，base/v3 不支持）\npayload = {\n    \"fields\": {\n        \"月份\": \"2026-05\",\n        ...\n    }\n}\n```\n\n错误响应：`\"Record write payload must not be wrapped in 'fields'.\"`\n\n## 2. Tenant Token 分页上限只有 ~20 条\n\n`page_size=100` 参数在 Tenant Token 下实际只返回 20 条（实测验证），`has_more` 正常指示。\n\n**正确翻页写法：**\n\n```python\noffset = 0\nwhile True:\n    url = f\"/records?page_size=100&offset={offset}\"\n    # ... 请求 ...\n    records = data[\"data\"][\"data\"]\n    if not records:\n        break\n    for rec in records:\n        process(rec)\n    offset += len(records)  # 按实际返回数累加，而非固定步长\n```\n\n**错误写法（会漏数据）：**\n```python\noffset += 100  # ❌ 实际只返回 20 条，offset=100 跳过了 21-100\n```\n\n## 3. 字段创建后需等待缓存生效\n\n创建字段后立即更新选项（UPDATE field）需要加 `time.sleep(1)`，否则飞书返回 400。\n\n```python\ndef update_field_options(...):\n    time.sleep(1)  # 等待字段创建缓存生效\n    # 然后才能 PUT 更新选项\n```\n\n## 4. 地址恢复与字段映射\n\n```\n创建多维表格: data[\"base_token\"]        # 不是 data[\"base\"][\"token\"]\n创建数据表:   data[\"id\"]                # 不是 data[\"table_id\"]\n创建字段:     data[\"id\"]                # 不是 data[\"field\"][\"id\"]\n更新字段:     用 PUT                     # 不是 PATCH\n```\n\n每次写字段前，建议调 `GET /fields` 确认字段顺序和 ID，不要靠记忆写死 index。\n\n## 6. APK 端：字段索引映射（FI）与实际 API 返回顺序不同步\n\n**问题：** 飞书 base/v3 API 的 `list records` 返回记录为**扁平数组**，不是对象。数组内字段顺序由 field_id 字母序决定（非创建顺序），且**自动编号字段占用 index 0**。修改 `dist/index.html` 中 `FI` 映射时必须对照实际 API 响应。\n\n```json\n// 实际返回结构\n[\n  \"NO.001\",                    // index 0: ID (auto_number，占位！)\n  \"2026-05-21 16:42麻辣烫\",    // index 1: 文本\n  22.4,                        // index 2: 金额\n  [\"餐饮\"],                    // index 3: 分类 (单选字段返回数组)\n  [\"支出\"],                    // index 4: 类型 (单选字段返回数组)\n  \"2026-05\"                    // index 5: 月份\n]\n```\n\n**正确映射：**\n```js\nvar FI={text:1, month:5, amount:2, category:3, type:4};\n```\n\n**错误写法（2026-05-21 踩坑，v1.3.0~v1.3.2 所有图表失效）：**\n```js\nvar FI={text:0, month:1, amount:2, category:3, type:4};\n// 后果：r[0] 是自动编号 \"NO.001\"（非文本），导致 getDashRecords 永远过滤掉所有记录\n//       r[1] 是文本（非月份），导致按月过滤时全跳过，饼图/柱状图/卡片全空\n```\n\n**调试方法：** 用 Python 直调飞书 API 查看第一条记录的原始数组结构：\n```python\nurl = f\"https://open.feishu.cn/open-apis/base/v3/bases/{BASE}/tables/{TABLE}/records?page_size=1\"\n# 解析响应 data.data[0]，看数组各元素的实际内容\n```\n\n**进阶：动态构建 FI 映射（避免硬编码）：** API 响应同时返回 `field_id_list`（数组顺序）和 `fields`（field_id→field_name 映射）。可以据此将 FI 映射改为运行时构建：\n```js\n// 在 fetchAll 或 init 中\nvar resp = await nativeReq(url);\nvar ids = resp.data.field_id_list;    // [\"fldFNeeS3f\",\"fld2Hm3Nnx\",...]\nvar names = {};\nresp.data.fields.forEach(function(f){names[f.id]=f.name});\n// 然后动态计算\nvar FI = {};\nids.forEach(function(id,i){\n  var n = names[id];\n  if(n==='文本') FI.text=i;\n  else if(n==='月份') FI.month=i;\n  else if(n==='金额') FI.amount=i;\n  else if(n==='分类') FI.category=i;\n  else if(n==='类型') FI.type=i;\n});\n```\n\n同时调 `GET /tables/{TABLE}/fields` 看字段定义列表，对比数组元素与 field 的对应关系。\n\n**注意：** 单选字段（select）返回数组 `[\"选项名\"]`，非单选字段返回标量。类型判断须 `Array.isArray()` 处理。\n\n## 7. `.env` 加载：用直接赋值覆盖父 shell 变量\n\n```python\n# ❌ 错误：setdefault 不覆盖已存在的环境变量\n# 如果父 shell 已有 FEISHU_APP_ID（旧应用的），.env 的值会被忽略\nos.environ.setdefault(k.strip(), v.strip())\n\n# ✅ 正确：直接赋值，.env 始终优先\nos.environ[k.strip()] = v.strip()\n```\n\nFile v1.3.4:references/feishu-permissions-api.md\n\n# 飞书开放平台权限申请 API 模式\n\n## 问题\n\n飞书自建应用需要开通 API 权限才能调用接口。传统的控制台手动搜索勾选效率低、易遗漏。\n\n## 两个 API 工具\n\n### 1. 一键授权链接（推荐用于 Setup 阶段）\n\n飞书支持把权限 scope 打包在 URL 里，用户点一次确认即可批量开通。\n\n**格式：**\n```\nhttps://open.feishu.cn/app/{appId}/auth?q=scope1,scope2,...&op_from=openapi&token_type=tenant\n```\n\n**示例（记账系统）：**\n```\nhttps://open.feishu.cn/app/cli_xxx/auth?q=base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only&op_from=openapi&token_type=tenant\n```\n\n**用户操作：** 点击链接 → 确认开通 → 完成。\n\n### 2. scopes/apply API（用于触发审批）\n\n```http\nPOST https://open.feishu.cn/open-apis/application/v6/scopes/apply\nAuthorization: Bearer {tenant_access_token}\nContent-Type: application/json; charset=utf-8\n```\n\nBody 为空 JSON `{}`。不需要额外权限即可调用（Required Scopes: None）。\n\n**返回码：**\n| code | 含义 |\n|------|------|\n| 0 | 成功，已提交审批 |\n| 212002 | 所有权限已授权，无需审批 |\n| 212003 | 同版本申请超过 10 次限制 |\n| 212004 | 重复申请 |\n\n### 完整流程\n\n1. 用户创建飞书自建应用，提供 App ID + App Secret\n2. Agent 生成**一键授权链接**给用户\n3. 用户点击链接 → 确认开通所有权限 → **即时生效** ✅\n\n> ⚠️ 常见误区：**不需要创建版本和发布**。对于自建应用，管理员（也是应用创建者）点击确认后权限立即生效。发版流程是商店应用或需要管理员审核的企业应用场景，不适用于个人自建应用。\n\n### 注意事项\n\n- `scopes/apply` 同版本上限 10 次。确认权限后调用返回 212002（均已授权）是正常现象，无需重复调用\n- Tenant Token 需通过 `POST /open-apis/auth/v3/tenant_access_token/internal` 获取\n- 权限生效后仍需重试 API 调用（之前的 400/403 错误已经过去，需要重新请求）\n- 自建应用场景下，应用开发者和管理员同一人时，无额外审批节点\n\nFile v1.3.4:bills/2026-05-21.md\n\n# 账单 2026-05-21\n\n| 时间 | 类型 | 分类 | 金额 | 备注 |\n|------|------|------|------|------|\n| 16:42 | 支出 | 餐饮 | ¥22.40 | 麻辣烫 |\n| 16:56 | 收入 | 工资 | ¥4400.00 | 本月工资 |\n\n---\n**今日支出：¥22.40 | 今日收入：¥4400.00 | 净额：+¥4377.60**\n\nArchive v1.3.3: 12 files, 29273 bytes\n\nFiles: bills/2026-05-21.md (291b), references/apk-architecture.md (5053b), references/apk-ui-polish-checklist.md (1273b), references/categories.md (2780b), references/feishu-base-api-pitfalls.md (3931b), references/feishu-permissions-api.md (2362b), scripts/apply_permissions.py (4574b), scripts/cleanup_bitable.py (4597b), scripts/record_bill.py (19016b), scripts/setup_bitable.py (6563b), SKILL.md (15783b), _meta.json (136b)\n\nFile v1.3.3:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入明细表，通过「类型」字段区分支出和收入。**\nversion: 1.3.3\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup, permissions]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 引导创建飞书应用 → 一键搭建多维表格 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书明细表（单表模式） |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 2：一键开通权限（Agent 自动生成授权链接，用户只需点击确认）\n\n**AI 执行** `apply_permissions.py`（自动获取 Tenant Token、生成一键授权链接）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本输出一个 **一键授权链接**，AI 直接把链接发给用户：\n\n> 点击下方链接，所有记账需要的权限已经预选好了，你只需确认一次：\n>\n> 🔗 `https://open.feishu.cn/app/{appId}/auth?q=base:app:read,base:app:update,...&op_from=openapi&token_type=tenant`\n>\n> 点击后 → 页面会列出所有需要的 base 权限 → 点击 **「确认开通权限」** → 完成。\n\n**然后 AI 调用** `scopes/apply` API 提交管理员审批申请。\n\n---\n\n### Step 3：一键搭建多维表格\n\n用户提供 App ID + App Secret 后，运行 `setup_bitable.py`（无需安装任何外部工具，直接调飞书 API）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本会自动完成：\n1. 获取 Tenant Token（永久有效）\n2. 创建多维表格「个人记账本」\n3. 创建一张明细表（单表模式，支出和收入共用）\n4. 创建所有字段（文本/月份/金额/分类/类型）+ 补充选项（18个分类 + 收支类型选项）\n\n输出 4 个凭证：App ID / App Secret / Base Token / 明细表 Table ID\n\n### Step 4：输出凭证给用户\n\n**AI 必须将以下 4 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 1 用户提供的值，Base Token / Table ID 来自 Step 3 脚本输出的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 4 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的全量账本数据）\n\n### Step 5：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF\n```\n\n### Step 6：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 单表模式**：支出和收入均写入同一张明细表，通过「类型」字段区分。App 端按类型字段分组聚合计算月度收支。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md` 和 `references/feishu-permissions-api.md`（飞书权限 API 模式），核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n| 支出 | 通讯 | 话费/流量/套餐 |\n| 支出 | 医疗 | 医院/药店/挂号/体检 |\n| 支出 | 住房 | 房租/水电/物业/宽带 |\n| 支出 | 教育 | 学费/课程/书/培训 |\n| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n| 收入 | 工资 | 工资/薪资/月薪 |\n| 收入 | 兼职 | 兼职/副业/接单 |\n| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个支出分类 + 5个收入分类（工资/奖金/兼职/投资/其他），在飞书明细表中均有对应选项，无需映射损耗。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md                   # 本文件\n├── scripts/\n│   ├── record_bill.py         # 记账核心脚本\n│   ├── setup_bitable.py       # 一键搭建多维表格脚本\n│   ├── cleanup_bitable.py     # 清空多维表格数据（重置/测试用）\n│   └── apply_permissions.py   # 一键权限申请——生成授权链接 + 调 scopes/apply\n└── references/\n    └── categories.md                # 分类关键词参考\n    └── feishu-base-api-pitfalls.md   # base/v3 API 踩坑记录（分页/字段/格式）\n    └── feishu-permissions-api.md     # 飞书权限一键授权 API 模式\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_APP_ID` | 飞书应用 App ID（必填） | `cli_xxxxxxxxxxxxxxxx` |\n| `FEISHU_APP_SECRET` | 飞书应用 App Secret（必填） | `xxxxxxxxxxxxxxxxxx` |\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID（单表，含类型字段区分收支） | `tblxxxxxxxxxxxxxxxx` |\n\n> **无需 User Access Token**：record_bill.py 使用永久有效的 Tenant Token（自动从 App ID + Secret 获取），不再有 7 天过期问题。\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 建表时 HTTP 400 Bad Request | 缺 `base:table:create` 权限 | 在开放平台单独开通此权限并重新发版 |\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 Tenant Token 调 `GET .../fields` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 ~20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset += len(records)` 动态累加（而非固定步长）。详见 `references/feishu-base-api-pitfalls.md` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 飞书同步失败 | 凭证未配置或权限不足 | 检查 .env 文件中的 4 个凭证，确认 `base:record:create` 权限已开通 |\n| `.env` 中 FEISHU_APP_ID 没生效，仍用了父 shell 的旧值 | `os.environ.setdefault()` 不覆盖已有变量 | `.env` 加载改用直接赋值 `os.environ[k] = v` |\n| **APK 端：收入记录混入支出图表/明细列表** | `catSummaryFromDetail()` 和 `getDashRecords()` 没按 FI.type 过滤收入 | 添加 `if(type==='收入')continue;`（参见 `incomeCatSummaryFromDetail` 的写法） |\n| **重装 skill 时把旧 .env 带了过去** | 备份恢复操作保留旧属性（如已不用的 SUMMARY_TABLE_ID） | 全新安装时不应备份旧 .env，让用户重新走 Setup 流程获取新凭证 |\n\n## 🔧 APK 开发与维护\n\n### Git 工作流（重要）\n\n本技能涉及 GitHub 仓库 `NaeemTC/feishu-accounting-skill` 的代码维护。**所有 git 操作必须遵守以下规则：**\n\n> ⚠️ **数据源可控，不加防御代码**：`record_bill.py` 是唯一的数据写入入口，`amount` 字段类型固定为 number。APK 端无需加 `parseFloat` 防御，所有字段类型都由你控制的脚本确定，不会变。不要加无意义的防御代码。\n\n**有关数据源确定性的重要原则：** `record_bill.py` 是唯一写入飞书多维表格的脚本，因此 `amount` 字段的类型始终是 number（来自脚本中的 `amount: float` 参数），`文本`、`月份` 字段始终是 string，`分类`、`类型` 是 single-select（返回数组）。APK 端读取时无需对字段类型做冗余防御（如 `parseFloat`），因为数据管道是封闭、可控的。如需改变字段类型，改 `record_bill.py` 并同时更新 APK 端 `FI` 映射即可。\n\n1. **任何 commit / push / tag / release 操作前，必须先问用户确认**\n2. 用户说「改了 APK 要先发测试」→ 先 build APK 发给用户测，确认无误再推 git\n3. github-repo-management 的审计清单（token 泄漏、硬编码路径等）必须过一遍\n4. 版本号三处同步：`dist/index.html` 的 `APP_VERSION` + `android/app/build.gradle` 的 `versionName/versionCode` + `SKILL.md` 的 frontmatter\n5. Release 上传 APK 固定命名 `app-release.apk`，使 latest 链接永久有效\n\n### 常见 APK 端 Bug 模式\n\n| Bug | 根因 | 修复 |\n|-----|------|------|\n| 收入记录出现在支出饼图/消费明细/日趋势图中 | `catSummaryFromDetail()` 和 `getDashRecords()` 遍历 detailRecords 时没按 `FI.type` 过滤 | 添加 `var type=r[FI.type]||''; if(Array.isArray(type))type=type[0]||''; if(type==='收入')continue;` |\n| 新安装 APK 提示「正在连接飞书...」无限转圈 | **① 旧版 localStorage 存了过期凭证** — 新应用 ID/Secret 不对应 | 错误页点「重新配置」按钮清除 localStorage，或手动填写新凭证 |\n| | **② JS 声明顺序崩溃（更致命）** — `var DEFAULT_CATS=ALL_CATS.slice()` 写在 `var ALL_CATS=[...]` 之前，`ALL_CATS` 未赋值导致 `undefined.slice()` 抛出 TypeError，脚本在加载期即中断，`init()` 永不执行，线上 spinner 永远转 | 确保 `ALL_CATS` 定义在 `DEFAULT_CATS` 之前。调试方法：用 `browser_console` 看是否有 `Uncaught TypeError`（脚本加载期错误不会被 Promise.catch 捕获） |\n| 检查更新按钮点了没反应/一直转 | **① fetch 回调没调 `.json()`** — 返回的是 Response 对象，`d.tag_name` 为 undefined，条件判断永不通过 | 加 `.then(r=>r.json())` 解析 JSON |\n| | **② 无超时保护** — 请求挂起时 spinner 无限转 | 加 `AbortController` + 10 秒超时，超时显示「检查更新失败，请稍后重试」 |\n| 主题切换后图表瞬间消失 | `applyTheme` 中 dispose/recreate 图表无过渡 | 已修复：render 后对 chart 容器加 `.chart-fade` 动画类 |\n| 所有图表/卡片按月查看全空，日趋势/明细永远「暂无数据」 | `var FI` 字段索引映射不对应飞书 API 返回的数组顺序。实际数组为 `[ID,文本,金额,分类,类型,月份]`（按 field_id 字母序），但代码写成了 `{text:0,month:1}`（实际 text 在 index 1，month 在 index 5） | 调 API 验证数组顺序，设 `FI={text:1,month:5,amount:2,category:3,type:4}`。注意自动编号字段占用 index 0，单选字段返回 `[值]` 数组。详见 `references/feishu-base-api-pitfalls.md` 第6节 |\n\n### UI 风格约定\n\n- 按钮反馈：所有可点击元素统一使用 `transform:scale(.88~.97)`，不用 `opacity`\n- 弹窗：必须支持点背景关闭（`if(e.target===this)hideXxx()`）\n- 禁态：`mbtn:disabled` 设 `opacity:.35;cursor:not-allowed;transform:none!important`\n- 过渡：页面切换加 `.fade-in`（`fadeUp` 动画），主题切换图表加 `.chart-fade`\n- 颜色：禁止硬编码 `#666`，必须用 `var(--dim)` 或 `CUR_THEME.axisLabel`\n\n---\n\nFile v1.3.3:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.3.3\",\n  \"publishedAt\": 1779354397342\n}\n\nFile v1.3.3:references/apk-architecture.md\n\n# APK 仪表盘 App 内部架构\n\n本 App 是 Capacitor 项目，核心为单文件 `dist/index.html`（~1100 行）。Android 层只提供一个 WebView 壳子，所有 UI 和业务逻辑在 HTML 内。\n\n## 文件结构（dist 目录）\n\n```\ndist/\n└── index.html          # 唯一源码，内嵌 CSS + JS + ECharts\nandroid/\n└── app/\n    └── build.gradle    # versionCode + versionName + 签名配置\n```\n\n## 字段索引映射（FI）\n\nFeishu base v3 API 使用 `offset` 翻页时，记录以**位置数组**返回。`FI` 对象定义字段位置：\n\n```javascript\nvar FI = {text: 0, month: 1, amount: 2, category: 3, type: 4};\n```\n\n| 索引 | 字段名 | Feishu 类型 | JS 访问方式 | 示例值 |\n|------|--------|-------------|------------|--------|\n| 0 | 文本 | 文本 | `r[FI.text]` | `\"2026-05-21 12:30 午饭\"` |\n| 1 | 月份 | 文本 | `r[FI.month]` | `\"2026-05\"` |\n| 2 | 金额 | 数字 | `r[FI.amount]` | `23.50` |\n| 3 | 分类 | 单选 | `r[FI.category]` | `[\"餐饮\"]` |\n| 4 | 类型 | 单选 | `r[FI.type]` | `[\"支出\"]` |\n\n注意：单选/多选字段在数组中的值是 **数组**（`[\"餐饮\"]`），取第一个用 `arr[0]`。\n\n**FI 顺序由 setup_bitable.py 中 create_field 的调用顺序决定**，不能随意调整。\n\n## 业务逻辑流程\n\n### 数据生命周期\n\n1. **登录** → 输入 App ID / Secret / Base Token / Table ID → 存 localStorage\n2. **init()** → getToken() → fetchAll() → 拉取全部明细记录 → showApp() + render()\n3. **刷新** → doRefresh() → 重新 fetchAll → 渲染\n4. **月份切换** → 改变 curMonth → re-render（不复拉数据）\n5. **全部模式** → isTotalMode=true → render(month=null) → 聚合所有月份\n\n### 渲染链\n\n```\nrender()\n├── getMonthSummary(month)      → 遍历 detailRecords，按 type 字段区分收支\n├── renderSummary(inc, exp)     → 三张卡片 + 自适应字号（canvas measureText）\n├── renderPie(cats)             → 支出饼图（ECharts 环形图）\n├── renderIncPie(incCats)       → 收入饼图（仅在 showIncomePie=true 时）\n├── renderHBar(cats)            → 分类金额水平条形图\n├── renderBar()                 → 月度对比柱状图（从 detailRecords 按月份聚合）\n├── renderLine(month)           → 日支出趋势折线图\n└── renderDetails(month)        → 消费明细列表 + 分页\n```\n\n### 样式架构\n\n- 主题通过 `data-theme` 属性切换（dark / light）\n- 所有颜色通过 CSS 变量引用（`var(--bg)`, `var(--card)` 等）\n- ECharts 颜色通过 `CUR_THEME` 对象传递\n- 按钮反馈统一使用 `transform:scale`\n- 页面入场：`fadeUp` 动画\n\n## UI 约定速查\n\n| 组件 | CSS 类 | 按压反馈 | 禁用态 |\n|------|--------|----------|--------|\n| 导航按钮 | `.mbtn` | `scale(.88)` | `opacity:.35, cursor:not-allowed` |\n| 主操作按钮 | `.lbtn` | `scale(.97)` | (无禁用态) |\n| 弹窗按钮 | `.dbtn` | `scale(.95)` | (内联控制) |\n| 功能按钮按下态 | `.pressed` | 背景色变 accent，颜色变白 | — |\n| header 齿轮 | `.mbtn.sett:active` | `rotate(45deg)` | — |\n| header 刷新 | `.mbtn.refresh:active` | `rotate(180deg)` | — |\n\n## 弹窗系统\n\n所有弹窗使用同一套模式：\n\n1. 点击触发 → `lock-scroll` → 移除 overlay 的 `hidden` → 显示 `dialogIn` 动画\n2. 关闭 → `closeOverlay(id)` → 加 `.closing` 类触发 `dialogOut` 动画（150ms）→ 加 `.hidden` → 移除 `lock-scroll`\n3. 背景关闭 → 绑定 `click` 事件检查 `e.target === this`\n\n| 弹窗 | overlay ID | 关闭方式 |\n|------|-----------|----------|\n| 设置 | `sett-overlay` | 点击 ✕ / 背景 |\n| 分类设置 | `cat-overlay` | 点击 ✕ / 背景 |\n| 检查更新 | `upd-overlay` | 点击按钮 / 背景 |\n| 关于 | `abt-overlay` | 点击 ✕ / 背景 |\n| 刷新确认 | `refresh-overlay` | 点击按钮 / 背景 |\n| 通用错误 | `.dialog` | 点击按钮 |\n\n## 主题系统\n\n```javascript\nvar THEMES = {\n  dark:  { tooltipBg: '#1a1a2e', tooltipBorder: '#2a2a4a', ... },\n  light: { tooltipBg: '#ffffff', tooltipBorder: '#ddd6cc', ... }\n};\n```\n\n`applyTheme(theme)` 会：\n1. 设置 `data-theme` 属性 + `localStorage` 持久化\n2. 更新按钮图标（☀ / 🌙）\n3. 全部 dispose 已有 ECharts 实例\n4. 调用 `render()` 重绘\n5. 给每个图表容器加 `.chart-fade` 淡入类（300ms 后移除）\n\n## 版本号三处同步\n\n| 文件 | 变量 | 示例 |\n|------|------|------|\n| `dist/index.html` (JS) | `APP_VERSION` | `'1.3.0'` |\n| `android/app/build.gradle` | `versionCode`, `versionName` | `14`, `\"1.3.0\"` |\n| 仓库 `SKILL.md` | `version:` | `1.3.0` |\n\nversionCode 计算：主×10000 + 次×100 + 修订，每次 release +1。\n\n## 构建与发布\n\n```bash\nexport JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64\ncd /path/to/feishu-dashboard-app\nbash sync.sh\n# APK 输出到 android/app/build/outputs/apk/release/app-release.apk\n```\n\n发布流程：构建 → 用户测试 → git add + commit → git tag → GitHub Release（手动）\n\nFile v1.3.3:references/apk-ui-polish-checklist.md\n\n# APK UI 润色检查清单\n\n执行 APK 全局 UI 审查时逐项检查：\n\n## 按钮反馈统一\n- [ ] `lbtn:active` → `transform:scale(.97)`\n- [ ] `dbtn:active` → `transform:scale(.95)`，所有 dbtn 统一 transition\n- [ ] `mbtn:active` → `transform:scale(.88)`\n- [ ] `mbtn:disabled` → `opacity:.35;cursor:not-allowed;transform:none!important`\n- [ ] 按钮类都有 `transition:transform .15s` 等平滑效果\n\n## 弹窗交互\n- [ ] 设置/分类/关于弹窗支持点背景关闭：`if(e.target===this)hideXxx()`\n- [ ] 弹窗关闭动画：`.closing` 类 + `dialogOut` 动画\n- [ ] 遮罩 `backdrop-filter:blur(8px)`\n\n## 颜色主题一致性\n- [ ] 无硬编码 `#666`（改用 `var(--dim)` 或 `CUR_THEME.axisLabel`）\n- [ ] 空状态文本使用主题色，非固定色值\n- [ ] CSS 变量全量覆盖：`--bg` `--card` `--text` `--dim` `--border` `--accent` 等\n\n## 动效\n- [ ] 页面切换有 `.fade-in` 入场动画（fadeUp）\n- [ ] 主题切换时图表有 `.chart-fade` 淡入\n- [ ] chart dispose 后重新 init 不应闪烁\n\n## 数据逻辑\n- [ ] 支出相关筛选（饼图/明细/日趋势）已加 `FI.type` 过滤，排除收入\n- [ ] 收入相关聚合也已加 `FI.type` 过滤，只包含收入\n- [ ] FI 索引与飞书表格字段顺序一致\n\nFile v1.3.3:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nFile v1.3.3:references/feishu-base-api-pitfalls.md\n\n# 飞书 base/v3 API 踩坑记录\n\n## 1. Record 创建：不加 `fields` 包装\n\n```python\n# ✅ 正确（base/v3 API 直接平铺字段）\npayload = {\n    \"月份\": \"2026-05\",\n    \"分类\": \"餐饮\",\n    \"金额\": 23.40,\n    \"文本\": \"2026-05-15 13:11午饭\",\n}\n\n# ❌ 错误（这是其他飞书 API 的格式，base/v3 不支持）\npayload = {\n    \"fields\": {\n        \"月份\": \"2026-05\",\n        ...\n    }\n}\n```\n\n错误响应：`\"Record write payload must not be wrapped in 'fields'.\"`\n\n## 2. Tenant Token 分页上限只有 ~20 条\n\n`page_size=100` 参数在 Tenant Token 下实际只返回 20 条（实测验证），`has_more` 正常指示。\n\n**正确翻页写法：**\n\n```python\noffset = 0\nwhile True:\n    url = f\"/records?page_size=100&offset={offset}\"\n    # ... 请求 ...\n    records = data[\"data\"][\"data\"]\n    if not records:\n        break\n    for rec in records:\n        process(rec)\n    offset += len(records)  # 按实际返回数累加，而非固定步长\n```\n\n**错误写法（会漏数据）：**\n```python\noffset += 100  # ❌ 实际只返回 20 条，offset=100 跳过了 21-100\n```\n\n## 3. 字段创建后需等待缓存生效\n\n创建字段后立即更新选项（UPDATE field）需要加 `time.sleep(1)`，否则飞书返回 400。\n\n```python\ndef update_field_options(...):\n    time.sleep(1)  # 等待字段创建缓存生效\n    # 然后才能 PUT 更新选项\n```\n\n## 4. 地址恢复与字段映射\n\n```\n创建多维表格: data[\"base_token\"]        # 不是 data[\"base\"][\"token\"]\n创建数据表:   data[\"id\"]                # 不是 data[\"table_id\"]\n创建字段:     data[\"id\"]                # 不是 data[\"field\"][\"id\"]\n更新字段:     用 PUT                     # 不是 PATCH\n```\n\n每次写字段前，建议调 `GET /fields` 确认字段顺序和 ID，不要靠记忆写死 index。\n\n## 6. APK 端：字段索引映射（FI）与实际 API 返回顺序不同步\n\n**问题：** 飞书 base/v3 API 的 `list records` 返回记录为**扁平数组**，不是对象。数组内字段顺序由 field_id 字母序决定（非创建顺序），且**自动编号字段占用 index 0**。修改 `dist/index.html` 中 `FI` 映射时必须对照实际 API 响应。\n\n```json\n// 实际返回结构\n[\n  \"NO.001\",                    // index 0: ID (auto_number，占位！)\n  \"2026-05-21 16:42麻辣烫\",    // index 1: 文本\n  22.4,                        // index 2: 金额\n  [\"餐饮\"],                    // index 3: 分类 (单选字段返回数组)\n  [\"支出\"],                    // index 4: 类型 (单选字段返回数组)\n  \"2026-05\"                    // index 5: 月份\n]\n```\n\n**正确映射：**\n```js\nvar FI={text:1, month:5, amount:2, category:3, type:4};\n```\n\n**错误写法（2026-05-21 踩坑，v1.3.0~v1.3.2 所有图表失效）：**\n```js\nvar FI={text:0, month:1, amount:2, category:3, type:4};\n// 后果：r[0] 是自动编号 \"NO.001\"（非文本），导致 getDashRecords 永远过滤掉所有记录\n//       r[1] 是文本（非月份），导致按月过滤时全跳过，饼图/柱状图/卡片全空\n```\n\n**调试方法：** 用 Python 直调飞书 API 查看第一条记录的原始数组结构：\n```python\nurl = f\"https://open.feishu.cn/open-apis/base/v3/bases/{BASE}/tables/{TABLE}/records?page_size=1\"\n# 解析响应 data.data[0]，看数组各元素的实际内容\n```\n\n同时调 `GET /tables/{TABLE}/fields` 看字段定义列表，对比数组元素与 field 的对应关系。\n\n**注意：** 单选字段（select）返回数组 `[\"选项名\"]`，非单选字段返回标量。类型判断须 `Array.isArray()` 处理。\n\n## 7. `.env` 加载：用直接赋值覆盖父 shell 变量\n\n```python\n# ❌ 错误：setdefault 不覆盖已存在的环境变量\n# 如果父 shell 已有 FEISHU_APP_ID（旧应用的），.env 的值会被忽略\nos.environ.setdefault(k.strip(), v.strip())\n\n# ✅ 正确：直接赋值，.env 始终优先\nos.environ[k.strip()] = v.strip()\n```\n\nFile v1.3.3:references/feishu-permissions-api.md\n\n# 飞书开放平台权限申请 API 模式\n\n## 问题\n\n飞书自建应用需要开通 API 权限才能调用接口。传统的控制台手动搜索勾选效率低、易遗漏。\n\n## 两个 API 工具\n\n### 1. 一键授权链接（推荐用于 Setup 阶段）\n\n飞书支持把权限 scope 打包在 URL 里，用户点一次确认即可批量开通。\n\n**格式：**\n```\nhttps://open.feishu.cn/app/{appId}/auth?q=scope1,scope2,...&op_from=openapi&token_type=tenant\n```\n\n**示例（记账系统）：**\n```\nhttps://open.feishu.cn/app/cli_xxx/auth?q=base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only&op_from=openapi&token_type=tenant\n```\n\n**用户操作：** 点击链接 → 确认开通 → 完成。\n\n### 2. scopes/apply API（用于触发审批）\n\n```http\nPOST https://open.feishu.cn/open-apis/application/v6/scopes/apply\nAuthorization: Bearer {tenant_access_token}\nContent-Type: application/json; charset=utf-8\n```\n\nBody 为空 JSON `{}`。不需要额外权限即可调用（Required Scopes: None）。\n\n**返回码：**\n| code | 含义 |\n|------|------|\n| 0 | 成功，已提交审批 |\n| 212002 | 所有权限已授权，无需审批 |\n| 212003 | 同版本申请超过 10 次限制 |\n| 212004 | 重复申请 |\n\n### 完整流程\n\n1. 用户创建飞书自建应用，提供 App ID + App Secret\n2. Agent 生成**一键授权链接**给用户\n3. 用户点击链接 → 确认开通所有权限 → **即时生效** ✅\n\n> ⚠️ 常见误区：**不需要创建版本和发布**。对于自建应用，管理员（也是应用创建者）点击确认后权限立即生效。发版流程是商店应用或需要管理员审核的企业应用场景，不适用于个人自建应用。\n\n### 注意事项\n\n- `scopes/apply` 同版本上限 10 次。确认权限后调用返回 212002（均已授权）是正常现象，无需重复调用\n- Tenant Token 需通过 `POST /open-apis/auth/v3/tenant_access_token/internal` 获取\n- 权限生效后仍需重试 API 调用（之前的 400/403 错误已经过去，需要重新请求）\n- 自建应用场景下，应用开发者和管理员同一人时，无额外审批节点\n\nFile v1.3.3:bills/2026-05-21.md\n\n# 账单 2026-05-21\n\n| 时间 | 类型 | 分类 | 金额 | 备注 |\n|------|------|------|------|------|\n| 16:42 | 支出 | 餐饮 | ¥22.40 | 麻辣烫 |\n| 16:56 | 收入 | 工资 | ¥4400.00 | 本月工资 |\n\n---\n**今日支出：¥22.40 | 今日收入：¥4400.00 | 净额：+¥4377.60**\n\nArchive v1.2.4: 5 files, 13330 bytes\n\nFiles: bills/2026-05-19.md (403b), references/categories.md (2780b), scripts/record_bill.py (17535b), SKILL.md (15358b), _meta.json (136b)\n\nFile v1.2.4:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.2.4\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\n# 安装到 ~/.feishu-cli/bin/（无需 sudo）\nINSTALL_DIR=\"$HOME/.feishu-cli/bin\"\nmkdir -p \"$INSTALL_DIR\"\n\n# 从 GitHub 官方 Releases 下载（带断点续传）\ncurl -L -C - --max-time 600 \\\n  \"https://github.com/riba2534/feishu-cli/releases/download/v1.26.0/feishu-cli_v1.26.0_linux-amd64.tar.gz\" \\\n  -o /tmp/feishu-cli.tar.gz\n\ncd /tmp && tar -xzf feishu-cli.tar.gz\ncp feishu-cli_v1.26.0_linux-amd64/feishu-cli \"$INSTALL_DIR/\"\nchmod +x \"$INSTALL_DIR/feishu-cli\"\n\n# 写入 PATH（如果 ~/.bashrc 里还没有）\nSHELL_RC=\"$HOME/.bashrc\"\nif ! grep -q \"$INSTALL_DIR\" \"$SHELL_RC\" 2>/dev/null; then\n  echo \"export PATH=\\\"\\$HOME/.feishu-cli/bin:\\$PATH\\\"\" >> \"$SHELL_RC\"\nfi\nexport PATH=\"$HOME/.feishu-cli/bin:$PATH\"\n\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发送给用户，让他们在浏览器打开链接，点击「授权」即可完成，无需扫码。**\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `your_base_token_here`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n> **已有用户升级分类**：如果你之前已经建好表，用以下命令给分类字段补充新选项（13分类）：\n> ```bash\n> # 先找到分类字段ID\n> feishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n> # 替换下方 <分类字段ID> 后执行\n> feishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n>   --field-id <分类字段ID> \\\n>   --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n> ```\n\n### Step 9：输出凭证给用户\n\n**AI 必须将以下 5 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 2 用户提供的值，Base Token / Table ID 来自 Step 6-7 创建的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n> 5. **汇总表 Table ID**：`你的汇总表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的明细表和汇总表）\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 飞书同步规则**：`--type expense`（支出）同时写入明细表和汇总表；`--type income`（收入）仅写入汇总表，明细表只存支出记录（用于 App 仪表盘分类图表展示）。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md`，核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n|| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n|| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n|| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n|| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n|| 支出 | 通讯 | 话费/流量/套餐 |\n|| 支出 | 医疗 | 医院/药店/挂号/体检 |\n|| 支出 | 住房 | 房租/水电/物业/宽带 |\n|| 支出 | 教育 | 学费/课程/书/培训 |\n|| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n|| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n|| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n|| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n|| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n|| 收入 | 工资 | 工资/薪资/月薪 |\n|| 收入 | 兼职 | 兼职/副业/接单 |\n|| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个分类在飞书明细表中均有对应选项，无需映射损耗。本地「其他/银行/工资/奖金/兼职/投资」→ 飞书「其它」。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md              # 本文件\n├── scripts/\n│   └── record_bill.py     # 记账核心脚本\n└── references/\n    └── categories.md      # 分类关键词参考\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID | `tblxxxxxxxxxxxxxxxx` |\n| `FEISHU_SUMMARY_TABLE_ID` | 汇总表 ID | `tblyyyyyyyyyyyyyyyy` |\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 `feishu-cli bitable field list` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset` 参数：第 1 页不带 offset，第 2 页 `offset=20`，第 3 页 `offset=40` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 只写明细表，汇总表数据缺失 | 汇总表是仪表盘收支数据来源之一，漏写会导致统计数据不完整 | 每次 `add_record()` 必须同时调用 `sync_to_feishu()` 写明细表 + `sync_summary_to_feishu()` 写汇总表 |\n\n---\n\n## 飞书文本字段格式（与仪表盘 app 关联）\n\n`record_bill.py` 写入飞书的文本格式为：\n\n```\n{YYYY-MM-DD} {HH:mm}{备注}\n例如：2026-05-15 13:11停车费\n```\n\n仪表盘 app 解析规则：\n- 有时间戳的记录：`(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})` → 提取日期 + 时间\n- 无时间戳的旧记录：`(\\d{4}-\\d{2}-\\d{2})` → 仅提取日期（兜底）\n\n> ⚠️ 如需修改 `record_bill.py` 的文本写入格式，请同步确认仪表盘 app 的正则解析逻辑能否兼容新旧两种格式。\n\nFile v1.2.4:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.2.4\",\n  \"publishedAt\": 1779330819704\n}\n\nFile v1.2.4:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nFile v1.2.4:bills/2026-05-19.md\n\n# 账单 2026-05-19\n\n| 时间 | 类型 | 分类 | 金额 | 备注 |\n|------|------|------|------|------|\n| 10:09 | 支出 | 餐饮 | ¥23.50 | 测试午饭 |\n| 10:09 | 支出 | 餐饮 | ¥23.50 | 测试午饭 |\n| 10:09 | 收入 | 工资 | ¥5000.00 | 测试工资 |\n| 10:09 | 收入 | 工资 | ¥5000.00 | 测试工资 |\n\n---\n**今日支出：¥47.00 | 今日收入：¥10000.00 | 净额：+¥9953.00**\n\nArchive v1.2.3: 4 files, 12979 bytes\n\nFiles: references/categories.md (2780b), scripts/record_bill.py (17535b), SKILL.md (15332b), _meta.json (136b)\n\nFile v1.2.3:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.2.3\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\n# 安装到 ~/.feishu-cli/bin/（无需 sudo）\nINSTALL_DIR=\"$HOME/.feishu-cli/bin\"\nmkdir -p \"$INSTALL_DIR\"\n\n# 直接从 GitHub 下载（不走第三方代理）\ncurl -L --max-time 120 \\\n  \"https://github.com/riba2534/feishu-cli/releases/latest/download/feishu-cli_linux-amd64.tar.gz\" \\\n  -o /tmp/feishu-cli.tar.gz\n\ncd /tmp && tar -xzf feishu-cli.tar.gz\ncp feishu-cli_linux-amd64/feishu-cli \"$INSTALL_DIR/\"\nchmod +x \"$INSTALL_DIR/feishu-cli\"\n\n# 写入 PATH（如果 ~/.bashrc 里还没有）\nSHELL_RC=\"$HOME/.bashrc\"\nif ! grep -q \"$INSTALL_DIR\" \"$SHELL_RC\" 2>/dev/null; then\n  echo \"export PATH=\\\"\\$HOME/.feishu-cli/bin:\\$PATH\\\"\" >> \"$SHELL_RC\"\nfi\nexport PATH=\"$HOME/.feishu-cli/bin:$PATH\"\n\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发送给用户，让他们在浏览器打开链接，点击「授权」即可完成，无需扫码。**\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `your_base_token_here`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n> **已有用户升级分类**：如果你之前已经建好表，用以下命令给分类字段补充新选项（13分类）：\n> ```bash\n> # 先找到分类字段ID\n> feishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n> # 替换下方 <分类字段ID> 后执行\n> feishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n>   --field-id <分类字段ID> \\\n>   --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n> ```\n\n### Step 9：输出凭证给用户\n\n**AI 必须将以下 5 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 2 用户提供的值，Base Token / Table ID 来自 Step 6-7 创建的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n> 5. **汇总表 Table ID**：`你的汇总表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的明细表和汇总表）\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 飞书同步规则**：`--type expense`（支出）同时写入明细表和汇总表；`--type income`（收入）仅写入汇总表，明细表只存支出记录（用于 App 仪表盘分类图表展示）。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md`，核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n|| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n|| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n|| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n|| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n|| 支出 | 通讯 | 话费/流量/套餐 |\n|| 支出 | 医疗 | 医院/药店/挂号/体检 |\n|| 支出 | 住房 | 房租/水电/物业/宽带 |\n|| 支出 | 教育 | 学费/课程/书/培训 |\n|| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n|| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n|| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n|| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n|| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n|| 收入 | 工资 | 工资/薪资/月薪 |\n|| 收入 | 兼职 | 兼职/副业/接单 |\n|| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个分类在飞书明细表中均有对应选项，无需映射损耗。本地「其他/银行/工资/奖金/兼职/投资」→ 飞书「其它」。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md              # 本文件\n├── scripts/\n│   └── record_bill.py     # 记账核心脚本\n└── references/\n    └── categories.md      # 分类关键词参考\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID | `tblxxxxxxxxxxxxxxxx` |\n| `FEISHU_SUMMARY_TABLE_ID` | 汇总表 ID | `tblyyyyyyyyyyyyyyyy` |\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 `feishu-cli bitable field list` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset` 参数：第 1 页不带 offset，第 2 页 `offset=20`，第 3 页 `offset=40` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 只写明细表，汇总表数据缺失 | 汇总表是仪表盘收支数据来源之一，漏写会导致统计数据不完整 | 每次 `add_record()` 必须同时调用 `sync_to_feishu()` 写明细表 + `sync_summary_to_feishu()` 写汇总表 |\n\n---\n\n## 飞书文本字段格式（与仪表盘 app 关联）\n\n`record_bill.py` 写入飞书的文本格式为：\n\n```\n{YYYY-MM-DD} {HH:mm}{备注}\n例如：2026-05-15 13:11停车费\n```\n\n仪表盘 app 解析规则：\n- 有时间戳的记录：`(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})` → 提取日期 + 时间\n- 无时间戳的旧记录：`(\\d{4}-\\d{2}-\\d{2})` → 仅提取日期（兜底）\n\n> ⚠️ 如需修改 `record_bill.py` 的文本写入格式，请同步确认仪表盘 app 的正则解析逻辑能否兼容新旧两种格式。\n\nFile v1.2.3:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.2.3\",\n  \"publishedAt\": 1779270866495\n}\n\nFile v1.2.3:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nArchive v1.2.2: 4 files, 12419 bytes\n\nFiles: references/categories.md (2428b), scripts/record_bill.py (17437b), SKILL.md (14282b), _meta.json (136b)\n\nFile v1.2.2:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.2.2\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - FEISHU_BASE_TOKEN\n        - FEISHU_DETAIL_TABLE_ID\n        - FEISHU_SUMMARY_TABLE_ID\n      bins:\n        - curl\n        - python3\n    primaryEnv: FEISHU_BASE_TOKEN\n    envVars:\n      - name: FEISHU_BASE_TOKEN\n        required: true\n        description: \"飞书多维表格 Base Token\"\n      - name: FEISHU_DETAIL_TABLE_ID\n        required: true\n        description: \"明细表 Table ID\"\n      - name: FEISHU_SUMMARY_TABLE_ID\n        required: true\n        description: \"汇总表 Table ID\"\n    emoji: \"💰\"\n    homepage: \"https://github.com/NaeemTC/feishu-accounting-skill\"\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\ncurl -L --max-time 60 -o /tmp/feishu-cli.tar.gz \\\n  \"https://gh-proxy.com/https://github.com/riba2534/feishu-cli/releases/download/v1.25.0/feishu-cli_v1.25.0_linux-amd64.tar.gz\"\ncd /tmp && tar -xzf feishu-cli.tar.gz\nsudo cp feishu-cli_v1.25.0_linux-amd64/feishu-cli /usr/local/bin/\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\n# 第一步：获取设备码\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发给用户，让他们在浏览器完成授权。**\n\n```bash\n# 用户授权完成后第二步\nfeishu-cli auth login --device-code <device_code> --json\n```\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable app create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `Cq5d8wXzuQ3y0kvLFHn12s34pAB`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"其它\"},{\"name\":\"生活\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"交通\"},{\"name\":\"购物\"},{\"name\":\"餐饮\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n### Step 9：输出凭证\n\n> ⚠️ **App ID 和 App Secret 来自用户在第 2 步提供的信息**，AI 应在此处引用用户之前给出的值，确保证书完整。\n\n**把以下信息发送给用户：**\n\n```\n|✅ 飞书记账配置完成！\n\n请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n\n1. App ID：<用户在第2步提供的 app_id>\n2. App Secret：<用户在第2步提供的 app_secret>\n3. Base Token：<base_token>\n4. 明细表 Table ID：<detail_table_id>\n5. 汇总表 Table ID：<summary_table_id>\n\n输入这 5 项后，App 就能正常查看你的账单数据了。\n```\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/latest/download/app-release.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 飞书同步规则**：`--type expense`（支出）同时写入明细表和汇总表；`--type income`（收入）仅写入汇总表，明细表只存支出记录（用于 App 仪表盘分类图表展示）。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md`，核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n| 支出 | 通讯 | 话费/流量/套餐 |\n| 支出 | 医疗 | 医院/药店/挂号/体检 |\n| 支出 | 住房 | 房租/水电/物业/宽带 |\n| 支出 | 教育 | 学费/课程/书/培训 |\n| 收入 | 工资 | 工资/薪资/月薪 |\n| 收入 | 兼职 | 兼职/副业/接单 |\n| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：本地「医疗/住房/教育/其他/银行/工资/奖金/兼职/投资」→ 飞书统一为「其它」。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md              # 本文件\n├── scripts/\n│   └── record_bill.py     # 记账核心脚本\n└── references/\n    └── categories.md      # 分类关键词参考\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `Cq5d8wXzuQ3y0kvLFHn12s34pAB` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID | `tblxxxxxxxxxxxxxxxx` |\n| `FEISHU_SUMMARY_TABLE_ID` | 汇总表 ID | `tblyyyyyyyyyyyyyyyy` |\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 `feishu-cli bitable field list` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset` 参数：第 1 页不带 offset，第 2 页 `offset=20`，第 3 页 `offset=40` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 只写明细表，汇总表数据缺失 | 汇总表是仪表盘收支数据来源之一，漏写会导致统计数据不完整 | 每次 `add_record()` 必须同时调用 `sync_to_feishu()` 写明细表 + `sync_summary_to_feishu()` 写汇总表 |\n\n---\n\n## 飞书文本字段格式（与仪表盘 app 关联）\n\n`record_bill.py` 写入飞书的文本格式为：\n\n```\n{YYYY-MM-DD} {HH:mm}{备注}\n例如：2026-05-15 13:11停车费\n```\n\n仪表盘 app 解析规则：\n- 有时间戳的记录：`(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})` → 提取日期 + 时间\n- 无时间戳的旧记录：`(\\d{4}-\\d{2}-\\d{2})` → 仅提取日期（兜底）\n\n> ⚠️ 如需修改 `record_bill.py` 的文本写入格式，请同步确认仪表盘 app 的正则解析逻辑能否兼容新旧两种格式。\n\nFile v1.2.2:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.2.2\",\n  \"publishedAt\": 1779265403934\n}\n\nFile v1.2.2:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮 | 餐饮 |\n| 购物 | 购物 |\n| 交通 | 交通 |\n| 娱乐 | 娱乐 |\n| 通讯 | 通讯 |\n| 生活 | 生活 |\n| 医疗/住房/教育/其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表只有「其它」，没有「其他」，脚本自动映射，不需要手动处理。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nArchive v1.2.1: 4 files, 12938 bytes\n\nFiles: references/categories.md (2780b), scripts/record_bill.py (17535b), SKILL.md (15553b), _meta.json (136b)\n\nFile v1.2.1:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.2.1\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - FEISHU_BASE_TOKEN\n        - FEISHU_DETAIL_TABLE_ID\n        - FEISHU_SUMMARY_TABLE_ID\n      bins:\n        - curl\n        - python3\n    primaryEnv: FEISHU_BASE_TOKEN\n    envVars:\n      - name: FEISHU_BASE_TOKEN\n        required: true\n        description: \"飞书多维表格 Base Token\"\n      - name: FEISHU_DETAIL_TABLE_ID\n        required: true\n        description: \"明细表 Table ID\"\n      - name: FEISHU_SUMMARY_TABLE_ID\n        required: true\n        description: \"汇总表 Table ID\"\n    emoji: \"💰\"\n    homepage: \"https://github.com/NaeemTC/feishu-accounting-skill\"\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\ncurl -L --max-time 60 -o /tmp/feishu-cli.tar.gz \\\n  \"https://github.com/riba2534/feishu-cli/releases/download/v1.25.0/feishu-cli_v1.25.0_linux-amd64.tar.gz\"\ncd /tmp && tar -xzf feishu-cli.tar.gz\nsudo cp feishu-cli_v1.25.0_linux-amd64/feishu-cli /usr/local/bin/\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发送给用户，让他们在浏览器打开链接，点击「授权」即可完成，无需扫码。**\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `your_base_token_here`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n> **已有用户升级分类**：如果你之前已经建好表，用以下命令给分类字段补充新选项（13分类）：\n> ```bash\n> # 先找到分类字段ID\n> feishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n> # 替换下方 <分类字段ID> 后执行\n> feishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n>   --field-id <分类字段ID> \\\n>   --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n> ```\n\n### Step 9：输出凭证给用户\n\n**AI 必须将以下 5 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 2 用户提供的值，Base Token / Table ID 来自 Step 6-7 创建的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n> 5. **汇总表 Table ID**：`你的汇总表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的明细表和汇总表）\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/download/v1.2.0/feishu-accounting-skill-v1.2.0.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 飞书同步规则**：`--type expense`（支出）同时写入明细表和汇总表；`--type income`（收入）仅写入汇总表，明细表只存支出记录（用于 App 仪表盘分类图表展示）。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md`，核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n|| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n|| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n|| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n|| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n|| 支出 | 通讯 | 话费/流量/套餐 |\n|| 支出 | 医疗 | 医院/药店/挂号/体检 |\n|| 支出 | 住房 | 房租/水电/物业/宽带 |\n|| 支出 | 教育 | 学费/课程/书/培训 |\n|| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n|| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n|| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n|| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n|| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n|| 收入 | 工资 | 工资/薪资/月薪 |\n|| 收入 | 兼职 | 兼职/副业/接单 |\n|| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个分类在飞书明细表中均有对应选项，无需映射损耗。本地「其他/银行/工资/奖金/兼职/投资」→ 飞书「其它」。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md              # 本文件\n├── scripts/\n│   └── record_bill.py     # 记账核心脚本\n└── references/\n    └── categories.md      # 分类关键词参考\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID | `tblxxxxxxxxxxxxxxxx` |\n| `FEISHU_SUMMARY_TABLE_ID` | 汇总表 ID | `tblyyyyyyyyyyyyyyyy` |\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 `feishu-cli bitable field list` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset` 参数：第 1 页不带 offset，第 2 页 `offset=20`，第 3 页 `offset=40` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 只写明细表，汇总表数据缺失 | 汇总表是仪表盘收支数据来源之一，漏写会导致统计数据不完整 | 每次 `add_record()` 必须同时调用 `sync_to_feishu()` 写明细表 + `sync_summary_to_feishu()` 写汇总表 |\n\n---\n\n## 飞书文本字段格式（与仪表盘 app 关联）\n\n`record_bill.py` 写入飞书的文本格式为：\n\n```\n{YYYY-MM-DD} {HH:mm}{备注}\n例如：2026-05-15 13:11停车费\n```\n\n仪表盘 app 解析规则：\n- 有时间戳的记录：`(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})` → 提取日期 + 时间\n- 无时间戳的旧记录：`(\\d{4}-\\d{2}-\\d{2})` → 仅提取日期（兜底）\n\n> ⚠️ 如需修改 `record_bill.py` 的文本写入格式，请同步确认仪表盘 app 的正则解析逻辑能否兼容新旧两种格式。\n\nFile v1.2.1:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.2.1\",\n  \"publishedAt\": 1779245253516\n}\n\nFile v1.2.1:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nArchive v1.2.0: 4 files, 12940 bytes\n\nFiles: references/categories.md (2780b), scripts/record_bill.py (17535b), SKILL.md (15553b), _meta.json (136b)\n\nFile v1.2.0:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.2.0\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - FEISHU_BASE_TOKEN\n        - FEISHU_DETAIL_TABLE_ID\n        - FEISHU_SUMMARY_TABLE_ID\n      bins:\n        - curl\n        - python3\n    primaryEnv: FEISHU_BASE_TOKEN\n    envVars:\n      - name: FEISHU_BASE_TOKEN\n        required: true\n        description: \"飞书多维表格 Base Token\"\n      - name: FEISHU_DETAIL_TABLE_ID\n        required: true\n        description: \"明细表 Table ID\"\n      - name: FEISHU_SUMMARY_TABLE_ID\n        required: true\n        description: \"汇总表 Table ID\"\n    emoji: \"💰\"\n    homepage: \"https://github.com/NaeemTC/feishu-accounting-skill\"\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\ncurl -L --max-time 60 -o /tmp/feishu-cli.tar.gz \\\n  \"https://github.com/riba2534/feishu-cli/releases/download/v1.25.0/feishu-cli_v1.25.0_linux-amd64.tar.gz\"\ncd /tmp && tar -xzf feishu-cli.tar.gz\nsudo cp feishu-cli_v1.25.0_linux-amd64/feishu-cli /usr/local/bin/\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发送给用户，让他们在浏览器打开链接，点击「授权」即可完成，无需扫码。**\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `your_base_token_here`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n> **已有用户升级分类**：如果你之前已经建好表，用以下命令给分类字段补充新选项（13分类）：\n> ```bash\n> # 先找到分类字段ID\n> feishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n> # 替换下方 <分类字段ID> 后执行\n> feishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n>   --field-id <分类字段ID> \\\n>   --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n> ```\n\n### Step 9：输出凭证给用户\n\n**AI 必须将以下 5 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 2 用户提供的值，Base Token / Table ID 来自 Step 6-7 创建的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n> 5. **汇总表 Table ID**：`你的汇总表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的明细表和汇总表）\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/download/v1.1.0/feishu-accounting-skill-v1.1.0.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n```\n\n**⚠️ Python 版本**：确保本机已安装 `python3`（Python 3.9+ 均可），可通过 `python3 --version` 确认。\n\n### 完整命令参数\n\n| 参数 | 必填 | 说明 |\n|------|------|------|\n| `--amount` | ✅ | 金额（元） |\n| `--type` | ✅ | `expense`（支出）或 `income`（收入） |\n| `--category` | | 分类，默认「其他」 |\n| `--note` | | 备注 |\n| `--date` | | 日期 YYYY-MM-DD，默认今天 |\n| `--feishu` | | 同步飞书（默认开启） |\n| `--no-feishu` | | 禁用飞书同步，仅写本地 |\n\n> **⚠️ 飞书同步规则**：`--type expense`（支出）同时写入明细表和汇总表；`--type income`（收入）仅写入汇总表，明细表只存支出记录（用于 App 仪表盘分类图表展示）。\n\n### 查询命令\n\n```bash\n# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05\n```\n\n### 图片记账\n\n用户发送账单图片（无文字）时：\n1. 用 vision 模型看图识别金额\n2. 直接按识别结果执行记账命令，不需要询问用户确认\n\n### 分类关键词（AI 解析参考）\n\n详见 `references/categories.md`，核心规则：\n\n| 类型 | 分类 | 关键词 |\n|------|------|--------|\n|| 支出 | 餐饮 | 早饭/午饭/晚饭/外卖/咖啡/奶茶/餐厅 |\n|| 支出 | 购物 | 超市/衣服/鞋子/电商/淘宝/京东/日用品 |\n|| 支出 | 交通 | 打车/地铁/公交/停车/加油/滴滴 |\n|| 支出 | 娱乐 | 电影/KTV/旅游/游戏氪金/彩票 |\n|| 支出 | 通讯 | 话费/流量/套餐 |\n|| 支出 | 医疗 | 医院/药店/挂号/体检 |\n|| 支出 | 住房 | 房租/水电/物业/宽带 |\n|| 支出 | 教育 | 学费/课程/书/培训 |\n|| 支出 | 服饰 | 衣服/鞋子/包包/穿搭/配饰 |\n|| 支出 | 生活 | 日用/日用品/理发/洗衣/五金 |\n|| 支出 | 数码 | 手机/数码/充电器/耳机/硬盘 |\n|| 支出 | 运动 | 健身/运动/游泳/羽毛球/球鞋 |\n|| 支出 | 宠物 | 宠物/猫粮/狗粮/猫砂/疫苗 |\n|| 收入 | 工资 | 工资/薪资/月薪 |\n|| 收入 | 兼职 | 兼职/副业/接单 |\n|| 收入 | 投资 | 理财/股票/基金/利息 |\n\n**飞书分类映射**：13个分类在飞书明细表中均有对应选项，无需映射损耗。本地「其他/银行/工资/奖金/兼职/投资」→ 飞书「其它」。\n\n---\n\n## 目录结构\n\n```\nfeishu-accounting/\n├── SKILL.md              # 本文件\n├── scripts/\n│   └── record_bill.py     # 记账核心脚本\n└── references/\n    └── categories.md      # 分类关键词参考\n```\n\n## 环境变量\n\n| 变量名 | 说明 | 示例 |\n|--------|------|------|\n| `FEISHU_BASE_TOKEN` | 多维表格 Base Token | `your_base_token_here` |\n| `FEISHU_DETAIL_TABLE_ID` | 明细表 ID | `tblxxxxxxxxxxxxxxxx` |\n| `FEISHU_SUMMARY_TABLE_ID` | 汇总表 ID | `tblyyyyyyyyyyyyyyyy` |\n\n---\n\n## ⚠️ 常见问题与注意事项\n\n| 常见问题 | 原因 | 解决办法 |\n|------|------|--------|\n| 飞书字段 index 写反，写入后数据全 null | 金额写成 index=4、分类写成 index=2，字段顺序和实际不匹配 | 写字段前用 `feishu-cli bitable field list` 确认字段顺序，不要靠记忆 |\n| `sync_to_feishu()` 漏传某些字段 | 只同步了月份/金额/分类，`文本` 和 `单选` 字段未传入。飞书 API 返回 200 但这些字段全 null | 新增飞书字段后，`sync_to_feishu()` 的 config 和函数签名必须同步更新 |\n| Tenant Token 下 `page_size=100` 实际只返回 20 条 | 飞书 API 对 Tenant Token 有分页限制，`page_token` 返回 null | 翻页用 `offset` 参数：第 1 页不带 offset，第 2 页 `offset=20`，第 3 页 `offset=40` |\n| 用 `text.includes('-')` 判断有效记录，漏掉了有效数据 | 明细表有些记录的 `文本` 字段为 null，但金额和分类有效。`text.includes('-')` 会把这些记录全过滤掉 | 判断标准：amount 非 null 且非 0 即可进入聚合，不管 text 是不是 null |\n| `record_bill.py` 只写明细表，汇总表数据缺失 | 汇总表是仪表盘收支数据来源之一，漏写会导致统计数据不完整 | 每次 `add_record()` 必须同时调用 `sync_to_feishu()` 写明细表 + `sync_summary_to_feishu()` 写汇总表 |\n\n---\n\n## 飞书文本字段格式（与仪表盘 app 关联）\n\n`record_bill.py` 写入飞书的文本格式为：\n\n```\n{YYYY-MM-DD} {HH:mm}{备注}\n例如：2026-05-15 13:11停车费\n```\n\n仪表盘 app 解析规则：\n- 有时间戳的记录：`(\\d{4}-\\d{2}-\\d{2}) (\\d{2}:\\d{2})` → 提取日期 + 时间\n- 无时间戳的旧记录：`(\\d{4}-\\d{2}-\\d{2})` → 仅提取日期（兜底）\n\n> ⚠️ 如需修改 `record_bill.py` 的文本写入格式，请同步确认仪表盘 app 的正则解析逻辑能否兼容新旧两种格式。\n\nFile v1.2.0:_meta.json\n\n{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"1.2.0\",\n  \"publishedAt\": 1779245163072\n}\n\nFile v1.2.0:references/categories.md\n\n# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类\n\nArchive v1.1.0: 4 files, 12939 bytes\n\nFiles: references/categories.md (2780b), scripts/record_bill.py (17535b), SKILL.md (15553b), _meta.json (136b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步规则：支出写明细表+汇总表，收入只写汇总表（明细表仅用于 App 仪表盘展示消费明细）。**\nversion: 1.1.0\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup]\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - FEISHU_BASE_TOKEN\n        - FEISHU_DETAIL_TABLE_ID\n        - FEISHU_SUMMARY_TABLE_ID\n      bins:\n        - curl\n        - python3\n    primaryEnv: FEISHU_BASE_TOKEN\n    envVars:\n      - name: FEISHU_BASE_TOKEN\n        required: true\n        description: \"飞书多维表格 Base Token\"\n      - name: FEISHU_DETAIL_TABLE_ID\n        required: true\n        description: \"明细表 Table ID\"\n      - name: FEISHU_SUMMARY_TABLE_ID\n        required: true\n        description: \"汇总表 Table ID\"\n    emoji: \"💰\"\n    homepage: \"https://github.com/NaeemTC/feishu-accounting-skill\"\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 安装 CLI → 创建飞书应用 → 建表 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书两个表 |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：安装 feishu-cli\n\n```bash\ncurl -L --max-time 60 -o /tmp/feishu-cli.tar.gz \\\n  \"https://github.com/riba2534/feishu-cli/releases/download/v1.25.0/feishu-cli_v1.25.0_linux-amd64.tar.gz\"\ncd /tmp && tar -xzf feishu-cli.tar.gz\nsudo cp feishu-cli_v1.25.0_linux-amd64/feishu-cli /usr/local/bin/\nfeishu-cli --version\n```\n\n### Step 2：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 3：引导用户开通权限\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台开通以下权限：**\n>\n> 1. 打开 https://open.feishu.cn/app/[你的AppID]/auth\n> 2. 点击「权限管理」→「开通权限」，搜索并开通：\n>\n> | 权限 | 标识 |\n> |------|------|\n> | 查看、编辑多维表格 | `base:app:read`、`base:app:update` |\n> | 创建多维表格 | `base:app:create` |\n> | 数据表 CRUD | `base:table:read/create/update/delete` |\n> | 字段 CRUD | `base:field:read/create/update/delete` |\n> | 记录 CRUD | `base:record:read/create/update/delete` |\n> | 视图读写 | `base:view:read`、`base:view:write_only` |\n>\n> 3. 开通权限后，点击「申请发版」→「线上版本」→「确认发布」\n>\n> **⚠️ 不发布版本权限不会生效！**\n\n### Step 4：配置 feishu-cli\n\n```bash\nfeishu-cli config init\n# 编辑 ~/.feishu-cli/config.yaml，填入用户的 App ID 和 App Secret\n```\n\n```yaml\napp_id: \"cli_用户的AppID\"\napp_secret: \"用户的AppSecret\"\nbase_url: \"https://open.feishu.cn\"\ndebug: false\n```\n\n### Step 5：认证\n\n```bash\nfeishu-cli auth login --domain bitable --recommend --json --no-wait\n```\n\n**把输出中的 `verification_url` 发送给用户，让他们在浏览器打开链接，点击「授权」即可完成，无需扫码。**\n\n### Step 6：创建多维表格\n\n```bash\nfeishu-cli bitable create --name \"个人记账本\"\n```\n\n**记录返回的 base_token**（格式如 `your_base_token_here`）。\n\n### Step 7：创建两个表\n\n```bash\nBASE_TOKEN=\"上面获取的base_token\"\n\n# 创建明细表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"明细表\"\n# 记录返回的 table_id（明细表ID）\n\n# 创建汇总表\nfeishu-cli bitable table create --base-token $BASE_TOKEN --name \"汇总表\"\n# 记录返回的 table_id（汇总表ID）\n```\n\n### Step 8：创建字段\n\n```bash\nBASE_TOKEN=\"你的base_token\"\nDETAIL_TABLE_ID=\"明细表table_id\"\nSUMMARY_TABLE_ID=\"汇总表table_id\"\n\n# ── 明细表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"文本\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"月份\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为明细表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n# 找到分类字段ID后\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n\n# ── 汇总表字段 ──\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"编号\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"描述\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"周期\",\"type\":\"text\"}'\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"分类\",\"type\":\"single_select\"}'\n\n# 为汇总表分类字段加选项\nfeishu-cli bitable field list --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID\nfeishu-cli bitable field update --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --field-id <分类字段ID> \\\n  --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"支出\"},{\"name\":\"收入\"}]}'\n\nfeishu-cli bitable field create --base-token $BASE_TOKEN --table-id $SUMMARY_TABLE_ID \\\n  --config '{\"field_name\":\"金额\",\"type\":\"number\"}'\n```\n\n> **已有用户升级分类**：如果你之前已经建好表，用以下命令给分类字段补充新选项（13分类）：\n> ```bash\n> # 先找到分类字段ID\n> feishu-cli bitable field list --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID\n> # 替换下方 <分类字段ID> 后执行\n> feishu-cli bitable field update --base-token $BASE_TOKEN --table-id $DETAIL_TABLE_ID \\\n>   --field-id <分类字段ID> \\\n>   --config '{\"field_name\":\"分类\",\"type\":\"select\",\"options\":[{\"name\":\"餐饮\"},{\"name\":\"购物\"},{\"name\":\"交通\"},{\"name\":\"娱乐\"},{\"name\":\"通讯\"},{\"name\":\"生活\"},{\"name\":\"医疗\"},{\"name\":\"住房\"},{\"name\":\"教育\"},{\"name\":\"服饰\"},{\"name\":\"数码\"},{\"name\":\"运动\"},{\"name\":\"宠物\"},{\"name\":\"其它\"}]}'\n> ```\n\n### Step 9：输出凭证给用户\n\n**AI 必须将以下 5 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 2 用户提供的值，Base Token / Table ID 来自 Step 6-7 创建的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 5 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n> 5. **汇总表 Table ID**：`你的汇总表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的明细表和汇总表）\n\n### Step 10：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_BASE_TOKEN=$BASE_TOKEN\nFEISHU_DETAIL_TABLE_ID=$DETAIL_TABLE_ID\nFEISHU_SUMMARY_TABLE_ID=$SUMMARY_TABLE_ID\nEOF\n```\n\n或通过环境变量注入（适合临时调用）：\n\n```bash\nexport FEISHU_BASE_TOKEN=\"你的base_token\"\nexport FEISHU_DETAIL_TABLE_ID=\"你的明细表ID\"\nexport FEISHU_SUMMARY_TABLE_ID=\"你的汇总表ID\"\n```\n\n### Step 11：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**要不要装 Android 仪表盘 App 来看图表和数据：\n\n> 飞书记账后台已经配好了！要不要装个手机 App 来看图表？\n>\n> - **📦 下载发布版**（推荐，即装即用）：https://github.com/NaeemTC/feishu-accounting-skill/releases/download/v1.1.0/feishu-accounting-skill-v1.1.0.apk\n> - **🔧 从源码构建**：需要 Node.js + Android SDK，克隆仓库后执行 `bash sync.sh`\n\n用户选发布版就直接发下载链接，选自己打就引导构建。\n\n---\n\n## 第二阶段：Usage（日常记账）\n\n### 触发词\n\n- \"记账\"、\"花了X元\"、\"支出X\"\n- \"收入X元\"\n- 上传账单图片（无文字说明）\n- \"查账单\"、\"本月花了多少\"、\"月度统计\"\n\n### 凭证检查\n\n每次记账前确认环境变量已设置：\n\n```bash\n# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\"\necho \"FEISHU_SUMMARY_TABLE_ID=${FEISHU_SUMMARY_TABLE_ID:-未设置}\"\n```\n\n**如果未设置**，跳回第一阶段（Setup）流程，重新引导用户获取凭证。\n\n### 记账命令\n\n```bash\n# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx FEISHU_SUMMARY_TABLE_ID=xxx \\","readmeExcerpt":"Skill: 飞书个人记账(含面板app) Owner: naeemtc Summary: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入... Tags: accounting:2.0.0, bitable:2.0.0, feishu:2.0.0, latest:2.1.0, setup:2.0.0 Version history: v2.1.0 | 2026-05-22T06:15:09.367Z | user v2.1.0: 饼图右侧图例, 删除逻辑修复(先飞书再本地), 单选框字段匹配修复, SKILL.md权限19个scope补全, 清理踩坑说明 v2.0","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"cd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\""},{"language":"bash","snippet":"cd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\""},{"language":"bash","snippet":"# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF"},{"language":"bash","snippet":"# 检查凭证\necho \"FEISHU_BASE_TOKEN=${FEISHU_BASE_TOKEN:-未设置}\"\necho \"FEISHU_DETAIL_TABLE_ID=${FEISHU_DETAIL_TABLE_ID:-未设置}\""},{"language":"bash","snippet":"# 方式一：直接调用（脚本自动加载同目录 .env）\npython3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\"\n\n# 方式二：环境变量注入（适合临时调用）\nFEISHU_BASE_TOKEN=xxx FEISHU_DETAIL_TABLE_ID=xxx \\\n  python3 /path/to/scripts/record_bill.py \\\n  --amount 23.40 --type expense --category 餐饮 --note \"午饭\""},{"language":"bash","snippet":"# 今日账单\npython3 scripts/record_bill.py --list\n\n# 指定日期\npython3 scripts/record_bill.py --list --date 2026-05-15\n\n# 月度汇总\npython3 scripts/record_bill.py --summary --month 2026-05"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: feishu-accounting\ndescription: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入明细表，通过「类型」字段区分支出和收入。**\nversion: 1.3.4\nauthor: Naeem\nhomepage: https://github.com/NaeemTC/feishu-accounting-skill\ntags: [feishu, bitable, accounting, setup, permissions]\n---\n\n# 飞书多维表格记账系统\n\n## 概述\n\n本技能是完整的飞书记账解决方案，分两个阶段：\n\n| 阶段 | 触发条件 | 做什么 |\n|------|----------|--------|\n| **Setup** | 用户请求配置记账系统 | 引导创建飞书应用 → 一键搭建多维表格 → 输出凭证 |\n| **Usage** | 用户记账（说金额/上传图片/查账单） | 解析记账输入 → 写本地 bills/ → 同步飞书明细表（单表模式） |\n\n---\n\n## 第一阶段：Setup（首次配置）\n\n### 触发词\n\n用户说以下内容时执行 Setup：\n\n- \"配置飞书记账\"\n- \"帮我搭建记账系统\"\n- \"飞书记账怎么配置\"\n- \"setup feishu accounting\"\n- \"我想用飞书记账\"\n\n### Step 1：引导用户创建飞书自建应用\n\n**把以下内容发给用户：**\n\n> **请在飞书开放平台创建一个自建应用：**\n>\n> 1. 打开 https://open.feishu.cn/app\n> 2. 点击「创建企业自建应用」\n> 3. 填写应用名称（如「记账助手」）和描述\n> 4. 创建完成后，在「凭证与基础信息」页面复制 **App ID** 和 **App Secret**\n>\n> 复制好后发给我。\n\n等待用户提供 App ID 和 App Secret。\n\n### Step 2：一键开通权限（Agent 自动生成授权链接，用户只需点击确认）\n\n**AI 执行** `apply_permissions.py`（自动获取 Tenant Token、生成一键授权链接）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/apply_permissions.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本输出一个 **一键授权链接**，AI 直接把脚本输出的完整链接原样发给用户\n\n> ⚠️ **AI 注意**：不要自己拼链接！必须运行 `apply_permissions.py`，取 stdout 里的链接，原样发给用户。链接里必须包含以下全部 19 个权限，一个不能少：\n>\n> `base:app:read,base:app:update,base:app:create,base:table:read,base:table:create,base:table:update,base:table:delete,base:field:read,base:field:create,base:field:update,base:field:delete,base:record:read,base:record:create,base:record:update,base:record:delete,base:view:read,base:view:write_only,bitable:app:readonly,bitable:app`\n>\n> 用户点击链接 → 页面列出所有权限 → 全选后点击 **「确认开通权限」** → 完成。\n\n**然后 AI 调用** `scopes/apply` API 提交管理员审批申请。\n\n---\n\n### Step 3：一键搭建多维表格\n\n用户提供 App ID + App Secret 后，运行 `setup_bitable.py`（无需安装任何外部工具，直接调飞书 API）：\n\n```bash\ncd /path/to/feishu-accounting/\npython3 scripts/setup_bitable.py \\\n  --app-id \"cli_用户的AppID\" \\\n  --app-secret \"用户的AppSecret\"\n```\n\n脚本会自动完成：\n1. 获取 Tenant Token（永久有效）\n2. 创建多维表格「个人记账本」\n3. 创建一张明细表（单表模式，支出和收入共用）\n4. 创建所有字段（文本/月份/金额/分类/类型）+ 补充选项（18个分类 + 收支类型选项）\n\n输出 4 个凭证：App ID / App Secret / Base Token / 明细表 Table ID\n\n### Step 4：输出凭证给用户\n\n**AI 必须将以下 4 个凭证填入实际值后发送给用户（App ID / App Secret 来自 Step 1 用户提供的值，Base Token / Table ID 来自 Step 3 脚本输出的）：**\n\n> ✅ 飞书记账配置完成！\n>\n> 请保存以下 4 个凭证——首次打开手机 App 时需要按顺序输入：\n>\n> 1. **App ID**：`你的App_ID`\n> 2. **App Secret**：`你的App_Secret`\n> 3. **Base Token**：`你的Base_Token`\n> 4. **明细表 Table ID**：`你的明细表ID`\n>\n> 输入后 App 就能正常查看你的账单数据了。\n>\n> 📊 **多维表格链接**：https://bytedance.feishu.cn/base/`你的Base_Token`\n> （浏览器打开就能直接看到你建的全量账本数据）\n\n### Step 5：配置凭证（让 record_bill.py 能用）\n\n**AI 执行**，在 skill 目录下创建 `.env` 文件（`record_bill.py` 启动时会自动加载）：\n\n```bash\n# 在技能目录创建 .env（record_bill.py 会自动从同目录读取）\ncat > /path/to/feishu-accounting/.env << 'EOF'\nFEISHU_APP_ID=你的App_ID\nFEISHU_APP_SECRET=你的App_Secret\nFEISHU_BASE_TOKEN=你的Base_Token\nFEISHU_DETAIL_TABLE_ID=你的明细表ID\nEOF\n```\n\n### Step 6：询问用户是否安装 App（仪表盘）\n\n配置完成后，**询问用户**"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7etcgy8pnarg34q82gvdz1ed84spgr\",\n  \"slug\": \"feishu-accounting\",\n  \"version\": \"2.1.0\",\n  \"publishedAt\": 1779430509367\n}"},{"path":"references/apk-architecture.md","content":"# APK 仪表盘 App 内部架构\n\n本 App 是 Capacitor 项目，核心为单文件 `dist/index.html`（~1100 行）。Android 层只提供一个 WebView 壳子，所有 UI 和业务逻辑在 HTML 内。\n\n## 文件结构（dist 目录）\n\n```\ndist/\n└── index.html          # 唯一源码，内嵌 CSS + JS + ECharts\nandroid/\n└── app/\n    └── build.gradle    # versionCode + versionName + 签名配置\n```\n\n## 字段索引映射（FI）\n\nFeishu base v3 API 使用 `offset` 翻页时，记录以**位置数组**返回。`FI` 对象定义字段位置：\n\n```javascript\nvar FI = {text: 0, month: 1, amount: 2, category: 3, type: 4};\n```\n\n| 索引 | 字段名 | Feishu 类型 | JS 访问方式 | 示例值 |\n|------|--------|-------------|------------|--------|\n| 0 | 文本 | 文本 | `r[FI.text]` | `\"2026-05-21 12:30 午饭\"` |\n| 1 | 月份 | 文本 | `r[FI.month]` | `\"2026-05\"` |\n| 2 | 金额 | 数字 | `r[FI.amount]` | `23.50` |\n| 3 | 分类 | 单选 | `r[FI.category]` | `[\"餐饮\"]` |\n| 4 | 类型 | 单选 | `r[FI.type]` | `[\"支出\"]` |\n\n注意：单选/多选字段在数组中的值是 **数组**（`[\"餐饮\"]`），取第一个用 `arr[0]`。\n\n**FI 顺序由 setup_bitable.py 中 create_field 的调用顺序决定**，不能随意调整。\n\n## 业务逻辑流程\n\n### 数据生命周期\n\n1. **登录** → 输入 App ID / Secret / Base Token / Table ID → 存 localStorage\n2. **init()** → getToken() → fetchAll() → 拉取全部明细记录 → showApp() + render()\n3. **刷新** → doRefresh() → 重新 fetchAll → 渲染\n4. **月份切换** → 改变 curMonth → re-render（不复拉数据）\n5. **全部模式** → isTotalMode=true → render(month=null) → 聚合所有月份\n\n### 渲染链\n\n```\nrender()\n├── getMonthSummary(month)      → 遍历 detailRecords，按 type 字段区分收支\n├── renderSummary(inc, exp)     → 三张卡片 + 自适应字号（canvas measureText）\n├── renderPie(cats)             → 支出饼图（ECharts 环形图）\n├── renderIncPie(incCats)       → 收入饼图（仅在 showIncomePie=true 时）\n├── renderHBar(cats)            → 分类金额水平条形图\n├── renderBar()                 → 月度对比柱状图（从 detailRecords 按月份聚合）\n├── renderLine(month)           → 日支出趋势折线图\n└── renderDetails(month)        → 消费明细列表 + 分页\n```\n\n### 样式架构\n\n- 主题通过 `data-theme` 属性切换（dark / light）\n- 所有颜色通过 CSS 变量引用（`var(--bg)`, `var(--card)` 等）\n- ECharts 颜色通过 `CUR_THEME` 对象传递\n- 按钮反馈统一使用 `transform:scale`\n- 页面入场：`fadeUp` 动画\n\n## UI 约定速查\n\n| 组件 | CSS 类 | 按压反馈 | 禁用态 |\n|------|--------|----------|--------|\n| 导航按钮 | `.mbtn` | `scale(.88)` | `opacity:.35, cursor:not-allowed` |\n| 主操作按钮 | `.lbtn` | `scale(.97)` | (无禁用态) |\n| 弹窗按钮 | `.dbtn` | `scale(.95)` | (内联控制) |\n| 功能按钮按下态 | `.pressed` | 背景色变 accent，颜色变白 | — |\n| header 齿轮 | `.mbtn.sett:active` | `rotate(45deg)` | — |\n| header 刷新 | `.mbtn.refresh:active` | `rotate(180deg)` | — |\n\n## 弹窗系统\n\n所有弹窗使用同一套模式：\n\n1. 点击触发 → `lock-scroll` → 移除 overlay 的 `hidden` → 显示 `dialogIn` 动画\n2. 关闭 → `closeOverlay(id)` → 加 `.closing` 类触发 `dialogOut` 动画（150ms）→ 加 `.hidden` → 移除 `lock-scroll`\n3. 背景关闭 → 绑定 `click` 事件检查 `e.target === this`\n\n| 弹窗 | overlay ID | 关闭方式 |\n|------|-----------|----------|\n| 设置 | `sett-overlay` | 点击 ✕ / 背景 |\n| 分类设置 | `cat-overlay` | 点击 ✕ / 背景 |\n| 检查更新 | `upd-overlay` | 点击按钮 / 背景 |\n| 关于 | `abt-overlay` | 点击 ✕ / 背景 |\n| 刷新确认 | `refresh-overlay` | 点击按钮 / 背景 |\n| 通用错误 | `.dialog` | 点击按钮 |\n\n## 主题系统\n\n```javascript\nvar THEMES = {\n  dark:  { tooltipBg: '#1a1a2e', tooltipBorder: '#2a2a4a', ... },\n  light: { tooltipBg: '#ffffff', tooltipBorder: '#ddd6cc', ... }\n};\n```\n\n`applyTheme(theme)` 会：\n1. 设置 `data-theme` 属性 + `"},{"path":"references/categories.md","content":"# 消费分类参考\n\n## 支出分类 (expense)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 餐饮 | 吃饭、早餐、午饭、晚饭、咖啡、奶茶、外卖、餐厅、饭店、小吃 |\n| 购物 | 超市、买、购物、衣服、鞋子、电商、淘宝、京东、日用品 |\n| 交通 | 打车、地铁、公交、高铁、机票、停车、加油、滴滴 |\n| 娱乐 | 电影、KTV、旅游、景区、演出、门票、球票、彩票、赌球、游戏氪金 |\n| 医疗 | 医院、药店、药、挂号、体检、看病 |\n| 住房 | 房租、水电、物业、燃气、宽带、房贷 |\n| 教育 | 学费、课程、培训、书、资料、考试 |\n| 通讯 | 话费、手机费、流量、套餐 |\n| 服饰 | 衣服、鞋子、包包、穿搭、配饰、首饰 |\n| 生活 | 日用、日用品、理发、洗衣、五金、杂货 |\n| 数码 | 手机、数码、充电器、耳机、硬盘、数据线 |\n| 运动 | 健身、运动、游泳、羽毛球、球鞋、瑜伽 |\n| 宠物 | 宠物、猫粮、狗粮、猫砂、疫苗、驱虫 |\n| 其他 | 未匹配到以上分类时使用 |\n\n## 收入分类 (income)\n\n| 分类 | 关键词示例 |\n|------|-----------|\n| 工资 | 工资、薪资、月薪、基本工资 |\n| 奖金 | 奖金、绩效、年终奖、提成 |\n| 兼职 | 兼职、副业、外包、接单 |\n| 投资 | 理财、股票、基金、利息、分红 |\n| 其他 | 红包、转账、报销、退款 |\n\n## ⚠️ 分类陷阱\n\n**不要把金额大的消费归入\"其他\"**：¥2100银行转账、¥1621五一汇总等大额消费若归入\"其他\"，统计时会掩盖真实支出结构。遇到无法归类的消费，应在备注里写清楚实际用途，尽量找到合适分类。\n\n**彩票/游戏 → 娱乐**：彩票（体彩、足彩）和游戏氪金都属于娱乐，记账时直接用\"娱乐\"分类，不要单独新建\"彩票\"或\"游戏\"分类。\n\n**\"其他收入\"慎用**：收入来源不明确时（如期初余额、红包、退款）才用，其他情况应尽量具体（工资/兼职/投资/股票等）。\n\n## 飞书分类映射\n\nrecord_bill.py 本地分类 → 飞书选项名映射：\n\n| 本地分类 | 飞书选项 |\n|----------|----------|\n| 餐饮/购物/交通/娱乐/通讯/生活/医疗/住房/教育/服饰/数码/运动/宠物 | 自身同名选项 |\n| 其他/银行/工资/奖金/兼职/投资 | 其它 |\n\n飞书明细表分类字段已预设 14 个选项（13分类+其它），本地分类与飞书选项名一致时直接匹配，无需映射。\n\n## 分类推断逻辑\n\nAI 在解析用户文字时，应根据关键词自动推断分类：\n1. 精确匹配关键词 → 直接使用对应分类\n2. 无法匹配 → 使用\"其他\"，并在回复中告知用户已使用默认分类\n3. 用户可在确认时纠正分类"},{"path":"references/feishu-base-api-pitfalls.md","content":"# 飞书 base/v3 API 踩坑记录\n\n## 1. Record 创建：不加 `fields` 包装\n\n```python\n# ✅ 正确（base/v3 API 直接平铺字段）\npayload = {\n    \"月份\": \"2026-05\",\n    \"分类\": \"餐饮\",\n    \"金额\": 23.40,\n    \"文本\": \"2026-05-15 13:11午饭\",\n}\n\n# ❌ 错误（这是其他飞书 API 的格式，base/v3 不支持）\npayload = {\n    \"fields\": {\n        \"月份\": \"2026-05\",\n        ...\n    }\n}\n```\n\n错误响应：`\"Record write payload must not be wrapped in 'fields'.\"`\n\n## 2. Tenant Token 分页上限只有 ~20 条\n\n`page_size=100` 参数在 Tenant Token 下实际只返回 20 条（实测验证），`has_more` 正常指示。\n\n**正确翻页写法：**\n\n```python\noffset = 0\nwhile True:\n    url = f\"/records?page_size=100&offset={offset}\"\n    # ... 请求 ...\n    records = data[\"data\"][\"data\"]\n    if not records:\n        break\n    for rec in records:\n        process(rec)\n    offset += len(records)  # 按实际返回数累加，而非固定步长\n```\n\n**错误写法（会漏数据）：**\n```python\noffset += 100  # ❌ 实际只返回 20 条，offset=100 跳过了 21-100\n```\n\n## 3. 字段创建后需等待缓存生效\n\n创建字段后立即更新选项（UPDATE field）需要加 `time.sleep(1)`，否则飞书返回 400。\n\n```python\ndef update_field_options(...):\n    time.sleep(1)  # 等待字段创建缓存生效\n    # 然后才能 PUT 更新选项\n```\n\n## 4. 地址恢复与字段映射\n\n```\n创建多维表格: data[\"base_token\"]        # 不是 data[\"base\"][\"token\"]\n创建数据表:   data[\"id\"]                # 不是 data[\"table_id\"]\n创建字段:     data[\"id\"]                # 不是 data[\"field\"][\"id\"]\n更新字段:     用 PUT                     # 不是 PATCH\n```\n\n每次写字段前，建议调 `GET /fields` 确认字段顺序和 ID，不要靠记忆写死 index。\n\n## 5. `.env` 加载：用直接赋值覆盖父 shell 变量\n\n```python\n# ❌ 错误：setdefault 不覆盖已存在的环境变量\n# 如果父 shell 已有 FEISHU_APP_ID（旧应用的），.env 的值会被忽略\nos.environ.setdefault(k.strip(), v.strip())\n\n# ✅ 正确：直接赋值，.env 始终优先\nos.environ[k.strip()] = v.strip()\n```"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入... Skill: 飞书个人记账(含面板app) Owner: naeemtc Summary: 飞书多维表格记账系统完整技能包。包含两步：1）运行 feishu-accounting-setup 引导用户完成飞书应用创建、多维表格搭建、凭证获取；2）使用 record_bill.py 进行日常记账（支持本地存储 + 飞书多维表格同步）。**同步使用永久有效的 Tenant Token。单表模式：所有记录写入... Tags: accounting:2.0.0, bitable:2.0.0, feishu:2.0.0, latest:2.1.0, setup:2.0.0 Version history: v2.1.0 | 2026-05-22T06:15:09.367Z | user v2.1.0: 饼图右侧图例, 删除逻辑修复(先飞书再本地), 单选框字段匹配修复, SKILL.md权限19个scope补全, 清理踩坑说明 v2.0","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":790,"uniquenessScore":54,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T10:04:13.007Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T13:43:21.982Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}