0.0.0
This commit is contained in:
140
docs/01-架构设计.md
Normal file
140
docs/01-架构设计.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# 01 · 架构设计
|
||||
|
||||
## 1. 技术选型理由
|
||||
|
||||
选 **原生小程序 + 云开发**,因为:
|
||||
|
||||
- 云开发是微信官方为原生小程序量身打造,集成度最高、免运维、免自建鉴权。
|
||||
- 汪圈 V1 是单机闭环,无跨端(App / H5 / 支付宝)需求,原生比 Taro / uni-app 更直接。
|
||||
- 云函数里 `cloud.getWXContext().OPENID` 直接拿到可信用户标识,省掉整套登录鉴权后端。
|
||||
|
||||
## 2. 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 微信小程序客户端 │
|
||||
│ pages/ (12屏) · components/ · utils/ │
|
||||
│ globalData + 事件总线 │
|
||||
└───────────────────┬─────────────────────────┘
|
||||
│ wx.cloud.callFunction
|
||||
┌────────────┴────────────┐
|
||||
▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
│ 云函数 │ │ 云数据库 │
|
||||
│ login │◄───────►│ users │
|
||||
│ dogManage │ │ dogs │
|
||||
│ walkSave │ │ walks │
|
||||
│ walkManual │ │ dog_achievements│
|
||||
│ getDogDetail │ └───────────────┘
|
||||
│ getHistory │
|
||||
└───────────────┘ │
|
||||
│ ▼
|
||||
▼ ┌───────────────┐
|
||||
成就判定/统计累加 │ 云存储 │
|
||||
│ 头像/照片/分享图 │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
**核心原则:写操作 + 敏感计算全部走云函数**,客户端只读(或经云函数读聚合结果)。连续天数、成就解锁、补记规则等绝不在客户端算。
|
||||
|
||||
## 3. 工程目录结构
|
||||
|
||||
```
|
||||
Pet3/
|
||||
├── cloudfunctions/ # 云函数(Node.js)
|
||||
│ ├── login/ # 登录 + 首次建用户
|
||||
│ │ ├── index.js
|
||||
│ │ └── package.json
|
||||
│ ├── dogManage/ # 狗狗增改查
|
||||
│ ├── walkSave/ # 保存遛狗 + 触发统计/成就
|
||||
│ ├── walkManual/ # 手动补记
|
||||
│ ├── getDogDetail/ # 狗狗主页聚合数据
|
||||
│ └── getHistory/ # 历史/记录 Tab 列表聚合
|
||||
│
|
||||
├── miniprogram/
|
||||
│ ├── app.js # 初始化 wx.cloud、globalData
|
||||
│ ├── app.json # 路由、tabBar、分包
|
||||
│ ├── app.wxss # 全局样式 + 设计 token
|
||||
│ ├── pages/
|
||||
│ │ ├── login/ # 0a 登录
|
||||
│ │ ├── dog-edit/ # 0b 建档/编辑(复用)
|
||||
│ │ ├── home/ # 1 我的(tab)
|
||||
│ │ ├── walking/ # 2/2b 遛狗中(含暂停态)
|
||||
│ │ ├── summary/ # 3 成果卡
|
||||
│ │ ├── dog-detail/ # 4 狗狗主页
|
||||
│ │ ├── history/ # 5 遛狗历史
|
||||
│ │ ├── records/ # 6/6b 记录(tab,含空状态)
|
||||
│ │ └── achievements/ # 7 完整成就页
|
||||
│ ├── components/
|
||||
│ │ ├── dog-card/ # 狗狗卡片
|
||||
│ │ ├── walk-row/ # 历史/记录行
|
||||
│ │ ├── stat-grid/ # 统计三宫格
|
||||
│ │ ├── achievement-medal/ # 成就勋章(解锁/锁定)
|
||||
│ │ ├── multi-dog-sheet/ # 0c 多狗选择弹层
|
||||
│ │ └── manual-add-sheet/ # 补记弹层
|
||||
│ ├── utils/
|
||||
│ │ ├── cloud.js # callFunction 统一封装 + 错误处理
|
||||
│ │ ├── format.js # 时长/距离/日期格式化
|
||||
│ │ ├── dogStep.js # 狗步换算(体型档位/步幅/体重校准)
|
||||
│ │ └── store.js # 全局状态 + 订阅
|
||||
│ └── images/ # 本地图标/占位图
|
||||
│
|
||||
├── docs/ # 设计文档(本目录)
|
||||
├── wangquan-prototype.html # 交互原型
|
||||
└── project.config.json
|
||||
```
|
||||
|
||||
## 4. 全局状态(store)
|
||||
|
||||
不引入重型状态库。`miniprogram/utils/store.js` 维护:
|
||||
|
||||
```js
|
||||
const store = {
|
||||
userInfo: null, // { openid, nickname, avatar, joinedAt, walkCount }
|
||||
dogs: [], // 当前用户的狗狗列表
|
||||
currentDogId: null, // 默认/上次选中的狗
|
||||
walkSession: null, // 进行中的遛狗会话(见下)
|
||||
};
|
||||
```
|
||||
|
||||
**遛狗会话(walkSession)** 是 V1 最关键的运行时状态,需支持小程序退到后台后恢复:
|
||||
|
||||
```js
|
||||
walkSession = {
|
||||
dogIds: ['xxx'], // 本次遛的狗(支持多狗)
|
||||
startAt: 1719230000000,
|
||||
pausedTotal: 0, // 累计暂停时长(ms),结算时扣除
|
||||
pausedAt: null, // 当前暂停起点,null=进行中
|
||||
pooped: false, // 便便打卡
|
||||
locationEnabled: false, // 是否获得定位授权
|
||||
distanceMeters: null, // GPS 累计距离;未授权为 null
|
||||
lastLocation: null, // 最近一次有效定位点,用于增量累计距离
|
||||
status: 'walking' | 'paused',
|
||||
}
|
||||
```
|
||||
|
||||
落地策略:会话写入 `wx.setStorageSync('walkSession')`,App `onShow` 时恢复,避免锁屏/切后台丢失计时。计时基于 `startAt` 与当前时间差实时计算,**不依赖 setInterval 累加**(后台被冻结也不丢)。定位为可选增强:获得授权时累计 GPS 距离并换算狗步;未授权时 `distanceMeters` / `dogStepsByDog` 为 `null`,界面隐藏距离与狗步,闭环仍成立。
|
||||
|
||||
## 5. 设计 Token(迁移自原型)
|
||||
|
||||
原型 CSS 变量直接转为 `app.wxss` 全局变量,保证视觉一致:
|
||||
|
||||
| Token | 值 | 用途 |
|
||||
|-------|-----|------|
|
||||
| `--bg` | `#F2EDE6` | 页面背景 |
|
||||
| `--surface` | `#FBF8F3` | 卡片 |
|
||||
| `--ink` | `#2E2A24` | 主文字 |
|
||||
| `--ink-2` | `#6E665B` | 次文字 |
|
||||
| `--accent` | `#E8A04B` | 主色(按钮/FAB) |
|
||||
| `--accent-deep` | `#C77E2E` | 主色深 |
|
||||
| `--success` | `#6B8E5A` | 遛狗中 |
|
||||
| `--warn` | `#D98A4E` | 暂停态 |
|
||||
| `--danger` | `#C25A4E` | 结束/二次确认 |
|
||||
|
||||
> 小程序 WXSS 支持 CSS 变量,可直接 `var(--accent)`。不引第三方组件库,全部基础 UI(按钮、卡片、chip、toggle、勋章等)按原型纯手写为 `components/` 下的可复用组件。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
136
docs/02-数据模型.md
Normal file
136
docs/02-数据模型.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# 02 · 数据模型(云数据库)
|
||||
|
||||
云数据库为文档型(类 MongoDB)。共 4 个集合。约定:`_openid` 由云开发自动写入,作为归属与权限依据;时间统一存毫秒时间戳(Number)。
|
||||
|
||||
---
|
||||
|
||||
## 1. `users` — 用户
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `_id` | String | 自动 |
|
||||
| `_openid` | String | 微信 openid,唯一 |
|
||||
| `nickname` | String | 昵称,默认「铲屎官」 |
|
||||
| `avatar` | String | 云存储 fileID,可空 |
|
||||
| `walkCount` | Number | 累计遛狗次数(冗余,展示用) |
|
||||
| `joinedAt` | Number | 加入时间戳 |
|
||||
| `createdAt` | Number | 创建时间 |
|
||||
|
||||
> 「加入 92 天」由 `joinedAt` 客户端算;「遛狗 87 次」读 `walkCount`。
|
||||
|
||||
---
|
||||
|
||||
## 2. `dogs` — 狗狗
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `_id` | String | 狗狗 ID |
|
||||
| `_openid` | String | 归属用户 |
|
||||
| `name` | String | **必填**,名字 |
|
||||
| `breed` | String | **必填**,犬种(如「柯基」) |
|
||||
| `sizeLevel` | String | 体型档位:`xs`/`s`/`m`/`l`/`xl`,由犬种映射;未知犬种由用户手动选择 |
|
||||
| `baseStride` | Number | 档位基础步幅,单位米/步 |
|
||||
| `stride` | Number | 最终步幅,填体重时在 `baseStride` 上校准,封顶 ±15% |
|
||||
| `gender` | String | `male` / `female` / null |
|
||||
| `ageStage` | String | `puppy` / `adult` / `senior` / null |
|
||||
| `ageText` | String | 展示文案,如「成犬 3 岁」,可空 |
|
||||
| `weight` | Number | kg,可空(二次校准狗步) |
|
||||
| `avatar` | String | 云存储 fileID,可空 |
|
||||
| `stats` | Object | 累计统计(见下,冗余加速主页) |
|
||||
| `createdAt` | Number | 建档时间 |
|
||||
|
||||
**`stats` 内嵌对象**(每次遛狗结算时在云函数原子更新):
|
||||
|
||||
```js
|
||||
stats: {
|
||||
totalWalks: 87, // 总次数
|
||||
totalDistance: 142.0, // 总公里
|
||||
totalSteps: 0, // 总狗步(可选)
|
||||
currentStreak: 7, // 连续天数
|
||||
lastWalkDate: '2026-06-24', // 最近一次有效遛狗的日期(yyyy-mm-dd),算连续用
|
||||
}
|
||||
```
|
||||
|
||||
> 仅「名字 + 犬种」必填——降低首次门槛。`sizeLevel/baseStride/stride` 由 `utils/dogStep.js` 按「犬种 → 体型档位 → 步幅」计算;中华田园犬、串串、找不到的犬种必须让用户手动选体型档位。
|
||||
|
||||
---
|
||||
|
||||
## 3. `walks` — 遛狗记录
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `_id` | String | 记录 ID |
|
||||
| `_openid` | String | 归属用户 |
|
||||
| `dogIds` | Array<String> | 本次遛的狗(支持多狗一起遛) |
|
||||
| `startAt` | Number | 开始时间戳 |
|
||||
| `endAt` | Number | 结束时间戳 |
|
||||
| `duration` | Number | 净遛狗秒数(已扣暂停) |
|
||||
| `distance` | Number | 公里,未授权定位时为 null |
|
||||
| `dogStepsByDog` | Object | `{ [dogId]: steps }`,按每只狗的 `stride` 分别换算;未授权定位时为 null |
|
||||
| `pooped` | Boolean | 便便打卡 |
|
||||
| `weather` | String | `sunny`/`cloudy`/`rainy`,可空 |
|
||||
| `mood` | String | 状态标签,可空 |
|
||||
| `note` | String | 备注,可空 |
|
||||
| `photos` | Array<String> | 云存储 fileID,可空 |
|
||||
| `source` | String | `realtime` / `manual`,对应 PRD 的数据来源 |
|
||||
| `isManual` | Boolean | 是否手动补记;兼容展示判断,等价于 `source === 'manual'` |
|
||||
| `countsForRanking` | Boolean | 是否计入排行榜;补记恒为 `false` |
|
||||
| `walkDate` | String | `yyyy-mm-dd`,按本地时区,连续/分组用 |
|
||||
| `createdAt` | Number | 入库时间 |
|
||||
|
||||
> 成果卡所有补充字段(photos/weather/mood/note)全部选填,跳过也能保存。`dogStepsByDog` 仅用于拟人化展示;成就与未来排行榜只使用距离、时长、连续天数等客观量。
|
||||
|
||||
---
|
||||
|
||||
## 4. `dog_achievements` — 成就解锁记录
|
||||
|
||||
成就**按狗维度**(原型「成就墙 · 豆豆」)。成就定义不入库,固化在代码 `utils/achievements.js`(含 key、名称、描述、判定规则、图标)。本集合只存「某狗解锁了某成就」。
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `_id` | String | 自动 |
|
||||
| `_openid` | String | 归属用户 |
|
||||
| `dogId` | String | 狗狗 ID |
|
||||
| `achievementKey` | String | 成就标识,如 `week_streak` |
|
||||
| `unlockedAt` | Number | 解锁时间戳 |
|
||||
|
||||
唯一性:`(dogId, achievementKey)` 不重复解锁(云函数判定前先查重)。
|
||||
|
||||
**成就 key 参考**(来自原型):
|
||||
|
||||
| key | 名称 | 解锁条件 |
|
||||
|-----|------|---------|
|
||||
| `first_walk` | 首遛 | 第一次记录遛狗 |
|
||||
| `week_streak` | 一周不断 | 连续遛狗满 7 天 |
|
||||
| `month_streak` | 满月坚持 | 连续遛狗满 30 天 |
|
||||
| `rainy_warrior` | 雨天战士 | 雨天也坚持遛狗 |
|
||||
| `hundred_km` | 百里同行 | 累计满 100 公里 |
|
||||
| `early_bird` | 早起鸟 | 7 点前遛狗 10 次 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 索引
|
||||
|
||||
| 集合 | 索引字段 | 说明 |
|
||||
|------|---------|------|
|
||||
| `users` | `_openid`(唯一) | 登录查重 |
|
||||
| `dogs` | `_openid` | 列出我的狗 |
|
||||
| `walks` | `_openid` + `walkDate`(降序) | 历史列表、连续判定 |
|
||||
| `walks` | `dogIds`(多键) | 按狗查记录 |
|
||||
| `dog_achievements` | `dogId` + `achievementKey`(联合唯一) | 查重与成就墙 |
|
||||
|
||||
## 6. 数据库权限(安全规则)
|
||||
|
||||
全部集合设为 **「仅创建者可读写」**,写操作再经云函数二次校验。客户端只允许读自己的数据;统计累加、成就解锁等只能由云函数(管理员权限)写,防止刷量。
|
||||
|
||||
```json
|
||||
// 示例:walks 集合权限
|
||||
{
|
||||
"read": "doc._openid == auth.openid",
|
||||
"write": false // 客户端禁写,统一走云函数
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
195
docs/03-云函数设计.md
Normal file
195
docs/03-云函数设计.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 03 · 云函数设计
|
||||
|
||||
约定:所有云函数用 `wx-server-sdk`,统一返回 `{ ok: true, data }` 或 `{ ok: false, code, msg }`。`openid` 一律从 `cloud.getWXContext().OPENID` 取,**绝不信任客户端传入的 openid**。
|
||||
|
||||
---
|
||||
|
||||
## 1. `login` — 登录 / 首次建用户
|
||||
|
||||
**职责**:拿 openid,若用户不存在则建档,返回用户信息 + 是否已有狗狗(决定跳建档还是首页)。
|
||||
|
||||
```
|
||||
入参: {}
|
||||
出参: {
|
||||
ok, data: {
|
||||
userInfo: { openid, nickname, avatar, walkCount, joinedAt },
|
||||
hasDog: Boolean // false → 前端跳 0b 建档;true → 跳首页
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
逻辑:`users` 查 `_openid`,无则插入默认用户;再 `dogs` count 判断 `hasDog`。
|
||||
|
||||
---
|
||||
|
||||
## 2. `dogManage` — 狗狗增 / 改 / 查
|
||||
|
||||
**职责**:建档、编辑、列表(建档与编辑复用,由 `action` 区分)。
|
||||
|
||||
```
|
||||
入参: {
|
||||
action: 'create' | 'update' | 'list',
|
||||
dog?: { _id?, name, breed, sizeLevel?, gender, ageStage, ageText, weight, avatar }
|
||||
}
|
||||
出参: { ok, data: dog | dogs[] }
|
||||
```
|
||||
|
||||
要点:
|
||||
- 服务端校验 `name`、`breed` 非空。
|
||||
- 由 `breed` 查表得到体型档位 `sizeLevel`;中华田园犬、串串、找不到的犬种必须由前端让用户手动选择 `sizeLevel` 后再提交。
|
||||
- 由 `sizeLevel` 得到 `baseStride`,填了 `weight` 时计算最终 `stride`:`baseStride * (1 + (weight - 档位标准体重) * 0.005)`,修正幅度封顶 ±15%。
|
||||
- `create` 时初始化 `stats` 全 0。
|
||||
- `update` 校验该 dog 的 `_openid` == 调用者,防越权改他人狗。
|
||||
---
|
||||
|
||||
## 3. `walkSave` — 保存遛狗(核心)
|
||||
|
||||
**职责**:写入一条 `walks`,**事务式**更新每只狗 `stats`,触发成就判定;并支持成果卡页回写选填字段。这是 V1 最重的云函数。
|
||||
|
||||
### 3.1 结束遛狗:`action='finish'`
|
||||
|
||||
```
|
||||
入参: {
|
||||
action: 'finish',
|
||||
dogIds: [String],
|
||||
startAt, endAt, duration,
|
||||
distance?,
|
||||
pooped
|
||||
}
|
||||
出参: {
|
||||
ok, data: {
|
||||
walkId,
|
||||
dogStepsByDog,
|
||||
newAchievements: [{ key, name, desc }] // 本次新解锁,成果卡展示
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
执行步骤:
|
||||
1. 校验 `dogIds` 均归属当前 openid;未建档任何狗时拒绝保存。
|
||||
2. 计算 `walkDate`(按用户本地时区,前端传时区偏移或统一 +8)。
|
||||
3. 插入 `walks`,`source='realtime'`、`isManual=false`、`countsForRanking=true`。
|
||||
4. 获得定位授权时写入 `distance`,并按每只狗的 `stride` 在服务端计算 `dogStepsByDog`;未授权时 `distance` 与 `dogStepsByDog` 为 `null`,只保存时长。
|
||||
5. 对每个 dogId:
|
||||
- `totalWalks += 1`,`totalDistance += distance||0`,`totalSteps += dogStepsByDog[dogId]||0`。
|
||||
- **连续天数**:比较 `lastWalkDate` 与 `walkDate`——同日不变;昨日则 `currentStreak += 1`;更早则重置为 1。更新 `lastWalkDate`。
|
||||
- 用 `db.command.inc()` 做原子自增,避免并发覆盖。
|
||||
6. `users.walkCount += 1`。
|
||||
7. 调成就判定(见 `achievementCheck`),收集新解锁返回。
|
||||
|
||||
### 3.2 成果卡补充字段:`action='attach'`
|
||||
|
||||
```
|
||||
入参: {
|
||||
action: 'attach',
|
||||
walkId,
|
||||
weather?, mood?, note?, photos?
|
||||
}
|
||||
出参: { ok, data: { walkId, newAchievements?: [{ key, name, desc }] } }
|
||||
```
|
||||
|
||||
要点:
|
||||
- `weather/mood/note/photos` 全部选填,用户跳过也不影响 `finish` 已保存的核心记录。
|
||||
- 只允许回写当前 openid 自己的 walk。
|
||||
- 若 `weather='rainy'`,可在 attach 后补触发「雨天战士」等场景成就,并返回新增成就给成果卡刷新。
|
||||
- 旧记录回看不复用 attach;后续单次记录详情页若支持编辑,应单独定义记录编辑能力。
|
||||
---
|
||||
|
||||
## 4. `walkManual` — 手动补记
|
||||
|
||||
**职责**:补记一次遛狗。规则与 `walkSave` 不同。
|
||||
|
||||
```
|
||||
入参: { dogId, startAt, duration, distance? }
|
||||
出参: { ok, data: { walkId, newAchievements?: [{ key, name, desc }] } }
|
||||
```
|
||||
|
||||
关键差异(**业务规则,必落地**):
|
||||
- `source='manual'`、`isManual=true`、`countsForRanking=false`(不计排行榜,防刷量)。
|
||||
- **可维持连续打卡**:同样参与 `currentStreak` 计算(不断签)。
|
||||
- 不触发「分享/成果卡」类成就,但可触发「连续」类成就。
|
||||
- 列表展示带「补记」标识(前端按 `isManual` 渲染)。
|
||||
|
||||
---
|
||||
|
||||
## 5. `getDogDetail` — 狗狗主页聚合
|
||||
|
||||
**职责**:一次返回狗狗主页所需全部数据,减少往返。
|
||||
|
||||
```
|
||||
入参: { dogId }
|
||||
出参: {
|
||||
ok, data: {
|
||||
dog: {...}, // 含 stats
|
||||
achievements: { // 成就墙
|
||||
unlocked: [{key,name,unlockedAt}],
|
||||
total: 12
|
||||
},
|
||||
recentWalks: [walk, ...] // 近期记录(取最近 5~10 条)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. `getHistory` — 历史 / 记录 Tab 聚合
|
||||
|
||||
**职责**:返回当前用户全部狗狗的遛狗记录列表,供历史页和记录 Tab 复用,减少前端跨集合拼装。
|
||||
|
||||
```
|
||||
入参: { dogId?, page?, pageSize? }
|
||||
出参: {
|
||||
ok, data: {
|
||||
list: [{ walk, dogNames, manualLabel }],
|
||||
hasMore: Boolean
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
要点:
|
||||
- 默认查当前 openid 下全部记录;传 `dogId` 时只查某只狗。
|
||||
- 按 `walkDate/startAt` 倒序返回,可由前端按周或日期分组。
|
||||
- 返回项带狗名、是否补记标识,避免列表层再多次请求 `dogs`。
|
||||
- 只读,不写库。
|
||||
---
|
||||
|
||||
## 7. 内部模块:`achievementCheck`(被 walkSave/walkManual 复用)
|
||||
|
||||
不是独立云函数,是云函数内共享的判定模块(也可做成被 `cloud.callFunction` 内部调用的函数)。
|
||||
|
||||
```
|
||||
输入: dogId, 该狗最新 stats, 本次 walk(含 weather/时间)
|
||||
流程:
|
||||
for 每个成就定义:
|
||||
if 已解锁(查 dog_achievements) → skip
|
||||
if 满足条件(基于 stats / walk):
|
||||
插入 dog_achievements
|
||||
收集进 newAchievements
|
||||
返回: newAchievements[]
|
||||
```
|
||||
|
||||
判定基于 **连续 / 累计 / 场景**,不基于「最多 / 最快」。
|
||||
|
||||
---
|
||||
|
||||
## 8. 云函数清单速查
|
||||
|
||||
| 云函数 | 触发时机 | 写库 |
|
||||
|--------|---------|------|
|
||||
| `login` | App 启动 | users |
|
||||
| `dogManage` | 建档/编辑/进首页 | dogs |
|
||||
| `walkSave` | 结束遛狗、成果卡补充字段回写 | walks, dogs, users, dog_achievements |
|
||||
| `walkManual` | 历史页补记保存 | walks, dogs, dog_achievements |
|
||||
| `getDogDetail` | 进狗狗主页 | 只读 |
|
||||
| `getHistory` | 进历史页 / 记录 Tab | 只读(跨全部狗狗,附狗名) |
|
||||
|
||||
> 后续若上排行榜(pending),新增定时触发云函数做聚合,按 `countsForRanking=true` 统计。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
89
docs/04-页面与路由.md
Normal file
89
docs/04-页面与路由.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 04 · 页面与路由
|
||||
|
||||
## 1. 页面清单(对应原型 12 屏)
|
||||
|
||||
| 原型 Frame | 页面/组件 | 路径 | 类型 | 说明 |
|
||||
|-----------|----------|------|------|------|
|
||||
| 0a 登录 | login | `pages/login/login` | 普通页 | 微信授权登录 |
|
||||
| 0b 建档/编辑 | dog-edit | `pages/dog-edit/dog-edit` | 普通页 | 建档与编辑复用,`?id=` 区分 |
|
||||
| 0c 多狗选择 | multi-dog-sheet | `components/multi-dog-sheet` | 组件(弹层) | 点遛狗时多狗才弹 |
|
||||
| 1 我的 | home | `pages/home/home` | **Tab** | 启动默认页 |
|
||||
| 2/2b 遛狗中 | walking | `pages/walking/walking` | 普通页 | 进行/暂停同页切状态 |
|
||||
| 3 成果卡 | summary | `pages/summary/summary` | 普通页 | 遛完总结 |
|
||||
| 4 狗狗主页 | dog-detail | `pages/dog-detail/dog-detail` | 普通页 | `?id=` |
|
||||
| 5 遛狗历史 | history | `pages/history/history` | 普通页 | 含补记弹层 |
|
||||
| 6/6b 记录 | records | `pages/records/records` | **Tab** | 含空状态 |
|
||||
| 7 完整成就 | achievements | `pages/achievements/achievements` | 普通页 | `?dogId=`,两入口共用 |
|
||||
|
||||
## 2. tabBar 配置(app.json)
|
||||
|
||||
底部三 Tab,中央「遛狗」为凸起按钮。微信原生 tabBar 不支持凸起 FAB,因此采用 **自定义 tabBar**(`custom: true` + `components/custom-tab-bar/`)实现原型的橙色凸起按钮和状态变色。
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"tabBar": {
|
||||
"custom": true, // 自定义,实现中央凸起 FAB
|
||||
"list": [
|
||||
{ "pagePath": "pages/records/records", "text": "记录" },
|
||||
{ "pagePath": "pages/home/home", "text": "我的" }
|
||||
// 中央“遛狗”由自定义 tabBar 渲染,非真实 tab 页
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
中央「遛狗」按钮行为:
|
||||
- 点击 → 单狗直接进 `walking`;多狗弹 `multi-dog-sheet` 选择后再进。
|
||||
- 遛狗中时按钮变绿显示「遛狗中」,点击回到 `walking`;暂停态变黄「已暂停」。
|
||||
|
||||
## 3. 路由跳转表
|
||||
|
||||
```
|
||||
login ──(新用户)──► dog-edit ──完成──► home(tab)
|
||||
login ──(老用户)──────────────────► home(tab)
|
||||
|
||||
home ──点狗卡片──► dog-detail
|
||||
home ──点「成就」──► achievements
|
||||
home ──中央按钮──┬─(单狗)─► walking
|
||||
└─(多狗)─► multi-dog-sheet ─选定─► walking
|
||||
|
||||
walking ⇄ (暂停态同页切换)
|
||||
walking ──结束+二次确认──► summary ──完成──► dog-detail / home
|
||||
walking ──定位/数据降级──► (未授权时隐藏距离·狗步;授权时累计 GPS 距离并换算狗步)
|
||||
|
||||
dog-detail ──右上编辑──► dog-edit?id=xxx(预填)
|
||||
dog-detail ──近期记录──► summary(只读回看,占位;后续替换为 record-detail)
|
||||
|
||||
records(tab) ──成就概览/全部──► achievements
|
||||
records(tab) ──+补记──► manual-add-sheet
|
||||
records(tab) ──历史项──► summary(只读回看,占位;后续替换为 record-detail)
|
||||
|
||||
history ──右上+──► manual-add-sheet ──保存──► 刷新历史
|
||||
```
|
||||
|
||||
## 4. 公共组件拆分
|
||||
|
||||
| 组件 | 用于页面 | 职责 |
|
||||
|------|---------|------|
|
||||
| `custom-tab-bar` | 全局 | 三 Tab + 中央状态化 FAB |
|
||||
| `dog-card` | home | 狗狗卡片(连续天数、犬种) |
|
||||
| `stat-grid` | summary, dog-detail | 三宫格统计 |
|
||||
| `walk-row` | history, records, dog-detail | 一条遛狗记录(含补记标识) |
|
||||
| `achievement-medal` | dog-detail, records, achievements | 勋章(解锁/锁定/进度) |
|
||||
| `multi-dog-sheet` | tabBar 触发 | 多狗选择弹层 |
|
||||
| `manual-add-sheet` | history, records | 补记表单弹层 |
|
||||
| `chip-group` | dog-edit, summary | 单选标签组(性别/年龄/天气/状态) |
|
||||
|
||||
## 5. 关键交互细节(迁移自原型注释)
|
||||
|
||||
- **遛狗中计时**:基于 `startAt` 实时差值计算,扣除累计暂停时长;切后台不丢(见架构文档 §4)。
|
||||
- **定位增强**:不在首次打开强制索权;开始遛狗后可请求定位。授权时累计 GPS 距离并按狗狗 `stride` 换算狗步,未授权时隐藏距离/狗步,只保留时长。
|
||||
- **便便打卡**:行内 toggle,遛狗中即时写入会话状态,结束时随 walk 落库。
|
||||
- **暂停态**:停止计时、数据置灰,主按钮变「继续」——防止等狗/捡便便污染数据。
|
||||
- **结束**:必须二次确认弹窗,再进成果卡。
|
||||
- **成果卡视角**:文案「豆豆今天走了 3,480 狗步」,非「你遛了」。
|
||||
- **空状态(6b)**:新用户「记录」Tab 显俏皮引导 +「带豆豆出门」按钮,成就墙全灰待解锁;遛完第一次切正常态。
|
||||
- **分享**:成果卡「生成图片分享朋友圈」用 Canvas 2D 绘制成果图,是拉新主入口。
|
||||
- **历史回看**:V1 可复用 `summary` 做只读态,但不得显示「完成」这类结束流程按钮;正式形态后续补 `record-detail`。
|
||||
|
||||
|
||||
69
docs/05-业务规则.md
Normal file
69
docs/05-业务规则.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# 05 · 业务规则(必落地)
|
||||
|
||||
> 这些规则散落在 PRD 与原型的橙色虚线注释里,是产品的「魂」。开发时务必逐条实现,不可省略。
|
||||
|
||||
## R1 · 登录与建档分流
|
||||
- 微信授权登录后:**无任何狗狗 → 直接进建档(0b)**;已有狗狗 → 跳过,进首页。
|
||||
- 协议/隐私为必须合规要素,登录页底部展示。
|
||||
|
||||
## R2 · 建档门槛最低
|
||||
- 仅 **名字、犬种** 必填,其余(性别/年龄/体重/头像)全选填——降低首次门槛。
|
||||
- 建档与编辑**复用同一表单**;编辑时预填已有值,标题改「编辑资料」。
|
||||
- 犬种用于映射体型档位;中华田园犬、串串、找不到的犬种必须让用户手动选体型档位。
|
||||
|
||||
## R3 · 狗步算法
|
||||
- 狗步公式:`dogStepsByDog[dogId] = round(distanceMeters / dog.stride)`。
|
||||
- `stride` 由体型档位决定,不做「每品种一个系数」。体型档位与基础步幅:超小型 `0.20m`、小型/短腿 `0.25m`、中型 `0.35m`、大型 `0.45m`、超大型 `0.55m`。
|
||||
- 填了体重时,在基础步幅上做二次校准:`stride = baseStride * (1 + (weight - 档位标准体重) * 0.005)`,修正幅度封顶 ±15%。
|
||||
- 狗步只是展示层:多狗同遛时按每只狗分别计算;成就、未来排行榜和防刷统计只用距离、时长、连续天数等客观量。
|
||||
|
||||
## R4 · 多狗选择
|
||||
- 仅多狗用户点遛狗时弹出选择层;单狗直接进遛狗中。
|
||||
- 选择层**可多选**,支持多只狗一起遛(一条 walk 关联多个 dogId)。
|
||||
|
||||
## R5 · 遛狗计时与暂停
|
||||
- 计时基于时间戳差值,扣除暂停时长;**切后台/锁屏不丢**。
|
||||
- **暂停 = 停止计时 + 数据置灰**,主按钮变「继续」。意义:遛狗常有等狗、捡便便的停顿,暂停防止污染数据。
|
||||
- 结束必须**二次确认**再生成成果卡。
|
||||
|
||||
## R6 · 定位与数据降级
|
||||
- V1 纳入可选 GPS 距离与狗步:授权时累计距离并换算狗步。
|
||||
- 未授权定位时,**距离 / 狗步隐藏**(存 null),时长照常。不阻断遛狗闭环。
|
||||
- 首次打开不强制索权;定位应在开始遛狗或用户主动开启增强能力时请求。
|
||||
- 地图轨迹回放、精准轨迹去噪后置,不阻塞 V1。
|
||||
|
||||
## R7 · 成果卡全选填
|
||||
- 照片、备注、天气、状态等所有输入字段**全部选填,跳过也能保存**——遛狗时用户腾不出手。
|
||||
- 视角为「狗狗走了」而非「你遛了」。
|
||||
- **分享朋友圈是首选 CTA**(拉新入口)。
|
||||
- 核心记录在结束遛狗时先保存;成果卡补充字段通过回写接口保存,跳过不影响记录沉淀。
|
||||
|
||||
## R8 · 手动补记
|
||||
- 入口:历史页 / 记录 Tab 右上「+」。
|
||||
- 数据层标记 `source='manual'`、`isManual=true`。
|
||||
- **补记可维持连续打卡不断签**(参与连续天数计算)。
|
||||
- **补记不计入排行榜**(`countsForRanking=false`,防刷量)。
|
||||
- 补记记录列表带「补记」标识区分。
|
||||
|
||||
## R9 · 统计维度
|
||||
- 累计只用 **次数 / 公里 / 连续天数**。
|
||||
- **不要配速、不要卡路里**——记录陪伴厚度,而非运动表现。
|
||||
|
||||
## R10 · 连续天数算法
|
||||
- 以 `walkDate`(本地时区 yyyy-mm-dd)为单位。
|
||||
- 同日多次遛狗:连续天数不变。
|
||||
- 距上次为「昨天」:`currentStreak += 1`。
|
||||
- 距上次 > 1 天(断签):重置为 1。
|
||||
- 补记同样按其 `walkDate` 参与此计算。
|
||||
|
||||
## R11 · 成就体系
|
||||
- 成就**按狗维度**,基于 **连续 / 累计 / 场景**,而非「最多 / 最快」。
|
||||
- 未解锁项显示进度(「还差 X」),强化收集与坚持动机。
|
||||
- 成就墙露灰锁制造收集欲;新用户也显示全灰待解锁(含「首遛」)。
|
||||
- 「记录」Tab 与「我的→成就」两入口指向**同一页**,文案统一叫「成就」。
|
||||
|
||||
## R12 · 安全与防刷
|
||||
- 所有写操作 + 统计累加 + 成就解锁**只在云函数执行**,客户端集合权限禁写。
|
||||
- openid 一律服务端取,不信任客户端传参。
|
||||
- 同一 `(dogId, achievementKey)` 不重复解锁。
|
||||
|
||||
145
docs/06-开发计划.md
Normal file
145
docs/06-开发计划.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 06 · 开发计划
|
||||
|
||||
按「先跑通核心闭环,再做沉淀与增长」的顺序。每阶段可独立验收。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 进度总览(截至 2026-06-25)
|
||||
|
||||
V1 开发主体(阶段 0 → 4)全部完成并部署。
|
||||
|
||||
**环境**:`cloud1-d0gmb6bjde8af3266` · AppId `wx6cfaffb865048e83` · 部署方式 CloudBase CLI(`tcb`,配置见根目录 `cloudbaserc.json`)。
|
||||
|
||||
**已部署云函数(7)**:`login`、`dogManage`、`walkSave`、`walkManual`、`getDogDetail`、`getHistory`、`sendReminder`(+ 每日 19:00 定时触发器 `dailyReminder`)。
|
||||
|
||||
**数据库集合(4,已建)**:`users`、`dogs`、`walks`、`dog_achievements`。
|
||||
|
||||
**页面(9,全部真实功能)**:login / dog-edit / home / walking / summary / dog-detail / history / records / achievements;组件:custom-tab-bar、manual-add-sheet。
|
||||
|
||||
| 阶段 | 状态 |
|
||||
|------|------|
|
||||
| 0 工程搭建 | ✅ 完成 |
|
||||
| 1 账号与建档闭环 | ✅ 完成 |
|
||||
| 2 遛狗核心闭环 | ✅ 完成 |
|
||||
| 2.5 定位与狗步 | ✅ 完成 |
|
||||
| 3 沉淀与激励 | ✅ 完成 |
|
||||
| 4 增长 | ✅ 完成(订阅消息待填模板 ID) |
|
||||
| 5 Pending | ⏸ 未启动(不在 V1) |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 逻辑漏洞修正(2026-06-25 代码审查)
|
||||
|
||||
对照 [05-业务规则](./05-业务规则.md) 审查现网代码,发现并修正以下逻辑漏洞:
|
||||
|
||||
### 1. 补记无法维持连续打卡(违反 R8 / R10)⭐
|
||||
- **问题**:`walkSave`/`walkManual` 的连续天数只依据 `lastWalkDate + currentStreak` 做增量推算。当用户「先实时遛了今天 → 再补记昨天」时,补记日期早于 `lastWalkDate`,算法走 `diff<=0` 分支原样返回,**连续天数不会向前补全**,直接违背 R8「补记可维持连续打卡不断签」。
|
||||
- **修正**:新增 `computeStreak(openid, dogId)`,落库后**从该狗全部 `walkDate` 历史重算**连续天数(`Set` 去重同日多次、以最新日期为锚向前数连续日、遇断签停止)。补记以任意顺序插入都能正确续签/断签。`walkSave` 与 `walkManual` 均改用此函数,`lastWalkDate` 也取自重算结果。
|
||||
|
||||
### 2. 「早起鸟」成就永不可解锁(违反 R11)
|
||||
- **问题**:`utils/achievements.js` 定义了 6 个成就且 `getDogDetail` 也按 6 统计,但「早起鸟」(早遛 10 次) **在任何云函数中都没有解锁逻辑、也无计数字段**,导致用户永远停在 5/6,成就墙存在一个不可达成项。
|
||||
- **修正**:`walkSave`(仅实时遛狗,场景类不计补记)按开始时间本地小时 `<7` 累加 `stats.earlyWalks`,达 10 次解锁;`STAT_ACHIEVEMENTS` 增加 `early_bird` 判定。前端 `achievements.js` 进度与「还差 X 次」文案改为基于 `earlyWalks` 真实计算。
|
||||
|
||||
### 3. 成果卡选填字段「先分享后补填」会丢失(违反 R7)
|
||||
- **问题**:`summary.js` 的 `ensureAttached` 在字段为空时即把 `_attached` 置 `true`。若用户先点「分享」(此时未填)再补填天气/备注/照片后点「完成」,回写被提前锁定跳过,**选填字段与「雨天战士」成就一并丢失**。
|
||||
- **修正**:空内容时仅 `return` 不置位,只有真正成功回写后才锁定 `_attached`,保证后续补填仍能写入。
|
||||
|
||||
> 数据兼容:旧狗档无 `earlyWalks` 字段,云函数与前端均以 `|| 0` 兜底;连续天数在下一次遛狗/补记时按历史自动重算修正,无需迁移。
|
||||
|
||||
---
|
||||
|
||||
**待你手动处理**:
|
||||
1. 订阅消息模板 ID — 公众平台创建后填入 `utils/config.js` 与 `sendReminder/index.js`,重新部署。
|
||||
2. (可选)数据库索引与权限收紧 — 见 [02-数据模型](./02-数据模型.md) §5/§6;当前客户端不直读库,默认管理端权限不影响功能。
|
||||
3. (可选)存量旧狗数据迁移 — 阶段1建的狗无 `sizeLevel/stride`,进编辑页重存即可补齐(walkSave 已兜底 0.35m 不报错)。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 0 · 工程搭建(地基)
|
||||
**目标**:能在微信开发者工具里跑起空壳,云开发环境就绪。
|
||||
|
||||
- [x] 创建小程序 + 开通云开发,建环境(实际 env `cloud1-d0gmb6bjde8af3266`)。
|
||||
- [x] 初始化目录结构(见 [01-架构设计](./01-架构设计.md))。
|
||||
- [x] `app.js` 初始化 `wx.cloud`,`app.wxss` 落地设计 token。
|
||||
- [x] 纯手写基础 UI,不引第三方库(全局 `.btn/.card` 等 + 组件 `custom-tab-bar`/`manual-add-sheet`;`dog-card`/`stat-grid` 等暂内联在页面,未抽独立组件)。
|
||||
- [x] 建 4 个数据库集合(CLI 建好)。 ⚠️ 索引未建、权限为默认管理端(客户端不直读,暂不影响)—— 见 [02-数据模型](./02-数据模型.md) §5/§6。
|
||||
- [x] `utils/cloud.js` 封装 callFunction(统一错误/loading)。
|
||||
|
||||
**验收**:✅ 工程可在开发者工具导入运行;云函数经 `tcb fn deploy` 部署可调通。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1 · 账号与建档闭环
|
||||
**对应屏**:0a 登录 → 0b 建档 → 1 我的
|
||||
|
||||
- [x] `login` 云函数 + 登录页(R1 分流)。
|
||||
- [x] `dogManage` 云函数(create/update/list,R2)。
|
||||
- [x] 建档/编辑页(复用表单,犬种 picker,chip 单选)。
|
||||
- [x] 首页:用户卡 + 狗狗卡 + 功能入口列表。
|
||||
- [x] 自定义 tabBar(中央状态化 FAB:idle/walking/paused 三态变色)。
|
||||
|
||||
**验收**:✅ 新用户登录→建档→进首页看到自己的狗;编辑能预填回写。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 2 · 遛狗核心闭环(V1 重点)⭐
|
||||
**对应屏**:2/2b 遛狗中 → 3 成果卡 → 4 狗狗主页
|
||||
|
||||
- [x] 遛狗会话状态机(walking/paused,时间戳计时,后台恢复,R5)。
|
||||
- [x] 多狗选择弹层(R4)。
|
||||
- [x] 便便打卡、暂停/继续、结束二次确认(R5)。
|
||||
- [x] 定位增强 + 降级处理(R6):授权时累计 GPS 距离并换算狗步;未授权时距离/狗步存 null 且界面隐藏。
|
||||
- 狗步模型按 R3 落地:体型档位→步幅→体重±15%校准(`utils/dogStep.js` + `dogManage`);未知犬种建档强制选体型档位。
|
||||
- `walkSave` 改 `action:'finish'`、收 `distanceMeters`、按每只狗 stride 算狗步;walk 增 `source` 字段。
|
||||
- [x] `walkSave` 云函数:落库 + stats 更新 + 连续天数(R10)+ 成就判定(R11);含 `finish/attach` 动作回写选填字段 + 雨天战士。
|
||||
- [x] 成果卡页(全选填 R7,新成就提示,三宫格统计)。
|
||||
- [x] `getDogDetail` + 狗狗主页(累计 R9、成就墙、近期记录)。
|
||||
|
||||
**验收**:完整走通「点遛狗→计时/距离/狗步(定位授权时)→结束→成果卡→记录沉淀进狗狗主页」;未授权定位时只保留时长,连续天数与统计正确累加。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 3 · 沉淀与激励
|
||||
**对应屏**:5 历史 → 6/6b 记录 → 7 成就
|
||||
|
||||
- [x] 遛狗历史页(按周分组,补记标识)。
|
||||
- [x] `walkManual` 补记云函数 + 补记弹层组件(R8)。
|
||||
- [x] 新增 `getHistory` 云函数(跨全部狗狗的历史列表,附狗名)。
|
||||
- [x] 记录 Tab(成就概览 + 历史;空状态 6b 引导)。
|
||||
- [x] 完整成就页(已解锁/未解锁含进度,两入口共用)。
|
||||
- [x] 成就定义表 `utils/achievements.js` 全量落地。
|
||||
|
||||
**验收**:补记不计排行但维持连续;成就解锁与进度展示正确;新用户空状态引导生效。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 4 · 增长
|
||||
- [x] 成果卡 Canvas 生成分享图(`canvas type=2d` → `showShareImageMenu`)+ `onShareAppMessage/onShareTimeline` 转发。
|
||||
- [x] 头像/照片云存储上传与压缩(`utils/media.js`:chooseMedia 压缩 → cloud.uploadFile);头像在首页/狗狗主页/成果卡显示。
|
||||
- [x] 连续打卡订阅消息:`sendReminder` 云函数 + 每日 19:00 定时触发器;成果卡「完成」时 `requestSubscribeMessage`。
|
||||
- ⚠️ 需手动:公众平台创建订阅消息模板 → 把模板 ID 填入 `miniprogram/utils/config.js` 与 `cloudfunctions/sendReminder/index.js`,并按模板字段改 `data`。未配置时该功能静默跳过。
|
||||
|
||||
**验收**:成果卡能生成带数据的分享图并分享;头像/照片可上传并展示;模板配置后定时提醒可发。
|
||||
|
||||
---
|
||||
|
||||
## 阶段 5 · 后置 / Pending(不在 V1)
|
||||
- 地图轨迹回放、GPS 去噪与更精细的轨迹纠偏。
|
||||
- 广场、附近、排行榜、信息站。
|
||||
- 排行榜需新增定时聚合云函数,按 `countsForRanking=true` 统计。
|
||||
|
||||
---
|
||||
|
||||
## 里程碑建议
|
||||
|
||||
| 里程碑 | 含阶段 | 可交付 | 状态 |
|
||||
|--------|--------|--------|------|
|
||||
| **M1 可建档** | 0 + 1 | 登录建档跑通 | ✅ 达成 |
|
||||
| **M2 可遛狗** ⭐ | 2 + 2.5 | 核心闭环可用(含 GPS/狗步),可内测 | ✅ 达成 |
|
||||
| **M3 可沉淀** | 3 | 完整 V1 体验 | ✅ 达成 |
|
||||
| **M4 可传播** | 4 | 上线 + 拉新 | ✅ 达成(订阅消息待填模板 ID) |
|
||||
|
||||
> 下一步建议:真机全流程联调 → 处理上方「待你手动」三项 → 提审上线。阶段 5(排行榜/广场等)需先做产品设计再排期。
|
||||
|
||||
|
||||
|
||||
42
docs/07-PRD对齐评审.md
Normal file
42
docs/07-PRD对齐评审.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 07 · PRD 对齐评审
|
||||
|
||||
> 目的:逐条对比 `wangquan-PRD.md` 与 `docs/` 落地设计,判断哪一边方案更合理,并记录已经写回设计文档的结论。
|
||||
|
||||
## 结论总览
|
||||
|
||||
整体方向以 PRD 为产品边界,以 `docs/` 为工程落地方式。PRD 在产品范围、狗步算法、定位降级、拟人化表达上更完整;`docs/` 在技术选型、云函数拆分、安全、防刷、后台计时恢复上更落地。最终方案采用「PRD 定边界,docs 定实现」的组合。
|
||||
|
||||
## 逐条对比
|
||||
|
||||
| 项 | PRD 方案 | docs 原方案 | 哪边更好 | 最终修改 |
|
||||
|---|---|---|---|---|
|
||||
| V1 范围 | V1 包含计时、距离、狗步;轨迹可后置 | 计时先跑通,GPS 距离/狗步后置 | PRD 更好。距离/狗步是成果卡拟人化的关键,不应整体后置 | V1 纳入可选 GPS 距离与狗步;后置仅保留轨迹回放、GPS 去噪 |
|
||||
| 定位权限 | 首版不强制定位,未授权隐藏距离/狗步 | 降级处理有,但把距离/狗步存 null 作为阶段方案 | PRD 更清晰 | 明确“授权则增强,未授权则降级”,首次打开不强制索权 |
|
||||
| 狗步算法 | 体型档位决定步幅,体重可二次校准 | `breedFactor` 犬种系数 | PRD 更好。犬种系数会把模型复杂化,也不利于串串/未知犬种 | 改为 `sizeLevel/baseStride/stride`,未知犬种手动选体型 |
|
||||
| 多狗同遛狗步 | 支持多狗一起遛,但 PRD 未展开字段结构 | 单个 `dogSteps` 字段 | 组合后更好。多狗同遛时每只狗步幅不同,不能只存一个狗步 | 改为 `dogStepsByDog: { [dogId]: steps }`,服务端按每只狗 `stride` 计算 |
|
||||
| 狗步用途 | 狗步只是展示层,不用于跨狗比较、成就、排行 | 有 `totalSteps`,但约束不够明确 | PRD 更好 | 文档补充:成就/排行只用距离、时长、连续天数等客观量 |
|
||||
| 登录建档分流 | 登录后按是否已有狗判断进入建档或首页 | `login` 返回 `hasDog` | docs 更落地 | 保留 `hasDog` 云函数方案 |
|
||||
| 建档字段 | 名字、犬种必填,其余选填 | 同 PRD | 一致 | 保留,补充未知犬种体型选择 |
|
||||
| 计时与暂停 | 暂停停止计时,结束二次确认 | 时间戳差值 + `pausedTotal`,支持后台恢复 | docs 更好 | 保留 docs 的时间戳实现,PRD 规则不变 |
|
||||
| 成果卡补充字段 | 照片/文字/天气/心情集中成果卡,全部选填 | `walkSave` 入参混在结束保存里,计划里提到 attach 但设计不完整 | PRD 交互更好,docs 的 attach 思路更落地 | `walkSave` 明确拆成 `finish` 和 `attach` 两个动作 |
|
||||
| 成果卡分享 | 分享是首选 CTA,分享图样式建议尽早做 | Canvas 分享图在增长阶段 | docs 更务实 | 保留增长阶段,但成果卡仍保留分享 CTA |
|
||||
| 狗狗主页统计 | 总次数/总公里/连续天数,不要配速/卡路里 | 同 PRD | 一致 | 保留 |
|
||||
| 记录 Tab | 成就概览 + 历史 + 补记;空状态露出灰锁 | 同 PRD | 一致 | 保留 |
|
||||
| 手动补记 | 可维持连续,不计未来排行榜,标记数据来源 | `isManual` + `countsForRanking` | 组合后更好 | 增加 `source='manual'/'realtime'`,保留 `isManual` 便于展示 |
|
||||
| 连续天数算法 | 补记可不断签,以日期判断 | docs 写了同日/昨日/断签逻辑 | docs 更落地 | 保留 docs 算法 |
|
||||
| 成就体系 | 按连续/累计/场景,不按最多 | 同 PRD,且有 `dog_achievements` 集合 | docs 更落地 | 保留集合设计,强调按狗维度 |
|
||||
| 单次记录详情页 | 建议补,只读详情页更合理;首版可暂用成果卡只读态 | 历史项直接跳 summary 回看 | PRD 更完整,docs 更省实现 | V1 允许 `summary` 只读占位,但禁止出现“完成”等流程按钮;后续补 `record-detail` |
|
||||
| 设置页 | PRD 建议补定位权限、关于、隐私政策 | docs 未纳入页面清单 | PRD 更完整,但不阻塞 V1 主闭环 | 暂不扩页面清单,作为后续待补项处理 |
|
||||
| 技术选型 | PRD 不限定 | 原生小程序 + 云开发 | docs 更好 | 保留 |
|
||||
| 安全与防刷 | 需要区分实时/补记,防排行刷量 | 所有写操作走云函数,openid 服务端取,客户端禁写 | docs 更好 | 保留并补充 `source` 字段 |
|
||||
| Pending 功能 | 社区、附近、排行榜、信息站、商城不进首版 | 同 PRD | 一致 | 保留 |
|
||||
|
||||
## 已写回的文档
|
||||
|
||||
- `README.md`:更新 V1 范围和文档索引。
|
||||
- `01-架构设计.md`:补充定位会话字段,修正 `dogStep.js` 职责。
|
||||
- `02-数据模型.md`:改为体型档位/步幅模型,新增 `source` 和 `dogStepsByDog`。
|
||||
- `03-云函数设计.md`:补齐 `dogManage` 步幅计算、`walkSave finish/attach`、服务端狗步计算。
|
||||
- `04-页面与路由.md`:明确定位增强、历史回看只读占位。
|
||||
- `05-业务规则.md`:重新整理必落地规则,新增狗步算法和定位规则。
|
||||
- `06-开发计划.md`:把 V1 距离/狗步拉回核心闭环,后置项改为轨迹回放与去噪。
|
||||
37
docs/README.md
Normal file
37
docs/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# 汪圈 · 遛狗小程序 — 设计文档
|
||||
|
||||
> 微信原生小程序 + 云开发(CloudBase)。V1 聚焦「遛狗单机闭环」:登录 → 建档 → 首页 → 遛狗 → 成果卡 → 沉淀。
|
||||
|
||||
## 一句话定位
|
||||
|
||||
记录「陪伴的厚度」而非运动表现。视角是「狗狗走了」而非「你遛了」。用 **连续 / 累计 / 成就** 沉淀情感,用 **成果卡分享朋友圈** 做拉新。
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 层 | 选型 |
|
||||
|----|------|
|
||||
| 客户端 | 微信原生小程序(WXML / WXSS / JS) |
|
||||
| UI 组件库 | 不用第三方库,纯手写 WXSS(最贴合原型视觉、包体最小) |
|
||||
| 后端 | 微信云开发:云数据库 + 云存储 + 云函数 |
|
||||
| 鉴权 | 云调用 `cloud.getWXContext().OPENID`(免自建 token) |
|
||||
| 状态管理 | 轻量全局 store(`app.globalData` + 事件总线,不引 Redux) |
|
||||
|
||||
## 文档索引
|
||||
|
||||
| 文档 | 内容 |
|
||||
|------|------|
|
||||
| [01-架构设计.md](./01-架构设计.md) | 技术选型、工程目录、全局状态、设计 token |
|
||||
| [02-数据模型.md](./02-数据模型.md) | 云数据库集合设计、索引、权限 |
|
||||
| [03-云函数设计.md](./03-云函数设计.md) | 云函数清单、入参出参、职责划分 |
|
||||
| [04-页面与路由.md](./04-页面与路由.md) | 页面清单(对应原型 12 屏)、路由表、组件拆分 |
|
||||
| [05-业务规则.md](./05-业务规则.md) | 关键业务规则(必落地)汇总 |
|
||||
| [06-开发计划.md](./06-开发计划.md) | 里程碑与阶段拆分 |
|
||||
| [07-PRD对齐评审.md](./07-PRD对齐评审.md) | PRD 与落地设计逐条对比、取舍结论 |
|
||||
|
||||
## 范围边界(V1)
|
||||
|
||||
- ✅ 纳入:登录、建档、遛狗计时闭环、可选 GPS 距离、狗步换算、成果卡、狗狗主页、历史、补记、成就。
|
||||
- ⏸ 后置:地图轨迹回放、精准轨迹去噪、单次记录详情页完整形态。
|
||||
- ❌ 不做(pending):广场、附近、排行榜、信息站。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user