Files
Pawer/docs/功能缺陷核验与修复设计.md

20 KiB
Raw Blame History

汪圈小程序 - 功能缺陷核验与修复设计

核验日期2026-06-20
来源报告:docs/功能缺陷审查报告.md
核验基线:当前工作区源码,重点核验 srccloudfunctions,忽略 dist 构建产物
目标:逐项确认报告中仍被标为缺陷/风险的条目是否真实存在,并为需要修改的条目形成可落地设计

1. 总体结论

报告中的“已修复确认”条目,当前代码整体能支撑报告结论;本次未发现需要重新打开的已修复项。消息页、发布页、附近页、聊天页的主要 v1 修复点均能在当前实现中找到对应逻辑。

报告中仍被标为遗留、新发现或系统性问题的条目共核验 35 项:

结论 数量 说明
成立 24 当前代码中确实存在对应行为或缺口
部分成立 5 现象存在,但报告描述、严重程度或根因需要修正
不成立 6 当前代码已解决或报告判断与实现不符

需要特别修正报告优先级:

  • nearbyPets 云函数不按距离排序:不成立。当前 cloudfunctions/nearbyPets/index.js 会计算距离、筛选半径内位置,并按 _dist 升序排序。
  • messageList 变量遮蔽:成立,但只是维护性风险,不应列为 P0。
  • 聊天图片 cloud:// 不显示:部分成立。服务层已经尝试解析 cloud:// 为临时 URL真实问题是解析失败后会丢失可重试的 fileId页面只能显示“图片暂不可用”。
  • 当前没有阻断级 P0 缺陷;建议从 P1 的数据一致性、分页、错误回滚开始修。

2. 已修复条目复核摘要

页面/模块 报告已修复项 本次复核
广场页 分页、动态话题、广告随机、详情页、点赞竞态、搜索入口 代码中存在 nextCursornormalizeTopicOptionscreateAdStartIndexpost-detail 导航、pendingLikeIds/pendingLikeOverrides、搜索防抖
附近页 位置上报、尊重可见性、喜欢乐观更新、online 过滤 代码中存在 updateLocationnearbyVisible 分支、pendingLikeIds 回滚、前后端 online 过滤
发布页 草稿恢复、字数上限、上传失败提示、关闭前保存草稿提示 代码中存在 getDraft/restoreDrafttextLength <= 2000UploadPostMediaErrorhandleClose 草稿弹窗
消息页 已读等待、系统会话区分、搜索 activeUsers 代码中 openConversation 会等待跳转/已读结果,系统消息不进聊天,搜索同时过滤在线汪友
聊天页 历史分页、智能轮询、发送失败不清空、发送状态、可靠滚动、图片/表情 代码中存在 loadOlder、3s/12s 轮询、成功后清空输入、sending 状态、scrollIntoView、图片和表情发送
我的动态 首次 onShow 重复加载 useRefreshOnShow 会跳过首次 show
跨页面 草稿系统、操作错误提示、commentCreate 类型 当前代码已接入草稿解析、常见操作 try/catch、CloudFunctionName 包含 commentCreate

3. 逐项核验清单

