Files
Pet3/docs/03-云函数设计.md
2026-06-25 18:24:29 +08:00

196 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` 统计。