Files
Pawer/docs/功能缺陷审查报告.md
2026-06-18 15:38:28 +08:00

16 KiB
Raw Blame History

汪圈小程序 — 功能逻辑缺陷审查报告

审查日期2026-06-18 审查范围:全部 10 个页面、10 个 Service、23 个云函数、3 个类型文件、关键组件 审查分支:master


一、广场页 pages/plaza/index.tsx

# 缺陷 严重程度 位置 说明
1 Feed 无分页 / 无限滚动 🔴 loadFeed() (L34-38) getFeedList 云函数返回 CursorResponse<T>nextCursor 分页字段但页面完全没有使用分页机制。只加载第一页数据用户无法浏览更多帖子。Feed 是社交应用的核心功能,此为致命缺陷。
2 话题列表硬编码 🟡 topics (L24) ['全部', '滨江公园', '金毛日常', ...] 写死在组件中,不会从云端动态获取热门话题,运营新增的话题无法展示。
3 广告卡片位置固定 🟡 PostCard 渲染逻辑 (L130-133) FeedAdCard 写死在 index === 0 的位置。每次 loadFeed 刷新后数据重置,广告位置永远在第一条帖子后,缺乏真实广告系统的随机插入和频次控制。
4 收藏功能存在但入口缺失 🟡 PostCard + PlazaPage feed.service.ts 导出了 setPostLike / setPostFavoritePost 类型有 favoritedByMe 字段,但 PostCardPlazaPage 均没有收藏操作的 UI 入口,收藏功能全链路断裂。
5 没有帖子详情页 🟡 commentPost() (L86-113) 评论通过 Taro.showModal 弹窗实现,无法查看评论列表、历史记录,也无法点击图片查看大图预览。社交类帖子的完整交互(评论链、转发、分享)均缺失。
6 点赞乐观更新存在竞态 🟡 likePost() (L54-84) 连续两次 setPosts(乐观更新 → 服务端返回覆盖),期间若 useDidShow 触发 loadFeed,可能覆盖掉刚点赞的中间状态。应考虑用 postId 粒度的状态管理或防抖。
7 搜索栏无功能 🟡 <SearchBar> (L118) SearchBar 组件已渲染但没有绑定 onInput / onSubmit 回调,搜索框为纯装饰。

二、附近页 pages/nearby/index.tsx

# 缺陷 严重程度 位置 说明
1 没有调用 updateLocation 上报自身位置 🔴 整个页面 nearby.service.ts 导出了 updateLocation(location, visible),用户位置变化从未上报云端。其他用户看不到"我"在附近地图上出现,双向发现功能完全失效。应在获取到位置后调用上报,并在 relocate 时重复上报。
2 没有尊重 preferences.nearbyVisible 偏好 🔴 整个页面 用户在个人资料中可关闭"附近可见"(preferences.nearbyVisible),但附近页完全不考虑此设置。即使关闭,仍请求并展示附近宠物,自身位置也没有根据偏好控制是否上报。应在 useEffect 中读取偏好,决定是否请求附近数据。
3 likePet 没有乐观更新和错误回滚 🟡 likePet() (L89-92) 只调用了 likeNearbyPet(id),没有先更新 UI 状态(不像 PlazaPage.likePost 做了乐观更新 + 回滚)。网络慢时用户看不到反馈,快速点击可能重复请求。
4 filter: 'online' 后端过滤能力不确定 🟡 loadPets() (L41-46) 前端传 { type: 'online' },但 nearbyPets 云函数是否支持此过滤逻辑取决于后端实现。如果后端不识别此 filter返回的数据未做二次前端过滤展示可能不准确。
5 搜索仅前端过滤 🟡 visiblePets (L139-142) 只按 namebreed 过滤,不支持按距离排序或更丰富的筛选组合。筛选器仅有 all/dog/cat/online 四种,缺少按距离、年龄段、标签等维度。

三、发布页 pages/publish/index.tsx

# 缺陷 严重程度 位置 说明
1 没有恢复草稿的逻辑 🔴 useEffect (L44-50) publish.service.ts 导出了 getDraft(),但发布页 mount从未调用它。用户保存的草稿在下次进入发布页时不会被恢复。应添加逻辑:进入时检测未提交内容 → 提示恢复草稿 → 调用 getDraft() 回填表单。
2 没有内容字数上限预警 🟡 ComposerToolbar count prop isValidPostContent 限制 12000 字,但 content.length 仅展示数字,没有在接近上限(如 >1800 字)时给出警告样式或禁用输入。
3 图片上传失败静默跳过 🟡 uploadPostMedia() (publish.service.ts L24-38) 单张图片上传失败时 catch 返回原 item,用户不知道哪张图没上传成功。帖子可能携带本地临时路径 wxfile://... 发布,其他用户无法查看。应在 UI 上展示上传失败提示。
4 返回没有未保存提示 🟡 关闭按钮 (L148-150) 点击 navigateBack() 直接返回,如果用户已输入内容但未发布,不会提醒"是否保存为草稿"。应检测 hasContent,有内容时弹窗确认。

四、消息页 pages/messages/index.tsx