# 报告条目 核验结论 是否需要修改 设计归属
1 广场收藏功能入口缺失 成立。Post/云函数有收藏字段与能力,但 PostCard 无入口,feed.service.ts 也没有封装 setPostFavorite 需要 D1
2 广场 loadFeed 依赖 debouncedKeyword 导致频繁清空 部分成立。每次防抖关键词变化都会重载并清空列表;这是搜索行为的一部分,但会造成闪空体验 建议修改 D4
3 PostCard 移除更多按钮 成立。当前只剩点赞/评论,无举报、分享等入口 暂缓,需产品确认更多菜单内容 D6
4 话题搜索与关键词不能同时生效 不成立。前端同时传 topickeyword,云函数也会按 topic 查询后做关键词匹配 不修改,仅可优化提示文案 D4
5 附近页 nearbyVisible=null 时显示默认上海与空列表 成立。偏好加载期间页面会渲染默认中心与空状态 需要 D4
6 关闭附近可见不清理旧位置 不成立。locationUpdatevisible=false 时会写入 location:nullgeo:nullvisible:false,不会被附近查询命中 不修改 -
7 useUploadMedia 暴露内部 setMedia 成立。发布页直接用 setter 恢复草稿 建议小改 D4
8 草稿恢复后宠物默认选中逻辑冲突 部分成立。当前逻辑会把“草稿无 petId”解释为“不关联宠物”但无法区分历史缺字段与用户主动不关联 需要明确语义后修改 D4
9 聊天图片 cloud:// 不显示 部分成立。正常路径会解析为临时 URL解析失败时会丢失 fileId无法重试 需要 D3
10 loadLatest 提前返回不清 loadingInitial 不成立。return 位于 try 内,finally 仍会执行 不修改 -
11 个人页偏好开关无失败回滚 成立。changePreference 先改 UIawait updateProfile 无 catch 需要 D1
12 useSession 与个人页重复 ensureLogin 成立但影响很低。store 有 inflight 去重,不会造成重复请求 暂不修改,可作为结构清理 D6
13 资料编辑 type='nickname' 仅真机生效 成立但属于微信平台限制 不按缺陷修,可补充提示 D6
14 avatarUrlavatarKey 共存冲突 不成立。当前是图片优先、渐变头像兜底;getProfile 已解析 cloud URL 不修改 -
15 资料编辑页无未保存离开提示 成立。关闭按钮直接 navigateBack 需要 D4
16 宠物数量无上限 部分成立。当前确实无限制,但是否是缺陷取决于产品策略 需要产品确定上限后修改 D6
17 宠物照片交互暗示必填 不成立。当前无必填标识,校验也只要求名字和品种 不修改,可加“可选”文案 -
18 联系人互关后 isFriend 未即时更新 成立。toggleFollow 返回 mutual,页面未使用 需要 D1
19 联系人“发现”搜索需手动提交 成立。onInput 只更新本地关键词,只有 onConfirm 请求 建议修改 D1
20 点击用户只能发起聊天,无个人主页 成立。当前没有用户主页页面 中期功能 D6
21 我的动态点赞无错误回滚 成立。likePost 无 try/catch 需要 D1
22 我的动态无分页,云函数 limit(50) 成立。userPosts 无 cursor前端一次加载 需要 D2
23 我的动态点赞事件导致重复 setPosts 成立但影响低。服务成功会广播,页面本地也已设置 可随点赞回滚一起收敛 D1
24 帖子详情评论缺少分页 成立。postDetail 一次最多 200 条评论 需要 D2
25 帖子详情点赞闭包竞态 成立。回滚用当前渲染闭包中的 post 需要 D1
26 发送评论后作者硬编码“我” 成立。乐观评论未使用当前用户资料 需要 D1
27 帖子详情加载失败也设 commentsLoaded=true 成立。load 无 catch失败后会显示空评论 需要 D4
28 全局登录态守卫缺失 成立。logout 是本地标记,非 profile 页面未统一拦截 需要设计为轻量会话门禁 D5
29 StatsRow 计数可能不同步 部分成立。profileGet 已实时计算,但 follow/favorite 等操作后没有统一标记 profile 失效 需要 D5
30 cloud-file.ts 临时 URL 缓存永不过期 成立 需要 D5
31 dataBus.ts postCache 永不清除 成立 需要 D5
32 messageListopenid 回调变量遮蔽 成立,但只是可维护性问题 顺手修 D6
33 messageThread 每次轮询都写已读 成立。云函数每次取线程都会 update 会话已读 需要 D3
34 nearbyPets 不按距离排序 不成立。当前会按距离排序 不修改 -
35 消息通知/推送未接入 成立,但这是新功能,不是当前消息列表逻辑缺陷 长期迭代 D6

4. 修复设计

D1. 互动状态一致性与回滚

目标:统一点赞、收藏、关注、偏好开关、评论乐观更新的失败回滚与跨页面同步,优先解决用户可感知的数据错乱。

