**发现并已修复的文档滞后**(后期代码先于文档,审计时补齐): | 滞后点 | 修复 | |---|---| | `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 处文档滞后已修复,无功能性问题。可以进入部署/上线阶段。
9.5 KiB
9.5 KiB
⛽ 三期 · 记账功能 — 概要设计
上游:
docs/10.概要设计.md(v1.2)、docs/22.API详细设计.md、docs/24.附录.md定位:加油记账 + 真实油耗计算 + 独立油耗计算器 + 油耗趋势折线图(H5 与微信小程序双端) 版本:v1.1 · 2026-09-25
目录
一、业务目标与核心问题
1.1 业务目标
记录每次加油,算出真实油耗(元/km、L/100km),展示油耗趋势折线图;并提供独立油耗计算器(无需登录/车辆也能算)。
1.2 必须解决的漏洞(用户指出)
"万一用户中间忘记一次记录,会产生很大的误差"
简单"每次记一笔"模型下,漏记会使后续油耗计算错误。
解决思路:补记模式(快照 + 差值)
- 每次加油记录是状态快照(里程 + 油价 + 实付金额 + 加油量)
- 油耗 = 相邻两次快照的差值计算,不依赖"每次必记"
- 漏记后自动以最近有效快照为基准(平均化,不报废)
- 异常检测:本次油价或油耗超历史平均 2 倍 → 提示"耗油量异常,是否漏记?"
1.3 设计约束
| 约束 | 说明 |
|---|---|
| 车辆维度 | 加油记录关联 vehicle_id(必填,无车先添加);每辆车独立油耗/里程/统计 |
| 加满为标签 | full_tank 复选框仅作标签展示,不参与油耗计算 |
| 历史可修正 | 可编辑/删除/补录(补录可改加油日期),并级联重算受影响区间 |
| 双端一致 | H5 与小程序共用同一套 API 与计算规则 |
| 计算器独立 | 计算真实油耗的页面无需登录/车辆;有车绑定保存,未登录不保存 |
二、核心模型:补记模式(快照 + 差值)
2.1 一次加油的完整生命周期(登录 + 有车)
用户加完油 → 进入"记一笔"页(或独立计算器)
├─ 后端回显(可修改):
│ ├─ 当前油价 price ← 默认取该车省份最新价(按车油号)
│ ├─ 上次码表里程 last_odo ← 该车最近一条记录
│ └─ 加油日期 refuel_at ← 默认当前日期,可改(补录场景)
├─ 用户输入(必填):支付金额 amount / 当前码表里程 odometer
│ 可选:优惠金额 discount(默认0) / 本次是否加满 full_tank(复选框,标签) / 备注
└─ 点击"完成"
├─ 加油量 liters = (amount - discount) / price
├─ 找上次有效记录 → distance = odometer - last_odo
├─ 若上次存在且 distance > 0:L/100km、元/km
├─ 存历史(refuel_records,油耗字段记在"本次"上)
└─ 异常检测:本次油价或油耗超历史平均 2 倍 → possible_missing 提示
2.2 快照 vs 区间
R1 ──── R2 ──── R3(快照:里程/油量/日期)
R1→R2 区间油耗记在 R2;R2→R3 记在 R3。首条无"上次",油耗 NULL。
2.3 漏记/异常行为
实际:R1 ──(漏记)── R3
记录:R1 ──────── R3
R3 的 distance = R3.odometer - R1.odometer(跨漏记区间)
liters = R3.liters(只有本次量)→ 平均油耗(偏低但可用)
- 异常检测:本次
price或calc_l_per_100km超历史平均 2 倍 →possible_missing=true→ 前端提示"耗油量异常,是否有漏记?"- 是 → 跳历史页补录(填漏记那次的日期/里程/金额/油价)→ 级联重算恢复精确
- 否 → 保留记录(平均油耗),继续
- 无历史平均(首条)→ 不检测
三、独立油耗计算器
定位:把"计算真实油耗"单独拎出,有车无车 / 登录未登录均可进入。
3.1 访问矩阵
| 场景 | 回填 | 保存 |
|---|---|---|
| 未登录 | 无回填(全手输) | 不保存(仅展示计算结果) |
| 已登录 + 有车 | 回填该车:当前油价 / 上次里程 / 上次日期 | 计算后可选"保存到车辆" → POST /api/refuels |
| 已登录 + 无车 | 无回填 | 提示"请先添加车辆",引导到爱车页 |
| 已登录 + 有车 + 无记录 | 无上次里程(提示"首次加油,无上次基准") | 保存为首条记录(油耗 NULL,后续可算) |
3.2 流程
进入计算器
├─ 已登录 + 有车 → 页面顶部展示【当前车辆】可切换(A4 车辆列表)
│ ├─ 切换车辆 → 请求 A22 prefill → 回填当前油价 / 上次里程 / 上次日期(可改)
│ └─ 该车无记录 → 展示"暂无历史"(无上次基准)
├─ 未登录 → 顶部展示登录入口"登录后可实时追踪真实油耗"(点击登录)
│ └─ 输入框:油价 / 上次里程 / 上次加油日期(可空,用户手输)
├─ 输入:本次里程 / 支付金额 / 优惠金额(0) / 是否加满(标签) / 加油日期(默认当前)
└─ 点"计算油耗" → 本地公式算出 L/100km、元/km → 展示结果卡片
├─ 已登录 + 有车 → 按钮"保存到车辆" → POST A19 → 保存 + 异常检测
└─ 未登录 → 结果卡片下方展示"登录后可实时追踪真实油耗"(点击登录)
计算逻辑为纯公式,前端本地即可完成(未登录不触达后端私有接口)。
四、公式概览
| 量 | 公式 |
|---|---|
实付金额 net |
net = amount - discount |
加油量 liters |
liters = net / price(保留 2 位) |
区间里程 distance |
distance = odometer_now - last_odometer |
区间油耗 L/100km |
l_per_100km = liters / distance × 100(保留 1 位) |
区间成本 元/km |
yuan_per_km = net / distance(保留 2 位) |
生效条件:无上次(首条)→ NULL;distance <= 0 → anomaly=odometer(里程回退,标黄提示);加满与否不参与计算(full_tank 仅标签)。
公式完整定义与异常检测规则见
docs/45.记账附录.md。
五、数据表概览
refuel_records(加油记录表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id / user_id / vehicle_id | — | 主键 / 归属用户 / 归属车辆 |
| refuel_at / odometer | — | 加油时间(默认当前,可补录)/ 码表里程(km) |
| price_per_liter / amount / discount / net_amount | — | 油价 / 支付 / 优惠 / 实付金额 |
| liters / fuel_type / full_tank / note | — | 加油量 / 油号 / 是否加满(标签) / 备注 |
| calc_distance_km / calc_l_per_100km / calc_yuan_per_km | — | 区间里程 / 区间油耗 / 区间成本(可空) |
| anomaly | — | odometer / NULL(里程回退标记) |
完整 DDL 见
docs/45.记账附录.md。
六、API 概览
| 接口 | 方法 | 功能 | 认证 |
|---|---|---|---|
/api/refuels |
GET | 记录列表(含油耗字段) | 🔒 |
/api/refuels |
POST | 新增(算油耗 + 异常检测) | 🔒 |
/api/refuels/:id |
PUT | 修正(级联重算) | 🔒 |
/api/refuels/:id |
DELETE | 删除(级联重算) | 🔒 |
/api/refuels/prefill |
GET | 记一笔回填(当前油价 + 上次里程) | 🔒 |
/api/refuels/stats |
GET | 统计(折线图 + 汇总 + 最近油耗) | 🔒 |
完整请求/响应/字段/SQL 见
docs/43.记账API详细设计.md。计算器本地计算不新增后端接口(保存复用 A19)。
七、前端概览
| 端 | 页面 | 功能 |
|---|---|---|
| H5 | /fuel-calc |
独立油耗计算器(无需登录/车辆) |
| H5 | /refuels?vehicle=X |
记录列表 + 记一笔 + 统计(ECharts 折线图) |
| H5 | 爱车页入口 | 每辆车"加油记录"按钮 + "最近一次油耗"卡片 |
| 小程序 | pages/refuels/refuels |
三 tab:记录 / 记一笔 / 统计(canvas 折线) |
| 小程序 | pages/calc/calc |
独立油耗计算器(首页导航入口) |
交互细节与折线图设计见
docs/44.记账前端详细设计.md。
八、与现有模块衔接
| 模块 | 衔接点 |
|---|---|
vehicles 表 |
加油记录 vehicle_id 归属(无车先添加);车辆卡片"加油记录" + "最近油耗" |
province_prices |
A22 回填"当前油价"(该车省份 + 该车油号最新价) |
api 路由 |
/api/refuels* 挂 authGuard |
service |
油耗计算/级联重算放 internal/service/refuel.go |
| 数据库 | schema.sql 增 refuel_records;db.Open 迁移兼容新旧库 |
九、已确认设计点(2026-09-25 用户确认)
| # | 确认项 | 定稿 |
|---|---|---|
| 1 | 计算器车辆选择 | 登录+有车:页面顶部展示当前车辆,可切换(A4 车辆列表);下方为"先算展示 → 保存到车辆" |
| 2 | 未登录引导 | 结果卡片下方展示"登录后可实时追踪真实油耗"(点击登录) |
| 3 | 无历史平均 | 直接展示"暂无历史"(该车无记录时提示,不弹异常) |
| 4 | 补录日期 | 补录可改加油日期 → 按 refuel_at 排序落位 + 级联重算 |
| 5 | 最近油耗卡片 | 爱车首页展示该车最近一次 calc_l_per_100km,点击跳统计页 |