001project_wildgrowth/ios/WildGrowth/COMPLETION_统一分页_零影响版代码审查报告.md

6.3 KiB
Raw Blame History

完成页「统一分页 + 零影响」代码审查报告(禁止应用)

审查对象:严格遵守 6 条零影响条件的 CompletionView + VerticalScreenPlayerView 完整代码(内部重构,外部兼容)。
结论:仅审查,不修改仓库内任何文件。对照 6 条逐项核对,并列出需补全/修正的细节以达「绝对零影响」。


一、6 条零影响条件对照

# 条件 本版代码 结论
1 VerticalScreenPlayerView init 保持 6 参 init(courseId, nodeId, initialScrollIndex, navigationPath?, isLastNode?, courseTitle?) 完整保留 满足
2 保留 CourseNavigation.completion 及三处 destination 未改枚举与三 TabCompletionView 三参destination 调用不变 满足
3 CompletionView 保留三参 courseId, courseTitle, completedLessonCount 均有 满足
4 LessonPageView 仍传 courseTitle、navigationPath courseTitle: mapData?.courseTitlenavigationPath: navigationPath ⚠️ 见下 4.1
5 保留 loadError、toast、hideTabBar/showTabBar、handleBack(path 优先) 错误态、toast、tabBar、handleBack 均保留 ⚠️ 见下 5.1、5.2
6 NoteTreeView / NoteListView 不修改 init 未改,笔记流仍只传 3 参 满足

二、CompletionView 审查

  • 接口courseId / courseTitle / completedLessonCount 全保留,与 CourseNavigation.completion 及三处 destination 一致。
  • 内部:纯 UI粉紫勋章+ navStore.switchToGrowthTab(),无 navigationPath、无侧滑 Hack。
  • 视觉:顶部「已完成」、底部「回到我的内容」淡蓝、无返回按钮。与需求一致。
  • 无遗漏:无依赖 dismiss、无依赖 path作为 TabView 一页或作为 push 目标均可。

结论CompletionView 满足零影响条件,无需改动。


三、VerticalScreenPlayerView 审查

3.1 已满足项

  • Init6 参完整,与现有 GrowthView / ProfileView / DiscoveryView / NoteTreeView / NoteListView 调用兼容。
  • PlayerItemlesson(MapNode) + completionid 分别为 node.id 与 "COMPLETION_PAGE"
  • loadMapDatarealNodes + append(.completion)allItems 构造正确loadError = nil 与 catch 内 set loadError 均有。
  • currentPositionProgress:仅用 lesson 项计算,完结页时返回 1.0,逻辑正确。
  • handleBackpath 非空则 removeLast(),否则 dismiss()。
  • hideTabBar / showTabBar / toast:保留。
  • LessonPageView:传 courseId, nodeId, currentGlobalNodeId, initialScrollIndex, headerConfig, courseTitle, navigationPath。
  • CompletionView内嵌:传 courseId, courseTitle, completedLessonCount。

3.2 需补全或修正的细节(达「绝对零影响」)

4.1 LessonPageView 的 courseTitle 传参(对应条件 4

  • 本版courseTitle: mapData?.courseTitle(仅用加载后的 mapData
  • 当前实现courseTitle: courseTitle(用调用方传入的 courseTitle如 MapView 的 data.courseTitle
  • 差异:加载完成前 mapData 为 nil本版会传 nil当前实现一进入就有值。若希望与现有行为完全一致建议传 courseTitle ?? mapData?.courseTitle,优先用传入值,再回退到加载结果。

5.1 loadMapData 失败时的 Toast对应条件 5

  • 当前实现catch 中除 set loadError 外,还调用 showToastMessage("加载失败")
  • 本版catch 中只 set loadError未调用 showToastMessage。
  • 建议:在 catch 的 MainActor.run 内补上 showToastMessage("加载失败"),与现有体验一致。

5.2 isFirstNodeInChapter 实现(对应条件 5逻辑不变

  • 当前实现:在 chapter 内取 validNodes = chapter.nodes.filter(locked).sorted { $0.order < $1.order },再 validNodes.first?.id == nodeId(即按 order 排序后的「第一章第一节」)。
  • 本版chapter.nodes.filter(locked).first,未按 order 排序,相当于用数组顺序的「第一个」。
  • 风险:若后端/本地 chapter.nodes 顺序与 order 不一致,本版可能与当前表现不同。
  • 建议:与当前保持一致,使用 validNodes = chapter.nodes.filter { $0.status != .locked }.sorted { $0.order < $1.order },再 validNodes.first?.id == nodeId

5.3 其他可选一致性(非必须)

  • 空状态文案:当前为「暂无内容」+「该课程还没有可用的学习内容」;本版为「暂无内容」+ 单行。若需完全一致可补副标题,否则可保留本版简化。
  • GeometryReader:当前 body 最外层包了一层 GeometryReader本版未包。若当前无依赖 geo 的布局,可不再加;若有,需保留或等价处理。
  • ImporthideTabBar/showTabBar 使用 UIApplicationimport UIKit。若文件当前已含 UIKit 则无需改;否则需补。

四、对外暴露与调用方

调用方 / 入口 是否需改 说明
GrowthView / ProfileView / DiscoveryView.player / .completion init 与 CompletionView 三参未变
MapViewappend .player 枚举与参数不变
NoteTreeView / NoteListView.player 仍只传 3 参,可选参默认 nil
CourseNavigation 枚举 未改
navigationDestination(.completion) 仍用 CompletionView(courseId, courseTitle, completedLessonCount)

结论:在补全 4.1、5.1、5.2 后,对外接口与所有调用方均可保持零改动、零行为差异。


五、审查结论汇总

项目 结论
6 条零影响 条件 1、2、3、6 已满足;条件 4、5 在按 3.2 补全后可达「绝对零影响」。
CompletionView 可直接采用,无需改。
VerticalScreenPlayerView 建议补全:① LessonPageView 传 courseTitle ?? mapData?.courseTitle;② loadMapData 失败时 showToastMessage("加载失败");③ isFirstNodeInChapter 按 order 排序取 first。
其他页面 / 功能 / 逻辑 在以上补全前提下,其他页面、其他功能、其他逻辑均不受影响。

未对仓库内任何文件进行修改。