涉及文件:

  • src/services/feed.service.ts
  • src/services/social.service.ts
  • src/pages/my-posts/index.tsx
  • src/pages/post-detail/index.tsx
  • src/pages/profile/index.tsx
  • src/pages/contacts/index.tsx
  • src/features/feed/components/PostCard/index.tsx
  • cloudfunctions/postFavorite/index.js

设计:

  1. 收藏能力补齐:

    • feed.service.ts 新增 setPostFavorite(postId, favorited),调用 postFavorite 云函数。
    • postFavorite 云函数补齐缺集合兜底,避免新库第一次收藏失败。
    • PostCard 增加收藏按钮与数量展示,使用 post.favoritedByMecounts.favorites
    • 广场、我的动态、帖子详情统一实现乐观收藏、失败回滚、成功后写入服务端返回值。
    • 新增收藏同步事件或复用 dataBus 扩展,例如 emitPostFavorite({ postId, favorited, favorites })
  2. 我的动态点赞:

    • 引入 postsRefpendingLikeIds,按广场页模式保存操作前快照。
    • setPostLike 失败时恢复 likedByMecounts.likes
    • onPostLike 监听中先比较目标 post 当前值,相同则返回原数组,减少重复 re-render。
  3. 帖子详情点赞:

    • 新增 postRef 保存最新 postlikePost 以 ref 为准,不用渲染闭包中的 post
    • pendingLikeIds 防止同一帖子连续点击造成并发请求。
    • 失败时回滚到请求开始时的 snapshot。
  4. 评论乐观作者:

    • PostDetailPage 使用 useSession() 获取当前用户。
    • 乐观评论 author 使用 user._iduser.nicknameuser.avatarKeyuser.avatarUrl
    • commentCreate 可在后续返回完整 comment短期先保持 { commentId, comments } 返回结构不变。
  5. 联系人关注:

    • onFollow 使用 toggleFollow 返回的 followingmutual 回写 isFollowingisFriend
    • 失败回滚到完整旧 user snapshot而不是只反转 isFollowing
    • social.service.toggleFollow 成功后调用 markStale('profile'),让资料页统计在返回时刷新。
  6. 偏好开关:

    • changePreference 保存 previous user。
    • 乐观更新后 try/catch 调用 updateProfile;失败恢复 previous user 并 toast。
    • updateProfilemarkStale('profile') 建议移动到云函数成功后,避免失败也标记新鲜/脏状态混乱。

验收:

  • 断网或云函数失败时,点赞/收藏/关注/偏好开关都能回滚 UI。
  • 互关后联系人页立即显示“汪友”。
  • 新评论展示当前用户昵称和头像,不再硬编码“我”。
  • 同一帖子在广场、我的动态、详情页的点赞/收藏状态保持一致。

D2. 列表与评论分页

目标:移除 50/200 条硬上限,保证长列表可继续加载。

涉及文件:

  • cloudfunctions/userPosts/index.js
  • cloudfunctions/postDetail/index.js
  • src/services/feed.service.ts
  • src/pages/my-posts/index.tsx
  • src/pages/post-detail/index.tsx
  • src/types/cloud.ts

设计:

  1. userPosts 分页:

    • 云函数入参新增 cursor?: stringpageSize?: number
    • createdAt desc 查询 pageSize + 1cursor 使用上一页最后一条 createdAt
    • 返回 { list, nextCursor }
    • getUserPosts 改为返回 CursorResponse<Post>,兼容 authorId
    • MyPostsPage 增加 nextCursorloadingMoreloadMore,在滚动到底部加载。
  2. 评论分页:

    • postDetail 入参新增 commentCursor?: stringcommentPageSize?: number
    • 评论按 createdAt asc 返回,初始取最早一页;下一页使用 createdAt > commentCursor
    • 返回 { post, comments, commentsNextCursor }
    • PostDetailPage 增加 commentsNextCursorloadingCommentsMore、底部“加载更多评论”。
    • 为避免刷新帖子详情时重复替换图片,继续保留当前“只更新计数”的策略。

验收:

  • 我的动态超过 50 条时可以继续加载。
  • 帖子评论超过单页限制时可以继续加载下一页。
  • 分页加载失败有 toast当前列表不被清空。

D3. 聊天图片可靠展示与已读写入控制

