74 lines
3.9 KiB
Markdown
74 lines
3.9 KiB
Markdown
|
|
# 完成页「最终交付 · 逻辑回滚」审查报告(禁止应用)
|
|||
|
|
|
|||
|
|
**审查对象**:isFirstNodeInChapter 已恢复为含 `.sorted { $0.order < $1.order }` 的最终交付代码;确认不影响现有逻辑与展示。
|
|||
|
|
**结论**:仅审查,不修改仓库内任何文件。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、isFirstNodeInChapter 与当前仓库一致性
|
|||
|
|
|
|||
|
|
| 项目 | 当前仓库 | 本版交付 | 结论 |
|
|||
|
|
|------|----------|----------|------|
|
|||
|
|
| **排序** | `validNodes = chapter.nodes.filter(...).sorted { $0.order < $1.order }` | 同:`.filter { $0.status != .locked }.sorted { $0.order < $1.order }` | ✅ 一致 |
|
|||
|
|
| **首节判定** | `validNodes.first?.id == nodeId`(在「包含 nodeId 的 chapter」内) | `validNodes.first?.id == nodeId`(遍历每章,等价语义) | ✅ 等价 |
|
|||
|
|
|
|||
|
|
本版写法:对每章取 `validNodes`(filter + sort by order),若 `validNodes.first?.id == nodeId` 则返回 true。
|
|||
|
|
当前写法:先找到包含 nodeId 的 chapter,再在该章内取 validNodes(filter + sort by order),返回 `validNodes.first?.id == nodeId`。
|
|||
|
|
二者语义相同:「nodeId 是否为其所在章内按 order 排序后的第一个未锁定节点」。
|
|||
|
|
**结论**:章节判定逻辑与现有实现保持 100% 一致,未改动核心逻辑。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、loadMapData:无全局排序
|
|||
|
|
|
|||
|
|
- **本版**:`realNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked }`,无 `.sorted`。
|
|||
|
|
- **当前**:`allCourseNodes = data.chapters.flatMap { $0.nodes }.filter { $0.status != .locked }`,无排序。
|
|||
|
|
|
|||
|
|
**结论**:保持「章节顺序 + 数组顺序」,未引入任何重排,与现有逻辑一致。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、CompletionView
|
|||
|
|
|
|||
|
|
- **职责**:仅 UI(粉紫勋章、共完成 N 节、底部「回到我的内容」)+ `navStore.switchToGrowthTab()`,无业务/数据逻辑。
|
|||
|
|
- **接口**:courseId / courseTitle / completedLessonCount 三参保留,与 CourseNavigation.completion 及三处 destination 兼容。
|
|||
|
|
- **操作**:全量替换 `Views/CompletionView.swift` 即可。
|
|||
|
|
|
|||
|
|
**结论**:仅完结页 UI 更新,不影响现有逻辑与展示。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、VerticalScreenPlayerView
|
|||
|
|
|
|||
|
|
### 4.1 已核对项
|
|||
|
|
|
|||
|
|
- **Init**:6 参未改,外部调用零影响。
|
|||
|
|
- **loadMapData**:flatMap + filter,无 sort;allItems = realNodes.map(.lesson) + append(.completion)。
|
|||
|
|
- **isFirstNodeInChapter**:含 `.sorted { $0.order < $1.order }`,与当前仓库等价。
|
|||
|
|
- **getChapterTitle**:与当前一致。
|
|||
|
|
- **currentPositionProgress**:仅按 lesson 项计算,忽略完结页。
|
|||
|
|
- **handleBack / 错误态 / toast / hideTabBar / showTabBar**:均保留。
|
|||
|
|
- **LessonPageView**:传 `self.courseTitle ?? mapData?.courseTitle`、navigationPath;headerConfig 仍用 isFirstNodeInChapter / getChapterTitle。
|
|||
|
|
- **CompletionView(内嵌)**:courseId、courseTitle、completedLessonCount。
|
|||
|
|
|
|||
|
|
### 4.2 合并范围(再次强调)
|
|||
|
|
|
|||
|
|
- **仅替换** `struct VerticalScreenPlayerView { ... }` 及内部的 `enum PlayerItem`。
|
|||
|
|
- **不得删除** 同文件内的 HeaderConfig、DuolingoProgressBar、CourseProgressNavBar、LessonPageView、LessonSkeletonView、LessonErrorView、CompletionPlaceholderPage(或占位相关)等其余类型。
|
|||
|
|
|
|||
|
|
**结论**:在仅替换主视图 Struct 的前提下,现有逻辑与展示不受影响。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、审查结论汇总
|
|||
|
|
|
|||
|
|
| 项目 | 结论 |
|
|||
|
|
|------|------|
|
|||
|
|
| **isFirstNodeInChapter** | 已恢复为含 `.sorted { $0.order < $1.order }` 的写法,与当前仓库语义一致,未改动核心判定逻辑。 |
|
|||
|
|
| **loadMapData** | 无全局排序,保持原有顺序。 |
|
|||
|
|
| **CompletionView** | 仅 UI 更新,可全量替换。 |
|
|||
|
|
| **VerticalScreenPlayerView** | 仅替换主视图 Struct,保留同文件其余代码;其他逻辑与展示不变。 |
|
|||
|
|
| **现有逻辑与展示** | 在按上述范围替换的前提下,不会受到影响。 |
|
|||
|
|
|
|||
|
|
**未对仓库内任何文件进行修改。**
|