90 lines
6.1 KiB
Markdown
90 lines
6.1 KiB
Markdown
|
|
# 完成页「最终修正版」代码审查报告(禁止应用)
|
|||
|
|
|
|||
|
|
**审查对象**:基于零影响审查报告修正后的 CompletionView + VerticalScreenPlayerView 最终版(参数优先、错误 Toast、排序逻辑、接口兼容)。
|
|||
|
|
**结论**:仅审查,不修改仓库内任何文件。核对三项修正与 6 条零影响条件,并说明应用时的合并范围。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、三项修正落实情况
|
|||
|
|
|
|||
|
|
| 修正项 | 审查报告要求 | 本版代码 | 结论 |
|
|||
|
|
|--------|----------------|----------|------|
|
|||
|
|
| **参数优先权** | LessonPageView 传 `courseTitle ?? mapData?.courseTitle` | `courseTitle: self.courseTitle ?? mapData?.courseTitle`(LessonPageView 与 CompletionView 均用) | ✅ 已落实 |
|
|||
|
|
| **错误处理** | loadMapData 失败时 `showToastMessage("加载失败")` | catch 内 `self.showToastMessage("加载失败")` | ✅ 已落实 |
|
|||
|
|
| **排序逻辑** | isFirstNodeInChapter 用 `validNodes.sorted { $0.order < $1.order }` 再取 first | `validNodes = chapter.nodes.filter(...).sorted { $0.order < $1.order }`,再 `validNodes.first?.id == nodeId` | ✅ 已落实 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、6 条零影响条件核对
|
|||
|
|
|
|||
|
|
| # | 条件 | 本版代码 | 结论 |
|
|||
|
|
|---|------|----------|------|
|
|||
|
|
| 1 | VerticalScreenPlayerView init 保持 6 参 | `init(courseId, nodeId, initialScrollIndex, navigationPath?, isLastNode?, courseTitle?)` 完整 | ✅ |
|
|||
|
|
| 2 | 保留 CourseNavigation.completion 及三处 destination | 未改枚举与三 Tab;CompletionView 三参 | ✅ |
|
|||
|
|
| 3 | CompletionView 保留三参 | courseId, courseTitle, completedLessonCount | ✅ |
|
|||
|
|
| 4 | LessonPageView 传 courseTitle、navigationPath | `self.courseTitle ?? mapData?.courseTitle`,`navigationPath` 透传 | ✅ |
|
|||
|
|
| 5 | 保留 loadError、toast、hideTabBar/showTabBar、handleBack(path 优先) | 错误态、toast、tabBar、handleBack 均保留;loadMapData 失败有 showToastMessage | ✅ |
|
|||
|
|
| 6 | NoteTreeView / NoteListView 不修改 | init 未改,笔记流仍只传 3 参 | ✅ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、CompletionView 审查
|
|||
|
|
|
|||
|
|
- **接口**:courseId / courseTitle / completedLessonCount 全保留,与 CourseNavigation.completion 及三处 destination 一致。✅
|
|||
|
|
- **内部**:纯 UI(粉紫勋章)+ handleReturnToRoot() → navStore.switchToGrowthTab(),无 navigationPath、无侧滑 Hack。✅
|
|||
|
|
- **视觉**:顶部「已完成」、底部「回到我的内容」淡蓝、无返回按钮。✅
|
|||
|
|
|
|||
|
|
**结论**:CompletionView 可直接全量替换 `Views/CompletionView.swift`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、VerticalScreenPlayerView 审查与合并范围
|
|||
|
|
|
|||
|
|
### 4.1 本版已包含且正确的部分
|
|||
|
|
|
|||
|
|
- Init 6 参、PlayerItem 枚举、allItems 数据源、loadMapData(realNodes + append .completion)、currentPositionProgress(仅 lesson)、handleBack(path 优先)、hideTabBar/showTabBar、showToastMessage、错误态 UI、toast、isFirstNodeInChapter(含 .sorted { $0.order < $1.order })、getChapterTitle。✅
|
|||
|
|
|
|||
|
|
### 4.2 应用时必须注意的合并范围(未应用,仅说明)
|
|||
|
|
|
|||
|
|
当前 **VerticalScreenPlayerView.swift** 文件中除 `VerticalScreenPlayerView` 结构体外,还包含:
|
|||
|
|
|
|||
|
|
- **HeaderConfig**、**DuolingoProgressBar**、**CourseProgressNavBar**(播放器依赖)
|
|||
|
|
- **CompletionPlaceholderPage** 或 **LastPageSwipeModifier**(本方案中不再需要,可删除)
|
|||
|
|
- **LessonPageView**、**LessonSkeletonView**、**LessonErrorView** 及后续所有类型与扩展
|
|||
|
|
|
|||
|
|
你提供的「最终修正版」只包含 **VerticalScreenPlayerView 结构体** 及 **PlayerItem** 枚举,未包含上述类型。因此:
|
|||
|
|
|
|||
|
|
- **不能**用该片段整文件覆盖 **VerticalScreenPlayerView.swift**,否则会删掉 HeaderConfig、CourseProgressNavBar、LessonPageView 等,导致编译失败。
|
|||
|
|
- **正确做法**:在 **VerticalScreenPlayerView.swift** 内只做「局部替换」:
|
|||
|
|
- 用本版的 **VerticalScreenPlayerView 结构体**(含 PlayerItem、body、loadMapData、handleBack、isFirstNodeInChapter 等)替换现有的 **VerticalScreenPlayerView** 结构体;
|
|||
|
|
- 删除 **CompletionPlaceholderPage**(或占位页相关逻辑),不再添加 LastPageSwipeModifier;
|
|||
|
|
- **保留** 文件内 **HeaderConfig**、**DuolingoProgressBar**、**CourseProgressNavBar**、**LessonPageView**、**LessonSkeletonView**、**LessonErrorView** 及之后所有内容不变。
|
|||
|
|
|
|||
|
|
### 4.3 realNodes 的 .sorted 与当前行为差异(可选核对)
|
|||
|
|
|
|||
|
|
- **本版**:`let realNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked }.sorted { $0.order < $1.order }`
|
|||
|
|
即对 **整课** 的节点列表按 `node.order` 做一次全局排序。
|
|||
|
|
- **当前实现**:`allCourseNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked }`
|
|||
|
|
即 **不** 对 flatMap 后的列表排序,顺序为:先 chapter 顺序,再各 chapter 内 nodes 的数组顺序。
|
|||
|
|
|
|||
|
|
若后端 `node.order` 是 **按章节内** 的(例如每章都是 0,1,2,…),则对整课 flat 列表只按 `order` 排序会 **打乱章节顺序**(例如把各章 order=0 的节点排在一起)。若希望与当前行为完全一致,可考虑:
|
|||
|
|
|
|||
|
|
- 要么 **去掉** realNodes 的 `.sorted { $0.order < $1.order }`,保持与当前一致的「章节顺序 + 章内数组顺序」;
|
|||
|
|
- 要么在确认后端 `order` 为全局唯一或全局有序的前提下保留当前排序。
|
|||
|
|
|
|||
|
|
是否保留该 sort,可根据产品/后端约定决定;不影响三项修正与 6 条零影响条件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、审查结论汇总
|
|||
|
|
|
|||
|
|
| 项目 | 结论 |
|
|||
|
|
|------|------|
|
|||
|
|
| **三项修正** | 参数优先权、错误 Toast、isFirstNodeInChapter 排序均已落实。 |
|
|||
|
|
| **6 条零影响** | 全部满足;对外接口与调用方无需改动。 |
|
|||
|
|
| **CompletionView** | 可直接全量替换 `ios/WildGrowth/WildGrowth/Views/CompletionView.swift`。 |
|
|||
|
|
| **VerticalScreenPlayerView** | 仅可替换 **结构体** 并删除占位页相关类型;必须保留同文件内 HeaderConfig、CourseProgressNavBar、LessonPageView 等所有其他类型,不能整文件覆盖。 |
|
|||
|
|
| **realNodes 排序** | 与当前实现存在差异,是否保留 `.sorted { $0.order < $1.order }` 需结合后端 order 语义决定。 |
|
|||
|
|
|
|||
|
|
**未对仓库内任何文件进行修改。**
|