# 汪圈小程序 — 功能逻辑缺陷审查报告 v2.0 > 审查日期:2026-06-19 > 基线版本:v1.0 报告审查后的最新代码 > 审查范围:全部 11 个页面、10 个 Service、25+ 个云函数、4 个类型文件、3 个 Store/Hook、1 个新增 `cloud-file` 工具模块 > 审查分支:`master` --- ## v1 → v2 修复总结 v1 报告共提出 **36 条** 问题(含跨页面系统性问题 6 条),本次审查确认的修复情况如下: | 类别 | v1 问题数 | ✅ 已修复 | ⚠️ 部分修复 | ❌ 未修复 | 🆕 新发现 | |------|-----------|-----------|-------------|-----------|-----------| | 广场页 | 7 | 5 | 0 | 1 | 3 | | 附近页 | 5 | 4 | 0 | 0 | 2 | | 发布页 | 4 | 4 | 0 | 0 | 2 | | 消息页 | 4 | 4 | 0 | 0 | 0 | | 聊天页 | 6 | 6 | 0 | 0 | 2 | | 个人资料页 | 2 | 0 | 1 | 0 | 1 | | 资料编辑页 | 3 | 1 | 0 | 2 | 0 | | 宠物编辑页 | 2 | 0 | 0 | 2 | 0 | | 联系人页 | 3 | 0 | 1 | 2 | 0 | | 我的动态页 | 3 | 2 | 0 | 0 | 2 | | 帖子详情页 | — | — | — | — | 4 (新增页) | | 跨页面系统 | 6 | 4 | 0 | 2 | 2 | | **合计** | **36+** | **26** | **2** | **7** | **18** | --- ## 一、广场页 `pages/plaza/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | Feed 无分页 / 无限滚动 | ✅ 已修复 | 引入 `nextCursor`、`loadNextPage`、`PageShell lowerThreshold={160}`、`loadingMore` 状态,实现了完整的无限滚动。 | | 2 | 话题列表硬编码 | ✅ 已修复 | 引入 `topicOptions` 状态 + `normalizeTopicOptions()`,从云端 `result.topics` 动态合并。 | | 3 | 广告卡片位置固定 | ✅ 已修复 | 引入 `createAdStartIndex()` 随机起点 + `AD_INTERVAL = 6` 间隔,每次加载重新随机化。 | | 5 | 没有帖子详情页 | ✅ 已修复 | 新增 `pages/post-detail/index` 页面,`PostCard` 支持 `onOpen` 导航。 | | 6 | 点赞乐观更新竞态 | ✅ 已修复 | 引入 `feedRequestSeq` + `pendingLikeIds` / `pendingLikeOverrides` 防重复机制,失败时回滚到 `previousPost` 快照。 | | 7 | 搜索栏无功能 | ✅ 已修复 | 绑定 `onInput` + 300ms 防抖 `debouncedKeyword`,搜索时展示结果计数 + 清除按钮。 | ### ❌ v1 遗留 | v1 # | 问题 | 说明 | |------|------|------| | 4 | 收藏功能入口缺失 | `Post.favoritedByMe` 字段和 `feed.service.setPostFavorite()` 仍然存在,`PostCard` 仍然没有收藏操作的 UI 入口。跨页面系统性问题 #2 未解决。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **`loadFeed` 依赖数组包含 `debouncedKeyword` 导致频繁重置** | 🟡 中 | `useEffect` (L156-158) | `loadFeed` 的 `useCallback` 依赖了 `debouncedKeyword`。防抖 300ms 后 `debouncedKeyword` 变化 → `loadFeed` 重建 → `useEffect` 触发 → 清空列表重新加载。用户每输入一个字符(停顿 300ms 后),整个列表会被清空重载一次,体验上表现为列表频繁闪烁空白再重新出现。应将 `loadFeed` 拆分为"参数变化时的首次加载"和"追加加载",或使用 ref 追踪 keyword 变化而非作为 `useCallback` 依赖。 | | 2 | **`PostCard` 移除了 `more` 按钮但无替代操作** | 🟡 中 | `PostCard` (L44-66) | v1 中 `PostCard` 有一个 `more` 图标按钮(三点点),v2 中完全移除了。用户无法对帖子执行更多操作(举报、分享、复制链接等),丢失了内容管理入口。 | | 3 | **话题搜索结果与关键词搜索混合逻辑不一致** | 🟡 中 | 搜索逻辑 (L278-306) | 关键词搜索通过 `debouncedKeyword` 传给 `getFeedList`,服务端过滤。但话题筛选通过 `topic` 参数传给同一个 `getFeedList`。两者不能同时生效——用户选择了某个话题后又输入搜索词,行为不明确。UI 上也没有层级提示告诉用户"在话题内搜索"还是"全局搜索"。 | --- ## 二、附近页 `pages/nearby/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | 没有调用 `updateLocation` 上报自身位置 | ✅ 已修复 | 获取位置后调用 `updateLocation(loc, true)`,`relocate` 时也会更新,`nearbyVisible === false` 时传 `null, false`。 | | 2 | 没有尊重 `preferences.nearbyVisible` 偏好 | ✅ 已修复 | 先 `getProfile()` 读取偏好,`nearbyVisible === false` 时不请求位置、清空宠物列表、不上报位置。 | | 3 | `likePet` 没有乐观更新和错误回滚 | ✅ 已修复 | 引入 `pendingLikeIds`、乐观设置 `likedByMe: true`,失败时回滚到 `previousLiked`。 | | 4 | `filter: 'online'` 后端过滤能力不确定 | ✅ 已修复 | `nearby.service.ts` 新增 `filterNearbyPets()` 前端兜底过滤。`nearbyPets` 云函数也已支持 `online` filter。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **`nearbyVisible` 为 `null` 时地图显示默认中心上海但无数据** | 🟡 中 | 初始化流程 (L32, L57-83) | `nearbyVisible` 初始值为 `null`(等待 `getProfile` 返回),此时地图渲染 `DEFAULT_CENTER`(上海),`center` 为 `null` 所以 `loadPets` 不触发,宠物列表为空。用户看到一个空地图和空列表,直到 `getProfile` 完成(可能 1-2 秒)。应显示加载指示器或骨架屏。 | | 2 | **没有清理自身旧位置(登出 / 关闭可见性)** | 🟢 低 | `nearbyVisible === false` 分支 (L61-67) | 调用 `updateLocation(null, false)` 但没有确认云函数是否正确处理 `null` location(从数据库中移除旧坐标)。如果云函数只是不写入,用户的旧位置数据会一直留在数据库中。 | --- ## 三、发布页 `pages/publish/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | 没有恢复草稿的逻辑 | ✅ 已修复 | `useEffect` 调用 `getDraft()`,通过 `hasDraftContent()` 判断后 `restoreDraft()` 回填所有表单字段。 | | 2 | 没有内容字数上限预警 | ✅ 已修复 | `canSubmit` 检查 `textLength <= 2000`,超限时 `submit()` 弹 `toast: '正文最多 2000 字'`。 | | 3 | 图片上传失败静默跳过 | ✅ 已修复 | 新增 `UploadPostMediaError` 自定义错误类,`showUploadFailure()` 弹窗明确告知第几张图片上传失败。 | | 4 | 返回没有未保存提示 | ✅ 已修复 | `handleClose()` 检查 `hasContent`,弹窗询问"保存草稿?" 或 "不保存"离开。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **`useUploadMedia` 的 `setMedia` 暴露了内部 setter** | 🟢 低 | `useUploadMedia` 解构 (L53) | `const { media, setMedia, addImages, removeMedia } = useUploadMedia([])` — 直接暴露 `setMedia` 并在 `restoreDraft` 中使用。绕过了 `useUploadMedia` 的内部管理逻辑,如果该 hook 未来添加了额外状态(如上传状态),直接 `setMedia` 不会触发这些逻辑。应通过 hook 暴露一个 `replaceMedia` 方法。 | | 2 | **草稿恢复成功后宠物默认选中逻辑冲突** | 🟡 中 | `useEffect` (L81-87) | `getPetList` 的 `useEffect` 有 `setSelectedPetId(prev => prev \|\| (draftRestoredRef.current ? '' : list[0]._id))`。当草稿恢复成功时 `draftRestoredRef.current = true`,但如果草稿没有设置 `petId`(`draft.petId` 为空),宠物不会被默认选中——这可能不是用户期望的(用户之前可能选中了一个宠物但草稿没保存 petId)。 | --- ## 四、消息页 `pages/messages/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | `markConversationRead` 是 fire-and-forget | ✅ 已修复 | `openConversation` 中正确 `await markConversationRead`,失败时回滚 `unreadCount`。`navigateTo` 失败时也回滚。 | | 2 | 没有区分 single / system 会话交互 | ✅ 已修复 | `item.type === 'system'` 时直接调用 `markConversationRead` 标记已读并 toast "系统消息已读",不再跳转聊天页。 | | 3 | 没有消息通知 / 推送机制 | ⚠️ 部分修复 | — | 见跨页面系统问题 #3(推送机制仍未接入,但消息页本身已正确处理未读状态)。 | | 4 | 搜索不会过滤 activeUsers | ✅ 已修复 | 搜索时也过滤 `activeUsers` → `visibleActiveUsers`,有匹配时显示"在线汪友"分区。 | ### v2 无新增问题 --- ## 五、聊天页 `pages/chat/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | 消息列表没有分页加载历史 | ✅ 已修复 | 引入 `loadOlder`、`nextCursor`、`upperThreshold={48}` 触发加载。加载后滚动到锚点消息位置。 | | 2 | 轮询频率固定 5 秒 | ✅ 已修复 | 引入 `ACTIVE_POLL_MS = 3000` / `IDLE_POLL_MS = 12000` / `ACTIVE_POLL_WINDOW_MS = 60000` 三档智能调节。 | | 3 | 发送失败时输入框闪空 | ✅ 已修复 | `send()` 中不再先 `setDraft('')`,而是在 `sendMessage` 成功后才 `setDraft('')`。`sendImageMessage` 也类似处理。 | | 4 | 没有消息发送状态指示 | ✅ 已修复 | `sending` 状态驱动 UI:按钮显示"发送中"、输入框 `disabled`、工具栏按钮 disabled。 | | 5 | `scrollTop` 递增 hack 不可靠 | ✅ 已修复 | 改用 `scrollIntoView` + 动态 `bottomAnchorId`(`scrollSeq` 递增)实现可靠滚动到底部。 | | 6 | 不支持图片 / 表情消息 | ✅ 已修复 | 新增图片发送 (`sendImages`)、表情面板 (`EMOJI_OPTIONS`)、图片消息展示 + 预览 (`previewImage`)。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **图片消息只显示非 `cloud://` URL 的图片** | 🔴 高 | 图片渲染逻辑 (L442) | `m.content && !m.content.startsWith('cloud://')` — 当消息的 content 是 `cloud://` 文件 ID(已上传到云端但 `resolveCloudFileUrl` 没有成功转换时),会显示"图片暂不可用"文本气泡。`messageThread` 云函数和 `resolveThreadAssets` 应该已经解析了这些 URL,但如果解析失败,用户会看到"图片暂不可用",没有重试机制。更严重的是,任何以 `cloud://` 开头的内容都被认为是"不可用图片"而非普通文本,如果某些消息的 type 被错误标记为 `image` 但 content 是 cloud ID,将无法展示。 | | 2 | **`loadLatest` 提前返回时可能不清除 `loadingInitial`** | 🟢 低 | `loadLatest` (L183-220) | 如果 `requestId !== latestRequestSeq.current` 导致提前 return,`loadingInitial` 不会被清除——但 `finally` 块仍会执行(return 在 try 块内),所以实际不会出现此问题。仅限极端竞态场景。 | --- ## 六、个人资料页 `pages/profile/index.tsx` ### ⚠️ v1 部分修复 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | 偏好 `changePreference` 无错误回滚 | ⚠️ 部分修复 | `updateProfile` 内部调用 `markStale('profile')`,数据会在下次 `useRefreshOnShow` 时刷新。但 `changePreference` 本身仍然没有 `try-catch`——如果 `updateProfile` 抛出异常,UI 状态已改但数据未持久化,直到下次刷新才恢复。用户仍然会看到一个短暂的"假成功"状态。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **`useSession` 初始化时 `ensureLogin` 与 `ProfilePage` 自身的 `ensureLogin` 重复调用** | 🟢 低 | `useEffect` (L40-47) | `useSession` hook 内部在 mount 时已经调用了 `ensureLogin()`,`ProfilePage` 在 `useEffect` 中又调用了一次。虽然有 `inflight` 去重机制不会产生两次网络请求,但代码结构上造成了理解困惑。可考虑依赖 `useSession` 的 user 即可。 | --- ## 七、资料编辑页 `pages/profile-edit/index.tsx` ### ❌ v1 遗留 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | `type='nickname'` 仅真机生效 | ❌ 未修复 | 仍然是 `type='nickname'`,没有非真机环境的校验提示。这是微信平台限制,可接受。 | | 2 | `avatarUrl` 与 `avatarKey` 共存冲突 | ❌ 未修复 | 新增了 `avatarDisplayUrl` 变量(L25: `avatarUrl && !avatarUrl.startsWith('cloud://') ? avatarUrl : ''`),解决了 `cloud://` ID 在 `` 中无法显示的问题。但 `avatarKey` 在头像已上传的情况下仍然是一个无用的遗留值,`Avatar` 组件和 `Image` 组件的优先级关系仍不明确。 | | 3 | 没有未保存离开提示 | ❌ 未修复 | 关闭按钮仍然是直接 `navigateBack()`,没有检测是否有未保存修改。 | ### v2 无新增问题 --- ## 八、宠物编辑页 `pages/pet-edit/index.tsx` ### ❌ v1 遗留 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | 没有宠物数量上限限制 | ❌ 未修复 | `PetShelf` 组件仍然无条件显示"添加宠物"按钮。后端也没有数量限制。 | | 2 | 照片隐式非必填但交互暗示必填 | ❌ 未修复 | 提交验证只检查 `name` 和 `breed`,无照片也能保存。新增了 `photoDisplayUrl` 逻辑(L81),解决了 `cloud://` ID 显示问题。 | ### v2 无新增问题 --- ## 九、联系人页 `pages/contacts/index.tsx` ### ⚠️ v1 部分修复 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 3 | 互关后 `isFriend` 未即时更新 | ⚠️ 部分修复 | v1 报告指出 `onFollow` 只更新 `isFollowing` 不更新 `isFriend`。当前代码仍然只更新 `isFollowing`,`isFriend` 未同步。需调用 `toggleFollow` 后根据返回的 `mutual` 更新 `isFriend`。 | ### ❌ v1 遗留 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 1 | "发现"搜索需手动提交 | ❌ 未修复 | 仍然只有 `onConfirm` 触发搜索,没有实时搜索或防抖输入触发。 | | 2 | 点击用户只能发起聊天 | ❌ 未修复 | 仍然没有用户个人主页入口。 | ### v2 无新增问题 --- ## 十、我的动态页 `pages/my-posts/index.tsx` ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 2 | `useDidShow` 首次触发导致重复加载 | ✅ 已修复 | 改用 `useRefreshOnShow('myPosts', () => load(true))`,首次 onShow 被跳过。 | ### ❌ v1 遗留 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 3 | `likePost` 没有错误回滚 | ❌ 未修复 | `likePost` 仍然没有 try-catch 和回滚逻辑——`await setPostLike(postId, target.likedByMe)` 失败时不会恢复之前的点赞状态。 | ### 🆕 v2 新发现 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **仍然没有分页加载** | 🟡 中 | `load()` (L21-31) | `userPosts` 云函数硬编码 `limit(50)`,前端一次性加载全部 50 条。如果用户帖子超过 50 条,超出部分无法查看。应添加 `cursor` / `pageSize` 参数到 `userPosts` 云函数和前端。 | | 2 | **`likePost` 通过 `onPostLike` 事件同步但有重复调用** | 🟡 中 | `likePost` (L49-63) | `likePost` 做了乐观更新 + 调用 `setPostLike`(后者通过 `emitPostLike` 广播)。同时还有一个 `useEffect` 订阅 `onPostLike` 事件。当用户在"我的动态"页点赞时,`setPostLike` → `emitPostLike` → 本页的 `onPostLike` 监听器也会触发 `setPosts`,导致同一条帖子的点赞状态被**设置了两次**(第一次是 `likePost` 直接设置,第二次是事件监听器设置)。虽然结果相同,但多了一次不必要的 re-render。 | --- ## 十一、帖子详情页 `pages/post-detail/index.tsx` 🆕 新增页面 | # | 缺陷 | 严重程度 | 位置 | 说明 | |---|------|----------|------|------| | 1 | **评论缺少分页加载** | 🟡 中 | `load()` (L30-59) | `postDetail` 云函数一次返回最多 200 条评论(`safeGet('comments', { postId }, 200)`),前端没有分页。如果帖子评论超过 200 条,超出部分无法查看。 | | 2 | **`likePost` 的乐观更新使用闭包中的 `post` 而非 ref** | 🟡 中 | `likePost` (L66-85) | `const previousPost = post`(L82 回滚时使用)来自当前渲染闭包中的 `post` state。如果用户快速双击点赞(第一次 `setPost(next)` 还没 re-render,第二次进入时 `post` 仍是旧值),乐观更新的"之前"状态会不准确。应使用 ref 追踪最新的 post。 | | 3 | **发送评论后新评论的 `author` 硬编码为"我"** | 🟡 中 | `send()` (L87-116) | 新评论被乐观添加到列表,但 `author: { id: 'me', name: '我', avatarKey: 'gradient-avatar-1' }` 是硬编码的,没有使用当前用户的真实昵称和头像。用户看到自己评论显示为"我"而非自己的昵称。应从 `useSession()` 获取当前用户信息。 | | 4 | **`load` 函数的 `finally` 中总是设置 `commentsLoaded = true`** | 🟢 低 | `load()` (L58) | 即使 `getPostDetail` 抛出异常,`commentsLoaded` 也会被设为 `true`,导致"评论加载中…"变成"还没有评论"。但此时用户不知道加载失败了(没有错误提示)。应在 catch 中显示错误状态。 | --- ## 十二、跨页面系统性问题 ### ✅ v1 修复确认 | v1 # | 问题 | 状态 | 说明 | |------|------|------|------| | 3 | 草稿系统断裂 | ✅ 已修复 | 发布页 mount 时调用 `getDraft()`,`resolveDraftMedia()` 解析草稿中的 cloud file URL,表单完整回填。 | | 5 | 没有全局错误边界 | ✅ 已修复 | 各页面和 service 层普遍添加了 try-catch 和错误回滚。虽然不是 React ErrorBoundary,但每个操作都有用户可感知的错误提示。 | | 6 | `CloudFunctionName` 缺少 `commentCreate` | ✅ 已修复 | `cloud.ts` 中已包含 `commentCreate`。 | ### ❌ v1 遗留 | v1 # | 问题 | 说明 | |------|------|------| | 1 | 全应用没有全局登录态守卫 | `session.store.ts` 实现了共享 session + `ensureLogin`,`app.tsx` 在 launch 时预热登录。但广场、附近、消息、发布等页面仍然**没有检查登录态**——未登录用户能看到空数据但不会跳转到登录页。 | | 4 | `StatsRow` 数据可能与子页面不同步 | 未修复。`profile.getProfile()` 和 `contacts.getFollowList()` 返回的计数仍然可能因缓存延迟不一致。 | ### 🆕 v2 新发现 | # | 问题 | 影响范围 | 严重程度 | 说明 | |---|------|----------|----------|------| | 1 | **`cloud-file.ts` 的 `tempUrlCache` 永不过期** | 全应用 | 🟡 中 | `resolveCloudFileUrls` 将 cloud file ID 到临时 URL 的映射缓存在内存 Map 中,但**永不清除**。长时间使用小程序后,这个 Map 会持续增长(每次加载帖子/头像/评论都添加条目)。虽然单个 URL 映射很小,但如果用户大量浏览内容(数百帖子,数千评论),累积效果不应忽视。应添加 LRU 或 TTL 淘汰策略。 | | 2 | **`dataBus.ts` 的 `postCache` 永不清除** | 跨页面 | 🟢 低 | `cachePost` 将帖子数据存入全局 Map,`getCachedPost` 只在 `PostDetailPage` 中调用。这个 Map 永远不会被清除——如果用户浏览了很多帖子,所有数据都会留在内存中。应在一定时间后或 Map 大小超过阈值时清除。 | | 3 | **`messageList` 云函数中 `peerOpenids` 过滤的变量遮蔽** | 消息页 | 🟡 中 | `messageList/index.js` L88: `(c.memberOpenids \|\| []).find(openid => openid !== OPENID)` — `find` 的回调参数名 `openid` 遮蔽了外层的 `OPENID` 常量。逻辑上结果正确(参数 `openid` !== `OPENID` 等价于"找到不是我的那个成员"),但变量命名遮蔽在未来维护时容易引入真实 bug。应重命名回调参数(如 `member`)。 | | 4 | **`messageThread` 云函数每次轮询都执行一次已读标记 update** | 聊天页 → 消息页 | 🟢 低 | `messageThread/index.js` L97-99: 每次请求消息列表都会 `update` conversation 清除未读。聊天页的轮询(3-12 秒一次)会频繁触发不必要的数据库写入。如果两个用户同时在看同一会话,一方的轮询会清除另一方的未读状态——虽然 `_.pull(OPENID)` 只清除当前用户,但频繁 update 仍是不必要的开销。应区分首次加载(标记已读)和轮询刷新(不标记已读)。 | | 5 | **`nearbyPets` 云函数不按距离排序** | 附近页 | 🔴 高 | `nearbyPets/index.js` L86: `db.collection('pets').where(query).limit(50).get()` — 没有 `.orderBy` 按距离排序。返回的宠物列表按 MongoDB 默认的写入顺序排列,用户看到的附近宠物不是按距离远近排列的。对于"附近"功能来说,距离排序是核心体验。应使用 geoNear 或在应用层按 `distanceText` 排序。 | --- ## 十三、修复优先级建议 ### P0 — 必须立即修复 1. **`nearbyPets` 云函数不按距离排序** — "附近"功能的核心体验缺失,用户期望看到最近的宠物排在最前面 2. **聊天页图片消息 `cloud://` 不显示** — 用户发送/接收的图片消息可能显示"图片暂不可用" 3. **`messageList` 云函数 `peerOpenids` 变量遮蔽** — 代码可维护性风险,未来修改时容易引入真实 bug ### P1 — 短期内修复 4. 联系人页 `onFollow` 互关后未即时更新 `isFriend` 5. 联系人页"发现"搜索无实时搜索 6. 我的动态页 `likePost` 错误回滚 7. 我的动态页无分页 + `userPosts` 云函数 `limit(50)` 硬编码 8. 广场页搜索输入导致列表频繁重载(`debouncedKeyword` → `loadFeed` 重建 → 清空列表) 9. 帖子详情页评论 `author` 硬编码"我" 10. 收藏功能 UI 入口补全(`PostCard` 添加收藏按钮) 11. `changePreference` 添加 `try-catch` 12. 帖子详情页 `likePost` 闭包问题 → ref ### P2 — 中期迭代 13. 资料编辑页 / 宠物编辑页未保存离开提示 14. 帖子详情页评论分页 15. `PostCard` 恢复"更多操作"按钮 16. 宠物数量上限 17. 全局登录态守卫(非 TabBar 页面检查登录) 18. 联系人页添加用户个人主页入口 19. `messageThread` 轮询时避免不必要的已读标记 update 20. 附近页 `nearbyVisible` 加载状态提示 ### P3 — 长期优化 21. `cloud-file.ts` tempUrlCache 添加 TTL / LRU 淘汰 22. `dataBus.ts` postCache 添加大小限制 / TTL 23. 消息通知 / 推送接入 24. 用户个人主页(完整帖子列表 + 宠物列表展示) 25. 广场页话题与关键词搜索混合逻辑优化 --- > 本报告基于源码静态审查生成,所有问题均指向代码层面的逻辑缺陷,不涉及 UI/UX 视觉设计层面的评审。