对照 ledgerly 自文档上次更新以来的全部改动,补充新功能文档、修正品牌与版本残留,并新增下载与安装页;配图已重新截取并上传 OSS,本地截图目录不纳入版本管理。 变更内容: - 新增「智能查数」「账单关系」两个使用文档页,并登记侧边栏与总览 - 设置页扩充为八个面板(账号安全、数据库实时进度、外观、导航等)并改为即时保存 - 收支记录补充关系列、批量操作、AI 搜索浮窗、可配置分页与「账单详情」弹窗 - 统计面板补充饼图/渠道图下钻与筛选双向联动;规则管理补充批量删除 - AI 能力补充智能查数与关系命名;新增下载与安装页 - 开发文档同步:AI 13 类调用、数据模型 24 张表、API、前端偏好、构建部署 - 统一「汇账 Ledgerly」品牌与「设置/日志」菜单文案,版本号对齐 0.1 - 截图脚本新增账单详情等场景并更新登记 说明: - download.md 的 OSS 下载链接保持待发布产物回填,暂不调整 - 已通过 npm run docs:build 与 npm run typecheck:scripts
4.8 KiB
4.8 KiB
账单解析
账单导入采用「解析预览 → 确认导入」两阶段流程,解析阶段不落库,用户确认后才写入。
解析器设计
解析器采用策略模式:BillParser 接口声明 getBillType() 与 parse(byte[]),各实现类对应一种账单类型。服务层构造时用 EnumMap<BillType, BillParser> 注册所有实现,按类型分发,便于扩展新来源。
| 解析器 | 格式 | 表头锚点 | 去重键来源 |
|---|---|---|---|
AlipayBillParser |
CSV(UTF-8/GBK) | 「交易号」 | 交易号 |
WechatBillParser |
xlsx(POI) | 「交易时间」 | 交易单号 |
MeituanBillParser |
CSV | 「交易创建时间」 | 交易单号 |
TaobaoBillParser |
xlsx(POI) | 「订单号」 | 订单号(按订单号聚合多商品行) |
JdBillParser |
CSV(UTF-8/GBK) | 「交易时间」 | 交易订单号 |
CmbBillParser |
CSV | 「交易日期」 | 生成 CMB_日期_类型_金额_余额 |
CmbPdfParser |
PDF(PDFBox) | 「记账日期」 | 同上(与 CSV 互通) |
BocomBillParser |
xls(POI) | 「记账日期」 | 生成 BOCOM_日期_时分秒_类型_金额 |
各解析器统一输出 ParsedBillRow:行号、externalNo、交易时间、类型、金额、交易对方、商品、交易状态、原始收/支方向、是否计入统计、是否可导入、是否重复、命中规则与建议分类/标签、rawData(保留原始列的 JSON)、错误信息。
解析要点
- 编码识别:CSV 自动识别 UTF-8 / UTF-8 BOM / GBK。
- 表头定位:以特定表头文字定位数据区,忽略元信息与统计行。
- 银行 PDF:按字符坐标切列、按纵坐标合并折行还原表格;用带符号金额判断收支;按「联机余额」做连续性校验(误差 0.005),不连续的行标记为不可导入。
- 时间兼容:微信账单兼容 Excel 日期序列号与文本时间;支付宝在付款时间缺失时回退交易创建时间;淘宝订单同样兼容文本时间与 Excel 日期序列号。
- 订单聚合:淘宝订单数据中多商品订单的订单级列(订单号、提交时间、状态、店铺、实付金额、运费)以合并单元格呈现,仅首个商品行有值;解析器按订单号分组聚合,每个订单输出一条记录,金额优先取订单级实付金额,为空时回退「Σ(商品金额×数量)+运费」。
- 不计收支处理:京东流水的「不计收支」行(白条还款、小金库转入、全额退款等)标记为可导入但不计入统计且默认不勾选,类型按「交易说明含『退款』→ INCOME,否则 EXPENSE」推断。
- 计入统计默认值:解析完成后按账单来源应用「计入统计」默认值(配置于设置页,见 动态数据源 同级的应用配置)。采用「解析器判定 && 来源默认」语义——来源默认不计入时整批置为不计入;来源默认计入时保留解析器对「不计收支/中性」行的排除。确认导入时若请求未显式提供该字段,同样以来源默认兜底。
压缩包解密
BillArchiveExtractor 处理 zip 压缩包:
- 按魔数
PK\x03\x04判断是否为 zip,并区分「xlsx 本身是 zip」与「账单压缩包」。 - 支持 ZipCrypto 与 AES 加密;未提供密码返回错误码
4001,密码错误返回4002。 - 限制条目数与总大小,防止 zip bomb;解析完成后清理临时文件。
两阶段流程
parse(不落库)
- 按账单类型分发到对应解析器;若为 zip 则先解密提取。
- 批量查询已存在的
externalNo,标记重复行并取消勾选。 - 调用规则引擎批量匹配,生成建议分类与标签(批量查询分类与标签,避免 N+1)。
confirm(落库,事务)
- 校验默认分类归属与类型,过滤默认标签。
- 再次批量运行规则匹配。
- 逐条校验类型、时间、金额;按
externalNo去重(含本批次内去重)。 - 规则建议分类优先于面板默认分类;标签取「默认标签 ∪ 规则标签」并去重。
- 批量插入(每 500 条一批),批次失败时回退逐条插入;标签关联在批量插入未回填主键时按
externalNo回查 ID。 - 返回成功 / 跳过 / 失败统计。
去重策略
- 统一使用「用户 +
externalNo」唯一约束uk_user_external去重,external_no为 NULL 的手动记录不受影响。 - 有交易号的账单直接使用交易号。
- 银行流水无交易号,则用「日期 + 类型 + 金额 + 余额(或时分秒)」生成稳定键,保证同一账单重复导入不会重复;招商银行 CSV 与 PDF 生成规则一致,可混用。