# 缺陷 严重程度 位置 说明
1 markConversationRead 是 fire-and-forget 🟡 openConversation() (L48-54) 调用了 markConversationRead 但没有 await,且 openConversationasync 函数却没有 try-catch。如果 navigateTo 失败(如页面栈满),异常不会被捕获。
2 没有区分 single / system 会话交互 🟡 openConversation() (L48-54) Conversationtype: 'single' | 'system',系统消息(如"汪圈小助手")不应有"发起聊天"行为,但 UI 上没有区分处理——点击系统消息也会跳转到 chat 页面。
3 没有消息通知 / 推送机制 🟡 整个页面 没有接入微信订阅消息或任何推送通知机制。preferences.notifications 偏好存在但无实际功能接入,用户即使打开通知设置也不会收到新消息提醒。
4 搜索不会过滤 activeUsers 🟡 kw 过滤逻辑 (L64-69) 搜索只过滤 conversations,不搜索 activeUsers。有搜索关键词时 activeUsers 被隐藏(kw ? null : <ActiveUserRow>),但清空搜索后立即恢复,交互上不连贯。

五、聊天页 pages/chat/index.tsx

# 缺陷 严重程度 位置 说明
1 消息列表没有分页加载历史 🔴 load() (L26-35) 只调用一次 getThread() 获取当前消息,没有向上滚动加载更早消息的机制。长时间对话的历史消息无法查看。应实现 ScrollView 到顶触发加载上一页。
2 轮询频率固定 5 秒,无智能调节 🟡 useDidShow (L43-45) 不管页面是否在前台活跃、消息密度如何,都固定 5 秒轮询一次。高频轮询消耗资源,低频则延迟高。对于聊天场景,建议使用 WebSocket 或根据消息活跃度动态调整轮询间隔。
3 发送失败时输入框闪空 🟡 send() (L53-71) 发送时先 setDraft('') 清空输入框,失败后 setDraft(text) 恢复。在发送到失败的间隙,输入框会先空再恢复,视觉闪烁。建议先不清空,成功后再清空。
4 没有消息发送状态指示 🟡 聊天气泡 UI (L92-103) sending 状态变量存在但没有用在 UI 上。用户发送消息后没有 loading / 发送中指示器,不知道消息是否正在发送。
5 scrollTop 递增 hack 不可靠 🟡 setScrollTop(prev => prev + 100000) (L34) 通过不断递增 scrollTop 强制滚动到底部。Number.MAX_SAFE_INTEGER9007199254740991,每次 +100000 约可调用 9×10¹⁰ 次才溢出——虽然实际不太可能触发,但设计上应改用 ref 记录并 toggle 一个标志位。
6 不支持图片 / 表情消息 🟡 输入栏 UI (L108-119) 只支持纯文本输入,没有图片、表情等富媒体消息功能。ChatMessage.type 字段存在但没有被使用,输入区域也没有附件按钮。

六、个人资料页 pages/profile/index.tsx

# 缺陷 严重程度 位置 说明
1 偏好 changePreference 无错误回滚 🟡 changePreference() (L92-102) 先乐观更新 UI 再 await updateProfile,但整个函数没有 try-catch。如果云端更新失败UI 状态已改但数据未持久化,下次加载会回滚,造成用户困惑(以为保存了但实际没有)。
2 "关于"功能是空壳 🟢 handleAction('about') (L89) 只弹 toast: '敬请期待新功能'。MVP 阶段可接受,但应在版本规划中补充。

七、资料编辑页 pages/profile-edit/index.tsx

# 缺陷 严重程度 位置 说明
1 type='nickname' 仅真机生效 🟡 <Input type='nickname'> (L116) type='nickname' 是微信小程序获取微信昵称的特殊能力仅在真机上有效。H5 预览 / 开发工具中用户可手动输入任意昵称(绕过微信身份验证)。应在非真机环境增加校验提示。
2 avatarUrlavatarKey 共存冲突 🟡 submit() (L56-82) 编辑后 uploadAvatar 返回 fileID 赋给 patch.avatarUrl,但 avatarKey 没有被更新或清除。如果 Avatar 组件优先读 avatarUrl,则 avatarKey 多余;若优先读 avatarKey,可能显示旧头像。需要明确两者的优先级关系。
3 没有未保存离开提示 🟡 关闭按钮 (L88-90) 直接 navigateBack() 没有检测是否有未保存修改。应比较当前表单值与初始值的差异,有差异时弹窗确认。

八、宠物编辑页 pages/pet-edit/index.tsx

# 缺陷 严重程度 位置 说明
1 没有宠物数量上限限制 🟡 submit() (L132-168) 没有检查用户已添加的宠物数量。用户可以无限添加宠物,可能导致数据膨胀。建议在后端限制(如最多 5 只),前端也做预检提示。
2 照片隐式非必填但交互暗示必填 🟡 choosePhoto() + 验证逻辑 提交验证只检查 namebreed,无照片也能保存。但展示逻辑依赖 photoKey 的兜底图,用户可能以为照片是必须的。建议明确标注照片为"可选",或在空照片时展示更友好的占位。

