微信原生小程序(WXML + WXSS + JS),无云开发、无运行时依赖、无任何网络请求,数据全部落在本机 Storage。
这个仓库不只是作业存档,是一个持续维护的项目。按目的选入口:
| 你想做什么 | 去哪 |
|---|---|
| 知道「什么算做完」「什么不能破」 | PROJECT.md —— 章程、里程碑、5 条架构不变量、三层验收口径 |
| 知道「接下来做什么」 | docs/backlog.md —— 编号条目、优先级、可验收标准 |
| 知道「已经验证过什么」 | docs/验收清单.md —— 逐项证据与截图 |
| 改完代码快速确认没弄坏 | npm test(= 静态校验 + 171 项逻辑断言 + 74 项端到端断言) |
| 想知道「为什么这么设计」 | docs/课程报告.md —— 15 页报告:架构、纸墨朱、AI 功能取舍、四层验证、四次翻车复盘,以及把设计指南做成 8 个技能的经过 |
| 想知道「规范是怎么被执行的」 | 报告第六章 —— 自建 8 个技能(1,342 行);审计脚本已随仓库提供:python tools/wxmp_ui_audit.py miaoguanjia |
| 看版本变化 | CHANGELOG.md |
| 只是想跑起来看看 | 往下读第二节 |
- 打开「微信开发者工具」→ 微信扫码登录
- 顶部菜单 设置 → 安全设置 → 开启「服务端口」 (开了之后才能用命令行打开项目、驱动它做自动验证和录屏;不开就只能手动点)
- 首页「导入项目」→ 目录选
D:\Claw\workbuddy-course\homework-4\miaoguanjia→ AppID 那一栏点 「测试号」 → 确定
project.config.json里填的是本项目的 AppID。你没有收录权限,直接改成"touristappid"(测试号)即可打开,功能不受影响——本项目不联网,不需要真实 AppID。
打开后模拟器应立即出现首页(三只示例猫:团子 / 芝麻 / 豆豆)。
把照片放进 miaoguanjia/images/cats/,覆盖同名文件即可,代码不用改:
| 文件名 | 对应 | 建议 |
|---|---|---|
cat1.jpg |
团子(布偶猫) | 3:2 横幅,1200×800,≤ 150 KB |
cat2.jpg |
芝麻(玄猫) | 同上 |
cat3.jpg |
豆豆(三花) | 同上 |
default.jpg |
新增猫咪的默认头像 | 同上 |
为什么是 3:2 而不是正方形:首页照片槽就是 3:2,mode="aspectFit" 会把整张图
原样放进去、一个像素都不裁。比例不符时不会切掉猫,而是在槽位里留边——
留边比切掉半张脸好。裁剪用 python tools/prep_cat_photo.py 原图 输出。
猫的名字、品种、生日、体重都能在 App 内改:我的 → 猫咪档案 → 点某只猫。 (示例三只猫只是种子数据,随便改。)
仓库里的三张示例图是 Pexels 免费授权照片,不是本项目作者的猫,来源见
docs/图片来源.md。三只猫的档案是虚构的演示数据。
| 页面 | 做了什么 |
|---|---|
| 首页 | 一屏五块:体重与增减趋势、今日照顾分(环)、进食/饮水/逗猫三条刻度、一行心情自评、五个动作(投食 / 喂水 / 逗猫 / 称重 / 症状);顶部多猫切换 |
| 记录 | 猫咪切换、canvas 2d 体重趋势折线图、按类型筛选(全部/喂食/饮水/体重/其他)、按天分组的时间线 |
| 我的 | 统计卡、猫咪档案增删改、3 台虚拟设备开关、提醒开关 + 提醒时间选择、关于、重置演示数据 |
| 档案编辑 | 新增/编辑猫咪:选头像(相册或相机)、名字、品种、性别、生日、体重、每日目标、备注、删除 |
数据流:所有写操作走 utils/store.js,页面 onShow 重新读取 → 一个页面改了,切回另一页立刻是最新的。
界面按「纸、墨、朱」三层配色收口,规则只有三条:
| 层 | 取值 | 用途 |
|---|---|---|
| 纸 | #FAF8F4 / #FFFFFF |
底色与需要浮起的块 |
| 墨 | #1E1B19 → #C9C2B8(六级灰阶) |
文字、线、图标 |
| 朱 | #AE412D |
每页只留一个焦点(首页=照顾分环,记录=体重,编辑=无) |
配套的五条硬规矩:
- 不画阴影。分隔靠留白和 1px 发丝线,框不再重复画一遍。
- 圆角收口:卡片 8rpx,按钮与徽章 4rpx。没有胶囊、没有大圆角。
- 字号只有四层:20(注释)/ 24(标签)/ 68(猫名)/ 92(体重数值),中间刻意空着。
- 不用 emoji 当图标。全部线条图标由
make_icons.py用 Pillow 4× 超采样绘制,墨黑描边,22px 下仍可辨。 - 控件不染色。开关、筛选、选中的 cat chip 全部走墨色(实心墨底或发丝描边),朱色只留给数字。
字体走全宋体(Songti SC / STSong / Noto Serif SC 逐级回退),行高 1.62。
注意:Android 真机通常没有宋体,会回退到系统黑体;模拟器与 iOS 上才是宋体效果。
miaoguanjia/
├── app.js / app.json / app.wxss # 全局入口、路由与 TabBar、全局样式与色彩 token
├── project.config.json # 项目配置(appid 换成 touristappid 即可本地打开)
├── sitemap.json
├── pages/
│ ├── index/ # 首页
│ ├── records/ # 记录(含体重折线图)
│ ├── mine/ # 我的
│ └── cat-edit/ # 猫咪档案新增 / 编辑
├── utils/
│ ├── store.js # 数据层:种子数据、增删改查、统计、格式化、业务校验
│ └── theme.js # 色彩 token(JS 侧):canvas 与 conic-gradient 取色
└── images/
├── tabbar/ # 6 个 tabBar 图标(常态 + 选中)
├── icons/ # 13 个线条图标(动作、设备、提醒、头像、空状态)
└── cats/ # 猫咪头像(你替换这里)
同目录下另有工程文件(不属于小程序包,只有 miaoguanjia/ 会被上传):
| 路径 | 作用 |
|---|---|
PROJECT.md / docs/backlog.md |
项目章程 / 待办条目 |
package.json |
只有 scripts,无依赖。npm test = check + simulate + e2e |
check.js |
L1 静态校验:JSON 语法、页面文件齐全、WXML 标签配对、事件处理函数存在、图片路径有效、设计 token 双份一致。失败时退出码 1 |
simulate.js |
L2 逻辑冒烟:打桩 wx API,在 Node 里真跑一遍数据层与六个页面生命周期,171 项断言 |
e2e.js |
L2+ 端到端:带页面栈的路由模拟器,把「记录页 → 症状页 → 报告页 → 返回 → 回看」连着走一遍,74 项断言。专抓单页测试测不出的接线问题 |
.github/workflows/verify.yml |
push / PR 时自动跑上面两层 |
tools/assets/ |
图标与占位图生成器(Pillow,4× 超采样) |
tools/capture/ |
开发者工具截图与窗口驱动(Windows,不抢前台焦点) |
tools/legacy/ |
一次性脚本归档,不再维护 |
.workbuddy/memory/ |
项目记忆:约定与踩过的坑 |
脚本用法与「必须先 cd 到项目根」这类前提,见 tools/README.md。
npm test三层依次跑完打印 ALL CHECKS PASSED、全部通过 ✅ 与 ✅ 端到端全流程通过;任何一层失败退出码为 1,CI 靠这个判定。也可以单独跑 npm run check / npm run simulate / npm run e2e。
| 校验 | 结果 |
|---|---|
node --check 全部 7 个 JS 文件 |
通过 |
check.js 结构与 WXML 静态校验 |
ALL CHECKS PASSED |
simulate.js 逻辑冒烟(171 项断言) |
全部通过 |
e2e.js 端到端流程(74 项断言) |
全部通过 |
| 开发者工具内编译 | 通过——四页渲染正常,状态栏 0 错误 / 0 警告 |
冒烟测试覆盖了:种子数据、今日摄入统计、体重趋势、按天分组、四页生命周期、投食/喂水/逗猫/称重四种操作对数据的真实改写、筛选、切猫、设备开关落库、新增/编辑/删除猫咪的完整闭环,以及数据层的 validateCat 边界值(空名 / 超长名 / 体重 0 与 31 / 目标 19 与 601 / 首尾空格修剪 / 两位小数归一化)。
其中两条是自洽性断言,专门防上一版那个坑:
eq('首页: 进食百分比与绝对值自洽', pct.food, round(pct.foodAbs / pct.foodTarget * 100))
eq('首页: 饮水百分比与绝对值自洽', pct.water, round(pct.waterAbs / pct.waterTarget * 100))
上一版首页同时显示「饱食度 68%」和「进食 45 / 200 g」(= 22.5%),两个数互相打脸。现在百分比与绝对值同出 store.intakePercent() 一个数据源。
补一句:静态校验与逻辑断言通过,不等于在微信开发者工具里能正常渲染。这两层现在都过了;页面内的逐项点击手验清单见
docs/验收清单.mdC 组。
- 零网络:全部数据走
wx.setStorageSync,Console 天然干净,没有域名/请求失败的可能 - 数据层收口:页面不直接碰 Storage,统一走
utils/store.js;连表单校验也放在数据层(validateCat),页面只负责显示msg - 设计 token 双份对齐:
app.wxss定义 CSS 变量,utils/theme.js提供同名同值的 JS 常量,check.js强制校验两者一致(canvas 与 conic-gradient 读不到 CSS 变量,只能走 JS) canvas 2d手绘折线图:渐变填充、端点、坐标轴标签,按pixelRatio做设备像素适配conic-gradient状态环:角度 = 百分比 × 3.6deg,由theme.ringGradient()统一生成- 本地持久化头像:
wx.chooseMedia拿到临时路径后,用FileSystemManager.saveFile转成永久路径,重启不掉图 - 触觉反馈(
wx.vibrateShort)、删除二次确认、空状态、下拉刷新、wx.showModal可编辑弹窗