Files
oil-price-monitoring/docs/42.记账功能大纲.md
maxf 28fcfc6aec ## 1️⃣ 文档与代码一致性 ✅(修复 4 处滞后)
**发现并已修复的文档滞后**(后期代码先于文档,审计时补齐):

| 滞后点 | 修复 |
|---|---|
| `24.附录` users 表缺 `wechat_openid` 列(二期微信登录加的) | ✅ 已补 |
| `24.附录` 缺 `refuel_records` 表(三期记账) | ✅ 已补 |
| `24.附录` 错误码缺 `1012/1013`(三期) | ✅ 已补 |
| `34.附录` 小程序页面目录缺 `calc/refuels`(三期) | ✅ 已补 |

**核对一致项**:
- API 路由 **A1-A23 + `/api/auth/wechat`** 全部注册,与 22/33/43 文档逐项对应
- `schema.sql` 11 表 = 24 附录(10 + refuel)+ 45 附录
- 小程序 8 页文件齐全(js/wxml/wxss/json × 8),`refuels.wxml` 数据绑定与 js 匹配
- H5 8 页面全部可访问

## 2️⃣ 后期变更对前期的影响 ✅ 无破坏

综合回归 **20 项全 PASS**:
- **一期**:账号密码登录 / Cookie 会话 / dashboard / provinces(31省) / history ✅
- **二期**:Bearer token 认证(与 Cookie **双通道共存**,互不冲突)✅
- **三期**:refuel 首条保存 / 区间油耗 8.25 / 统计 / 预填 ✅
- **前端**:9 个资源(8 页 + 静态 JS)全部 200 ✅

关键:二期的 `users` 加列是**幂等增量迁移**(ALTER),未动一期任何表结构;一期 API 与前端全部正常。

## 3️⃣ 整体可行性 ✅ 在可控范围

| 维度 | 状态 |
|---|---|
| 构建/静态检查 | `go build / vet` 全绿 |
| 单元测试 | 6 包 17 单测全过(auth/crawler/cron/db/push/service) |
| 规模 | 11 表 · 23+ 接口 · 8 H5 页面 · 8 小程序页面 · 17 份文档 · ~90 代码文件 |
| 三阶段功能 | 监控预测提醒 → 微信小程序 → 加油记账/真实油耗,全部落地 |

**非阻塞小项**(可后续优化,不影响运行):
1. `refuels.wxml` 第 11 行 `wx:for` 与 `wx:if` 同节点——功能正常,写法可规范
2. api 包 handler 层无独立单测——由端到端回归覆盖(service 层已有单测)

---

**结论:项目整体健康、文档与代码对齐、三阶段功能完整可用。** 4 处文档滞后已修复,无功能性问题。可以进入部署/上线阶段。
2026-09-25 16:56:07 +08:00

6.5 KiB
Raw Permalink Blame History

⛽ 三期 · 记账功能 — 功能大纲(编号生命周期)

上游:docs/40.记账概要设计.md 编号体系:201-206(三期功能),与一期 H5(001-014)、二期小程序(P01-P06)区分


编号体系

编号 功能 类型
201 记一笔(加油录入 + 回显 + 计算) 前端交互
202 记录列表(查看/修正/删除/补录) 前端交互
203 油耗统计(折线图) 前端交互
204 油耗计算(后端核心公式) 后端逻辑
205 级联重算(修正/删除/补录后) 后端逻辑
206 异常检测与漏记补录提示 后端逻辑 + 前端
207 独立油耗计算器(无需登录/车辆) 前端交互

通用约定:▲前端(H5/小程序)▼后端(Go);⟶ [A19] 表示跳转对应 API 详设。


201 记一笔(核心流程)

触发:爱车页某辆车 → "记一笔"

生命周期:

201.1 ▲前端 进入记一笔页
  ├─ 请求 GET /api/refuels/prefill?vehicle_id=X ⟶ [A22]
  │    ├─ 成功 → 回显(可改):
  │    │     当前油价 current_price / 上次码表里程 last_odometer / 该车平均油耗 avg
  │    └─ 失败 → 提示加载失败
  ├─ 用户输入(必填):支付金额 / 当前码表里程;可选:优惠金额(默认0)/ 加油日期(默认当前,可补录)/ 本次是否加满(复选框,仅标签)/ 备注
  └─ 点击"完成"
201.2 ▲前端 POST /api/refuels ⟶ [A19]
  ├─ 成功:
  │    ├─ 响应含 possible_missing:
  │    │     true  → 弹"可能漏记,建议补录?" → 跳 202 列表页补录
  │    │     false → 返回列表页,展示本条油耗
  │    └─ anomaly 标记(odometer 里程回退 / not_full 未加满)→ 标黄提示
  └─ 失败(1012 参数非法 / 1013 重复)→ 回显错误

出口:记录入库;油耗已计算;回到列表页。


202 记录列表

触发:爱车页 → "加油记录"

生命周期:

