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

6.3 KiB
Raw Permalink Blame History

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[] }

要点:

  • 服务端校验 namebreed 非空。
  • breed 查表得到体型档位 sizeLevel;中华田园犬、串串、找不到的犬种必须由前端让用户手动选择 sizeLevel 后再提交。
  • sizeLevel 得到 baseStride,填了 weight 时计算最终 stridebaseStride * (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. 插入 walkssource='realtime'isManual=falsecountsForRanking=true
  4. 获得定位授权时写入 distance,并按每只狗的 stride 在服务端计算 dogStepsByDog;未授权时 distancedogStepsByDognull,只保存时长。
  5. 对每个 dogId
    • totalWalks += 1totalDistance += distance||0totalSteps += dogStepsByDog[dogId]||0
    • 连续天数:比较 lastWalkDatewalkDate——同日不变;昨日则 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=truecountsForRanking=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 统计。