目标:图片临时 URL 解析失败后可重试;聊天轮询不再每次写数据库。

涉及文件:

  • src/services/message.service.ts
  • src/pages/chat/index.tsx
  • src/types/domain.ts
  • cloudfunctions/messageThread/index.js

设计:

  1. 图片消息数据结构:

    • ChatMessage 增加可选字段 fileId?: stringassetState?: 'ready' | 'unresolved'
    • resolveThreadAssets 解析图片时保留原始 cloud://fileIdcontent 存临时 URL解析失败时 content=''assetState='unresolved'
    • 页面渲染 unresolved 图片时展示占位和“重试”操作。
    • 重试时调用 resolveCloudFileUrl(fileId),成功后只更新该条消息。
  2. 已读写入控制:

    • messageThread 入参新增 markRead?: boolean,默认 true 以兼容旧调用。
    • 首次打开会话、用户主动刷新时传 markRead:true
    • 静默轮询 loadLatest({ silent:true }) 和加载历史传 markRead:false
    • 云函数仅在 markRead !== false 且会话存在时执行已读 update。

验收:

  • 图片临时 URL 获取失败后,页面不会永久丢失 cloud fileId。
  • 静默轮询不再触发会话已读 update。
  • 首次进入聊天仍会清除当前用户未读数。

D4. 页面加载、搜索与离开保护

目标:减少空白闪烁,补齐错误状态与未保存提示。

涉及文件:

  • src/pages/plaza/index.tsx
  • src/pages/nearby/index.tsx
  • src/features/nearby/components/NearbySheet/index.tsx
  • src/pages/post-detail/index.tsx
  • src/pages/profile-edit/index.tsx
  • src/hooks/useUploadMedia.ts
  • src/pages/publish/index.tsx

设计:

  1. 广场搜索:

    • 搜索参数变化时保留旧列表,设置 searching=true,新结果回来后替换。
    • 或仅在用户按确认键时清空列表,防抖输入走静默刷新。
    • 搜索结果文案增加当前 topic例如“在 #遛弯 中搜索...”,解决语义提示问题。
  2. 附近偏好加载:

    • 增加 preferenceLoading = nearbyVisible === null
    • 偏好未返回前,地图可显示默认中心,但列表区展示“正在读取附近设置”,不展示“附近暂时没有汪友”。
    • NearbySheet 接收 loadingstate,区分 loading、disabled、empty 三种状态。
  3. 帖子详情加载失败:

    • load 增加 catch设置 commentsError
    • 失败时展示“评论加载失败,点击重试”,不显示“还没有评论”。
    • finally 只负责关闭 loading不吞掉错误状态。
  4. 资料编辑未保存提示:

    • initialRef 保存首次加载后的表单快照。
    • 关闭按钮走 handleClosedirty 时弹窗确认放弃/继续编辑。
    • 保存成功后更新 dirty 基线或直接返回。
  5. 上传媒体 hook

    • useUploadMedia 对外暴露 replaceMedia(next),发布页草稿恢复改用该方法。
    • 保留内部 setMedia 私有,后续上传状态不会被外部绕过。
  6. 草稿宠物语义:

    • 新草稿保存时增加 petSelectionExplicit: boolean 或将 petId 扩展为 string | null
    • petId=null 表示用户明确选择“不关联宠物”;petId 缺失表示历史草稿/未选择,可默认第一只宠物。
    • 对旧草稿做兼容:没有该字段时默认第一只宠物,除非后续产品明确要求保持“不关联”。

验收:

  • 广场搜索输入时不出现明显空白闪烁。
  • 附近页读取设置期间不显示错误的空列表语义。
  • 评论加载失败有可见错误和重试。
  • 编辑资料有未保存离开确认。
  • 草稿恢复不会误把历史缺字段理解为用户主动不关联。

D5. 会话门禁、统计失效与缓存淘汰

目标:统一“本地登出/资料未完成”的门禁语义,并控制长期运行内存增长。

涉及文件:

  • src/store/session.store.ts
  • src/services/auth.service.ts
  • src/services/social.service.ts
  • src/services/feed.service.ts
  • src/services/pet.service.ts
  • src/store/dataBus.ts
  • src/services/cloud-file.ts
  • src/pages/home/index.tsx