九、联系人页 pages/contacts/index.tsx

# 缺陷 严重程度 位置 说明
1 "发现"搜索需手动提交,不支持实时搜索 🟡 <Input onConfirm> (L101-102) 搜索需要点击键盘"搜索"按钮才触发 (onConfirm),没有 onInput 实时触发搜索。对于"发现陌生人"场景,用户期望输入即搜索,应增加防抖实时搜索。
2 点击用户只能发起聊天,无个人主页入口 🟡 openChat() (L63-67) 点击用户头像/名称只能跳转到聊天页,没有查看对方个人主页(宠物列表、帖子等)的选项。用户想了解对方更多信息需要退出再找,交互断裂。
3 互关后 isFriend 未即时更新 🟡 onFollow() (L51-61) toggleFollow 返回 { mutual } 但只更新了 isFollowing,没有同步更新 isFriend。互关后列表中不会立即显示"汪友"标签,需手动刷新页面才能看到。

十、我的动态页 pages/my-posts/index.tsx

# 缺陷 严重程度 位置 说明
1 没有分页加载 🔴 load() (L19-23) 只加载一次 getUserPosts(),没有翻页。如果用户帖子很多,无法查看全部历史帖子。应实现 ScrollView 到底触发加载下一页。
2 useDidShow 首次触发导致重复加载 🔴 useDidShow(load) (L31) useDidShow 没有用 firstShow ref 跳过首次加载(对比 PlazaPageMessagesPage 有此保护),首次进入页面时 load() 会被调用两次useEffect + useDidShow),浪费一次网络请求。
3 likePost 没有错误回滚 🟡 likePost() (L33-47) 乐观更新后调用 setPostLike,但如果失败不会回滚到之前的状态。对比 PlazaPage.likePostpreviousPosts 回滚逻辑,此处遗漏了。

十一、跨页面系统性问题

# 问题 影响范围 说明
1 全应用没有全局登录态守卫 所有页面 所有 service 通过 canUseCloud() 判断是否可用,但没有统一的"未登录则拦截/跳转"逻辑。只有 ProfilePage 单独处理了登录态,其他页面(广场、附近、消息、发布等)均假定已登录,未登录用户可能看到空数据或报错。
2 Post.favoritedByMe 收藏能力全链路断裂 PlazaPage, PostCard 类型定义有 favoritedByMe 字段,feed.service.ts 导出 setPostFavorite 方法,但 PostCard 组件和 PlazaPage 均没有收藏操作的 UI 入口,前端从未调用过该 service 方法。
3 草稿系统断裂 PublishPage draftSavedraftGet 云函数完整存在,publish.service.ts 导出了 getDraft(),但发布页 mount 时从不调用它。草稿保存后永远无法恢复,草稿功能形同虚设。
4 StatsRow 数据可能与子页面不同步 ProfilePage → ContactsPage, MyPostsPage 个人资料页 stats.posts/following/followers 来自 getProfile(),跳转到 contacts?tab=followinggetFollowList() 可能因缓存延迟返回不同计数,造成数字前后不一致。
5 没有全局错误边界 全应用 任何 service 层未处理的异常会直接在页面崩溃。没有 React ErrorBoundary 或全局 Toast 兜底机制,用户体验差。
6 CloudFunctionName 联合类型缺少 commentCreate feed.service.ts L43 createPostComment 调用了 callCloud('commentCreate', ...),但 CloudFunctionName 联合类型中是否包含 commentCreate 取决于 cloud.ts 的定义。如果未声明TypeScript 不会报错但运行时可能失败。

十二、修复优先级建议

P0 — 必须立即修复(影响核心功能)

  1. Feed / 我的动态分页 — 社交应用内容流的基础能力
  2. 发布页草稿恢复getDraft() 已存在,只需在页面 mount 时调用
  3. 附近页上报自身位置updateLocation() 已存在,只需在获取位置后调用

P1 — 短期内修复(影响用户体验)

  1. 我的动态页 useDidShow 重复加载 → 添加 firstShow ref
  2. 我的动态页 likePost 错误回滚
  3. 附近页 likePet 添加乐观更新
  4. 附近页尊重 nearbyVisible 偏好
  5. 聊天页消息分页加载
  6. 个人资料页 changePreference 添加 try-catch
  7. 收藏功能 UI 入口补全

P2 — 中期迭代(完善产品体验)

  1. 搜索栏功能实现(广场页)
  2. 联系人页实时搜索
  3. 聊天页发送状态指示 + 发送失败 UX
  4. 未保存离开提示(发布页、编辑页)
  5. 全局登录态守卫
  6. 全局错误边界
  7. 消息通知 / 推送接入

P3 — 长期优化(性能和扩展性)

  1. 话题列表动态化
  2. 广告系统正规化
  3. 图片 / 富媒体消息
  4. 帖子详情页 + 评论列表
  5. 聊天页轮询策略优化WebSocket
  6. 宠物数量上限
  7. 用户个人主页入口(从联系人页)

本报告基于源码静态审查生成,所有问题均指向代码层面的逻辑缺陷,不涉及 UI/UX 视觉设计层面的评审。