① 新用户默认空数据:首次进入不再预置示例记录,只有一个空车辆;想要历史数据就导入 CSV。
② 导入导出改用 CSV:导出 .csv 文件(UTF-8,Excel 可直接打开编辑),导入支持从聊天记录选文件或粘贴内容,按车辆名称匹配、可选覆盖或合并。
③ 移除「写入示例数据」入口:不再有内置的一键写示例按钮,示例数据改为随源码提供的独立 CSV 文件。
④ 加油均摊提示拆行:「尚未均摊到月份的油费金额」与「本期最多可均摊金额」各占一行,金额红色加粗显示。
⑤ 联动开关默认不勾选:「加油费用均摊 = 当月加油费用」默认关闭,避免录入当月加油费用时自动改写均摊值。
⑥ 录入卡片重排:能费周期 → 里程数据 → 公共快充 → 家充桩 → 加油数据 → 保养 / 保费,按每月抄表动线排列。
⑦ 版本水印:录入页底部、设置页「关于」显示居中的 版本 vX.Y.Z · YYYY-MM-DD HH:MM(版本号 + 代码生成时间,不显示其它内容)。模拟器里若看不到这行或数字不对,说明跑的不是本份源码 —— 先核对「项目目录」与重新编译,再谈别的。
⑧ 备份数据至邮箱:设置 → 数据管理新增入口,填邮箱即可把全部车辆的 CSV 作为附件发到该邮箱(走云开发云函数 sendBackupMail,发件邮箱 wce@qq.com)。云开发不可用或云函数未部署时,自动降级引导到「导出数据」,入口不会点了没反应。
⑨ 邮箱输入即记住:收件邮箱改成「边输边记」—— 不管邮件发没发出去、成功还是失败,下次打开设置页都会自动带出(hy_mail_to);「上次成功备份」的时间仍只在校验真正发送成功后才更新(hy_mail_sent_at)。
⑩ 默认值与「关于」调整:纯油油车每公里费用默认 0.60 元/km、年保费总额默认 4800.00 元/年;「均摊月数」固定 12 个月、不再作为可配置项(建议值提示保留);「关于」改为五条编号说明,去掉了云端存储那段。
⑪ 分析页图表调整:把原「累计油费节省」走势图改为 「当月油费节省」 走势图 —— 累计值是单调递增的,看不出每月波动;改为当月值后能直接看出哪个月省得多、哪个月省得少。同时上面那张卡原来也叠了一条「当月油费节省」,为免重复,该卡精简为只看月度用车总费用。
⑫ 分析结果一键生成分享图:分析页底部新增「分享当前区间能耗分析数据」—— 把本页整页内容(结论横幅 + 四张走势图 + 费用构成 + 区间指标)按页面原样绘成一张长图,高随内容自动伸缩,底部放小程序码 + 引导语,好友长按即可识别进入小程序。生成后可「保存到相册」,或长按图片直接转发给朋友(详见 ⑯)。
⑬ 四张走势图补上纵坐标:分享图与页面上的「月度行驶里程 / 百公里费用趋势 / 月度用车总费用 / 当月油费节省」原先只有图形、没有纵轴,看不出具体数值。现已补上水平网格线与刻度值,并把量程收成整齐步长(如 0/750/1500/2250/3000),刻度读起来利落。
⑭ 分享图标注极值、去掉水印:每张走势图都用气泡标出本图的最高值与最低值(双系列图按上下错开,避免气泡打架);分享图里不再出现版本号和生成时间。
⑮ 码区左右排列 + 长图按钮不再被顶出屏幕:底部改回码在左、引导语在右的一左一右布局,并整体向中间靠拢(左右留白做成一模一样,整块与上方卡片左右边缘对齐)。同时修掉一个实打实的 bug —— 分享图很长,预览弹层原先不限高,图片会把「保存到相册」按钮顶到屏幕外面。现在弹层限高 82vh,图片区可上下滚动,按钮固定在底部始终可见。
⑯ 分享弹层改名、去掉「分享给好友」按钮:浮窗标题改为「分享图片已生成」;图片下方提示语改为「长按图片可转发给朋友」;底部只保留「保存到相册」一个按钮。原因:原按钮调用的是 wx.shareFileMessage,发出去的其实是文件卡片(好友要先点开文件才看得到图),并不是转发图片本身;而小程序没有接口能以代码调起系统的「转发给朋友」面板 —— 那是长按图片才出现的系统菜单。按钮名与实际行为不符,索性去掉,转发统一引导走长按。
⑰ 分享图底部码区左右留白对齐:原来码区的左边距是写死的 52px、右边只按「文案自然结束」收尾,结果左侧 52px、右侧约 248px,整块明显偏左。现在改成由「左右留白相等」反解小程序码的横向位置 —— 左侧留白 = 右侧留白 = 150px,整块与上方卡片左右边缘对齐,看起来才真正居中。
⑱ 修复分析页误报「暂无可分析的数据」:有数据时页面底部仍会多出一块空状态,这是 wx:else 用错了 —— wx:else 只认紧邻的兄弟节点,而紧邻它的是「分享图预览弹层」的遮罩,于是它的语义变成了「没弹预览时才显示」,有数据、没开弹层时必然误报。现在空状态改挂 wx:if="{{!hasData}}",与弹层状态彻底解耦。
⑲ 分析页区间口径统一:① 指标栏标题由「区间统计指标」改为写明具体期数,如「2025年9月至2026年8月统计指标」;② 「用车费用构成」原先只统计最后一期,与同页其它板块口径不一致,现改为整个区间的汇总(合计 ¥4,851.75,与「区间用车总费用」完全对得上);③ 指标顺序调整 —— 「平均充电电价」提到第 4 位,「区间油费节省」移到列表最后;④ 分享卡文案由「分享本期分析」改为「分享当前区间能耗分析数据」。
⑳ 修复分析页白屏:v1.1.3 在算区间范围时用了变量 last,却漏写它的定义,导致页面刷新时抛 ReferenceError、ready 永远停在第 false 步,整个分析页一片空白。现已补上 const last = list[list.length - 1]。根因是当时 373 项自检只做源码文本匹配、不真跑页面代码,所以全绿却没拦住。自检已新增 [I] 页面级冒烟:把各页面的 refresh() 真执行一遍(有数据 / 无数据两种),任何运行时报错立刻 FAIL。
㉑ 指标顺序微调:分析页统计指标里 「区间用车总费用」与「平均充电电价」互换位置,现顺序为:区间行驶里程 → 平均充电电价 → 区间能耗总费用 → 区间用车总费用 → 平均每公里总费用 → 平均每公里电费用 → 最省的一期 → 最贵的一期 → 区间油费节省。分享图同步该顺序,并新增两条断言(页面源码 9 项顺序、预览页与源码逐项一致)防止再次漂移。
㉒ 极值两项口径调整:分析页指标栏 「最省的一期」改为「每公里总费用最低值」、「最贵的一期」改为「每公里总费用最高值」,主副值对调——主值(大号字)显示费用(如 ¥0.045),副值(小号灰字)显示期数(如 2026年4月)。核心数据由「期数」改为「费用」,与指标名一致。分享图同步。新增 6 条断言钉住「主值是费用、副值是期数」不再回退。
㉓ 主值去重单位 + 副值换口径:① 「每公里总费用最低值 / 最高值」两项指标名里已经有「每公里」,主值不再重复拼接「 /km」,与「平均每公里总费用」保持同一格式(都显示 `¥0.193` 这样纯数值);② 「平均每公里总费用」的副值由 「纯油车基准 ¥0.60/km」改为「比纯油车省 ¥0.407/km」 —— 旧副值讲的是「基准是多少」,与指标名关联弱;新副值直接给出同口径下每公里省下的钱(主值 + 副值 = 纯油车基准,口径自洽)。新增 4 条断言(主值不带 /km、副值文案与运行值一致、旧副值已移除)防止回退。
㉔ 新增记录的保费默认值改取建议值:录入本期时,「当年保费均摊」过去默认带入上一期的实际数值(上一期可能被手工改过,不代表本期应摊金额),现改为默认带入 年保费总额 ÷ 12 个月的建议值(示例数据下 4800 ÷ 12 = ¥400.00),留空保存时的兜底值同样取建议值。建议值抽成单一来源 store.suggestedInsurance(),录入页与设置页共用同一口径。
顺带修掉第⑥屏「记录本期」的一处遗留:该屏此前仍残留 0.55 纯油单价(纯油油费 638.00 = 1160 × 0.55),是 v1.1.3 统一口径时漏掉的一屏,现全部对齐到 0.60。新增 7 条断言把第⑥屏整屏钉在真实计算链路上。
㉕ 概览页补录提示改为按「上个月」判断:记录惯例是当月录入上一期的费用与补能数据,所以「本期」其实指上个月。过去概览页却拿当月去比对 —— 10 月份只要 10 月还没录就一直在催,而这是完全正常的(10 月的数据要 11 月才录)。现改为以上个月为「应记录期」:上个月(或更早)缺记录才提示「点击补录本期能耗数据」;只缺当月则不提示,转为「已记录」态。若连续缺多期,标题会写明缺口起点与期数(如「2026年6月 起 4 期未记录」)。
本页第②屏即示例数据(截至 2026年8月)在 10 月的真实状态:2026年9月 尚未记录(橙色补录提示);把 9 月补上后就会变成绿色的「2026年9月 已记录」。新增 20 条断言真跑 refresh() 覆盖「缺上个月→提示」「只缺当月→不提示」「连缺多期→写明期数」三种场景。
㉖ 修复「已记录」态点击提醒却打开新增空白页:概览页的提醒块过去不论什么状态都跳到新增记录页,于是绿态文案写着「点击查看或修改本期数据」、点进去却是一张下一期的空白录入表 —— 名实不符。现在提醒块改绑 goNotice() 按状态分流:已记录 ⇒ 打开应记录期(上个月)那一期的编辑页并回填该期数据;未记录 ⇒ 才进新增记录页。同时「+ 记录本期」「立即记录第一期」两个按钮保持纯新增语义不变。新增 5 条断言(含反向验证)钉住该分流,并补一条闭环断言:真跑 edit.js 的 onLoad({period}),确认回填的是传入那期的数据而非空白页。
㉗ 首屏卡片指标调整:概览页第一张卡片原为「累计用车总费用 + 累计油费节省」,现在前面增加「累计能耗总费用」(= 油 + 快充 + 家充),并把「累计油费节省」下移到下方「核心指标」网格里原本「累计能耗总费用」的位置 —— 因为「累计能耗总费用」已升到首屏,若网格再放一份就会同屏重复。现首屏为「累计能耗总费用(前)+ 累计用车总费用(后)」两项,网格第 3 格为「累计油费节省」(副值「相对纯油车同里程」,与分析页区间油费节省同口径)。三项数值全部取自真实计算链路:累计能耗 ¥3,395.04、累计用车 ¥11,299.71、累计油费节省 ¥25,016.16。新增 16 条断言(源码/预览页结构顺序 + 真跑 refresh() 比对累计能耗/用车/节省),反向验证可复现 FAIL。
㉘ 首屏回归三项累计数据 + 新增「平均每公里能耗费用」:① 首屏卡片恢复为三项累计数据——「累计能耗总费用 / 累计用车总费用 / 累计油费节省(最右)」,三项同为累计口径,风格统一(因每列变窄,数值字号 36rpx→34rpx、分割线左右 24rpx→16rpx,实测最长「¥25,016.16」约 178rpx < 190rpx 可用宽度,仍由 ellipsis 兜底)。
② 核心指标网格重排为「第一排:平均每公里电费用 / 平均每公里能耗费用(新增);第二排:平均每公里总费用 / 累计充电电量」,按口径由窄到宽排序:仅充电支出 ¥0.037 → 含电/油(不含保险/保养)¥0.072 → 含电/油/保险/保养 ¥0.239。
③ 新增指标口径:平均每公里能耗费用 = 累计能耗总费用 ÷ 累计行驶里程(= 累计油费 1,657.18 + 累计电费 1,737.86 = 3,395.04,÷ 47,352 km = ¥0.072),与「平均每公里总费用 / 电费用」共用同一分母(累计里程),三个数可直接横向比较。新增 16 条断言(源码与预览页首屏 3 项 / 网格 4 项顺序双份对拍、真跑 refresh() 比对 AC/AD/AG 与三项每公里口径、口径自洽「电费用 < 能耗费用 < 总费用」)。
㉙ 订正「总费用」命名错误 + 分析页新增「平均每公里能耗费用」:㉙ 命名订正——U(百公里)/ W(每公里)的公式是「(当月家充费用 + 加油费用均摊 + 当月快充费用) ÷ 当月行驶里程」,只含「油 + 电」,不含当年保费均摊与保养维修,实质是能耗费用而非用车总费用。问题由「平均每公里总费用 ¥0.193,最高值却只有 ¥0.097」这一自相矛盾的现象暴露(¥0.193 是 Y/G 含保险保养,¥0.097 是 W 不含)。现订正为「百公里能耗费用 / 每公里能耗费用」:分析页走势图、概览页「百公里能耗费用」与「近 6 期每公里能耗费用」趋势图、记录列表「每公里能耗」、详情页与录入页的字段行、详情页「每公里能耗费用变化」、设置页字段说明、calc.js 字段注释。分析页「平均每公里总费用」(= Y/G,确实含保险保养)名实相符,保持不变。
② 分析页新增「平均每公里能耗费用」(= 区间能耗总费用 ÷ 区间里程,示例数据 ¥0.064),「区间统计指标」由 9 项增至 10 项并重排为:区间行驶里程 → 平均充电电价 → 区间能耗总费用 → 区间用车总费用 → 平均每公里电费用 → 平均每公里能耗费用 → 平均每公里总费用(按口径由窄到宽)→ 区间油费节省 → 每公里能耗费最低值 → 每公里能耗费最高值。
③ 极值两项改名——「每公里总费用最低值 / 最高值」自 v1.1.6 起取的就是 W 列,名字却写成「总费用」,现改为「每公里能耗费最低值 / 最高值」,改名后 平均 ¥0.064 正好落在 0.045 ~ 0.097 之间,口径自洽。分享图同步。
㉚ 分析页绿卡改口径 + 三联费用曲线 + 用车费用堆叠柱:① 绿卡主体由「平均每公里总费用」改为「平均每公里能耗费用」——本小程序关注的本来就是能耗,主值 ¥0.193 → ¥0.064;下方百分比必须同口径,故由 67.9% 改为 89.3%(67.9% 是按含保险保养的总费用算的,留着就会出现「主体 0.064 却写低约 67.9%」的名实不符)。顺带修正概览屏 hero-tip 的静态值 67.9% → 88.1%:该处运行值是累计油费节省 ÷ 纯油油费(25,016.16 ÷ 28,411.20 = 88.1%),预览页此前写错了。
② 百公里费用趋势补上第三条线「百公里总费用」(= 用车总费用 ÷ 里程 × 100,含保险与保养),与原有的百公里电费用、百公里能耗费用按口径由窄到宽排列,三条线共用同一分母、可直接横向比较;图例去掉冗余的「(元)」(卡片副标题已写明「元 / 100km」)。
③ 月度用车总费用改为堆叠柱——柱高仍是当月用车总费用,自下而上拆成 绿色 = 用车能耗费用(油 + 电)与 橙色 = 用车非能耗费用(当年保费均摊 + 保养维修),橙色图例名由「用车总费用」改为「用车非能耗费用」。mini-chart 组件新增 stacked 属性与 barPath()(只有顶段带圆角、段间不留缝),分享图同步。新增 [N] 段断言(绿卡口径与百分比同源、三系列顺序与口径、堆叠两段之和 = 柱高、真跑 refresh() 校验运行值),全量自检 512 → 558 项。
㉛ 费用口径配色成体系:此前只有概览页「平均每公里电费用」一项是蓝的(早期版本留下的孤例,另三项同屏却是黑的),现统一为一套口径色 —— 电(仅充电)= 蓝、能耗(油 + 电)= 绿、总费用(含保险保养)= 橙,口径由窄到宽、颜色按 蓝 → 绿 → 橙 递进,与走势图三条线、堆叠柱两段的颜色完全对应。概览页网格前三项的数值按口径上色(「累计充电电量」是电量不是费用,不参与);分析页十项指标中属这三个费用口径的 8 项上色(「区间行驶里程」「区间油费节省」不属该口径,保持默认色)。色值定义收口到 app.wxss 的 --blue / --brand / --orange 与语义类 .tone-elec / .tone-energy / .tone-total,分享图由 poster.js 的 TONE 映射到 canvas 颜色,新增 [O] 段断言锁定三处色值同源。顺带发现项目里原本有两个不同的橙(--warn: #ff7a45 与图表 #ff9f43),现明确分工:--orange 只表示费用口径,--warn 只管警示态。
㉜ 车牌底色按号牌类型区分:车辆管理页与设置页的车牌底色跟着号牌类型走 —— 燃油车号牌保持蓝色,新能源号牌(纯电与插混 / 增程都算)显示绿色(渐变绿 + 深色字,贴近真实绿牌)。判定完全由车牌号本身推出,不需要另选「动力类型」:新能源号牌是 8 位(小型车第 3 位为 D/A/B/C/E(纯电)或 F/G/H/J/K(非纯电),大型车末位为 D/F),燃油号牌是 7 位(省简称 + 发牌机关字母 + 5 位);混动 / 增程按新能源号牌显绿底。录入车牌号时同时加了格式校验:可以留空,但填了就必须是合法号牌,不合法会直接拦下、不入库并把提示变红;合法时输入框下方会实时显示「识别为燃油车号牌 · 蓝底」或「识别为新能源号牌 · 绿底」。车牌里的空格、·、- 以及全角写法都能正常识别。
㉝ 车牌底色铺到概览 / 记录 / 分析三页:上一版只改了车辆管理页与设置页,概览页 / 记录页 / 分析页的「当前车辆」处还是清一色蓝牌 —— 同一辆车换个页面就换个底色。现三页一并跟随号牌类型(燃油蓝 / 新能源绿),判定仍只有 utils/format.js 的 plateTone() 一份。
底色按所在背景分两套,不能硬套同一组色值:白卡上(记录页 / 分析页的车辆条、概览页空状态)用「浅底 + 饱和字」——燃油 --blue-soft 底 + --blue 字、新能源 --brand-soft 底 + --brand-dark 字;而概览页 hero 卡本身就是深绿渐变底,绿色号牌叠上去会糊成一片,所以 hero 上改用「白底 + 口径字色」(白底蓝字 / 白底绿字),在绿卡上反而最清楚 —— 车辆管理页那种实心渐变绿只适合白卡,这里刻意不复用。
㉞ 分析页「统计指标」新增数值配色说明:指标数值从 v1.1.15 起就带口径色(电 = 蓝 / 能耗 = 绿 / 总费用 = 橙),但页面上只有颜色、没有解释 —— 三个颜色的数字各是什么口径,光看是看不出来的。现于指标栏标题与网格之间加一段图例,三条逐字写明:该值仅基于电费分析 / 该值基于电费和油费分析 / 该值基于所有费用分析。三条文案收口在 analysis.js 的 INSIGHT_LEGEND 常量(wxml 只 wx:for 渲染,不写死),色块不写死色值:数值是 color: var(--blue)、色块是 background: var(--blue),同一个变量 ⇒ 以后改口径色不会只改一处。另有集合一致性断言守住「图例 tone 集合 == 指标实际用到的 tone 集合」。不参与费用口径的两项(区间行驶里程 / 区间油费节省)保持默认黑色,故不在图例里。
㉟ 修复「生成分析图片」主体值恒为 0:分析页绿卡显示「平均每公里能耗费用 ¥0.064」,但生成分析图片出来的海报上,同一个位置却是 ¥0.000。
病根在页面组装层:v1.1.14 把海报结论横幅的主体值换成能耗口径时,只改了绘制层读的字段名,漏了在页面的 buildShareStats() 白名单里补上这一项 —— 拿到的是 undefined,又被 || '0.000' 静态兜底,于是永远是 0。之所以能藏这么久,是因为本页内嵌的分享图由 tools/render-share.js 另外自己构造数据(那里有这一项),一直是好的,把真机那条路径的缺陷盖住了。
现补上字段,并加了一条机制性守卫:把数据包成 Proxy 送进 poster.draw(),运行期记录绘制层实际读到的每个字段,只要组装层没供给就报错 —— 以后海报新增任何字段漏了组装都会立刻现形。
㊱ 分享长图也带上「统计指标配色说明」:v1.1.18 给分析页加了那块图例,但 分享长图没有 —— 长图是要转发出去的,收图的人只看到三种颜色的数字,无从理解,等于把上一版想解决的问题又留在了图里。现把同一块说明按同一位置(指标卡标题下方、网格上方)画进分享图。三点讲究:文案仍只有一份(analysis.js 的 INSIGHT_LEGEND,页面通过 stats.legend 只传 { tone, text },绘制层不写死说明文字);色块色值不写死,走 poster.js 的 TONE 映射(与指标数值同一个映射);高度必须严格一致 —— 新增 legendHeight() 由 measure() 与 draw() 共用,少算会把底部裁掉、多算会多出一块空白(自检里用探针 canvas 记录内容底边做反向验证)。整图高度 2737 → 2896px。
㊲ 分享长图两处版式微调:① 图注改为居中—— 走势图卡下方那行「色块 + 名称」(多系列图例),页面上一直是居中的,分享图却从卡片左内边线起左对齐,右侧空出一大截(「百公里费用趋势」卡最明显)。现按「整组宽度 = Σ(色块 + 块文间距 + 文字宽) + 项间距」先算总宽,再在卡片内边线内居中,与页面同一口径。② 底部小程序码区上下留白拉平:原先码区上方视觉留白 60px(卡间距 24 + 写死的 36)、下方只有 40px,于是「码 + 引导语」整块压在下边、看着偏低。现上下各 50px(24 + 26 = 50),整图高度不变(仍 2896px)。
两条关键验证都是量真实绘制结果:图注用探针取首条文字的 x 反推整组左右边界,断言左右留白相差 ≤ 1px;码区用探针记录每次 fill() 的完整包围盒,抓出那块 152×152 的白色码底卡片,断言「卡片顶边到上一张卡底边的距离 == 卡片底边到画布底边的距离 == 50px」—— 这就是「视觉平衡」的机器可验证定义(旧版量到的是 60 / 40)。
㊳ 分析页绿卡脚注改口径(见下一条 ㊴ 已再改为区间口径):结论横幅(绿色渐变)最下面那行三项,由「累计油费节省 / 累计里程 / 月均节省」改为 「累计里程 / 累计能耗费用 / 累计油费节省」。关键是让三项同为「全部已记录期」的累计量 —— 首槽放里程(原来放的是金额,两项性质不一致却并排)、中间新增累计能耗费用(= 油 + 快充 + 家充,不含当年保费均摊与保养维修,与页面上「能耗费用」同一口径的累计值)、末位仍是累计油费节省;「月均节省」被去掉(它只是累计节省 ÷ 期数,信息量是派生出来的、价值最低)。三项取的都是末期记录的累计列,不随右上角「近 6 / 12 / 24 / 全部」切换 —— 横幅主体「平均每公里能耗费用」才是区间口径,两者口径不同,故三项统一冠以「累计」。示例数据下为 47,352 km / ¥3,395.04 / ¥25,016.16,页面、分享长图、本预览页三处同步;自检里除了结构对拍,还加了两条口径守卫:累计能耗费用 + 累计油费节省 == 累计里程 × 纯油单价(取错列会立刻现形)、真跑把区间切到「近 6 期」后三项一字不变。
㊴ 绿卡脚注三项改「区间」口径:结论横幅(绿色渐变)最下面那行三项,由 「累计里程 / 累计能耗费用 / 累计油费节省」 改为 「区间里程 / 区间能耗费用 / 区间油费节省」。上一版把三项定成「全部已记录期」的累计值、刻意与期数切换解耦,但它与同一张卡的主体自相矛盾 —— 主体「平均每公里能耗费用」本就是区间口径(随右上角「近 6 / 12 / 24 / 全部」切换,分母正是区间里程),脚注却摆着 25 期的累计值:看到「近 12 期每公里 ¥0.064」旁边挂着「47,352 km」,两个数不属于同一个区间,既对不上也读不出关系。
现三项改为当前区间的汇总 —— 区间里程 = ΣG、区间能耗费用 = ΣX(油 + 快充 + 家充,不含保险/保养)、区间油费节省 = ΣAF,与卡片主体共用同一个分母,也与第 4 张卡「区间统计指标」里同名那三项同源同值(同一个数不再在页面上出现两个版本)。示例数据「近 12 期」下为 25,161 km / ¥1,618.46 / ¥13,478.14;切到「全部 25 期」则回到 47,352 km / ¥3,395.04 / ¥25,016.16。
自检 824 项里最有价值的是 [V] 段「区间语义」的反向守卫:真跑 refresh() 后分别切到「近 6 期」「全部」再切回「近 12 期」,三项必须各自等于独立重算的该区间 ΣG / ΣX / ΣAF,且三次互不相等 —— 退回归成末期累计列或写死常量都会立刻 FAIL;另加「绿卡脚注三项 == 指标栏同名三项」的同源一致性断言。
㊵ 分析页车辆切换挪到顶部:概览 / 记录 / 设置三页的车辆切换都在最顶部,唯独分析页把它排在「区间切换」下方 —— 同一功能的入口在四个页面里的位置不一致,每页都要重新找一遍。现把分析页的「当前车辆」条提到「区间切换」之前,与记录页对齐。
这不只是美观问题,而是这几页共同的阅读顺序:车辆是一切数据的限定条件(先选车),区间期数只是同一辆车内部的时间窗(后选区间) —— 放在期数切换下面,等于先让人在一个还没确定属于哪辆车的时间窗里挑范围。样式无需调整:两块共用同一份 .veh-chip / .seg 规则、margin-bottom 都是 24rpx,互换后垂直节奏完全不变;空状态里的车辆条也仍在原位(没数据照样能换车)。
自检 846 项中新增 [W] 段 22 条,分四层:① 首屏第一个内容块 —— 分析页与记录页都必须是车辆条(概览页是含切换入口的 hero 卡、设置页是第一张「当前车辆」卡,四页一并守);② 分析页内部顺序 —— 车辆条 → 区间切换 → 结论横幅,另加负向「区间切换不许再出现在车辆条之前」;③ 跨页一致性 —— 两页车辆条整段标记逐字相同、两块 margin-bottom 相等;④ 预览页对拍 —— 分析屏容器内的首块必须是车辆条。两组变异(源码退回旧序、预览页退回旧序)分别复现 4 / 2 条 FAIL。
㊶ 备份扶正为「转发到微信」,并新增备份提醒:本项目此前唯一依赖服务端的功能是「把备份发到邮箱」,走的是微信云开发。而云开发的免费云环境在小程序发布上线后第 15 天即到期,之后 19.9 元/月(免费体验活动本身也在 2026-12-31 截止)—— 一个纯公益、一个月才用一次的低频小工具,为一次「点一下转发」养一个云环境并不划算。
所以这一版把「把 CSV 交给用户自己保管」扶正为主备份路径:设置页「数据管理」里的入口由「导出数据(CSV 文件)」改名为「备份数据(转发到微信)」,生成 .csv 后转发到微信聊天(推荐发给「文件传输助手」—— 文件长期留在聊天记录里,换手机、换电脑都能取回;长按文件卡片还能收藏进「微信收藏」,多一份独立副本);电脑端微信则直接另存到磁盘。两条路径都不经过任何服务端,零成本、零运维、零域名、零备案 —— 也不受小程序「只能请求已备案 https 域名」这条硬约束的限制。
光有入口不够:一个月才打开一次的页面,没有提醒就等于没有备份。概览页因此新增一条备份提醒(蓝色卡片,位置在「本期记录提醒」之后、核心指标网格之前),三种情形各写各的话:从未备份过(已积累 ≥3 期时)、距上次备份已 ≥90 天、自上次备份后新增 ≥3 期;数据不足 3 期时不打扰。点整条卡片直接跳到设置页的备份入口。
「备份过没有」只有一个口径(hy_last_backup_at,记时间的同时记下当时的期数,否则「新增几期」永远算不出来):转发成功、另存成功、发邮箱成功三处都写它,否则只用邮箱的用户会被一直提醒。只有剪贴板兜底刻意不算备份 —— 那只是把文本放进剪贴板,用户还没存成文件。首次备份成功会给一次完整引导(选「文件传输助手」、长按可收藏、需要还原时回本页点「导入数据 → 从聊天记录选择 CSV 文件」),之后只给轻提示。
邮件备份链路原样保留(utils/mail.js、云函数、设置页邮箱面板都不动),仅把其中的指路文案跟着改名,并在成功时也写入统一的备份时间。
自检 905 项中新增 [X] 段,分七层:① 设置页入口与文案;② 阈值只有一份(3 期 / 90 天 / 3 期都住在 store.backupReminder() 里,概览页只调不算);③ 真跑 backupReminder 的全部边界(从未备份 / 89 天 / 90 天 / 新增 2 期 / 新增 3 期 / 引导标记);④ 概览页提醒块与「本期记录提醒」类名分离且位置在网格之前;⑤ 负向守卫(剪贴板不算备份、邮件成功必须写、两处 success 都接 afterBackup);⑥ 真跑概览页四态并核对跳转地址;⑦ 预览页对拍(提醒标题与描述由真跑结果推导,不是另写一份硬编码)。五组变异分别复现 1 / 1 / 2 / 1 / 1 条 FAIL。
㊷ 小程序码换新:小程序码本身变了 —— 旧码中心的 logo 是通体绿色的「小汽车 + 闪电」,现换成绿蓝双色的「水滴 + 闪电」,码点阵随之重排。分享图与本页展示的那张成品图都已同步。
本版只换了一张资源,却顺手把「换码」这件事的整条链路钉上了守卫 —— 因为要动的地方其实有三处,而后两处正是这个项目的老毛病「改了没生效」的高发地(源码换了图,预览页里却还挂着旧码):
① assets/share/mpcode.jpg(源图);② 跑 tools/render-share.js 重出 preview/_share-preview.svg(它会把源图 base64 内嵌进去);③ 再跑光栅化把新 SVG 回写成预览页内嵌的那张成品 PNG —— 也就是本页下面「分享图成品」里那张图。
自检 918 项中新增 [Y] 段 13 条,做三层同源守卫:① 源图自身 —— 必须是真 JPEG(SOI / EOI 标记完整,不是改名的占位文件)、正方形、边长 ≥ 200px、非空白;② SVG 与源图同源 —— SVG 里内嵌的那份 base64 必须逐字节等于源图,专挡「换了图没重出 SVG」;③ 预览页与 SVG 同源 —— 把预览页那张 base64 PNG 真解出来(用 Node 自带的 zlib 解压 + 逐行反滤波,不引第三方库),在底部码区带里数新码 logo 才有的那抹蓝。
为什么拿「蓝」当指纹:在同一个判别窗口(x 60~348、y 取图底往上 50~202 这段)里,旧码只有 58 个蓝像素(全是文字次像素抗锯齿的噪声),新码有 612 个(真 logo 右半)—— 差 10 倍,阈值取 300 稳稳分得开;而右侧文案区那些假蓝在窗口之外,不参与统计。
分享图的其余部分一律不变:里程 / 费用 / 结论横幅 / 四张走势图 / 费用构成 / 十项指标逐像素相同,整图仍是 750×2896。三组变异分别复现 1 / 1 / 5 条 FAIL(换图不重出 SVG / 预览页不重出 / 码图位置被塞入非 JPEG)。
㊸ 记录页长按 / 详情页底部都能「分享本期数据」:以前只有分析页能出图,而那张图是
整页复刻的长图(750×2896),适合自己复盘,发到微信聊天里却会被压成一条窄缩略图,好友得点开才看得清。这一版给
每一期都加了张「单期账单卡」,两个入口:① 「记录」页
长按任意一期,菜单里选「
分享本期数据」;② 「单期详情」页底部操作栏的「
分享本期」。
两个入口
共用同一份实现(
utils/single-card.js)—— 这类「同一样东西两个入口」最容易慢慢长歪,所以数据组装、绘制、导出、弹层整条链路只写一次,两个页面都只负责转发。
菜单顺序是
查看 → 分享 → 删除:删除放到最后,避免长按之后顺手一划就误删;列表上方的提示也同步改成了「长按单条可分享或删除」。详情页底部则是
删除 → 分享本期 → 编辑本期,主操作「编辑本期」仍在最右、拇指易达。
卡片
750×940(4:5),
一屏读完 —— 这是它和长图最本质的区别。版式分六块:
①抬头(哪一期、哪辆车)→
②一个主数字(本期每公里能耗费用 + 纯油车基准与省率)→
③六项关键数字(两行三项:本期里程 / 本期能耗费用 / 本期油费节省,本期充电电费均价 / 本期充电总电量 / 本期用车总费用,
主值 32px、单位 20px)→
④一行环比 →
⑤小程序码。
为什么删掉「每公里成本对比」那一块:主数字卡上已经写了纯油车基准(¥0.60/km)与省率,再画两根条只是把同一件事说两遍;腾出的位置换成六项关键数字,信息量更实。
三个取舍值得说明。其一,
主数字用「每公里」而不是「省了多少钱」:每公里成本
与里程无关,开多开少都是同一个稳定好看的数字;而「本月省 ¥373」碰上开得少的月份会缩水到几十块,反倒没了分享欲。其二,
新增的三项口径与详情页完全一致:充电电费均价取
S(= 当月充电总费用 ÷ 当月充电总电量)、充电总电量取
Q(快充 + 家充)、用车总费用取
Y(
含保险保养,比「能耗费用」口径宽)—— 同一个数在卡片与详情页不会出现两个版本。其三,
没有走势图、没有保养保费明细、没有累计数据:单期没有趋势可言,保费是每月固定的均摊值,把累计混进一张「单期」卡上还会让人分不清这是哪个月。这些都留在长图里。
口径上还守两条:卡片上的数
全取自详情页同一期(W / G / X / AF / S / Q / Y,一个不差),省率沿用分析页绿卡那一条公式
(1 − W ÷ 纯油单价) × 100;
环比涨跌有语义色 —— 每公里单价
降为绿、升为橙,油费节省
增为绿、减为橙,而
里程多开少开一律中性(多开车不算好事也不算坏事,不该替用户下判断)。涨跌判定只有
tone() 一处。环比金额刻意
取整,保证再大的金额也不会把这一行顶出画布。
首期没有上一期可比,卡片自动换成一句「首期记录 · 从这一期开始,累积你自己的用车账单」,
不会凭空编一个上期。转发方式与分析页一致:小程序
没有接口能以代码调起系统的「转发给朋友」面板,所以统一是
生成图 → 预览 → 长按图片转发。
㊹ 单期账单卡与详情页的数值统一按「费用口径」上色:单期账单卡上那六个关键数字原来一律是黑色,详情页「当月分析」里一堆数字也是清一色,看不出哪个数属于哪个口径。现在统一成一套「电 → 能耗 → 总费用」由窄到宽的三档语义色:纯电(仅充电支出)用蓝 #3d7eff,能耗费用(油 + 电)用绿 #0bb07b,用车总费用(再加保险保养)用橙 #ff9f43。不属任何费用口径的(里程、油费节省)保持默认深灰,不强行上色。
单期卡上:充电电费均价、充电总电量 → 蓝;本期能耗费用 → 绿;本期用车总费用 → 橙;本期里程、本期油费节省 → 默认色。单位跟数字同色(不再是数字带色、单位黑色)。
详情页「当月分析」:首张卡两个大数字、下方 10 行细项,以及「累计」区的四项(累计电量 / 累计电费 → 蓝,累计能耗总费用 → 绿,累计用车总费用 → 橙)同步上色。升级的一项日运行里程仍然留给「自动计算」那类蓝色(那是另一种含义:表示这一行是自动算出来、不是手填,与费用口径无关)。
这套颜色只有一个来源:全局 app.wxss 里的 .tone-elec / .tone-energy / .tone-total 语义类,按复合选择器覆盖各页默认字色;画布端则取 poster.js 的同一张 TONE 映射表。两边取值相同、同步改。自检升到 1117 项(新增约 47 项),其中 [Z] 探针会真跑 drawSingle()、把每个数字的实际填色也记下来逐个比对,并验证单位与数字同色;变异测试十个病毒全部被抓。
自检 1070 项中
[Z] 段分十三层:① 记录页菜单三项与顺序、索引映射;②
单一来源(两个页面都不直接碰绘制层,
poster. 只出现在 single-card.js 里);③ 两页的离屏画布与预览弹层;④ 尺寸与 4:5 比例;⑤ 口径同源 +
新增三项各取自哪一列 +
单位拆段与字号(32 → 20、固定 6px 间隙);⑥ 涨跌语义色的单一来源与三档取值;⑦ 环比金额取整;⑧
真跑 drawSingle() —— 用探针 canvas 抓全部文本、
实际字号与坐标与绘制底边,验证单位确实比主值小一号(32 → 20)、与数字共用基线、间隔正好 6px,并验证对比条那三条文本
一条都不再出现;⑨
真跑 buildStats(),把卡片上的七个值与详情页同期的展示值逐项对照;⑩ 首期与不存在的期;⑪ 详情页底部三项与顺序;⑫ 弹层样式只在 app.wxss 一份;⑬ 预览页与源码同步。
㊺ 新增「首期初始化向导」:新增车辆、还没有数据时,用一条六步向导录首期:此前新用户第一次打开是一辆空车,唯一的出口是「记录本期」那张表单 —— 一上来就是十个数字框,既没解释「为什么要按月记」,也没说「每个数从哪来」,很容易在第一屏就放弃。现在空车辆的主入口换成一条六步向导:步骤一 了解工具(每月只记一次,与「每次补能都要记」的常规工具不同,尤其适合混动车纯电里程小、补电频繁的场景)→ 步骤二 记录原理(每月记里程 / 补能 / 费用三类数据,由实际里程与实际支出核算实际能耗与行驶成本)→ 步骤三 里程(初始里程=上月最后一天表显里程;本月记录里程=本月最后一天表显里程)→ 步骤四 加油(期初尚未均摊油费=油箱里剩的油值多少钱;本月加油费用;本月加油均摊费用=本月用掉的油值多少钱)→ 步骤五 快充(商用充电桩费用与电量)→ 步骤六 家充(自家充电桩费用与电量)。
每一步都写了数据从哪来(加油看壳牌 / 中石油 / 中石化订单,快充看商用充电 App,家充看网上国网账单);填数时实时显示本期行驶里程与四项核算,数字用 v1.2.3 定下的三档口径色,填错会在那一步当场拦住并说明原因(比如「均摊超过期初 + 本月加油」);完成后直接进这一期的详情页,可以立刻核对。
两处取舍说明:① 向导不采集保养与保费 —— 首期保养按 0、保费按建议值(年保费 ÷ 12)带入,并在最后一步明写出来,不静默假设;② 初始里程留空时,若里程数上万会红字提醒「本期行驶里程会等于里程表读数」,因为「把总里程当本期里程」是这个表单最容易犯的错。
入口有三处:概览页空状态、记录页空状态、以及新增车辆保存后自动进入(仅在「该车 0 期记录」时触发);概览页同时保留一条「跳过向导,直接记录第一期」,向导是引导不是关卡。步骤模型与首期组装抽成 utils/setup-steps.js 单一来源,每步校验 = calc.validate() 的结论 ∩ 这一步的字段 —— 规则不重写,错误能按字段指回那一步。全量自检 1117 → 1232 项,其中新增 [AA] 段 115 条,19 组变异 19/19 全部复现(含真跑整条向导:从空车填到「完成」,核对写出的记录与车辆参数、首期行驶里程、四项核算与结转池)。
㎋ 去掉「初始化向导」页底部的版本水印:向导共六步,原先每一步的页面底部都挂着一行 版本 v1.2.5(当时那版),连挂六屏,纯属噪音 —— 版本水印的用途是「确认模拟器跑的是哪一版源码」,而向导是一次性的引导流程,不需要逐屏自证。现已整块移除;录入页与设置页的水印保留(那两页是长期反复使用的入口,出问题时最需要一眼确认版本)。同时清掉向导页对 utils/version.js 的引用与 versionLabel 数据项,不让「没人看的字段」留在 data 里。全量自检 1232 → 1240 项([G] 段新增 8 条负向断言,逐条锁死「向导页不得再出现版本水印」,并把预览页⑩向导屏之后的切片单独切出来查,不影响⑥录入页与⑨设置屏保留的那两行),4 组变异(向导 wxml 加回 / 向导 js 加回依赖 / 预览页 ⑩ 屏加回 / 三张向导屏全加回)4/4 全部复现。
㊻ 修一个「指着一个不存在的按钮」的 BUG:月度记录空状态现在真的有右下角「+」:记录页在没有任何数据时的那段文案写着「也可以点右下角「+」直接录入第一期」,但那个悬浮「+」按钮原先被关在 wx:if="{{hasData}}" 分支里 —— 只有已经有记录才渲染,于是新用户(恰恰是最需要它的那群人)看不到任何「+」,文案指向一个不存在的按钮。现已把「+」移到 .page-wrap 直属层(与空状态同级),有数据、没数据都在场;空状态里那条「也可点右下角「+」」从「骗人」变成「真的」。
顺带把记录页空状态补进预览页(此前预览页只有「有数据」的月度记录屏,空状态压根没画 —— 这类「文案与实际对不上」的问题,正是因为没有一张图能一眼看出来)。预览页 12 屏 → 13 屏:新屏排在第⑤屏之后(⑤ 有数据 / ⑥ 空数据,并排可比)。全量自检 1240 → 1251 项([AA] 段新增 12 条:源码侧锁死「+」必须在 wx:else 之后、在 hasData 分支之外,且全页只有一个;预览侧锁死新屏存在、屏数 13、新屏里「+」与空状态文案同时在场),7 组变异(把「+」塞回 hasData 分支 / 删掉「+」/ 改绑到别的入口 / 缩进成 .empty 的子节点 / 预览新屏去掉「+」/ 屏数改回 12 / 新屏标题去掉「空数据」)7/7 全部复现。