设计:

  1. 轻量登录态守卫:

    • 新增 useSessionGate({ requireCompleted?: boolean }) 或等价 helper。
    • 对发布、消息、联系人、附近等需要真实用户态的页面/操作,若 isLoggedOut()!user.profileCompleted,引导到“我的”完成登录资料。
    • 广场可保持只读,但点赞、收藏、评论、关注等写操作必须先过 gate。
    • 由于微信 openid 是静默登录,本设计不把“未登录”理解为无 openid而是“用户本地退出或资料未完成”。
  2. 统计失效:

    • follow、favorite、post create/delete、pet save/delete 成功后统一 markStale('profile')
    • 资料页返回时通过现有 useTabRefresh('profile') 获取实时 profileGet 统计。
    • 如后续新增联系人资源 key可扩展 ResourceKeycontacts,用于关注列表自身失效。
  3. 临时 URL 缓存:

    • tempUrlCacheMap<string,string> 改为 Map<string,{ url:string; expiresAt:number; lastAccess:number }>
    • 默认 TTL 50 分钟,低于微信临时 URL 常见有效期。
    • 最大容量建议 500超出时按 lastAccess 淘汰最旧项。
    • 每次 resolve 前执行轻量 prune。
  4. 帖子 hand-off 缓存:

    • postCache 增加 TTL 10 分钟、最大容量 100。
    • getCachedPost 读取过期项时删除并返回 undefined
    • cachePost 写入时执行容量淘汰。

验收:

  • 本地退出后,写操作不会继续静默执行。
  • 关注/收藏后回到资料页,统计能刷新。
  • 长时间浏览大量帖子/图片后,缓存 Map 不会无界增长。

D6. 中长期产品能力与低风险清理

这些条目成立或部分成立,但不建议混入第一批稳定性修复。

  1. 更多菜单:

    • PostCard 预留 onMore
    • 菜单项建议先做“分享”“复制内容/链接”“举报”。
    • 举报若上线,需要新增 postReport 云函数和审核字段,不只是前端按钮。
  2. 用户个人主页:

    • 新增 /pages/user-profile/index?userId=...
    • 复用 profileGet({ userId })userPosts({ authorId }),只展示公开资料与公开动态。
    • 联系人列表头像/名称点击进主页,聊天按钮保留为独立操作。
  3. 宠物数量上限:

    • 需要先确定产品上限,例如 6 或 10。
    • 前端 PetShelf 达上限隐藏/禁用“添加宠物”。
    • 后端 petSave 新增创建前 count 校验,防止绕过前端。
  4. 消息推送:

    • 作为订阅消息能力单独立项。
    • 需要用户授权订阅模板、发送时机、频率限制、退订处理。
  5. 低风险清理:

    • messageList 回调参数 openid 改名为 memberOpenid
    • 个人页重复 ensureLogin 可在重构时简化,但当前无需优先。
    • type='nickname' 平台限制可在开发/非真机环境补充提示,不作为功能修复。

5. 推荐实施顺序

阶段 内容 原因
P1 D1 互动状态一致性、D2 我的动态分页、D3 聊天图片重试、D4 帖子详情错误状态 直接影响用户操作结果与内容可见性
P2 D2 评论分页、D4 广场/附近加载体验、资料编辑离开保护、D5 统计失效与会话门禁 提升长列表、返回刷新和基础流程可靠性
P3 D5 缓存淘汰、D6 更多菜单/用户主页/宠物上限/推送/清理项 风险较低或属于产品能力扩展

6. 开发校验建议

  1. 每个云函数分页改动都保留旧入参兼容,避免旧包调用失败。
  2. 点赞、收藏、关注、偏好开关需要分别模拟云函数失败,确认 UI 回滚。
  3. 图片消息需要模拟 getTempFileURL 失败,确认 fileId 被保留且可重试。
  4. 使用 npm run typecheck 验证类型改动。
  5. 微信开发者工具中重点回归:广场搜索、附近首次进入、聊天轮询、我的动态滚动加载、帖子详情评论加载。