# 完成页「统一分页架构」— 审查报告(禁止应用) **审查对象**:虚拟节点 (PlayerItem.completion) 作为 TabView 最后一页,CompletionView 内嵌于播放器;是否导致「完成小节统计虚高」。 **结论**:仅审查,不修改仓库内任何文件。 --- ## 一、核心问题:会不会导致完成小节统计虚高? **结论:不会。** ### 1.1 数据流梳理 | 环节 | 来源 / 行为 | 是否计入「完成小节」 | |------|-------------|----------------------| | **展示数字** | CompletionView 显示的 `completedLessonCount` 来自 `UserManager.shared.studyStats.lessons` | 仅展示,不写入 | | **统计来源** | `studyStats.lessons` 由后端/用户接口(如 `completed_lessons`)拉取并写入 UserManager | 后端口径为真实完课数 | | **完课上报** | 仅在 **LessonPageView** 内,当该节进度 ≥ 1.0 时调用 `LearningService.shared.completeLesson(nodeId: ...)` | 只对**真实课程节点**上报 | | **虚拟节点** | `PlayerItem.completion` 仅存在于前端的 `allItems`,id 为 `"COMPLETION_PAGE"` | 不参与任何完课 API,无 nodeId | ### 1.2 为何不会虚高 - **总结页不是一节课**:虚拟节点只用于 TabView 的「最后一页」展示,没有对应的 `MapNode`,也不会调用 `completeLesson(nodeId:)`。 - **完课只发生在 LessonPageView**:只有渲染 `PlayerItem.lesson(node)` 时才会加载该节的进度、在达到条件时上报完课;渲染 `PlayerItem.completion` 时只渲染 CompletionView,没有任何完课或统计写入逻辑。 - **展示用既有统计**:CompletionView 只是读取并展示 `UserManager.shared.studyStats.lessons`,不修改该值;该值的增加只来自真实小节在 LessonPageView 中的完课上报与后端同步。 因此:**把总结页当作 TabView 最后一页、用虚拟节点渲染 CompletionView,不会把总结页算成一节,也不会导致完成小节统计虚高。** --- ## 二、方案本身审查(与当前实现对比) ### 2.1 优点 - **交互统一**:左滑/右滑完全由 TabView(UIScrollView)负责,无需自定义 DragGesture、无需 SwipeBackEnabler。 - **CompletionView 职责单一**:只做 UI 与「回到技能页根」按钮,不碰 navigationPath、不碰侧滑 Hack。 - **状态集中**:完结页是 `PlayerItem` 枚举的一支,与课程节点同属一个数据源,逻辑清晰。 ### 2.2 需注意的改动(若将来应用) 1. **VerticalScreenPlayerView 的 init** 方案中去掉了 `navigationPath`、`isLastNode`、`courseTitle`。当前 **GrowthView / ProfileView / DiscoveryView** 的 `.player` 分支会传这三个参数;若直接按方案改 init,调用方会报错。需要二选一: - 保留这三个参数(兼容现有调用),或 - 同时改三处调用方,不再传这些参数。 2. **CompletionView 的接口** 方案中 CompletionView 只有 `courseTitle` 和 `completedLessonCount`(无 `courseId`)。若项目中别处仍通过 `CourseNavigation.completion(courseId: ...)` 等 push 进 CompletionView,则需保留 `courseId` 或同步改那些入口。 3. **进度条与 TabBar** 当前实现有 `currentPositionProgress`(不含占位页)、hideTabBar/showTabBar、loadError、toast 等。方案里进度条在 `currentNodeId == "COMPLETION_PAGE"` 时隐藏,其余若省略需确认是否要保留(如错误态、toast、tabBar 隐藏)。 4. **笔记流** NoteTreeView / NoteListView 里用的 VerticalScreenPlayerView 目前传的是 `NoteNavigationDestination.player`,不传 navigationPath。若播放器 init 去掉 navigationPath,笔记流不受影响;若保留可选 navigationPath 以兼容,也需在方案里写明。 --- ## 三、审查结论汇总 | 问题 | 结论 | |------|------| | **会不会导致完成小节统计虚高?** | **不会**。总结页只是虚拟的一页,用于展示;完课统计只由 LessonPageView 对真实节点调用 completeLesson 产生,CompletionView 仅读取 studyStats.lessons 做展示。 | | 统一分页架构本身 | 交互简单、无需手势与侧滑 Hack,CompletionView 可做纯 UI;若应用需处理 init 与调用方兼容、以及错误/toast/tabBar 等现有能力是否保留。 | **未对仓库内任何文件进行修改。**