202.1 ▲前端 GET /api/refuels?vehicle_id=X&limit=50 ⟶ [A18] → 渲染列表
  ├─ 每条:日期 / 里程 / 油量 / 单价 / 实付 / 区间油耗 / 异常标记
  └─ 异常记录(anomaly)标黄 + 角标说明
202.2 点击"编辑" → 表单预填 → PUT /api/refuels/:id ⟶ [A20] → 级联重算 → 刷新
202.3 点击"删除" → confirm → DELETE /api/refuels/:id ⟶ [A21] → 级联重算 → 刷新
202.4 点击"补录"(漏记场景)→ 弹出表单(填漏记那次的里程/金额/油价)→ POST ⟶ [A19]
      → 按 refuel_at 排序自动落位 → 级联重算 → 刷新
202.5 点击"统计" → 跳 203

出口:列表数据一致;油耗已级联重算。


203 油耗统计(折线图)

触发:记录列表页"统计"

生命周期:

203.1 ▲前端 GET /api/refuels/stats?vehicle_id=X ⟶ [A23]
  ├─ 汇总卡:总次数 / 累计金额 / 累计油量 / 平均 L/100km / 平均元/km
  ├─ ECharts(H5)/ canvas(小程序):
  │     油耗 L/100km 折线(markLine 平均线)
  │     元/km 折线 / 油价折线 / 累计费用面积图
  └─ 异常点(anomaly)空心标记,hover 提示
203.2 图例/指标切换(前端本地状态)

出口:油耗趋势可视化。


204 油耗计算(后端核心公式)

触发:A19 新增 / A20 修正 / A21 删除 / 补录后级联

生命周期:

204.1 ▼后端 输入(本次记录 + 上次有效记录)
  ├─ net = amount - discount
  ├─ liters = net / price
  ├─ distance = odometer_now - last_odometer
204.2 ▼后端 判定:
  ├─ 无上次(首条)→ calc_* 全 NULL
  ├─ distance <= 0 → anomaly=odometer
  ├─ full_tank=0 → 不参与计算,anomaly=not_full
  └─ 正常 → calc_l_per_100km = liters/distance×100;calc_yuan_per_km = net/distance
204.3 ▼后端 落库(calc_* + anomaly 随记录保存)

公式与精度见 docs/45.记账附录.md 第二节。


205 级联重算

触发:修正 / 删除 / 补录后

生命周期:

205.1 ▼后端 定位受影响的记录范围
  ├─ 新增 R3   → 重算 R3(与 R2)
  ├─ 编辑 R2   → 重算 R2(与 R1)+ R3(与 R2)
  ├─ 删除 R2   → R3 的基准改为 R1 → 重算 R3
  └─ 补录 R2   → 重算 R2(与 R1)+ R3(与 R2)
205.2 ▼后端 同一事务内逐条重算(recalc(vehicleID, fromID))
205.3 ▼后端 返回受影响记录 id 列表(A20 响应 recalc_ids)

206 漏记检测与补录提示

触发:A19 新增 / A20 修正后

生命周期:

206.1 ▼后端 对本次记录判定(相比该车历史平均;无历史平均的首条跳过):
  ├─ 本次油价 price > 历史平均 price × 2
  └─ 或 本次油耗 calc_l_per_100km > 历史平均 L/100km × 2
  → possible_missing = true
206.2 ▲前端 收到 possible_missing=true → 弹"耗油量异常,是否有漏记?"
  ├─ 是 → 跳 202 列表页 → 补录(填漏记日期/里程/金额/油价)→ 级联重算
  └─ 否 → 保留记录(平均油耗),继续

出口:异常可被发现并修复;不修复也可继续使用。


207 独立油耗计算器(无需登录/车辆)

触发:首页 / 导航进入"油耗计算器"(有车无车 / 登录未登录均可)

生命周期:

207.0 ▲前端 进入计算器
  ├─ 已登录 → 请求 GET /api/refuels/prefill?vehicle_id=所选车 ⟶ [A22]
  │    ├─ 有记录 → 回填:当前油价 / 上次里程 / 上次日期(可改)
  │    └─ 无记录 → 提示"首次加油,无上次基准"
  └─ 未登录 / 无车 → 全手输(油价 / 上次里程 / 上次日期可空)
207.1 ▲前端 输入:本次里程 / 支付金额 / 优惠金额(0) / 是否加满(标签) / 加油日期(默认当前)
  └─ 点"计算油耗" → **前端本地公式**算出 L/100km、元/km → 展示结果卡片
207.2 ▲前端 保存分支:
  ├─ 已登录 + 有车 → 按钮"保存到车辆" → POST /api/refuels ⟶ [A19]
  │    ├─ 成功 → 保存为加油记录 → 异常检测提示(206)
  │    └─ 可返回计算器继续算
  └─ 未登录 → 显示"登录后可保存到车辆" → 登录入口
207.3 ▲前端 爱车首页"最近一次油耗"卡片 → 展示该车最近一条 calc_l_per_100km → 点击跳统计页(203)

出口:未登录仅本地计算展示;登录+有车可保存为正式记录。