6.3 KiB
6.3 KiB
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 }] // 本次新解锁,成果卡展示
}
}
执行步骤:
- 校验
dogIds均归属当前 openid;未建档任何狗时拒绝保存。 - 计算
walkDate(按用户本地时区,前端传时区偏移或统一 +8)。 - 插入
walks,source='realtime'、isManual=false、countsForRanking=true。 - 获得定位授权时写入
distance,并按每只狗的stride在服务端计算dogStepsByDog;未授权时distance与dogStepsByDog为null,只保存时长。 - 对每个 dogId:
totalWalks += 1,totalDistance += distance||0,totalSteps += dogStepsByDog[dogId]||0。- 连续天数:比较
lastWalkDate与walkDate——同日不变;昨日则currentStreak += 1;更早则重置为 1。更新lastWalkDate。 - 用
db.command.inc()做原子自增,避免并发覆盖。
users.walkCount += 1。- 调成就判定(见
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统计。