diff --git a/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate b/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate index ef0ae12..98c9ed4 100644 Binary files a/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate and b/AIStudyApp/AIStudyApp.xcodeproj/project.xcworkspace/xcuserdata/Admin1.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/AIStudyApp/AIStudyApp/Core/Network/APIConfig.swift b/AIStudyApp/AIStudyApp/Core/Network/APIConfig.swift index 4b15c6d..27786e9 100644 --- a/AIStudyApp/AIStudyApp/Core/Network/APIConfig.swift +++ b/AIStudyApp/AIStudyApp/Core/Network/APIConfig.swift @@ -5,7 +5,11 @@ import Foundation enum APIConfig { + #if DEBUG + static let baseURL = "http://127.0.0.1:3000/api" + #else static let baseURL = "https://api.longde.cloud/api" + #endif static let timeout: TimeInterval = 30 diff --git a/AIStudyApp/Info.plist b/AIStudyApp/Info.plist index 5a2a91f..8e43e60 100644 --- a/AIStudyApp/Info.plist +++ b/AIStudyApp/Info.plist @@ -20,6 +20,11 @@ $(MARKETING_VERSION) CFBundleVersion $(CURRENT_PROJECT_VERSION) + NSAppTransportSecurity + + NSAllowsLocalNetworking + + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/docs/system-map/capabilities/01-文档阅读.md b/docs/system-map/capabilities/01-文档阅读.md new file mode 100644 index 0000000..5c7fc54 --- /dev/null +++ b/docs/system-map/capabilities/01-文档阅读.md @@ -0,0 +1,421 @@ +# 01 文档阅读 — 跨项目完整能力分析 + +> 试点能力一:从 C 端业务能力"文档阅读"出发,跨项目完整整理。 +> 项目角色分类:主链路(iOS、Rust Document Runtime、主 API、数据库/COS)、上游支撑(Python RAG)、下游消费(Heavy Runtime)、运维可观测(Admin)。 + +--- + +## 1. 能力目标 + +用户能够在知习 App 中流畅地阅读上传到知识库的学习资料,支持多种文件格式,自动记录阅读位置,标记已读状态,并在下次打开时从上次中断处继续阅读。 + +--- + +## 2. C 端入口 + +用户可以从以下 iOS 页面进入文档阅读: + +| 入口页面 | 触发方式 | 进入场景 | +|---------|---------|---------| +| 学习主页 | 点击主操作卡片("继续上次学习") | 继续上次未读完的资料 | +| 知识库详情页·来源 Tab | 点击来源文件条目 | 阅读知识库中的资料 | +| 知识点详情页 | 点击"阅读原文件"或自动渲染 | 阅读知识点关联的原始资料 | +| 学习分析页 | 点击"继续阅读"卡片 | 从分析页继续阅读 | +| AI 反馈页 | "加入待巩固" → 学习主页 → 资料阅读 | 间接进入 | + +在资料阅读页中,用户可以执行以下操作: + +- 阅读内容(滚动浏览,支持 Markdown/纯文本/图片/EPUB 的原生渲染) +- 系统预览 PDF、Word、Excel(通过 QuickLook) +- 外部打开 PowerPoint(通过 ShareLink) +- 标记已读(本地即时生效,marked_as_read 事件异步上报) +- 取消标记已读(本地即时生效,服务端同步方式暂未确认) +- 打开 AI 对话(资料范围,需 RAG 已完成向量化才能获得语义检索结果) +- 查看资料详情(元数据、AI 处理状态、阅读进度) +- 开始专注学习会话(主动计时) +- 添加笔记(自动记录锚点位置) + +--- + +## 3. 用户主流程 + +以下使用纯业务语言描述用户从进入资料到退出阅读的完整流程: + +1. **进入资料:** 用户从知识库来源文件列表、继续学习推荐或知识点详情中点击资料,进入资料阅读页。 + +2. **资料加载:** App 检查设备上是否已有该文件。 + - 如果有本地文件:直接打开。 + - 如果没有:从云端 COS 下载文件到本地缓存目录。 + - 只要资料记录存在、用户有访问权限且 COS/本地文件可用,用户即可阅读原文件,不需要等待 Python RAG 的文本解析、分块、向量化和索引完成。 + +3. **类型检测与渲染:** 系统检测文件类型,根据类型选择渲染方式。 + - Markdown/文本/图片/EPUB:由 Rust Document Runtime 解析并渲染为可读内容。 + - PDF/Word/Excel:提供"系统预览"按钮,用户点击后使用 iOS QuickLook 预览。 + - PowerPoint:提供"外部打开"按钮,用户点击后使用系统分享功能在外部应用打开。 + - 不支持的格式:显示"暂不支持此格式"提示。 + +4. **自动阅读会话启动:** 用户进入资料阅读页时,系统自动创建阅读会话(无需用户手动操作)。iOS 调用 Rust Document Runtime 开启 V2 ReadingSession,生成唯一的 client_session_id。该会话自动推送 material_opened 事件。 + +5. **阅读位置恢复:** 系统按优先级恢复上次阅读位置。 + - 优先:从服务端 API 查询该资料的阅读进度(上次位置)。 + - 其次:从本地缓存读取上次位置。 + - 最后:从当前 Rust 阅读会话的 lastPosition 恢复。 + +6. **阅读中:** 用户滚动浏览内容。 + - 系统自动记录阅读位置(2 秒防抖,iOS 调用 Rust push_position_changed)。 + - iOS 创建并管理 15 秒心跳定时器,仅在阅读会话为 active 且 App 位于前台时触发。每次 Tick 调用 Rust heartbeat 接口,Rust 根据 ActiveTimeTracker 计算 activeSecondsDelta 后创建 heartbeat 事件并写入缓冲区。 + - Rust 不创建也不管理 iOS 的系统定时器。 + +7. **前后台切换:** 用户将 App 切到后台时,iOS 暂停心跳定时器,阅读会话自动暂停,时间跟踪停止。切回前台时自动恢复。 + +8. **标记已读:** 用户点击工具栏"标记已读"按钮。该操作在本地 UserDefaults 立即更新,同时推送 marked_as_read 事件到 Rust 缓冲区,后续通过上传链路同步至服务端。取消标记已读可在本地即时生效,但服务端同步方式暂未确认(当前事件模型只有 marked_as_read,没有 unmarked_as_read)。 + +9. **添加笔记:** 用户点击工具栏笔记按钮,弹出快速笔记 Sheet。系统自动捕获当前阅读位置作为笔记锚点。用户输入笔记文字并保存(本地 UserDefaults 存储)。 + +10. **AI 对话(资料范围):** 用户点击工具栏 AI 按钮,跳转到 AI 对话页。对话自动限定在当前资料范围内。如果 Python RAG 已完成该资料的向量化索引,AI 可通过语义检索引用资料内容回答用户问题;如果 RAG 未完成,AI 范围对话、语义检索和知识点候选提取可能暂不可用。 + +11. **开始专注学习会话:** 用户点击工具栏"开始学习"按钮,启动专注学习计时器。计时器以 1 秒精度运行,默认目标 30 分钟。该学习会话是用户主动发起的专注时段,与进入资料时自动创建的阅读会话是不同的业务对象。 + +12. **退出阅读:** 用户返回上一页或切换到其他 Tab。 + - iOS 调用 Rust close_reading_session,Rust 计算最终活跃时长增量,推送 material_closed 事件。 + - 阅读位置保存到本地缓存。 + - iOS 周期性地从 Rust 导出已缓冲事件,写入本地持久化上传队列,后续由队列负责 API 上传。 + +--- + +## 4. 项目参与关系 + +### iOS(AIStudyApp)— 主链路参与者 + +**职责:** +- 提供资料阅读页的用户界面 +- 调用 Rust Document Runtime(通过 UniFFI FFI)进行文件解析 +- 管理 COS 文件下载和本地文件缓存 +- 驱动自动阅读会话生命周期(调用 Rust V2 Session API) +- 创建并管理 15 秒心跳定时器(仅在 session active 且前台时触发) +- 驱动阅读事件采集(调用 Rust push 函数 + heartbeat 接口) +- 管理本地上传队列:将 Rust 导出事件映射为 UploadItem、写入持久化队列、确认 Rust 交接完成 +- 管理阅读位置本地缓存 +- 提供系统预览和外部打开能力 +- 提供笔记创建界面和本地存储 +- 提供标记已读本地缓存 +- 前台/后台切换时管理会话暂停/恢复和心跳定时器启停 +- App 被杀死后重启时执行崩溃恢复 + +### Rust Document Runtime(zhixi-document-runtime)— 主链路参与者 + +**职责:** +- 检测文件类型(根据扩展名和文件内容推断 MaterialType) +- 解析 Markdown 为结构化文档块树 +- 解析纯文本为段落块 +- 提取 EPUB 章节结构和元数据 +- 提取 PDF 页数和基本文本(用于搜索) +- 提取图片元数据 +- 管理自动阅读会话(V2 ReadingSession:start、pause、resume、close、interrupt) +- 管理阅读事件缓冲区(push、export、ack、reload) +- 根据 ActiveTimeTracker 计算 activeSecondsDelta(由 iOS heartbeat tick 触发) +- 提供阅读位置模型 +- 提供文件搜索能力 +- 提供笔记锚点模型 +- 提供活跃时间跟踪器 +- 提供崩溃恢复机制(stale event reload、stale session cleanup) + +**不负责:** 网络请求、COS 下载、API 调用、用户认证、UI 渲染、Office 文件高清预览、PDF 完整渲染、iOS 系统定时器创建和管理。 + +### 主 API(api-server)— 主链路参与者 + +**职责:** +- 提供资料信息查询 +- 提供文件下载 URL(COS 预签名 URL) +- 提供资料阅读进度查询 +- 接收并处理阅读事件批量上传 +- 将原始阅读事件聚合为:自动阅读会话(LearningSession)、资料阅读进度、每日学习活动、学习记录 +- 提供文件上传 URL +- 管理知识源的三个处理状态(parseStatus、indexStatus、learningStatus) +- 提供继续学习推荐 +- 提供学习摘要 +- 提供阅读趋势 + +### Python RAG Worker — 上游支撑 + +**不直接参与文档阅读。** 只要资料记录、文件访问权限和 COS/本地文件可用,用户即可阅读原文件。Python RAG 负责文档导入后的异步处理(下载上传的文件 → 解析文本内容 → 分块 → 向量化嵌入 → 存入 Qdrant → AI 提取候选知识点)。RAG 未完成时,阅读原文件不受影响,但资料范围 AI 问答的语义检索和知识点候选提取可能暂不可用。 + +### Heavy Runtime — 下游数据消费者 + +**不直接参与文档阅读。** 消费已聚合的阅读数据,生成 AI 分析结果(掌握度评估、薄弱点识别、学习建议、测验题目、闪卡)。位于阅读数据采集链的下游,不属于用户阅读时的同步调用链。 + +### Admin(admin-projects)— 运维与可观测 + +**不属于用户阅读时的同步调用链。** 职责包括: +- 知识库来源文件列表查看 +- 来源文件详情查看(含解析状态、索引状态) +- 文件管理(查看、删除上传文件) +- 资料阅读进度查看 +- 资料诊断 +- 文档导入监控与重试 + +--- + +## 5. 项目间调用关系 + +### 5.1 iOS → Rust Document Runtime + +| 调用目的 | 调用方向 | 业务结果 | +|---------|---------|---------| +| 检测文件类型 | iOS → Rust | 返回 MaterialType 和 PreviewMode 建议 | +| 解析 Markdown/文本文件 | iOS → Rust | 返回 DocumentBlock 数组 | +| 提取 EPUB/PDF/图片信息 | iOS → Rust | 返回对应元数据 | +| 搜索文档内容 | iOS → Rust | 返回 SearchResult 列表 | +| 开启自动阅读会话 | iOS → Rust | 创建 V2 ReadingSession,返回 client_session_id | +| 推送阅读事件 | iOS → Rust | 事件进入内存缓冲区(Pending 状态) | +| 心跳 Tick | iOS → Rust | Rust 计算 activeSecondsDelta,创建 heartbeat 事件写入缓冲区 | +| 导出待交接事件 | iOS → Rust | 返回 Exported 状态的事件列表,交接给 iOS | +| 确认事件交接完成 | iOS → Rust | 已 Ack 的事件从 Rust 缓冲区移除(交接给 iOS 本地队列后立即调用) | +| 崩溃恢复 | iOS → Rust | Exported 未 Ack 事件重置为 Pending | +| 清理过期会话 | iOS → Rust | 超时会话标记为 Interrupted 并从内存移除 | + +### 5.2 iOS → 主 API + +| 调用目的 | 调用方向 | 业务结果 | +|---------|---------|---------| +| 获取文件下载 URL | iOS → API | 返回 COS 预签名下载链接 | +| 查询阅读进度 | iOS → API | 返回上次阅读位置、累计阅读时长、是否已读 | +| 上传阅读事件批次 | iOS → API | 从 iOS 本地持久化队列发起,返回 processed/duplicate/failed 计数 | +| 查询继续学习 | iOS → API | 返回最近阅读的资料信息 | +| 查询学习摘要/趋势 | iOS → API | 返回聚合数据 | +| 查询资料信息 | iOS → API | 返回知识源详情 | + +### 5.3 主 API 内部调用 + +| 调用目的 | 调用方向 | 业务结果 | +|---------|---------|---------| +| 阅读事件处理 | API 内部(同步事务) | 事件入库 → 聚合自动阅读会话 → 聚合阅读进度 → 聚合每日活动 → 创建学习记录 | +| 资料解析触发 | API → Redis 队列 | 将资料加入 document-import 队列,由 Python RAG Worker 异步处理(不阻塞阅读) | + +### 5.4 Admin → 主 API(运维可观测,非同步调用链) + +| 调用目的 | 调用方向 | 业务结果 | +|---------|---------|---------| +| 查看知识库来源文件 | Admin → API | 返回来源文件列表(含解析和索引状态) | +| 查看/删除文件 | Admin → API | 文件管理 | +| 查看资料阅读进度 | Admin → API | 阅读进度详情 | +| 资料诊断 | Admin → API | 全部阅读数据和关联会话 | +| 文档导入监控/重试 | Admin → API | 导入任务列表、重试失败任务 | + +--- + +## 6. 核心业务数据 + +### 6.1 资料(Material / KnowledgeSource) + +- **谁创建:** iOS 用户在导入资料页或添加知识点页上传文件后,API 创建 KnowledgeSource 记录。 +- **谁更新:** Python RAG Worker 更新解析状态和索引状态(异步,不阻塞阅读);API 在处理阅读事件时更新关联的阅读状态。 +- **谁查询:** iOS 在知识库详情页来源 Tab 查询列表、在资料详情页查询详情;Admin 在来源文件页查询列表。 +- **用于什么功能:** 知识库内容组织、文档阅读入口、资料处理状态展示。 + +### 6.2 阅读位置(ReadingPosition) + +- **谁创建:** Rust Document Runtime 在 iOS 推送 position_changed 事件时创建。 +- **谁更新:** 每次用户滚动时更新(2 秒防抖),由 Rust Document Runtime 维护 last_position。 +- **谁查询:** iOS 在进入阅读页时恢复上次位置(优先 API、其次本地缓存、最后会话位置);API 在阅读进度查询时返回。 +- **用于什么功能:** 跨会话的阅读位置恢复、"继续学习"推荐。 + +### 6.3 自动阅读会话(ReadingSession,Rust V2) + +- **谁创建:** Rust Document Runtime 在 iOS 调用 start_reading_session 时创建(用户进入资料阅读页时自动触发,无需用户手动操作)。 +- **谁更新:** Rust 在每次事件推送时更新内存中的会话状态(lastEventAt、totalActiveSeconds、lastPosition)。 +- **谁查询:** iOS 在恢复会话时查询 lastPosition 用于位置恢复。 +- **用于什么功能:** 自动追踪单次阅读行为的持续时长和事件序号,管理阅读会话生命周期(active→paused→closed)。产生 opened、closed、position_changed、heartbeat、marked_as_read 事件。 + +### 6.4 专注学习会话(LearningSessionView 计时) + +- **谁创建:** 用户主动点击资料阅读页工具栏"开始学习"按钮后,iOS 创建本地计时器。 +- **谁更新:** 用户操作暂停/继续/结束(含确认弹窗),计时器以 1 秒精度运行,默认目标 30 分钟。 +- **谁查询:** iOS 学习会话页展示当前进度。 +- **用于什么功能:** 用户主动发起的专注学习时段计时。**与自动阅读会话(ReadingSession)是不同的业务对象。** 当前 iOS 是否调用专注学习会话 API(LearningSessionService)持久化仍标记为"暂未确认"。 + +### 6.5 阅读事件(ReadingEvent) + +- **谁创建:** Rust Document Runtime 创建(5 种事件类型:material_opened、material_closed、position_changed、heartbeat、marked_as_read)。 +- **谁更新:** 事件创建后不可修改。API 更新其处理状态(processing → processed/failed/duplicate)。 +- **谁查询:** API 在批处理时查重;Admin 在阅读事件列表和异常检测页查询。 +- **用于什么功能:** 所有学习分析的原始数据源。API 根据事件聚合自动阅读会话、阅读进度、每日活动、学习记录。 + +### 6.6 资料阅读进度(MaterialReadingProgress) + +- **谁创建:** API 在收到该资料的第一个阅读事件时自动创建。 +- **谁更新:** API 在每次事件处理事务中 upsert(递增总时长、更新最后位置、更新会话数、标记已读状态)。 +- **谁查询:** iOS 在进入阅读页时查询(恢复位置);Admin 在阅读进度页查询。 +- **用于什么功能:** 资料级别的阅读进度追踪、"继续学习"推荐的数据源、阅读统计。 + +### 6.7 笔记(QuickNote) + +- **谁创建:** iOS 用户在快速笔记 Sheet 中输入并保存时创建。 +- **谁更新:** 当前不支持修改(仅创建和删除)。 +- **谁查询:** iOS 在资料阅读页和知识点详情页查询(本地 UserDefaults)。 +- **用于什么功能:** 阅读过程中的快速记录。当前仅本地存储,未同步到服务端。 + +--- + +## 7. 查询入口 + +### 用户在哪里查看 + +- **阅读内容:** iOS 资料阅读页直接渲染文档内容。 +- **阅读进度:** iOS 资料详情页的阅读进度卡片(累计时长、阅读状态、上次阅读时间)。 +- **资料信息:** iOS 资料详情页(文件名、格式、大小、上传日期、AI 处理状态)。 +- **来源文件列表:** iOS 知识库详情页的来源 Tab。 +- **继续阅读:** iOS 学习主页的主操作卡片(继续上次学习)。 + +### Admin 在哪里查看(运维可观测) + +- **来源文件列表:** Admin 知识库→来源文件页(含解析状态、索引状态)。 +- **文件管理:** Admin 文件与 COS 管理页(按类型筛选、查看详情、删除)。 +- **阅读进度:** Admin 学习数据→阅读进度页(按用户/资料查看进度)。 +- **资料诊断:** Admin 学习数据→资料诊断页。 +- **导入监控:** Admin 知识库→文档导入监控页(任务状态、步骤日志、重试)。 + +### 系统内部在哪里使用 + +- **继续学习推荐:** API GET /learning/continue → iOS 学习主页优先级算法。 +- **学习摘要:** API GET /learning/summary → iOS 分析页 + 学习主页每周摘要。 +- **阅读趋势:** API GET /learning/trend → iOS 分析页阅读时长趋势图。 +- **学习记录:** API GET /learning/records → iOS 分析页最近学习记录。 +- **资料范围 AI 问答:** API 在 RAG 对话中根据资料范围检索相关 Chunk(依赖 Python RAG 的向量化结果;RAG 未完成时不可用)。 + +--- + +## 8. 修改入口 + +### 用户主动修改 + +- **标记已读:** iOS 资料阅读页工具栏按钮。本地 MarkedReadStore 即时生效,marked_as_read 事件通过事件采集链路上报。服务端同步已完成。 +- **取消标记已读:** 本地 MarkedReadStore 即时生效。服务端同步方式暂未确认(当前事件模型无 unmarked_as_read 事件类型)。 +- **添加笔记:** iOS 快速笔记 Sheet(本地 UserDefaults 存储)。 +- **删除来源文件:** iOS 知识库详情页来源 Tab 滑动删除(API 软删除)。 +- **开始/结束专注学习会话:** iOS 资料阅读页工具栏学习按钮 / 学习会话页结束按钮。 +- **上传新资料:** iOS 导入资料页(文件/相册/链接)。 + +### Admin 人工修改(运维可观测) + +- **删除文件:** Admin 文件管理页删除上传文件。 +- **重试导入:** Admin 文档导入监控页重试失败任务。 +- **重新解析:** Admin 可触发知识源的重新解析。 + +### 系统自动修改 + +- **阅读位置更新:** iOS 2 秒防抖自动调用 Rust push_position_changed。 +- **心跳:** iOS 15 秒定时器 Tick → 调用 Rust heartbeat 接口 → Rust 计算 activeSecondsDelta 并创建事件。 +- **阅读会话状态切换:** iOS 前后台切换时自动暂停/恢复 Rust ReadingSession,同步控制心跳定时器。 +- **阅读进度聚合:** API 在每次事件处理事务中自动更新 MaterialReadingProgress。 +- **会话中断检测:** API 在事件处理前自动清理 30 分钟无新事件的活跃会话(标记为 interrupted)。 +- **解析状态更新:** Python RAG Worker 异步更新 KnowledgeSource 的 parseStatus(不阻塞阅读)。 +- **文件过期处理:** API 自动检测临时资料是否过期。 + +### 系统配置修改 + +- **文件大小限制:** API 配置(待确认具体配置入口)。 +- **COS 预签名 URL 有效期:** API 文件上传服务配置。 +- **解析触发轮询间隔:** iOS 端硬编码(60×2s),非配置化。 + +--- + +## 9. 异常与恢复 + +### 9.1 文件加载失败 + +- **场景:** 本地文件不存在或 COS 下载失败。 +- **iOS 处理:** 资料阅读页进入错误状态,显示错误提示和重试按钮。自动尝试从 COS 重新下载。 +- **API 处理:** 文件下载 URL 返回 COS 预签名链接,含过期时间。过期后 iOS 需重新请求。 + +### 9.2 解析失败 + +- **场景:** 文件内容损坏、格式不支持、或解析器报错。 +- **iOS 处理:** 资料阅读页显示"暂不支持此格式"或错误提示。 +- **API 处理:** Python RAG Worker 解析失败时更新 DocumentImport 状态为 FAILED,记录错误步骤。Admin 可查看步骤日志并重试。解析失败不影响用户阅读原文件。 + +### 9.3 网络中断 + +- **场景:** 阅读过程中网络断开。 +- **iOS 处理:** Rust Document Runtime 继续在本地采集事件,事件缓冲区正常运行。iOS 本地持久化队列中的事件暂停上传,NetworkMonitor 检测到网络恢复后自动触发队列 flush。阅读会话继续,心跳和位置事件照常写入 Rust 缓冲区。 + +### 9.4 App 被关闭(强制杀死或系统回收) + +- **场景:** 用户在阅读过程中 App 被系统杀死或用户强制关闭。 +- **iOS 处理(App 重新启动时):** + 1. RuntimeRecoveryService.run() 执行崩溃恢复 + 2. Rust reload_stale_events_v2:所有 Exported 但未 Ack 的事件重置为 Pending(处理 export 后、本地写入前崩溃的场景) + 3. Rust cleanup_stale_sessions_v2:清理超过 24 小时的非活跃会话 + 4. iOS 本地队列 reloadOnLaunch:重新从 Rust 导出事件、映射为 UploadItem、写入持久化队列、立即 Ack。已持久化但未上传的队列条目继续上传。 + 5. 服务器端:API 在下次处理事件前,清理超过 30 分钟的活跃会话(标记为 interrupted) + +### 9.5 Export/Ack 链路中的三种崩溃场景 + +- **export 后、本地写入前崩溃:** Rust reload_stale_events_v2 将 Exported 事件重置为 Pending,下次启动重新导出。 +- **本地写入成功、Ack 前崩溃:** 重新启动后重新导出,API 端通过 eventId 去重(已在队列中的重复事件不会产生重复数据),iOS 再调用 Ack 完成交接。 +- **Ack 后、API 上传前崩溃:** 事件已从 Rust 缓冲区安全交接至 iOS 本地持久化队列。重启后本地队列继续上传,Rust 不需要再参与。 + +### 9.6 阅读位置恢复失败 + +- **场景:** API 未返回阅读进度(首次打开)或本地缓存丢失。 +- **iOS 处理:** 三级回退——API 位置 → 本地缓存位置 → Rust 会话位置 → 从头开始。 + +### 9.7 事件上传失败 + +- **场景:** 上传请求返回错误或超时。上传完全由 iOS 本地持久化队列负责,失败时不再调用 Rust markFailed。 +- **iOS 本地队列处理:** + - 401 错误:暂停队列(保留 pending 状态),等待 Token 刷新 + - 403/404 错误:标记条目为永久失败(dead) + - 其他错误:标记条目为 failed,进入指数退避重试(5s × 2^n,最多 3 次,最长 5 分钟) + - 重试次数耗尽:条目进入 dead 状态,不再重试 +- **API 处理:** + - 重复事件(相同 userId + eventId):标记为 duplicate,返回已处理 + - 验证失败(无效类型/超限/无权限):标记为 failed,返回错误码 + - 材料不存在:标记为 failed + +### 9.8 资料被删除或失去权限 + +- **场景:** 用户正在阅读的资料被管理员删除或用户失去访问权限。 +- **API 处理:** 事件处理时校验材料存在性、归属性和状态。不存在的材料标记事件为 failed;无权限的标记为 failed;已过期的临时材料标记为 failed。 +- **iOS 处理:** 当前的阅读会话仍可继续(本地文件未被删除),但后续事件上传将被拒绝。 + +--- + +## 10. 当前完成情况 + +统一使用以下口径: +- **已完成:** 跨项目链路已接通,用户可以获得最终结果。 +- **部分完成:** 只有部分项目、部分页面或部分场景完成。 +- **占位实现:** 存在结构,但使用 Mock、硬编码或静态数据。 +- **暂未确认:** 无法确认完整调用链。 + +| 组件 | 状态 | 说明 | +|------|------|------| +| iOS 多格式渲染(Markdown/文本/图片/EPUB) | 已完成 | Rust FFI 解析 + SwiftUI 渲染 | +| iOS 系统预览(PDF/Word/Excel/PPT) | 已完成 | QuickLook + ShareLink | +| iOS 阅读位置记录与恢复 | 已完成 | 三级优先级(API→本地→会话) | +| iOS 标记已读(服务端同步) | 已完成 | 本地 UserDefaults + marked_as_read 事件上报链路已接通 | +| iOS 取消标记已读(服务端同步) | 暂未确认 | 本地即时生效,但当前事件模型无 unmarked_as_read,API 是否支持待确认 | +| iOS 自动阅读会话管理 | 已完成 | Rust V2 ReadingSession(含前后台自动切换) | +| iOS 专注学习会话计时 | 暂未确认 | 本地计时已完成,API 持久化调用待确认 | +| iOS 快速笔记 | 已完成 | 锚点记录,本地 UserDefaults 存储 | +| iOS 15 秒心跳定时器 | 已完成 | iOS 创建 Timer,仅在 session active 且前台时触发 | +| Rust Document Runtime 文件解析 | 已完成 | 9 种 MaterialType 检测 + Markdown/文本/EPUB/图片/PDF 基础解析 | +| Rust Document Runtime V2 自动阅读会话 | 已完成 | 完整生命周期 + 5 种事件类型 + 缓冲区管理 | +| Rust 活跃时间跟踪器 | 已完成 | ActiveTimeTracker,由 iOS heartbeat tick 驱动 | +| Rust 崩溃恢复 | 已完成 | stale event reload + stale session cleanup | +| Rust → iOS 事件交接链路 | 已完成 | export → 本地队列写入 → Ack(交接在本地完成,不依赖网络) | +| iOS 本地上传队列 | 已完成 | JSON 持久化,独立于 Rust 缓冲区的网络上传队列 | +| iOS 上传重试与网络恢复 | 已完成 | 指数退避重试 + NetworkMonitor 自动恢复 | +| API 文件上传与下载 | 已完成 | COS 预签名 URL 流程 | +| API 阅读事件处理管线 | 已完成 | 去重→验证→事件入库→自动阅读会话聚合→进度聚合→每日活动→学习记录 | +| API 阅读进度查询 | 已完成 | GET /materials/:id/reading-progress | +| API 继续学习推荐 | 已完成 | 最近的未读完资料 | +| Admin 来源文件查看 | 已完成 | 列表+筛选+解析状态(运维可观测) | +| Admin 资料诊断 | 已完成 | material-diagnose 端点(运维可观测) | +| Admin 阅读进度查看 | 已完成 | 列表+详情(运维可观测) | +| 原文件阅读(不依赖 RAG) | 已完成 | 只要资料记录+权限+COS/本地文件可用即可阅读 | +| 资料范围 AI 问答(依赖 RAG) | 部分完成 | 需 RAG 完成向量化后才可用;RAG 未完成时语义检索不可用 | +| iOS 解析触发轮询 | 部分完成 | 使用硬编码 60×2s 轮询,非事件驱动 | +| 笔记服务端同步 | 未完成 | 当前仅本地 UserDefaults 存储 | +| Office 文件高清预览 | 暂未确认 | Word/Excel/PPT 依赖系统预览或外部打开,无内置高清渲染 | diff --git a/docs/system-map/capabilities/02-学习信息收集.md b/docs/system-map/capabilities/02-学习信息收集.md new file mode 100644 index 0000000..9ce30e9 --- /dev/null +++ b/docs/system-map/capabilities/02-学习信息收集.md @@ -0,0 +1,444 @@ +# 02 学习信息收集 — 跨项目完整能力分析 + +> 试点能力二:从 C 端业务能力"学习信息收集"出发,跨项目完整整理。 +> 项目角色分类:主链路(iOS、Rust Document Runtime、主 API、数据库)、上游支撑(无直接上游)、下游消费(Heavy Runtime)、运维可观测(Admin)。 + +--- + +## 1. 能力目标 + +自动采集用户在学习过程中的所有行为数据(阅读行为、学习时长、阅读位置、标记已读等),经过 Rust 内存缓冲、iOS 本地持久化队列、批量上传、服务端去重验证、聚合计算后,为学习分析、继续学习推荐提供数据基础。 + +--- + +## 2. C 端入口 + +学习信息收集是一个**用户不可见的自动能力**。用户不需要主动触发,系统在以下场景自动采集: + +| 触发场景 | 收集的数据 | iOS 页面 | 驱动方式 | +|---------|-----------|---------|---------| +| 用户打开一份资料 | material_opened 事件 | 资料阅读页 | iOS 调用 Rust push | +| 用户滚动阅读内容 | position_changed 事件(2 秒防抖) | 资料阅读页 | iOS 调用 Rust push | +| iOS 15 秒定时器触发 | heartbeat 事件 | 资料阅读页(自动) | iOS Timer → Rust heartbeat 接口 | +| 用户关闭/离开资料 | material_closed 事件 | 资料阅读页(自动) | iOS 调用 Rust close → push | +| 用户点击"标记已读" | marked_as_read 事件 | 资料阅读页 | iOS 调用 Rust push | +| 用户开始专注学习 | 学习会话计时开始 | 学习会话页 | iOS 本地计时器(用户主动触发) | + +用户在分析页和学习主页**消费**这些数据的结果,但数据采集本身是透明的。 + +--- + +## 3. 用户主流程 + +### 3.1 数据采集阶段(iOS + Rust Document Runtime) + +1. 用户打开资料进入阅读页。iOS 调用 Rust start_reading_session,Rust 创建 V2 自动阅读会话,生成唯一的 client_session_id。iOS 调用 Rust push_material_opened,事件进入 Rust 内存缓冲区(Pending)。 + +2. 阅读过程中: + - 用户滚动时,iOS 以 2 秒防抖调用 Rust push_position_changed。 + - iOS 创建并管理 15 秒心跳定时器。仅在阅读会话为 active 且 App 位于前台时触发。每次 Tick,iOS 调用 Rust heartbeat 接口,Rust 根据 ActiveTimeTracker 计算 activeSecondsDelta,创建 heartbeat 事件并写入缓冲区。 + - Rust 不创建也不管理 iOS 的系统定时器。 + +3. 用户点击"标记已读",iOS 本地更新 MarkedReadStore,同时调用 Rust push_marked_as_read。 + +4. 用户离开资料,iOS 调用 Rust close_reading_session,Rust 计算最终活跃时长增量,推送 material_closed 事件。 + +### 3.2 Rust 内存缓冲与交接阶段(Rust → iOS 本地队列) + +5. 所有事件暂存在 Rust 内存缓冲区中,状态为 Pending。 + +6. iOS 周期性地调用 Rust export_pending_events_v2 导出事件(事件状态变为 Exported)。**Rust 缓冲区不是网络上传队列**——导出仅完成从 Rust 到 iOS 的内存交接。 + +7. iOS 将导出的原始事件映射为 UploadItem(补充 knowledgeBaseId、platform、appVersion、timezone 等元数据)。 + +8. iOS 将 UploadItem 成功写入持久化 ReadingEventUploadQueue(JSON 文件)后,**立即**调用 Rust ack_events_v2。Rust 从内存缓冲区删除已完成交接的事件。 + +9. 后续 API 上传完全由 iOS 本地持久化队列负责。API 上传失败时,只更新本地队列条目的 failed/dead/retry 状态,不再调用 Rust markFailed。 + +### 3.3 上传阶段(iOS 本地持久化队列 → API) + +10. iOS 上传队列定期调用 flush,从本地持久化队列中取出事件,批量 POST /learning/reading-events/batch(每批最多 100 条)。 +11. 上传中的条目状态为 uploading。API 上传成功后,从 iOS 本地队列删除该条目记录。 +12. 上传失败时: + - 401(未授权):暂停队列(保留 pending),等待 Token 刷新 + - 403/404(禁止/不存在):标记条目为永久失败(dead) + - 其他错误:标记条目为 failed,进入指数退避重试(5s × 2^n,最多 3 次,最长 5 分钟) + - 重试耗尽:条目进入 dead 状态 + +### 3.4 崩溃恢复的三种场景 + +13. **export 后、本地写入前崩溃:** Rust reload_stale_events_v2 将所有 Exported 未 Ack 事件重置为 Pending。下次启动重新导出。 +14. **本地写入成功、Ack 前崩溃:** 重新启动后从 Rust 重新导出(含已持久化但未 Ack 的事件)。API 端通过 eventId 去重。iOS 再次 Ack 完成交接。 +15. **Ack 后、API 上传前崩溃:** 事件已安全在 iOS 本地持久化队列中,Rust 不再参与。重启后本地队列继续上传。 + +### 3.5 服务端处理阶段(API) + +16. API 收到事件批次后,逐条处理每个事件。单条事件处理在一个数据库事务中完成: + - **验证:** 校检事件类型、目标类型、活跃时长(上限 300 秒)、时间戳。 + - **去重:** 检查 userId + eventId 是否已处理,已处理的标记为 duplicate。 + - **权限校验:** 验证材料存在、属于当前用户、未删除、未过期。 + - **事件入库:** 插入 ReadingEvent 行。 + - **自动阅读会话聚合:** Upsert LearningSession(按 clientSessionId,增量累加 totalActiveSeconds)。 + - **进度聚合:** Upsert MaterialReadingProgress(按 userId+materialId)。 + - **每日活动聚合:** Upsert DailyLearningActivity(按 userId+localDate,时区感知)。 + - **学习记录:** 为里程碑事件(opened/closed/marked_as_read)插入 LearningRecord。 + - **标记完成:** 事件 status 更新为 processed。 + +### 3.6 数据消费阶段(iOS 查询) + +17. 用户在分析页和学习主页看到的结果: + - **继续学习:** GET /learning/continue → 最近未读完的资料。 + - **学习摘要:** GET /learning/summary → 今日/本周/总计分钟、活跃天数。 + - **阅读趋势:** GET /learning/trend?days=7 → 每日阅读时长序列。 + - **连续天数:** GET /activity/streak → 当前连续、最长连续。 + - **活动摘要:** GET /activity/summary → 总分钟、复习卡片、活跃天、日均。 + - **学习记录:** GET /learning/records → 分页学习记录列表。 + +--- + +## 4. 项目参与关系 + +### iOS(AIStudyApp)— 主链路参与者 + +**职责:** +- 驱动 Rust Document Runtime 的自动阅读会话和事件采集 +- 创建并管理 15 秒心跳定时器(仅在 session active 且前台时触发,每次 Tick 调用 Rust heartbeat 接口) +- 管理阅读位置本地缓存和标记已读本地缓存 +- 管理本地上传队列(独立于 Rust 缓冲区的网络上传队列):事件映射、JSON 持久化、重试策略、从队列删除已上传条目 +- Rust → iOS 事件交接:export → UploadItem 映射 → 持久化写入 → **立即 Ack**(不等待 API 上传) +- 提供网络恢复自动上传(NetworkMonitor 监听) +- 崩溃恢复:App 重启时调用 RuntimeRecoveryService +- 提供专注学习会话页的本地计时 +- 查询并展示学习分析数据 + +### Rust Document Runtime(zhixi-document-runtime)— 主链路参与者 + +**职责:** +- V2 自动阅读会话管理(start/pause/resume/close/interrupt) +- 活跃时间跟踪器(ActiveTimeTracker),由 iOS heartbeat tick 驱动计算 activeSecondsDelta +- 5 种阅读事件类型的创建和推送(opened/closed/position_changed/heartbeat/marked_as_read) +- 事件内存缓冲区管理(Pending → Exported 状态机) +- 事件导出(export_pending_events_v2):将事件从内存交接给 iOS +- 事件确认(ack_events_v2):iOS 本地持久化写入成功后立即调用,Rust 删除已交接事件 +- 崩溃恢复:stale event reload(Exported → Pending)、stale session cleanup +- 缓冲区容量管理(最大 1000 条,溢出时按优先级淘汰) +- 阅读位置模型 + +**不负责:** 网络请求、API 调用、事件上传、iOS 系统定时器创建和管理。 + +### 主 API(api-server)— 主链路参与者 + +**职责:** +- 接收阅读事件批量上传(POST /learning/reading-events/batch,每批最多 100 条) +- 单条事件处理管线(验证→去重→权限→入库→聚合→记录→标记) +- 事件去重(userId + eventId 唯一约束) +- 自动阅读会话聚合(按 clientSessionId upsert,自动处理 completed/interrupted 状态) +- 资料阅读进度聚合(按 userId + materialId upsert) +- 每日学习活动聚合(按 userId + localDate upsert,时区感知) +- 学习记录创建(里程碑事件记录) +- 异常检测和警告代码 +- 提供学习数据查询端点(/learning/*, /activity/*) +- 提供内部管理端点(事件重放、失败事件重处理) + +### Heavy Runtime — 下游数据消费者 + +**不直接参与学习信息收集。** 消费已聚合的学习数据,生成 AI 分析结果(掌握度评估、薄弱点识别、学习建议、测验题目、闪卡)。位于数据采集链的下游,不属于学习信息采集链路。 + +### Python RAG Worker — 上游支撑(不直接参与) + +**不直接参与学习信息收集。** 负责文档导入后的预处理(解析→分块→嵌入→索引),产生的知识库结构化数据是阅读的前提,但不参与阅读行为的采集、传输和聚合。 + +### Admin(admin-projects)— 运维与可观测 + +**不属于学习信息采集链路的同步环节。** 职责包括: +- 学习数据总览仪表板 +- 阅读事件/会话/进度/活动/记录查询 +- 用户时间线与诊断 +- 异常数据页(失败/警告/重复事件) +- 事件重放(单条 + 批量) +- 学习数据重算 +- 数据导出 + +--- + +## 5. 项目间调用关系 + +### 5.1 数据采集链路(iOS → Rust Document Runtime) + +| 调用目的 | 方向 | 业务结果 | +|---------|------|---------| +| 开启自动阅读会话 | iOS → Rust | 创建 V2 ReadingSession,返回 client_session_id | +| 推送阅读事件(opened/closed/position_changed/marked_as_read) | iOS → Rust | 事件进入内存缓冲区(Pending) | +| 心跳 Tick | iOS → Rust | Rust 计算 activeSecondsDelta,创建 heartbeat 事件写入缓冲区 | +| 活跃时间累计 | iOS → Rust | ActiveTimeTracker 由 iOS heartbeat tick 驱动,暂停时停止 | +| 导出待交接事件 | iOS → Rust | 返回 Exported 状态的事件列表 | +| 确认事件交接完成 | iOS → Rust | iOS 本地队列写入成功后立即 Ack,Rust 删除已交接事件 | +| 崩溃恢复 | iOS → Rust | Exported 未 Ack 事件重置为 Pending;清理超时 24h 的过期会话 | +| 暂停/恢复/关闭会话 | iOS → Rust | 会话状态切换,时间跟踪同步 | + +### 5.2 数据上传链路(iOS 本地持久化队列 → API) + +| 调用目的 | 方向 | 业务结果 | +|---------|------|---------| +| 批量上传阅读事件 | iOS 本地队列 → API | POST /learning/reading-events/batch,返回 processed/duplicate/failed | +| 查询阅读进度 | iOS → API | GET /materials/:id/reading-progress | +| 查询继续学习 | iOS → API | GET /learning/continue | +| 查询学习摘要 | iOS → API | GET /learning/summary | +| 查询学习趋势 | iOS → API | GET /learning/trend?days=N | +| 查询学习记录 | iOS → API | GET /learning/records | +| 查询活动摘要/连续天数/推荐 | iOS → API | GET /activity/summary, /activity/streak, /activity/recommendations | + +### 5.3 数据处理链路(API 内部) + +| 调用目的 | 方向 | 业务结果 | +|---------|------|---------| +| 事件批处理 | API Controller → Event Processor | 逐条处理,单条一个 DB 事务 | +| 事件去重 | Event Processor → DB | 检查 userId+eventId 唯一性 | +| 材料权限校验 | Event Processor → DB | 验证存在性、所有权、状态 | +| 自动阅读会话聚合 | Event Processor → DB(LearningSession) | Upsert by clientSessionId | +| 进度聚合 | Event Processor → DB(MaterialReadingProgress) | Upsert by userId+materialId | +| 每日活动聚合 | Event Processor → DB(DailyLearningActivity) | Upsert by userId+localDate | +| 学习记录创建 | Event Processor → DB(LearningRecord) | 里程碑事件插入 | +| 事件重放 | API → Event Processor | 重新处理失败事件 | +| 数据重算 | API → LearningActivityService | 用户或全局学习数据重新计算 | + +### 5.4 Admin 查询链路(Admin → API,运维可观测) + +| 调用目的 | 方向 | 业务结果 | +|---------|------|---------| +| 学习仪表板 | Admin → API | 总览 KPI | +| 阅读事件/会话/进度/活动/记录列表 | Admin → API | 分页列表(多条件筛选+排序) | +| 用户时间线与诊断 | Admin → API | 时序视图+完整诊断 | +| 异常检测 | Admin → API | 失败/警告/重复事件列表 | +| 事件重放/数据重算/导出 | Admin → API | 运维操作 | + +--- + +## 6. 核心业务数据 + +### 6.1 阅读事件(ReadingEvent) + +- **谁创建:** Rust Document Runtime(在 iOS 端内存中创建),API 入库(MySQL)。 +- **谁更新:** API 更新处理状态(processing → processed/failed/duplicate)和警告代码。 +- **谁查询:** API 在批处理时查重;Admin 在事件列表和异常检测页查询。 +- **用于什么功能:** 所有学习分析的原始数据源。每条事件包含 eventId、clientSessionId、materialId、eventType、position、activeSecondsDelta、timestampMs、sequence、platform、appVersion、timezoneOffset。 + +### 6.2 自动阅读会话(LearningSession,API 聚合自 ReadingEvent) + +- **谁创建:** API 在收到第一个 material_opened 事件时通过 upsert 创建(按 clientSessionId)。 +- **谁更新:** API 在每次事件处理中 upsert(增量 totalActiveSeconds、更新 lastPosition、更新 lastEventAt)。material_closed 事件触发状态变为 completed。30 分钟无新事件自动标记为 interrupted。 +- **谁查询:** iOS 学习主页(通过继续学习 API 间接使用);Admin 在学习会话页和用户诊断页查询。 +- **用于什么功能:** 自动阅读会话的服务端聚合记录。注意:这是 API 根据 Rust V2 ReadingSession 产生的事件聚合而来的服务端数据对象,与客户端 Rust 内存中的 ReadingSession 是不同的存储层对象。 + +### 6.3 专注学习会话(LearningSessionView 本地计时) + +- **谁创建:** 用户主动点击"开始学习"按钮后,iOS 创建本地计时器。 +- **谁更新:** 用户操作暂停/继续/结束(含确认弹窗),计时器以 1 秒精度运行。 +- **谁查询:** iOS 学习会话页展示当前进度。 +- **用于什么功能:** 用户主动发起的专注学习时段计时。**与自动阅读会话是不同的业务对象。** 当前 iOS 是否调用专注学习会话 API(LearningSessionService)持久化仍标记为"暂未确认"。 +- **关键区别:** 自动阅读会话随进入/离开资料自动产生;专注学习会话由用户主动开始/结束。自动阅读会话已通过事件链路上报至 API;专注学习会话的 API 持久化调用链待确认。 + +### 6.4 资料阅读进度(MaterialReadingProgress) + +- **谁创建:** API 在收到某资料第一个事件时 upsert 创建。 +- **谁更新:** API 每次事件处理中 upsert。累计 totalActiveSeconds、sessionCount。更新 lastPosition、lastProgress。marked_as_read 时设置 isMarkedRead=true、status=read。 +- **谁查询:** iOS 在进入阅读页时查询;Admin 在阅读进度页查询。 +- **用于什么功能:** 阅读位置恢复、"继续学习"推荐、阅读进度展示。 + +### 6.5 每日学习活动(DailyLearningActivity) + +- **谁创建:** API 在收到某用户某日第一个事件时 upsert 创建。 +- **谁更新:** API 每次事件处理中 upsert。增量累加 durationSeconds、readingSeconds、materialsReadCount、markedReadCount。日期按用户时区(clientTimezoneOffsetMinutes)计算。 +- **谁查询:** API 在学习摘要/趋势/活跃热力图/连续天数计算中查询;Admin 在每日活动页查询。 +- **用于什么功能:** 日级别的学习活动聚合、趋势分析、连续天数计算、分析页数据。 + +### 6.6 学习记录(LearningRecord) + +- **谁创建:** API 为里程碑事件(material_opened/closed/marked_as_read)创建。 +- **谁更新:** 创建后不可修改。 +- **谁查询:** iOS 在分析页查询(最近 5 条);Admin 在学习记录页查询。 +- **用于什么功能:** 用户学习时间线、分析页"最近学习记录"展示。 + +### 6.7 继续学习状态(ContinueLearning) + +- **谁创建:** API 实时计算(查询最近阅读的未完成资料)。 +- **谁更新:** 不持久化(每次查询实时计算)。 +- **谁查询:** iOS 学习主页(优先级算法首选项)。 +- **用于什么功能:** 用户快速回到上次阅读位置继续学习。 + +### 6.8 学习摘要(LearningSummary) + +- **谁创建:** API 实时聚合(查询 DailyLearningActivity)。 +- **谁更新:** 不持久化(每次查询实时聚合)。 +- **谁查询:** iOS 学习主页和学习分析页。 +- **用于什么功能:** 今日/本周/总计的阅读分钟、活跃天数等汇总展示。 + +### 6.9 学习趋势(LearningTrend) + +- **谁创建:** API 实时计算(过去 N 天每日阅读时长序列)。 +- **谁更新:** 不持久化。 +- **谁查询:** iOS 分析页阅读时长趋势图。 +- **用于什么功能:** 展示用户阅读时长的日间变化趋势。 + +--- + +## 7. 查询入口 + +### 用户在哪里查看 + +- **继续学习:** iOS 学习主页主操作卡片。 +- **每周摘要:** iOS 学习主页每周摘要卡片。 +- **学习分析:** iOS 学习分析页(掌握度/总分钟/复习卡片/活跃天/阅读统计/趋势图/连续统计/学习记录/推荐/AI 综合分析)。 +- **资料阅读进度:** iOS 资料详情页(阅读进度卡片)。 + +### Admin 在哪里查看(运维可观测) + +- **学习仪表板:** Admin 学习数据→总览(KPI 汇总)。 +- **阅读事件列表:** Admin 学习数据→阅读事件页(按用户/材料/状态/类型筛选)。 +- **学习会话列表:** Admin 学习数据→学习会话页。 +- **阅读进度/每日活动/学习记录列表:** Admin 学习数据→对应页面。 +- **用户时间线:** Admin 学习数据→用户时间线。 +- **用户诊断:** Admin 学习数据→用户诊断。 +- **异常数据:** Admin 学习数据→异常数据(失败/警告/重复三 Tab)。 +- **数据导出:** Admin 学习数据→导出。 + +### 系统内部在哪里使用 + +- **活动趋势 AI 分析:** API GET /activity/trend → Heavy Runtime 生成学习趋势洞察(Heavy Runtime 是下游消费者)。 +- **推荐系统:** API GET /activity/recommendations → 学习主页优先级算法。 +- **学习连续天数:** API GET /activity/streak → 连续天数计算。 +- **活跃热力图:** API GET /activity/heatmap → 每日阅读时长热力图。 + +--- + +## 8. 修改入口 + +### 用户主动修改 + +- **标记已读:** iOS 资料阅读页工具栏按钮。本地 MarkedReadStore 即时生效,marked_as_read 事件通过采集链路上报至 API。 +- **取消标记已读:** 本地 MarkedReadStore 即时生效。服务端同步方式暂未确认(当前事件模型只有 marked_as_read,没有 unmarked_as_read 事件类型)。 +- **开始专注学习会话:** iOS 资料阅读页工具栏"开始学习"按钮。 +- **结束专注学习会话:** iOS 学习会话页结束按钮(含确认弹窗)。 + +### Admin 人工修改(运维可观测) + +- **事件重放:** Admin 单条或批量重放失败事件。 +- **事件重处理:** API 内部端点批量重处理失败事件。 +- **数据重算:** Admin 触发用户或全局学习数据重新计算。 +- **数据导出:** Admin 导出原始事件或会话数据。 + +### 系统自动修改 + +- **事件去重:** API 自动检测并标记重复事件为 duplicate。 +- **活跃时长封顶:** API 将超过 300 秒的 activeSecondsDelta 截断为 300 秒,添加警告。 +- **时间戳偏差检测:** API 检测客户端时间戳与服务器时间的偏差(>5 分钟),添加警告。 +- **乱序事件检测:** API 检测 sequence 不连续的事件,添加警告。 +- **会话自动关闭:** API 在事件处理前自动将 30 分钟无新事件的活跃会话标记为 interrupted。 +- **过期材料自动检测:** API 在事件处理时自动检测临时材料的过期状态。 +- **崩溃恢复:** Rust + iOS 在 App 重启时自动恢复(Rust reload + iOS 队列 reloadOnLaunch)。 + +### 系统配置修改 + +- **批次大小上限:** API 配置(每批最多 100 条)。 +- **活跃时长上限:** API 硬编码 300 秒。 +- **时间戳偏差阈值:** API 硬编码 5 分钟。 +- **会话中断超时:** API 硬编码 30 分钟。 +- **事件缓冲区上限:** Rust Document Runtime 硬编码 1000 条。 +- **上传重试策略:** iOS 硬编码(指数退避 5s×2^n,最多 3 次,最长 5 分钟)。 + +--- + +## 9. 异常与恢复 + +### 9.1 App 崩溃 / 系统杀死恢复 + +- **Rust 侧:** App 重启时调用 reload_stale_events_v2() → 所有 Exported 未 Ack 事件重置为 Pending。调用 cleanup_stale_sessions_v2(now_ms, 24h) → 清理超过 24 小时的过期会话。 +- **iOS 侧:** RuntimeRecoveryService.run() 在 App 启动时执行。处理三种场景: + 1. export 后、本地写入前崩溃 → Rust reload 恢复 Pending,重新导出 + 2. 本地写入成功、Ack 前崩溃 → 重新导出后 API 通过 eventId 去重,再 Ack + 3. Ack 后、API 上传前崩溃 → 本地持久化队列重启后继续上传 +- **API 侧:** 下次事件处理时清理超过 30 分钟无新事件的活跃会话(标记为 interrupted)。 + +### 9.2 网络失败重试 + +- **iOS 本地队列:** 401 → 暂停(pending),等待 Token 刷新。403/404 → 永久失败(dead)。其他错误 → failed + 指数退避重试。重试耗尽 → dead。 +- **NetworkMonitor:** 检测到网络恢复时,自动触发本地队列 flush。 +- **API 鉴权:** Token 过期时 APIClient 自动尝试 refresh,成功后重试原请求一次。 + +### 9.3 事件去重 + +- **API 处理:** userId + eventId 唯一约束。重复事件跳过处理、不更新聚合数据,标记为 duplicate。 +- **客户端保障:** Rust V2 每个事件有 UUID v4 的 eventId,崩溃恢复时 eventId 不变,确保重传不会产生重复聚合。 + +### 9.4 事件乱序 + +- **API 处理:** 检测 sequence 不连续 → 添加 OUT_OF_ORDER_EVENT 警告。事件仍然正常处理(不拒绝)。通常由崩溃恢复后重传较早事件引起,不影响聚合结果(增量累加而非绝对值替换)。 + +### 9.5 活跃时长异常 + +- **API 处理:** activeSecondsDelta > 300 秒 → 截断为 300 秒,添加 ACTIVE_SECONDS_CAPPED 警告。Admin 异常页可筛选复核。 + +### 9.6 时间戳偏差 + +- **API 处理:** 客户端时间戳与服务器时差 > 5 分钟 → 添加 CLIENT_TIMESTAMP_SKEWED 警告,事件正常处理。 + +### 9.7 材料被删除或失去权限 + +- **API 处理:** 标记为 FATAL_MATERIAL_NOT_FOUND / FATAL_ACCESS_DENIED / FATAL_TEMPORARY_MATERIAL_EXPIRED。 +- **Admin 恢复:** 无法恢复已删除材料的关联事件。 + +### 9.8 用户切换隔离 + +- **实现方式:** 所有 API 操作基于 JWT Token 中的 userId 进行用户隔离。 +- **阅读事件:** 每个事件在 API 处理时使用当前登录用户的 userId 关联。 +- **所有聚合数据:** 按 userId 分区存储和查询,用户只能看到自己的数据。 +- **Admin:** 可通过 userId 筛选查看任一用户的数据,需 admin 权限。 + +--- + +## 10. 当前完成情况 + +统一使用以下口径: +- **已完成:** 跨项目链路已接通,用户可以获得最终结果。 +- **部分完成:** 只有部分项目、部分页面或部分场景完成。 +- **占位实现:** 存在结构,但使用 Mock、硬编码或静态数据。 +- **暂未确认:** 无法确认完整调用链。 + +| 组件 | 状态 | 说明 | +|------|------|------| +| Rust Document Runtime V2 自动阅读会话 | 已完成 | start/pause/resume/close/interrupt 完整生命周期 | +| Rust Document Runtime V2 事件采集(5 种) | 已完成 | material_opened/closed/position_changed/heartbeat/marked_as_read | +| Rust 活跃时间跟踪器 | 已完成 | ActiveTimeTracker,由 iOS heartbeat tick 驱动 | +| Rust 事件缓冲区管理 | 已完成 | Pending → Exported,export/ack/reload | +| iOS 15 秒心跳定时器 | 已完成 | iOS 创建 Timer,仅在 session active 且前台时触发,Tick 调用 Rust heartbeat 接口 | +| Rust → iOS 事件交接链路 | 已完成 | export → 本地队列写入 → 立即 Ack(交接在本地完成,不依赖网络) | +| iOS 本地上传队列 | 已完成 | JSON 持久化,独立于 Rust 缓冲区的网络上传队列 | +| iOS 上传重试与网络恢复 | 已完成 | 指数退避 + NetworkMonitor 自动恢复 | +| iOS 阅读位置本地缓存 | 已完成 | ReadingPositionStore | +| iOS 标记已读本地缓存 | 已完成 | MarkedReadStore(本地即时生效) | +| iOS 标记已读服务端同步 | 已完成 | marked_as_read 事件 → 上传链路 → API 聚合 | +| iOS 取消标记已读服务端同步 | 暂未确认 | 当前事件模型无 unmarked_as_read,API 是否支持待确认 | +| iOS 崩溃恢复 | 已完成 | RuntimeRecoveryService + 本地队列 reloadOnLaunch | +| Rust 崩溃恢复 | 已完成 | stale event reload + stale session cleanup | +| API 事件批处理端点 | 已完成 | POST /learning/reading-events/batch | +| API 事件去重 | 已完成 | userId+eventId 唯一约束 | +| API 事件验证 | 已完成 | 类型校验 + 时长上限 + 时间戳检测 + 乱序检测 | +| API 权限校验 | 已完成 | 材料存在性、归属、状态、过期校验 | +| API 自动阅读会话聚合 | 已完成 | 按 clientSessionId upsert,自动完成/中断 | +| API 资料阅读进度聚合 | 已完成 | 按 userId+materialId upsert | +| API 每日学习活动聚合 | 已完成 | 按 userId+localDate upsert,时区感知 | +| API 学习记录创建 | 已完成 | 里程碑事件自动创建 | +| API 学习摘要/趋势/连续天数 | 已完成 | GET /learning/*, GET /activity/* | +| API 继续学习推荐 | 已完成 | GET /learning/continue | +| API 活动推荐 | 已完成 | GET /activity/recommendations | +| API 活跃时长封顶 | 已完成 | 超 300s 截断 + 警告码 | +| API 时间戳偏差检测 | 已完成 | >5 分钟偏差警告 | +| 用户切换隔离 | 已完成 | JWT userId + 所有查询按 userId 分区 | +| Admin 学习仪表板 | 已完成 | KPI 总览(运维可观测) | +| Admin 事件/会话/进度/活动/记录查看 | 已完成 | 列表+筛选+详情(运维可观测) | +| Admin 用户时间线与诊断 | 已完成 | 时序视图+完整诊断(运维可观测) | +| Admin 异常检测 | 已完成 | 失败/警告/重复三视图(运维可观测) | +| Admin 事件重放 | 已完成 | 单条+批量(运维可观测) | +| Admin 数据重算 | 已完成 | 触发重算(运维可观测) | +| Admin 数据导出 | 已完成 | CSV/JSON 导出(运维可观测) | +| iOS 专注学习会话 API 持久化 | 暂未确认 | 本地计时已完成,代码中未发现调用 LearningSessionService API 的代码 | diff --git a/docs/system-map/capabilities/03-资料上传与处理.md b/docs/system-map/capabilities/03-资料上传与处理.md new file mode 100644 index 0000000..a209b92 --- /dev/null +++ b/docs/system-map/capabilities/03-资料上传与处理.md @@ -0,0 +1,446 @@ +# 03 资料上传与处理 — 跨项目完整能力分析 + +> 项目角色分类:主链路参与者(iOS、主 API、COS、Python RAG Worker、Qdrant——资料上传后必须经过这些项目才能完成处理)、运维可观测(Admin)。 +> Rust Document Runtime 不参与上传与处理链路。Heavy Runtime 不参与此链路。 +> 注意:Python RAG Worker 和 Qdrant 在本能力中是主链路参与者;在"知识库与知识点管理"和"AI 对话与知识库问答"能力中角色不同(分别为上游支撑和不参与对话上下文加载)。 + +--- + +## 1. 能力目标 + +用户将外部学习资料(PDF、Word、Markdown、图片等)上传至知识库,系统自动完成文本解析、分块、向量索引和知识点候选提取,使资料成为可阅读、可检索、可被 AI 引用的结构化知识。 + +--- + +## 2. C 端入口 + +| 入口页面 | 触发方式 | 进入场景 | +|---------|---------|---------| +| 知识库详情页 | 操作菜单 → "上传" | 向已有知识库导入资料 | +| 知识库详情页 | 操作菜单 → "添加" → 文件模式 | 以文件形式添加知识点 | +| 添加知识点页·文件模式 | 点击"选择文件"或"图片"按钮 | 选择文件/照片作为知识点 | +| 导入资料页 | 点击"文件导入"/"相册导入"/"链接导入" | 三种导入方式 | + +用户可执行的操作: + +- 从系统文件选择器选择文件(PDF、纯文本、图片等) +- 从相册选择照片(自动压缩大于 2MB 的图片) +- 输入 URL 进行链接导入 +- 查看上传进度 +- 查看导入任务的 AI 处理状态(处理中/就绪/失败) +- 审核 AI 提取的知识点候选(接受/拒绝/批量接受) + +--- + +## 3. 用户主流程 + +``` +用户选择资料 +→ iOS 校验文件类型和大小(图片 >2MB 自动压缩) +→ iOS 调用 API 获取 COS 预签名上传 URL +→ iOS 将文件直接 PUT 到 COS +→ iOS 调用 API 确认上传完成(API 验证 COS 中文件存在) +→ API 创建资料记录(KnowledgeSource) +→ API 创建导入任务(DocumentImport,状态 QUEUED) +→ Python RAG Worker 轮询获取导入任务 +→ Worker 下载文件 → 解析文本 → 清洗 → 分块 → 向量嵌入 → 索引到 Qdrant → 生成知识点候选 +→ Worker 更新 KnowledgeSource 的 parseStatus/indexStatus/learningStatus +→ 用户可在资料详情页查看 AI 处理状态 +→ 用户可在导入候选审核页审核 AI 提取的知识点候选 +→ 用户接受候选 → API 创建 KnowledgeItem +→ 资料进入可阅读、可被 AI 检索的状态 +``` + +--- + +## 4. 处理阶段与状态 + +资料上传后经历多个异步处理阶段,每个阶段有独立的状态追踪: + +### 4.1 原文件上传状态 + +- **谁创建:** iOS 调用 API 确认上传后,API 创建 UploadedFile 记录。 +- **谁更新:** 上传完成后状态不再变化。文件删除时 API 从 COS 和数据库移除。 +- **用户在哪里看到:** iOS 上传过程中显示进度指示器;上传完成后在资料详情页看到文件名、格式、大小。 +- **Admin 在哪里看到:** Admin 文件管理页查看所有上传文件列表,可按类型筛选。 +- **失败后如何处理:** COS 上传失败时 iOS 显示错误提示,用户可重试。 + +### 4.2 文本解析状态(parseStatus) + +- **谁创建:** API 创建 KnowledgeSource 时默认为 `pending`。 +- **谁更新:** Python RAG Worker 在处理过程中更新(pending → processing → complete/failed)。同时更新 textLength、parsedObjectKey、errorCode、errorMessage。 +- **用户在哪里看到:** iOS 资料详情页的 AI 处理状态横幅(处理中为琥珀色、就绪为绿色、失败为红色)。 +- **Admin 在哪里看到:** Admin 来源文件页的 parseStatus 列;导入监控页的步骤日志。 +- **失败后如何处理:** Admin 可触发重新解析(POST /knowledge-bases/:kbId/sources/:id/parse);导入任务自动重试最多 3 次。 + +### 4.3 向量索引状态(indexStatus) + +- **谁创建:** API 创建 KnowledgeSource 时默认为 `pending`。 +- **谁更新:** Python RAG Worker 在嵌入和索引阶段更新(pending → processing → complete/failed)。 +- **用户在哪里看到:** iOS 不单独展示索引状态(合并在 AI 处理状态中)。 +- **Admin 在哪里看到:** Admin 来源文件页的 indexStatus 列。 +- **失败后如何处理:** 同解析失败,Admin 可触发重新解析,系统自动重试。 + +### 4.4 学习内容提取状态(learningStatus) + +- **谁创建:** API 创建 KnowledgeSource 时默认为 `pending`。 +- **谁更新:** Python RAG Worker 在知识点候选生成完成后更新为 `complete`。 +- **用户在哪里看到:** 不直接展示;用户通过导入候选审核页间接感知(有候选 = 已完成提取)。 +- **Admin 在哪里看到:** Admin 来源文件详情中查看。 +- **失败后如何处理:** 候选生成是非致命步骤——即使失败,解析和索引仍可成功。 + +### 4.5 候选审核状态 + +- **谁创建:** Python RAG Worker 生成候选后,API 创建 ImportCandidate 记录(状态 PENDING)。 +- **谁更新:** iOS 用户操作:接受 → ACCEPTED;拒绝 → REJECTED;编辑 → EDITED。内容安全拦截 → BLOCKED。 +- **用户在哪里看到:** iOS 导入候选审核页(候选列表含置信度分数、标题、摘要)。 +- **Admin 在哪里看到:** Admin 知识运营页的候选巡检 Tab。 +- **失败后如何处理:** 被内容安全拦截的候选标记为 BLOCKED,Admin 可查看但不可恢复。 + +--- + +## 5. 项目职责 + +### iOS — 主链路参与者 + +- 提供文件选择器、相册选择器、链接输入弹窗 +- 校验文件类型和大小(图片 >2MB 自动 JPEG 压缩) +- 调用 API 获取 COS 预签名上传 URL +- 直接 PUT 文件到 COS +- 调用 API 确认上传 +- 展示上传进度和 AI 处理状态 +- 提供导入候选审核界面(接受/拒绝/批量接受) + +### 主 API — 主链路参与者 + +- 提供 COS 预签名上传 URL(POST /files/upload-url) +- 验证文件类型和大小:iOS 端进行初步校验(文件选择器限制可选类型、图片压缩);API 端进行最终校验(允许 PDF/TXT/Markdown/CSV/XLSX/DOCX/PNG/JPEG/WebP,最大 20MB) +- 文件名内容安全检查 +- 确认上传完成(POST /files/complete),验证 COS 中文件存在后创建记录 +- 创建 KnowledgeSource 记录并自动创建 DocumentImport 任务 +- 管理导入任务状态(Redis 实时状态 + 数据库持久化) +- 提供导入状态查询(GET /imports/:id/status) +- 提供候选审核 API(accept/reject/batch-accept) +- 文件下载 URL 生成(COS 预签名链接) +- 速率限制(文件上传端点) + +### COS(腾讯云对象存储)— 主链路参与者 + +- 存储用户上传的原始文件 +- 提供预签名 PUT URL(iOS 直接上传,不经 API 中转) +- 提供预签名 GET URL(iOS 下载,Python RAG Worker 下载) +- 对象键格式:`{userId}/{YYYYMM}/{sanitizedFilename}` + +### Python RAG Worker — 主链路参与者 + +- 轮询 API 获取待处理导入任务(每 5 秒) +- 定期发送心跳保持任务活跃(每 30 秒) +- 完整处理管线:下载文件 → 解析文本 → 清洗(当前仅做 >10 字符长度验证,无实质性文本清洗) → 分块 → 向量嵌入 → 索引到 Qdrant → 生成知识点候选 +- 解析器支持:PDF(PyMuPDF 提取文本层 → 若每页平均 <50 字符则回退到 SiliconFlow Qwen3-VL OCR)、DOCX(python-docx)、TXT/MD(直接读取)、CSV/XLSX(pandas 转 Markdown 表格)、图片(SiliconFlow 多模态 OCR) +- 分块策略:递归字符分割,中文句子边界保护,Markdown 标题感知,512 token 块 + 64 token 重叠 +- 嵌入模型:BAAI/bge-m3(1024 维),通过 SiliconFlow API +- 候选生成:DeepSeek 分析全文提取知识点(标题、摘要、内容、标签、回忆问题、难度、置信度) +- 更新 KnowledgeSource 的 parseStatus/indexStatus/learningStatus + +### Qdrant(向量数据库)— 主链路参与者 + +- 存储文档块的向量索引(集合 `zhixi_chunks`,1024 维,余弦距离) +- 每个向量点携带 payload:userId、knowledgeBaseId、sourceId、chunkId、pageNumber、sectionTitle +- 支持按 sourceId 软删除(mark_deleted) +- 为资料范围 AI 问答和语义检索提供向量搜索能力 + +### Admin — 运维与可观测 + +- 文件管理页(查看所有上传文件,删除) +- 来源文件页(查看所有 KnowledgeSource,按解析/索引状态筛选) +- 导入监控页(查看所有导入任务,步骤级日志,重试失败任务) +- 候选巡检 Tab(查看所有候选及其审核状态) +- 分块管理 Tab(按 sourceId 查看分块详情) +- RAG 调试 Tab(向量搜索调试) + +### Rust Document Runtime — 不参与 + +文件上传和异步处理链路不涉及 Rust Document Runtime。Rust 仅在用户打开已上传资料进行阅读时参与文件解析。 + +### Heavy Runtime — 不参与 + +Heavy Runtime 不参与文件上传、解析、分块、索引和候选生成流程。 + +--- + +## 6. 项目间调用关系 + +### 6.1 iOS → API + +| 调用目的 | 业务结果 | +|---------|---------| +| 请求上传授权 | 返回 COS 预签名 PUT URL + objectKey | +| 确认上传完成 | API 验证 COS 文件存在,创建 UploadedFile 记录 | +| 创建知识源 | 创建 KnowledgeSource + DocumentImport 任务(QUEUED) | +| 查询导入状态 | 返回 Redis 实时状态(进度百分比 + 文字描述) | +| 获取下载 URL | 返回 COS 预签名下载链接 | + +### 6.2 iOS → COS(直接) + +| 调用目的 | 业务结果 | +|---------|---------| +| 上传文件 | 文件直接 PUT 到 COS,不经 API 中转 | + +### 6.3 Python RAG Worker → API + +| 调用目的 | 业务结果 | +|---------|---------| +| 轮询待处理任务 | 获取 QUEUED 状态的导入任务 | +| 锁定任务 | 原子转换 QUEUED → CLAIMED | +| 心跳上报 | 保持任务活跃,防止超时回收 | +| 更新任务状态 | 更新 Redis 进度/消息 | +| 更新 KnowledgeSource | 更新 parseStatus/indexStatus/learningStatus | +| 保存分块 | 批量写入 KnowledgeChunk 记录 | +| 保存候选 | 批量写入 ImportCandidate 记录 | + +### 6.4 Python RAG Worker → COS + +| 调用目的 | 业务结果 | +|---------|---------| +| 下载文件 | 通过预签名 URL 下载原始文件用于处理 | + +### 6.5 Python RAG Worker → Qdrant + +| 调用目的 | 业务结果 | +|---------|---------| +| 写入向量 | 将文档块的嵌入向量写入 zhixi_chunks 集合 | +| 软删除 | 标记指定 sourceId 的向量为 deleted | + +### 6.6 Python RAG Worker → 模型服务 + +| 调用目的 | 业务结果 | +|---------|---------| +| 文本嵌入 | 调用 SiliconFlow BAAI/bge-m3 生成 1024 维向量 | +| 图片 OCR | 调用 SiliconFlow Qwen3-VL 多模态模型提取图片文字 | +| 候选生成 | 调用 DeepSeek 分析全文提取知识点候选 | + +### 6.7 Admin → API(运维可观测) + +| 调用目的 | 业务结果 | +|---------|---------| +| 查看/删除文件 | 文件管理 | +| 查看来源文件 | 列表 + 按状态筛选 | +| 查看导入任务 | 列表 + 步骤日志 | +| 重试导入 | 重置失败任务为 QUEUED | +| 查看候选 | 候选巡检 | +| 查看分块 | 按 sourceId 查看分块详情 | + +--- + +## 7. 核心业务数据 + +### 7.1 上传文件(UploadedFile) + +- **谁创建:** API 在确认上传时创建。 +- **谁更新:** 不更新(创建后不可变)。 +- **谁查询:** iOS 在上传后获取文件信息;Admin 在文件管理页查询。 +- **用途:** 记录已上传到 COS 的文件,作为 KnowledgeSource 的 fileId 引用来源。 + +### 7.2 知识源(KnowledgeSource) + +- **谁创建:** API 在添加来源时创建(关联 fileId)。 +- **谁更新:** Python RAG Worker 更新 parseStatus/indexStatus/learningStatus。 +- **谁查询:** iOS 在知识库详情页来源 Tab;Admin 在来源文件页。 +- **用途:** 知识库中每个导入资料的记录,追踪处理状态。 + +### 7.3 导入任务(DocumentImport) + +- **谁创建:** API 在创建 KnowledgeSource 时自动创建(状态 QUEUED)。 +- **谁更新:** Python RAG Worker 更新状态、进度、步骤日志;Admin 可重置为 QUEUED(重试)。 +- **谁查询:** iOS 查询导入状态;Admin 在导入监控页。 +- **用途:** 追踪单个文档的完整处理生命周期,从排队到完成或失败。 + +### 7.4 知识分块(KnowledgeChunk) + +- **谁创建:** Python RAG Worker 在分块和索引阶段批量创建。 +- **谁更新:** 创建后不可修改(软删除通过 Qdrant 实现)。 +- **谁查询:** Admin 在分块管理 Tab 按 sourceId 查看;系统内部通过 Qdrant 向量搜索使用。 +- **用途:** 文档的语义分块,每个块有向量嵌入,用于资料范围 AI 问答的语义检索。 + +### 7.5 导入候选(ImportCandidate) + +- **谁创建:** Python RAG Worker 在候选生成阶段批量创建(状态 PENDING)。 +- **谁更新:** iOS 用户操作(accept → ACCEPTED,reject → REJECTED,edit → EDITED)。内容安全拦截 → BLOCKED。 +- **谁查询:** iOS 在候选审核页按 sourceId 查询;Admin 在候选巡检 Tab 查看。 +- **用途:** AI 从文档中提取的知识点候选,等待用户审核确认。 + +### 7.6 知识点(KnowledgeItem,由候选接受生成) + +- **谁创建:** API 在用户接受候选时创建(itemType: ai_generated)。 +- **谁更新:** 用户在编辑知识点页修改。 +- **谁查询:** iOS 在知识点详情页和知识库详情页。 +- **用途:** 用户确认后的正式知识点,进入知识库内容体系。 + +### 7.7 向量索引(Qdrant Collection) + +- **谁创建:** Python RAG Worker 在索引阶段写入。 +- **谁更新:** 软删除通过 mark_deleted(sourceId) 实现。 +- **谁查询:** API 在资料范围 AI 问答时通过向量搜索检索相关块;Admin 通过向量管理页查看统计。 +- **用途:** 为资料范围 AI 问答提供语义级检索能力。 + +--- + +## 8. 查询入口 + +### 用户查询 + +- **上传进度:** iOS 添加知识点页/导入资料页的上传进度指示器。 +- **AI 处理状态:** iOS 资料详情页的 AI 处理状态横幅(处理中/就绪/失败)。 +- **导入候选:** iOS 导入候选审核页(列表含置信度、标题、摘要)。 +- **来源文件列表:** iOS 知识库详情页来源 Tab(含处理状态标签)。 + +### Admin 查询 + +- **文件列表:** Admin 文件管理页(按类型查看、删除)。 +- **来源文件列表:** Admin 来源文件页(按解析/索引状态筛选)。 +- **导入任务列表:** Admin 导入监控页(状态、进度、步骤日志、重试)。 +- **候选巡检:** Admin 知识运营页候选巡检 Tab。 +- **分块管理:** Admin 知识运营页分块管理 Tab(按 sourceId 查看)。 +- **RAG 调试:** Admin 知识运营页 RAG 调试 Tab(向量搜索测试)。 + +### 系统内部查询 + +- **RAG Worker 轮询任务:** Python RAG Worker 定期轮询 QUEUED 导入任务。 +- **向量搜索:** API 在资料范围 AI 问答时查询 Qdrant 获取相关块。 +- **Redis 状态查询:** API 提供导入任务实时状态(24 小时 TTL)。 + +--- + +## 9. 修改入口 + +### 用户操作 + +- **上传新文件:** iOS 导入资料页/添加知识点页。 +- **接受候选:** iOS 候选审核页接受单个候选。 +- **拒绝候选:** iOS 候选审核页拒绝单个候选。 +- **批量接受:** iOS 候选审核页"全部接受"按钮。 +- **编辑候选:** iOS 可编辑候选内容后再接受。 + +### Admin 操作 + +- **删除文件:** Admin 文件管理页删除上传文件(同时从 COS 删除)。 +- **重试导入:** Admin 导入监控页重试失败任务(重置为 QUEUED,最多 3 次系统自动重试,Admin 手动重置不占重试次数)。 +- **触发重新解析:** Admin 可触发知识源的重新解析。 + +### 系统自动修改 + +- **导入任务自动重试:** Python RAG Worker 失败时系统自动重试(最多 3 次,超时后标记 FAILED_FINAL)。 +- **过期任务回收:** 心跳超过 5 分钟的 CLAIMED 任务被重置为 QUEUED。 +- **内容安全检查:** 文件名、KB 标题、候选内容接受时自动进行敏感词检查。 +- **Redis 状态过期:** 导入任务 Redis 状态在 24 小时后自动清除。 +- **分布式锁过期:** 重复上传防护锁在 5 分钟后自动释放。 + +### 配置修改 + +- **允许的文件类型:** API 端配置(PDF/TXT/Markdown/CSV/XLSX/DOCX/PNG/JPEG/WebP)。 +- **最大文件大小:** API 端硬编码 20MB。 +- **COS 预签名 URL 有效期:** 上传 1 小时,下载 24 小时(知识点详情页 7 天)。 +- **分块参数:** Python RAG Worker 配置(512 token 块大小,64 token 重叠)。 +- **嵌入模型:** Python RAG Worker 配置(BAAI/bge-m3)。 +- **候选生成模型:** Python RAG Worker 配置(deepseek-chat,temperature 0.3)。 + +--- + +## 10. 异常与恢复 + +### 10.1 文件类型不支持 + +- **场景:** 用户选择不支持的文件类型。 +- **iOS 处理:** 文件选择器限制可选类型(PDF/纯文本/图片);API 在请求上传 URL 时二次校验,返回错误。 +- **用户感知:** iOS 提示"不支持的文件格式"。 + +### 10.2 文件过大 + +- **场景:** 文件超过 20MB 限制。 +- **iOS 处理:** 图片 >2MB 自动 JPEG 压缩;非图片文件 >20MB 时 API 拒绝。 +- **用户感知:** API 返回文件过大错误。 + +### 10.3 COS 上传失败 + +- **场景:** 网络问题或 COS 服务异常导致 PUT 失败。 +- **iOS 处理:** 显示上传错误提示,用户可重试。上传使用预签名 URL,不经过 API 中转。 +- **API 处理:** 确认上传时如果 COS 中文件不存在(headObject 失败),返回确认失败。 + +### 10.4 上传成功但 API 创建记录失败 + +- **场景:** COS 上传成功,但确认 API 调用失败(网络中断、服务错误)。 +- **结果:** 文件在 COS 中存在但数据库无记录(孤儿文件)。 +- **恢复:** 用户重新上传(生成新的 objectKey);Admin 可手动清理孤儿文件(file-cleanup 队列定期执行)。 + +### 10.5 导入任务失败 + +- **场景:** Python RAG Worker 处理过程中出错(下载失败、解析失败、API 调用失败)。 +- **系统处理:** 自动重试最多 3 次,每次重置为 QUEUED。3 次失败后标记 FAILED_FINAL。 +- **用户感知:** iOS 资料详情页 AI 处理状态显示红色"失败"横幅。 +- **Admin 恢复:** Admin 在导入监控页查看步骤日志,手动重试(不占系统重试次数)。 + +### 10.6 RAG 解析失败 + +- **场景:** PDF 损坏、DOCX 格式异常、OCR 无法识别。 +- **Worker 处理:** 解析阶段失败 → 任务标记 FAILED,更新 parseStatus 为 failed,记录 errorCode 和 errorMessage。 +- **影响范围:** 解析失败的文件无法进行后续分块、嵌入和索引。 +- **恢复:** Admin 触发重新解析;用户可尝试重新上传。 + +### 10.7 向量索引失败 + +- **场景:** Qdrant 不可用、嵌入 API 调用失败。 +- **Worker 处理:** 索引阶段失败 → 任务标记 FAILED。parseStatus 可能已 complete,但 indexStatus 为 failed。 +- **影响范围:** 资料可阅读但不可用于语义检索。 +- **恢复:** Admin 重试导入任务;系统自动重试。 + +### 10.8 重复上传 + +- **场景:** 用户短时间内上传相同文件多次。 +- **API 处理:** 使用 Redis 分布式锁(`lock:document-import:{fileName}:{timestamp}`,5 分钟 TTL)防止并发重复导入。 +- **边界:** 锁只防止并发重复;用户间隔 5 分钟后仍可上传相同文件创建新的 KnowledgeSource。 + +### 10.9 用户删除处理中资料 + +- **场景:** 用户在导入任务处理过程中删除知识源。 +- **API 处理:** KnowledgeSource 使用软删除(设置 deletedAt)。Python RAG Worker 在处理前应检查源是否已被删除(具体行为待确认)。 +- **影响:** 已生成的 KnowledgeChunk 和 ImportCandidate 可能成为孤儿数据。 + +### 10.10 候选审核失败 + +- **场景:** 接受候选时内容安全检查失败。 +- **API 处理:** 候选标记为 BLOCKED,返回原因。用户无法强制接受。 +- **Admin 查看:** Admin 可在候选巡检中看到 BLOCKED 状态的候选。 + +--- + +## 11. 当前完成状态 + +| 组件 | 状态 | 说明 | +|------|------|------| +| iOS 文件选择与上传 | 已完成 | 文件选择器 + 相册选择器 + 链接导入 | +| iOS 图片压缩 | 已完成 | >2MB 自动 JPEG 压缩 | +| iOS 上传进度展示 | 已完成 | 进度指示器 | +| iOS 候选审核界面 | 已完成 | 接受/拒绝/批量接受 | +| iOS AI 处理状态展示 | 已完成 | 资料详情页三色横幅(处理中/就绪/失败) | +| API COS 预签名 URL 上传流程 | 已完成 | 请求 URL → 直接 PUT → 确认 | +| API 文件类型与大小校验 | 已完成 | 8 种类型,最大 20MB | +| API 内容安全检查(文件名) | 已完成 | 敏感词匹配 | +| API 速率限制 | 已完成 | 文件上传端点 | +| API KnowledgeSource 创建与管理 | 已完成 | 含自动 DocumentImport 任务创建 | +| API 导入状态查询 | 已完成 | Redis 实时状态(进度+消息) | +| API 候选审核 API | 已完成 | accept/reject/batch-accept | +| Python RAG Worker 轮询与锁定 | 已完成 | 每 5 秒轮询,心跳每 30 秒 | +| Python RAG Worker 文本解析 | 已完成 | PDF/DOCX/TXT/MD/CSV/XLSX/图片 OCR | +| Python RAG Worker 分块与嵌入 | 已完成 | 递归分割 + BAAI/bge-m3 | +| Python RAG Worker 向量索引 | 已完成 | Qdrant zhixi_chunks 集合 | +| Python RAG Worker 候选生成 | 已完成 | DeepSeek 提取知识点 | +| Python RAG Worker 状态更新 | 已完成 | parseStatus/indexStatus/learningStatus | +| 导入任务自动重试 | 已完成 | 最多 3 次,过期任务自动回收 | +| Admin 文件管理 | 已完成 | 查看/删除 | +| Admin 来源文件查看 | 已完成 | 列表 + 按状态筛选 | +| Admin 导入监控 | 已完成 | 步骤日志 + 重试 | +| Admin 候选巡检 | 已完成 | 列表查看 | +| Admin 分块管理 | 已完成 | 按 sourceId 查看 | +| Admin RAG 调试 | 部分完成 | 基础向量搜索测试工具,展示原始 JSON 响应;非生产级检索调试界面 | +| 孤儿文件自动清理 | 暂未确认 | file-cleanup 队列存在但清理策略待确认 | +| 处理中删除源的行为 | 暂未确认 | Worker 是否检查软删除标志待确认 | diff --git a/docs/system-map/capabilities/04-知识库与知识点管理.md b/docs/system-map/capabilities/04-知识库与知识点管理.md new file mode 100644 index 0000000..b63d310 --- /dev/null +++ b/docs/system-map/capabilities/04-知识库与知识点管理.md @@ -0,0 +1,322 @@ +# 04 知识库与知识点管理 — 跨项目完整能力分析 + +> 项目角色分类:主链路参与者(iOS、主 API、数据库、COS——知识库 CRUD 必须经过这些项目)、上游支撑(Python RAG Worker——异步处理导入资料,不阻塞知识库管理操作)、运维可观测(Admin)。 +> Rust Document Runtime 不参与知识库管理链路。Heavy Runtime 不参与此链路。 +> 注意:Python RAG Worker 在本能力中是上游支撑(知识库 CRUD 不依赖它);在"资料上传与处理"能力中是主链路参与者。 + +--- + +## 1. 能力目标 + +用户可以创建、组织、维护个人知识库,管理其中的知识点和来源资料,通过文件夹分类、排序、搜索、公开发现和订阅来高效组织和获取学习内容。 + +--- + +## 2. C 端入口 + +| 入口页面 | 触发方式 | 功能 | +|---------|---------|------| +| 知识库首页 | Tab "知识库" 默认 | 查看知识库列表、筛选、搜索入口、创建入口 | +| 知识库搜索页 | 搜索图标 | 搜索知识库和知识点 | +| 创建知识库页 | + 按钮 / 我的页学习资产 | 创建新知识库(封面、名称、描述) | +| 知识库详情页 | 点击知识库卡片 | 查看知识点列表/来源文件列表、管理操作 | +| 添加知识点页 | 操作菜单"添加" | 手动/文件模式添加知识点 | +| 知识点详情页 | 点击知识点条目 | 查看/收藏/笔记/原文 | +| 编辑知识点页 | 工具栏菜单 | 编辑标题和内容 | +| 文件夹管理 Sheet | 操作菜单"文件夹管理" | 创建/重命名/删除文件夹 | +| 导入资料页 | 操作菜单"上传" | 文件/相册/链接导入 | +| 导入候选审核页 | 导入完成后 | 审核 AI 提取的知识点候选 | +| 发现公开库页 | "我的"页"发现公开库" | 浏览/订阅公开知识库 | + +--- + +## 3. 业务对象关系 + +``` +知识库(KnowledgeBase) +├── 来源资料(KnowledgeSource)── 原始上传文件,含解析/索引/学习状态 +├── 知识点(KnowledgeItem)── 知识库的基本内容单元 +│ ├── 类型:章节(chapter)、课程(lesson)、概念(concept)、笔记(note)、导入文档(imported_doc)、AI生成(ai_generated) +│ ├── 层级:通过 parentId 形成树状结构 +│ └── 关联:通过 sourceId 关联到来源资料 +├── 文件夹(KnowledgeFolder)── 用于组织知识点 +│ └── 同步创建 folder 类型的 KnowledgeItem(保证 iOS 兼容) +├── 知识分块(KnowledgeChunk)── 来源资料的语义分块,含向量嵌入 +├── 导入候选(ImportCandidate)── AI 提取的知识点候选,等待审核 +├── 测验(Quiz)── 基于知识库内容生成的测验 +├── 订阅关系(KnowledgeBaseSubscription)── 用户对公开知识库的订阅 +└── AI 会话范围(ChatScope)── AI 对话可限定在知识库范围 +``` + +--- + +## 4. 用户主流程 + +### 4.1 创建知识库 + +用户点击创建按钮 → 输入名称(必填)和描述(必填)→ 可选上传封面图(从相册选择,自动裁剪为 512×512)→ 点击创建 → API 创建知识库记录(默认 private)→ 用户可在列表中看到新知识库。每个用户最多创建 20 个知识库。 + +### 4.2 浏览与筛选 + +用户进入知识库首页 → 查看知识库卡片列表(封面、名称、描述、日期、置顶标记、公开标记)→ 可通过分类筛选(全部/我的/已订阅/官方)切换视图 → 滚动到底部自动加载更多(分页 20 条/页)→ 下拉刷新。 + +### 4.3 添加资料 + +用户进入知识库详情页 → 点击操作菜单"上传" → 选择文件/相册/链接导入 → 文件上传至 COS → API 创建 KnowledgeSource → 自动创建 DocumentImport 任务 → Python RAG Worker 异步处理 → 用户可查看 AI 处理状态 → 审核 AI 提取的候选知识点。 + +### 4.4 手动添加知识点 + +用户进入添加知识点页 → 选择"手动"模式 → 输入标题和内容文字 → 保存 → API 创建 KnowledgeItem。 + +### 4.5 编辑与删除知识点 + +用户在知识库详情页点击知识点 → 进入知识点详情页查看内容 → 工具栏菜单选择编辑 → 修改标题/内容 → 保存。滑动或长按可删除知识点(单个或批量)。 + +### 4.6 批量操作 + +用户进入批量选择模式 → 逐选或全选知识点 → 点击批量删除 → 确认弹窗 → API 批量软删除。 + +### 4.7 文件夹管理 + +用户打开文件夹管理 Sheet → 查看已有文件夹列表 → 新建(输入名称)→ 重命名(滑动操作)→ 删除(滑动操作)。创建文件夹时同步创建 folder 类型的 KnowledgeItem。注意:重命名文件夹时仅更新 KnowledgeFolder 记录的 name 字段,不会同步更新对应 KnowledgeItem 的 title 字段。当前无文件夹数量上限。 + +### 4.8 排序 + +用户在知识库详情页点击排序菜单 → 选择排序方式(默认/文件大小/创建时间/更新时间)→ 知识点列表按所选方式重新排列。 + +### 4.9 搜索 + +用户点击搜索图标 → 进入搜索页 → 输入关键词。当前搜索逻辑未实现——搜索页仅展示空状态,输入关键词不触发 API 调用。 + +### 4.10 公开库发现与订阅 + +用户进入发现公开库页 → 查看所有公开知识库列表(含标题、描述、条目数)→ 点击订阅按钮 → API 创建订阅记录。用户可在知识库首页"已订阅"筛选中查看已订阅的知识库。用户不可订阅自己的知识库。取消订阅可随时操作。 + +### 4.11 删除知识库 + +用户在知识库详情页操作菜单点击"删除知识库"→ 确认弹窗 → API 软删除知识库(设置 deletedAt)。删除后知识点和来源资料仍保留在数据库中(软删除),但不再对用户可见。 + +--- + +## 5. 项目职责 + +### iOS — 主链路参与者 + +- 知识库列表展示(卡片、筛选、分页、下拉刷新) +- 创建知识库(封面选择与裁剪、名称/描述输入) +- 知识库详情(双 Tab:知识点 + 来源文件,排序,批量操作) +- 知识点详情(多格式渲染、收藏、笔记、原文) +- 添加/编辑知识点 +- 文件夹管理 Sheet +- 搜索页(界面已搭建,逻辑未实现) +- 公开库发现与订阅 +- 导入与候选审核 + +### 主 API — 主链路参与者 + +- 知识库 CRUD(创建/列表/详情/更新/软删除) +- 知识库所有权校验(私有 KB 对非所有者返回 404) +- 置顶切换 +- 知识点 CRUD(创建/列表/详情/更新/单个删除/批量删除) +- 知识点排序 +- 公开库发现(GET /knowledge-bases/discover,含搜索参数) +- 订阅管理(订阅/取消订阅/查看已订阅) +- 文件夹 CRUD(创建/列表/更新/删除) +- 知识库数量限制(每用户最多 20 个) +- 内容安全检查(KB 标题、标签) + +### 数据库 — 主链路参与者 + +- 存储知识库、知识点、来源资料、文件夹、订阅、导入任务等核心业务数据 +- 软删除支持(deletedAt 字段) +- 唯一约束(userId + knowledgeBaseId 订阅防重、userId + parentId + name 文件夹防重) + +### COS — 主链路参与者 + +- 存储知识库封面图 +- 存储知识点关联文件的内容(通过 COS URL 引用) + +### Python RAG Worker — 上游支撑 + +- 不直接参与知识库 CRUD +- 异步处理导入资料,生成 KnowledgeChunk、ImportCandidate +- 用户在 RAG Worker 完成处理前即可查看和管理知识库及知识点 + +### Admin — 运维与可观测 + +- 知识库列表查看(全部 KB,含所属用户、条目数) +- 知识库详情抽屉(元数据 + 嵌套来源文件列表) +- 来源文件查看(全部来源,按 KB 和解析状态筛选) +- 来源文件引用追踪(查看哪些 AI 产物引用了该来源) +- 知识库删除 +- 用户管理(查看/状态管理) +- 会员与配额管理 + +--- + +## 6. 权限与可见性 + +### 6.1 私有知识库 + +- **可见性:** 仅所有者可查看和操作。非所有者请求返回 404(隐藏存在性)。 +- **所有者操作:** 全部 CRUD + 置顶 + 可见性切换 + 删除。 +- **非所有者操作:** 无任何操作权限。 + +### 6.2 公开知识库 + +- **可见性:** 任何人可通过发现页查看和搜索。所有者仍可正常管理。 +- **所有者操作:** 同私有知识库。 +- **非所有者操作:** 可查看详情、订阅。不可编辑或删除。 +- **订阅:** 用户可订阅公开知识库。不可订阅自己的知识库。 + +### 6.3 官方知识库 + +- **当前状态:** API 和数据库模型支持 ownerType 字段,但 iOS 端"官方"筛选返回空数组(TODO 注释:等后端支持)。 +- **计划行为:** 由平台创建和维护的精选知识库,所有用户可查看和订阅。 + +### 6.4 删除权限 + +- **知识库删除:** 仅所有者可删除(软删除)。 +- **知识点删除:** 所有者可单个或批量删除。 +- **来源资料删除:** 服务层无所有权检查(代码缺陷),任何认证用户可通过 ID 删除任意来源。 +- **文件夹删除:** 服务层无显式所有权检查(代码缺陷),但通过 KB 所有权间接保护。 + +### 6.5 资料访问权限 + +- **所有者:** 完整读写权限。可阅读原文件、使用 AI 对话(知识库范围)。 +- **订阅者:** 可查看知识库内容。原文件阅读权限待确认(取决于 COS 文件访问控制)。 +- **非所有者非订阅者:** 对私有 KB 无任何访问权限。对公开 KB 可查看详情和订阅。 + +--- + +## 7. 查询入口 + +### 用户查询 + +- **知识库列表:** iOS 知识库首页(卡片 + 筛选 + 分页)。 +- **知识库详情:** iOS 知识库详情页(双 Tab + 排序)。 +- **知识点详情:** iOS 知识点详情页(多格式渲染)。 +- **搜索:** iOS 知识库搜索页(界面已搭建,逻辑未实现)。 +- **公开库:** iOS 发现公开库页。 +- **已订阅:** iOS 知识库首页"已订阅"筛选。 + +### Admin 查询 + +- **知识库列表:** Admin 知识库页(全部 KB,含所属用户、条目数)。 +- **知识库详情抽屉:** 元数据 + 嵌套来源文件列表 + 引用追踪。 +- **来源文件列表:** Admin 来源文件页(按 KB 和解析状态筛选)。 +- **引用追踪:** 查看特定来源被哪些 AI 产物(测验、摘要等)引用。 + +### 系统内部查询 + +- **RAG 对话上下文:** API 从 KnowledgeItem 表按知识库 ID 查询最多 30 条,构建对话上下文。 +- **导入任务关联:** API 创建 KnowledgeSource 时自动关联 DocumentImport。 +- **订阅关系:** API 在订阅和已订阅列表查询时使用。 + +--- + +## 8. 修改入口 + +### 用户修改 + +- **创建知识库:** iOS 创建知识库页 → POST /knowledge-bases。 +- **更新知识库:** iOS 知识库设置 → PATCH /knowledge-bases/:id。 +- **置顶/取消置顶:** iOS 知识库卡片操作 → POST /knowledge-bases/:id/pin。 +- **创建知识点:** iOS 添加知识点页 → POST /knowledge-items。 +- **编辑知识点:** iOS 编辑知识点页 → PATCH /knowledge-items/:id。 +- **删除知识点:** iOS 知识库详情页(单个/批量) → DELETE /knowledge-items/:id 或 POST /knowledge-items/batch-delete。 +- **文件夹操作:** iOS 文件夹管理 Sheet → POST/PATCH/DELETE /knowledge-bases/:id/folders。 +- **订阅/取消订阅:** iOS 发现公开库页 → POST/DELETE /knowledge-bases/:id/subscribe。 +- **删除知识库:** iOS 知识库详情页 → DELETE /knowledge-bases/:id。 + +### Admin 修改 + +- **删除知识库:** Admin 知识库页删除按钮(危险确认弹窗)。 +- **删除文件:** Admin 文件管理页。 +- **重试导入:** Admin 导入监控页。 + +### 系统自动修改 + +- **itemCount 维护:** 创建/删除知识点时自动更新知识库的 itemCount。 +- **软删除传播:** 删除文件夹时自动软删除子文件夹和对应的 KnowledgeItem。 +- **内容安全检查:** KB 标题和标签自动进行敏感词匹配。 + +--- + +## 9. 删除影响 + +### 9.1 删除知识库 + +- **影响范围:** 知识库本身被软删除(设置 deletedAt)。 +- **知识点:** 保留在数据库中(不被级联删除),但用户不可见。 +- **来源资料:** 保留但关联的 KB 不可访问。 +- **订阅:** 保留但已删除 KB 不出现在已订阅列表中。 +- **测验:** 保留但关联的 KB 不可访问。 +- **AI 会话:** 保留但知识库范围对话可能无法加载上下文。 + +### 9.2 删除来源资料 + +- **影响范围:** 来源资料被软删除。 +- **关联知识点:** 保留(sourceId 变为悬空引用)。 +- **关联分块:** KnowledgeChunk 保留,Qdrant 向量需手动或通过软删除标记清理。 +- **关联候选:** ImportCandidate 保留但关联的 sourceId 不可访问。 + +### 9.3 删除知识点 + +- **影响范围:** 知识点被软删除,itemCount 递减。 +- **子知识点:** 保留在数据库中(parentId 变为悬空引用)。 +- **关联笔记:** 知识点详情页的笔记入口不可用。 +- **AI 对话上下文:** 已删除知识点不再出现在上下文加载结果中。 + +### 9.4 删除文件夹 + +- **影响范围:** 文件夹被软删除,对应的 folder 类型 KnowledgeItem 也被软删除。 +- **子文件夹:** 级联软删除。 +- **文件夹内知识点:** 保留在数据库中(parentId 引用可能变为悬空)。 + +### 9.5 取消订阅 + +- **影响范围:** 订阅记录被删除。 +- **已订阅列表:** 知识库从用户的已订阅筛选中消失。 +- **其他数据:** 无影响。用户之前查看的知识库内容仍可查看(只要知识库保持公开)。 + +--- + +## 10. 当前完成状态 + +| 组件 | 状态 | 说明 | +|------|------|------| +| iOS 创建知识库 | 已完成 | 封面、名称、描述,API 创建 | +| iOS 知识库列表与筛选 | 部分完成 | 全部/我的/已订阅可用;"官方"筛选返回空 | +| iOS 知识库详情(双 Tab) | 已完成 | 知识点列表 + 来源文件列表 | +| iOS 手动添加知识点 | 已完成 | 标题 + 内容编辑 | +| iOS 文件模式添加知识点 | 已完成 | COS 上传 + 创建知识点 | +| iOS 知识点详情(多格式渲染) | 已完成 | 文本/Markdown/文件 | +| iOS 编辑知识点 | 已完成 | 标题 + 内容修改 | +| iOS 删除知识点(单个+批量) | 已完成 | 单个软删除 + 批量选择删除 | +| iOS 文件夹管理 | 已完成 | 创建/重命名/删除 | +| iOS 排序 | 已完成 | 4 种排序方式 | +| iOS 搜索 | 未完成 | 搜索页界面已搭建,搜索逻辑未实现 | +| iOS 公开库发现与订阅 | 已完成 | 查看/订阅/取消订阅 | +| iOS 删除知识库 | 已完成 | 确认弹窗 + API 软删除 | +| iOS 收藏知识点 | 部分完成 | UI 切换存在,后端 API 未支持(TODO) | +| iOS 重命名知识点 | 未完成 | 菜单项存在但 action 为空(TODO) | +| iOS 移动到文件夹 | 未完成 | 菜单项存在但 action 为空(TODO) | +| iOS 知识库管理页 | 未完成 | 操作菜单"知识库管理"按钮 action 为空(TODO) | +| API 知识库 CRUD | 已完成 | 创建/列表/详情/更新/软删除 | +| API 知识库所有权校验 | 已完成 | 私有 KB 对非所有者返回 404 | +| API 知识库数量限制 | 已完成 | 每用户最多 20 个 | +| API 置顶切换 | 已完成 | | +| API 公开库发现与搜索 | 已完成 | 支持标题+描述搜索 | +| API 订阅管理 | 已完成 | 订阅/取消订阅/已订阅列表 | +| API 知识点 CRUD | 已完成 | 创建/列表/详情/更新/单个删除/批量删除 | +| API 知识点排序 | 已完成 | createdAt/updatedAt/fileSize/orderIndex | +| API 文件夹 CRUD | 已完成 | 含 folder 类型 KnowledgeItem 同步;当前无文件夹数量限制 | +| API 内容安全检查 | 已完成 | KB 标题 + 标签 + 候选内容 | +| Admin 知识库查看 | 已完成 | 列表 + 详情抽屉 | +| Admin 来源文件查看 | 已完成 | 按 KB 和解析状态筛选 | +| Admin 来源文件引用追踪 | 已完成 | 查看 AI 产物引用了哪些来源 | +| Admin 知识库删除 | 已完成 | | +| 官方知识库 | 未完成 | API 模型支持但后端筛选未实现 | +| API 来源资料删除权限校验 | 暂未确认 | 代码中无所有权检查(疑似缺陷) | +| API 文件夹更新/删除权限校验 | 暂未确认 | 代码中无显式所有权检查 | diff --git a/docs/system-map/capabilities/05-AI对话与知识库问答.md b/docs/system-map/capabilities/05-AI对话与知识库问答.md new file mode 100644 index 0000000..88d2113 --- /dev/null +++ b/docs/system-map/capabilities/05-AI对话与知识库问答.md @@ -0,0 +1,398 @@ +# 05 AI 对话与知识库问答 — 跨项目完整能力分析 + +> 项目角色分类:主链路(iOS、主 API、DeepSeek 模型服务)、上游支撑(Python RAG Worker,仅为知识库内容供给,不参与对话上下文加载)、运维可观测(Admin)。 +> Qdrant 不参与对话上下文加载——所有 5 种 Scope 的上下文均来自 PostgreSQL KnowledgeItem 表。 +> Heavy Runtime 不直接参与基础 AI 对话——它负责异步 AI 分析任务(学习状态分析、测验生成等),对话链路走 AiGateway 直达模型。 +> Rust Document Runtime 不参与 AI 对话链路。 + +--- + +## 1. 能力目标 + +用户可以通过自然语言与 AI 进行学习相关的对话。对话可以限定在特定知识库、资料或知识点的范围内,AI 基于范围内知识内容回答问题,并提供来源引用。支持流式回复、思考过程展示和多会话管理。 + +--- + +## 2. C 端入口 + +| 入口页面 | 对话范围 | 触发方式 | +|---------|---------|---------| +| AI 反馈页 | 全局 | "深入提问"按钮 | +| 知识库详情页 | 知识库 | 底部 AI 对话按钮 | +| 资料阅读页 | 资料 | 工具栏 AI 按钮 | +| 知识点详情页 | 知识点 | 工具栏菜单(如有) | +| AI 反馈页 → AIChatPage | 全局 | "深入提问" → AIChatPage | +| (废弃)AI 首页 | 全局 | 底部输入栏(页面无入口) | + +--- + +## 3. 对话范围 + +### 3.1 全局对话(scopeType: global) + +- **上下文来源:** 无知识库上下文。AI 仅基于通用知识回答。 +- **RAG 查询范围:** 不进行任何检索。 +- **会话识别:** 创建 session 时 scopeType=global 且 scopeId 为空。 +- **切换处理:** 用户从范围对话点击"新建对话"可创建全局对话。 + +### 3.2 知识库范围(scopeType: knowledge_base) + +- **上下文来源:** 从 KnowledgeItem 表查询该知识库下的知识点(最多 30 条,每条截取前 500 字符,总计最多 4000 字符)。 +- **RAG 查询范围:** 上下文直接从 PostgreSQL 的 KnowledgeItem 表加载。所有 5 种 Scope 均不调用 Qdrant——`loadContextByScope` 在代码中完全不涉及向量搜索。 +- **会话识别:** 创建 session 时 scopeType=knowledge_base,scopeId=。相同知识库范围的会话通过 "open-or-create" 模式复用(同一用户同一知识库只有一个活跃对话会话)。 +- **切换处理:** 用户切换到另一个知识库的对话时,创建新会话或恢复已有会话。 + +### 3.3 资料范围(scopeType: material) + +- **上下文来源:** 按 sourceRef 匹配该资料关联的知识点。与知识库范围相同,上下文直接从 PostgreSQL 的 KnowledgeItem 表加载。Qdrant 不参与对话上下文加载。 +- **会话识别:** session 的 scopeType=material,scopeId=。 +- **切换处理:** 用户离开资料阅读页后,对话会话保留。下次进入同一资料时恢复。 + +### 3.4 知识点范围(scopeType: knowledge_item) + +- **上下文来源:** 单个知识点的完整内容。 +- **RAG 查询范围:** 单个知识点本身,无需检索。 +- **会话识别:** session 的 scopeType=knowledge_item,scopeId=。 +- **切换处理:** 每个知识点有独立会话。 + +### 3.5 范围切换机制 + +- 用户在不同入口进入 AI 对话时,系统根据当前上下文自动确定对话范围。 +- 每个范围维护独立的 ChatSession。 +- 会话列表 Sheet 可按范围过滤显示。 +- ScopeSnapshot 保存在每条消息中,确保历史消息知道其产生时的范围上下文。 + +--- + +## 4. 用户主流程 + +``` +用户进入对话(从知识库详情页/资料阅读页/AI 反馈页等入口) +→ iOS 调用 API 创建或恢复会话(open-or-create,相同范围复用会话) +→ 用户输入消息 +→ iOS 调用流式发送 API(POST /rag-chat/sessions/:id/stream) +→ API 校验会话所有权 +→ API 内容安全检查(敏感词匹配) +→ API 保存用户消息(含 scopeSnapshot) +→ API 自动生成会话标题(首次消息时,截取前 40 字符) +→ API 根据 scopeType 加载上下文: + - global:空上下文 + - knowledge_base:从 KnowledgeItem 表查询最多 30 条(每条约 500 字符) + - material/folder:按相应过滤条件查询 + - knowledge_item:查询单个知识点 +→ API 将上下文注入系统提示模板 +→ API 调用 AiGateway → 路由到 DeepSeek Provider → deepseek-v4-pro +→ DeepSeek 流式返回(content 块 + thinking 块) +→ API 通过 SSE 逐块转发给 iOS +→ iOS 实时展示 AI 回复(含思考过程可折叠动画) +→ 流式完成后 API 保存 AI 消息(含 token 计数) +→ API 保存引用(前 5 个上下文项作为 ChatCitation) +→ iOS 展示引用信息 +→ 用户可复制回复、重新生成、或发送新消息 +``` + +--- + +## 5. 项目职责 + +### iOS — 主链路参与者 + +- AI 对话界面(消息气泡、思考过程展示、引用展示) +- 流式接收与实时渲染(SSE 解析) +- 输入栏(文字输入、语音图标占位、发送按钮) +- 会话列表 Sheet(搜索、切换、删除、归档、置顶) +- 新建对话 +- 范围标签展示(当前对话限定范围) +- 复制回复、重新生成 + +### 主 API — 主链路参与者 + +- 会话 CRUD(open-or-create、列表、更新、软删除) +- 会话所有权校验 +- 消息发送(同步 + 流式) +- 内容安全检查(输入消息和 AI 输出) +- 上下文加载(按 scopeType 从 KnowledgeItem 表查询) +- 系统提示构建(上下文注入) +- AiGateway 路由(模型选择、回退、重试) +- SSE 流式转发 +- 引用保存(ChatCitation) +- Token 使用记录(ModelInvocationLog) +- 自动标题生成 + +### DeepSeek 模型服务 — 主链路参与者 + +- 接收系统提示 + 用户消息 + 上下文 +- 流式生成回复(content + reasoning_content) +- 模型:deepseek-v4-pro(primary tier),deepseek-v4-flash(cheap tier) +- 通过 AiGateway 统一管理 API 密钥和路由 + +### Python RAG Worker — 上游支撑(间接参与) + +- 不直接参与对话流程。负责文档导入后的处理(解析→分块→嵌入→索引),为知识库提供结构化的知识点内容。 +- RAG 处理结果(KnowledgeItem、KnowledgeChunk)是对话上下文的间接来源——KnowledgeItem 表中的内容可能来自 RAG 生成的候选知识点。 +- 注意:知识库范围对话的上下文来自 KnowledgeItem 表(PostgreSQL),**不依赖** Qdrant 向量搜索,也不依赖 RAG 的实时处理状态。 + +### Qdrant — 不参与对话上下文加载 + +- 存储文档块的向量索引,用于文档导入后的语义检索(Admin RAG 调试页使用)。 +- **不参与 AI 对话的上下文加载**——`loadContextByScope` 完全不调用 Qdrant,所有 5 种 Scope 的上下文均来自 PostgreSQL。 + +### Admin — 运维与可观测 + +- 会话日志查看(Admin 聊天日志页,查看所有会话和消息) +- AI 网关管理(路由规则、提供商管理、回退日志) +- AI 使用统计(调用次数、延迟、失败率、成本,按提供商和模型) +- AI 成本管理(费用记录、按用户统计、导出) +- 模型配置(temperature、max_tokens 等参数) +- 内容安全审核(敏感词库、审核记录、举报管理、违规处罚) + +### Heavy Runtime — 不直接参与 + +Heavy Runtime 负责异步 AI 分析任务(学习状态分析、薄弱点识别、测验生成、闪卡生成),通过独立的作业排队机制运作。**基础 AI 对话不经过 Heavy Runtime**,而是通过 AiGateway 直接调用 DeepSeek。 + +--- + +## 6. 会话管理 + +### 6.1 创建 + +- **方式:** open-or-create 模式。用户从入口进入对话时,iOS 调用 POST /rag-chat/sessions。 +- **复用逻辑:** 相同 scopeType + scopeId + userId 下存在未归档未删除的会话时,返回已有会话(HTTP 200)。否则创建新会话(HTTP 201)。 +- **这意味着:** 每个用户在每个知识库范围内只有一个活跃对话会话。 + +### 6.2 切换 + +- **方式:** 用户在会话列表 Sheet 中点击历史会话 → iOS 调用 API 加载该会话的消息历史。 +- **效果:** 当前对话界面切换到所选会话,范围标签更新。 + +### 6.3 搜索 + +- **方式:** 在会话列表 Sheet 中输入搜索词 → 本地过滤或 API 搜索。 +- **范围:** 当前范围内的会话。 + +### 6.4 归档 + +- **方式:** 会话列表 Sheet 中滑动 → "归档"。 +- **效果:** API 更新会话 isArchived=true。已归档会话不在默认列表中显示。 +- **恢复:** 可通过更新 isArchived=false 取消归档。 + +### 6.5 删除 + +- **方式:** 会话列表 Sheet 中滑动 → "删除"。 +- **效果:** API 软删除会话(isDeleted=true)。消息保留在数据库中但不再对用户可见。 + +### 6.6 置顶 + +- **方式:** 会话列表 Sheet 中左滑 → "置顶"/"取消置顶"。 +- **效果:** API 更新会话 isPinned 状态。置顶会话排在最前。 + +### 6.7 Scope(对话范围) + +- 每个会话有 scopeType 和 scopeId,确定上下文来源。 +- 新建对话时,如果用户从范围入口(知识库/资料)进入,新会话继承该范围。 +- 用户也可以在对话中切换到全局模式创建新会话。 + +### 6.8 Scope Snapshot(范围快照) + +- 每条消息保存一个 scopeSnapshot 对象:{ scopeType, scopeId, parentKnowledgeBaseId }。 +- 作用:将消息冻结到发送时的范围上下文。即使后续范围发生变化,历史消息仍知道自己引用了哪个范围的上下文。 + +### 6.9 引用(Citation) + +- AI 回复后,系统从上下文项中提取前 5 个创建 ChatCitation。 +- 每个引用包含:chunkId(知识点 ID)、sourceTitle(标题)、excerptText(内容前 500 字符)。 +- iOS 在消息气泡中展示引用信息。 + +### 6.10 历史消息 + +- iOS 进入会话时调用 GET /rag-chat/sessions/:id/messages 加载历史。 +- 消息按时间排序,含角色(user/assistant)、内容、token 数和引用。 + +--- + +## 7. 核心业务数据 + +### 7.1 对话会话(ChatSession) + +- **谁创建:** API 在 iOS 调用 open-or-create 时创建(或返回已有)。 +- **谁更新:** API 在每次消息发送时更新 lastMessageAt;iOS 操作更新 isPinned/isArchived/isDeleted/title/modelMode/modelId。 +- **谁查询:** iOS 获取会话列表和消息历史;Admin 在聊天日志页查看。 +- **用途:** 对话的组织单元,承载范围信息和消息列表。 + +### 7.2 对话范围(ChatScope) + +- **概念性对象**(非独立数据库表),由 ChatSession 的 scopeType + scopeId 定义。 +- **取值:** global、knowledge_base、folder、material、knowledge_item。 +- **用途:** 确定上下文加载策略和会话唯一性。 + +### 7.3 消息(ChatMessage) + +- **谁创建:** API 在发送流程中创建用户消息和 AI 消息。 +- **谁更新:** 创建后不可修改。 +- **谁查询:** iOS 加载会话消息历史;Admin 在聊天日志详情中查看。 +- **用途:** 对话的完整记录,含角色、内容、token 数、scopeSnapshot。 + +### 7.4 引用(ChatCitation) + +- **谁创建:** API 在 AI 回复保存后自动创建(从前 5 个上下文项提取)。 +- **谁更新:** 创建后不可修改。 +- **谁查询:** iOS 在消息详情中展示;消息列表查询时惰性加载。 +- **用途:** 为 AI 回复提供可追溯的来源引用。 + +### 7.5 范围快照(ScopeSnapshot) + +- **概念性对象**(嵌入在 ChatMessage 中),包含 { scopeType, scopeId, parentKnowledgeBaseId }。 +- **用途:** 冻结每条消息产生时的对话范围。 + +### 7.6 知识分块(KnowledgeChunk) + +- **谁创建:** Python RAG Worker 在文档处理时创建。 +- **谁更新:** 不更新(软删除通过 Qdrant 实现)。 +- **谁查询:** Admin 在分块管理页查看;Qdrant 向量搜索(当前仅 Admin RAG 调试页使用,不用于对话上下文加载)。 +- **用途:** 文档的语义检索向量索引。当前不参与 AI 对话上下文构建。 + +### 7.7 模型配置(Model Configuration) + +- **谁管理:** Admin 通过 AI 网关管理页配置路由规则和提供商。 +- **谁使用:** AiGateway 在每次对话请求时根据 tier(primary/cheap/strong)和 taskType 选择模型。 +- **当前配置:** primary tier → deepseek-v4-pro;cheap tier → deepseek-v4-flash。 + +--- + +## 8. 异常与降级 + +### 8.1 RAG 尚未处理完成 + +- **场景:** 资料已上传但 Python RAG Worker 尚未完成向量索引。 +- **影响:** 知识库范围对话的上下文来自 KnowledgeItem 表——**不受 RAG 处理状态影响**。所有 Scope 的上下文加载均不依赖 Qdrant,RAG 未完成不影响对话功能。 + +### 8.2 检索无结果 + +- **场景:** 知识库为空或范围内无匹配知识点。 +- **API 处理:** loadContextByScope 返回 isEmpty=true。系统提示注入"当前知识库中暂无相关内容"。 +- **模型行为:** AI 基于通用知识回答,可能告知用户知识库内容不足。 + +### 8.3 模型调用失败 + +- **场景:** DeepSeek API 返回错误(超时、限流、服务异常)。 +- **API 处理:** AiGateway 自动回退(fallback 到同 tier 的备用模型/提供商),最多重试 3 次。 +- **用户感知:** 如果所有重试均失败,返回错误提示。Admin 可在回退日志中查看详情。 + +### 8.4 流式响应中断 + +- **场景:** SSE 连接在网络问题或客户端断开时中断。 +- **API 处理:** 检测 res.destroyed,优雅停止流式输出。已生成的部分内容可能不保存为完整消息(取决于中断时机)。 +- **iOS 处理:** 显示连接中断提示。用户可重新发送消息。 + +### 8.5 用户取消生成 + +- **场景:** 用户在 AI 生成过程中取消(iOS 断开 SSE 连接或发送取消请求)。 +- **API 处理:** 检测连接断开,停止流式输出。 +- **影响:** 部分生成的内容不保存。用户可重新发送。 + +### 8.6 会话被删除 + +- **场景:** 用户或 Admin 删除会话。 +- **API 处理:** 软删除(isDeleted=true)。消息保留但不可见。 +- **用户感知:** 会话从列表中消失。已删除会话不可恢复(当前无回收站功能)。 + +### 8.7 资料被删除 + +- **场景:** 对话引用的知识库/资料/知识点被删除。 +- **API 处理:** 上下文加载时自动过滤已删除项。历史消息的 scopeSnapshot 仍保留原范围信息,但该范围可能不再可访问。 +- **用户感知:** 新对话中该范围无上下文可用。历史消息仍可查看但引用可能失效。 + +### 8.8 无权限 + +- **场景:** 用户尝试访问其他用户的会话。 +- **API 处理:** 会话所有权校验失败,返回 403/404。 +- **用户感知:** 无法查看或操作非自己的会话。 + +### 8.9 Token 超限 + +- **场景:** 上下文 + 对话历史超过模型上下文窗口。 +- **API 处理:** 上下文加载有 4000 字符硬限制。长对话历史可能需要截断(具体策略待确认)。 +- **用户感知:** 较早的对话内容可能不被模型考虑。 + +### 8.10 模型 API Key 无效 + +- **场景:** 平台 DeepSeek API Key 过期或余额不足。 +- **API 处理:** AiGateway 调用失败。如果用户配置了自己的 API Key,可回退到用户 Key。 +- **Admin 处理:** Admin 在密钥管理页更新或轮换 Key。 +- **用户感知:** 对话报错。用户可在 AI 设置中提供自己的 DeepSeek Key。 + +### 8.11 DeepSeek 服务不可用 + +- **场景:** DeepSeek API 全面不可用。 +- **API 处理:** AiGateway 尝试所有提供商后失败。 +- **用户感知:** 对话完全不可用,显示服务异常提示。 +- **Admin 处理:** Admin 在 AI 网关管理页监控提供商状态,配置备用提供商。 + +--- + +## 9. 查询与管理入口 + +### 用户查询 + +- **会话列表:** iOS 对话页工具栏 → 会话列表 Sheet(搜索、筛选)。 +- **消息历史:** iOS 对话页加载历史消息。 +- **引用信息:** iOS 消息气泡中展示。 +- **AI 使用统计:** iOS 端当前未展示(无用户可见的 token 用量或成本页面)。 + +### Admin 查询 + +- **会话日志:** Admin 聊天日志页 → 查看所有会话(含用户 ID、知识库 ID、消息数)。 +- **消息详情:** Admin 聊天日志页 → 点击会话查看全部消息(角色、内容预览、token 数、时间)。 +- **AI 网关管理:** Admin AI 网关页(路由规则 CRUD、提供商启用/禁用、回退日志)。 +- **AI 使用统计:** Admin 指标页(按提供商/模型的调用次数、延迟、失败率、成本)。 +- **AI 成本管理:** Admin 计费页(费用记录 CRUD、按用户统计、导出 CSV)。 +- **内容安全审核:** Admin 内容安全页(敏感词库、审核记录、举报管理、违规处罚)。 + +### 系统内部查询与管理 + +- **AiGateway 路由:** 每次对话请求时自动查询路由规则和提供商配置。 +- **Token 使用记录:** AiGateway 自动记录每次调用的 inputTokens/outputTokens/延迟/成本到 ModelInvocationLog。 +- **每日使用聚合:** 系统自动聚合用户和平台的每日 AI 使用量(UserAiUsageDaily、PlatformAiBudgetDaily)。 +- **配额检查:** 发送消息前检查用户每日配额和平台预算。 + +--- + +## 10. 当前完成状态 + +| 组件 | 状态 | 说明 | +|------|------|------| +| iOS 流式对话界面 | 已完成 | SSE 解析 + 思考过程展示 + 引用展示 | +| iOS 消息气泡渲染 | 已完成 | 用户消息紫色渐变 + AI 消息含思考折叠 | +| iOS 复制/重新生成 | 已完成 | 复制到剪贴板 + 重新发送 | +| iOS 会话列表 Sheet | 已完成 | 搜索、切换、删除、归档、置顶 | +| iOS 新建对话 | 已完成 | 强制创建新会话 | +| iOS 范围标签展示 | 已完成 | 对话顶部显示当前范围 | +| iOS 全局对话 | 已完成 | 无上下文对话 | +| iOS 知识库范围对话 | 已完成 | 从知识库详情页底部按钮进入 | +| iOS 资料范围对话 | 已完成 | 从资料阅读页工具栏 AI 按钮进入 | +| iOS 知识点范围对话 | 暂未确认 | API scopeType=knowledge_item 已定义;iOS 知识点详情页工具栏菜单未发现直接 AI 对话入口,可能需从知识点详情页手动跳转 | +| API open-or-create 会话 | 已完成 | 相同范围复用已有会话 | +| API 内容安全检查 | 已完成 | 输入消息 + AI 输出敏感词匹配 | +| API 上下文加载(KnowledgeItem 表) | 已完成 | 按 scopeType 查询最多 30 条 | +| API 系统提示构建 | 已完成 | 上下文注入到提示模板 | +| API AiGateway 路由 | 已完成 | tier 路由 + 回退 + 重试 | +| API SSE 流式转发 | 已完成 | Content-Type: text/event-stream | +| API 引用保存 | 已完成 | 前 5 个上下文项 → ChatCitation | +| API 自动标题生成 | 已完成 | 首次消息截取前 40 字符 | +| API Token 使用记录 | 已完成 | ModelInvocationLog | +| DeepSeek 模型调用 | 已完成 | deepseek-v4-pro(primary)、deepseek-v4-flash(cheap) | +| Qdrant 参与对话上下文加载 | 未完成 | `loadContextByScope` 完全不调用 Qdrant;所有 5 种 Scope 上下文均来自 PostgreSQL KnowledgeItem 表 | +| 联网搜索 | 暂未确认 | 未发现联网搜索功能实现 | +| 深度思考 | 已完成 | DeepSeek reasoning_content → SSE thinking 块 → iOS 思考过程展示 | +| 文件附件 | 暂未确认 | 未发现对话中上传文件功能 | +| 导图 | 暂未确认 | 未发现 AI 生成导图功能 | +| 分享 | 暂未确认 | 未发现对话分享功能 | +| 生成笔记 | 暂未确认 | 未发现从对话生成笔记功能 | +| Admin 会话日志查看 | 已完成 | 聊天日志页 | +| Admin AI 网关管理 | 已完成 | 路由规则 + 提供商 + 回退日志 | +| Admin AI 使用统计 | 已完成 | 按提供商/模型的调用统计 | +| Admin AI 成本管理 | 已完成 | 费用记录 + 按用户统计 + 导出 | +| Admin 内容安全审核 | 已完成 | 敏感词库 + 审核记录 + 举报 + 违规 | +| 用户 AI 用量展示 | 未完成 | iOS 端无 token 用量或配额展示 | +| 用户自定义 API Key | 已完成 | iOS 设置页 → AI 设置 → 输入自己的 DeepSeek Key | +| 平台预算回退 | 已完成 | 平台预算不足时自动回退到用户 Key | diff --git a/docs/system-map/capabilities/06-内容与对话项目矩阵.md b/docs/system-map/capabilities/06-内容与对话项目矩阵.md new file mode 100644 index 0000000..2950063 --- /dev/null +++ b/docs/system-map/capabilities/06-内容与对话项目矩阵.md @@ -0,0 +1,120 @@ +# 06 内容与对话项目矩阵 + +> 三项业务能力(资料上传与处理、知识库与知识点管理、AI 对话与知识库问答)在各项目中的职责分布。 +> 项目角色:主链路参与者、上游支撑、下游消费、运维可观测。 + +--- + +## 一、资料上传与处理 — 项目参与矩阵 + +| 业务环节 | iOS | 主 API | COS | Python RAG Worker | Qdrant | Admin(运维可观测) | +|---------|-----|--------|-----|-------------------|--------|-------------------| +| 文件选择 | 系统文件选择器/相册/链接输入 | — | — | — | — | — | +| 文件校验与压缩 | 校验类型;图片 >2MB 自动 JPEG 压缩 | 校验文件类型(8 种)和大小(≤20MB) | — | — | — | — | +| 上传授权 | 调用 API 获取预签名 URL | 生成 COS 预签名 PUT URL(1 小时有效),内容安全检查文件名 | 提供预签名 URL 能力 | — | — | — | +| 文件上传 | 直接 PUT 文件到 COS | — | 接收文件数据 | — | — | — | +| 上传确认 | 调用 API 确认 | 验证 COS 中文件存在,创建 UploadedFile 记录 | 供 headObject 验证 | — | — | — | +| 创建资料记录 | — | 创建 KnowledgeSource + DocumentImport(QUEUED),Redis 状态初始化 | — | — | — | — | +| 异步处理 | — | 管理导入任务状态,提供查询端点 | 存储原始文件供 Worker 下载 | 轮询→锁定→下载→解析→清洗→分块→嵌入→索引→生成候选 | 存储向量索引(zhixi_chunks 集合,1024 维) | 监控导入任务(步骤日志、重试) | +| 状态展示 | 资料详情页 AI 处理状态横幅 | 提供 parseStatus/indexStatus/learningStatus 查询 | — | 更新 KnowledgeSource 处理状态 | — | 查看来源文件状态 | +| 候选审核 | 接受/拒绝/批量接受候选 | 候选审核 API,内容安全检查 | — | 生成候选(DeepSeek 提取知识点) | — | 候选巡检 | +| 失败处理 | 展示错误提示 | 自动重试(最多 3 次)+ 过期任务回收 | — | 失败时更新状态和错误信息 | — | 手动重试导入 | +| 文件删除 | 来源文件删除 | 软删除;Admin 可从 COS 删除 | 删除对象 | — | 软删除向量标记 | 文件管理页删除 | + +--- + +## 二、知识库与知识点管理 — 项目参与矩阵 + +| 业务环节 | iOS | 主 API | 数据库 | COS | Python RAG Worker | Admin(运维可观测) | +|---------|-----|--------|--------|-----|-------------------|-------------------| +| 创建知识库 | 封面选择+裁剪、名称/描述输入 | 创建 KB 记录(默认 private),限制 20 个/用户 | 存储 KB 记录 | 存储封面图 | — | — | +| 知识库列表 | 卡片列表+筛选+分页+下拉刷新 | 分页查询,支持 visibility/ownerType 筛选 | 查询+排序 | — | — | 查看全部 KB | +| 知识库详情 | 双 Tab(知识点+来源文件)+排序 | 提供详情查询+知识点列表+来源列表 | 关联查询 | — | — | 详情抽屉+来源文件列表 | +| 知识库更新/删除 | 更新信息/确认弹窗删除 | 所有权校验,软删除 | 更新/软删除 | — | — | 可删除 KB | +| 添加知识点 | 手动模式(标题+内容)+文件模式 | 创建 KnowledgeItem | 存储记录 | 文件模式下存储内容 | — | — | +| 知识点编辑 | 标题+内容编辑 | 白名单字段更新 | 更新记录 | — | — | — | +| 知识点删除 | 单个删除+批量选择删除 | 单个软删除+批量软删除 | 软删除+itemCount 递减 | — | — | — | +| 文件夹管理 | Sheet 弹窗(创建/重命名/删除) | 文件夹 CRUD,同步创建 folder 类型 KnowledgeItem | 存储文件夹+同步 KnowledgeItem | — | — | — | +| 排序 | 排序菜单(4 种方式) | 排序参数查询 | ORDER BY 排序 | — | — | — | +| 搜索 | 搜索页界面(逻辑未实现) | 公开库支持标题+描述搜索 | 全文搜索未实现 | — | — | — | +| 公开库发现 | 公开库列表+订阅/取消订阅 | 发现 API,订阅管理 | 存储订阅关系 | — | — | — | +| 权限校验 | — | 所有权校验(私有 KB 返回 404) | — | — | — | Admin 权限分级 | +| 内容安全 | — | KB 标题+标签敏感词检查 | — | — | — | 敏感词库管理 | + +--- + +## 三、AI 对话与知识库问答 — 项目参与矩阵 + +| 业务环节 | iOS | 主 API | DeepSeek 模型 | Python RAG Worker | Admin(运维可观测) | +|---------|-----|--------|-------------|-------------------|-------------------| +| 会话创建/恢复 | 调用 API open-or-create | open-or-create 逻辑(相同范围复用) | — | — | — | +| 消息发送 | 输入文字,调用流式 API | 校验→内容安全→保存用户消息→加载上下文→构建提示→调用模型 | — | — | — | +| 上下文加载 | — | 按 scopeType 从 KnowledgeItem 表查询(最多 30 条×500 字符),完全不调用 Qdrant | — | 知识点内容来自 RAG 处理结果(间接供给) | — | +| 模型调用 | — | AiGateway 路由→DeepSeek Provider | 流式生成(content+reasoning_content) | — | — | — | +| 流式展示 | SSE 解析+实时渲染+思考过程折叠 | SSE 流式转发 | 提供流式响应 | — | — | — | +| 引用展示 | 消息气泡中展示引用 | 保存前 5 个上下文项为 ChatCitation | — | — | — | — | +| 会话管理 | 列表+搜索+切换+删除+归档+置顶 | 会话 CRUD+所有权校验 | — | — | — | 查看所有会话和消息 | +| 内容安全 | — | 输入消息+AI 输出敏感词匹配 | — | — | — | 敏感词库+审核记录+举报+违规 | +| 模型路由 | — | AiGateway:tier 路由+回退+重试(最多 3 次) | — | — | — | 路由规则 CRUD+提供商管理+回退日志 | +| Token 与成本 | — | 记录 ModelInvocationLog+每日聚合 | — | — | — | 调用统计+成本管理+导出 | +| 用户 API Key | 设置页输入自己的 Key | 加密存储+测试+回退使用 | — | — | — | — | +| 联网搜索 | 暂未确认 | 暂未确认 | — | — | — | — | +| 文件附件 | 暂未确认 | 暂未确认 | — | — | — | — | +| 导图/分享/生成笔记 | 暂未确认 | 暂未确认 | — | — | — | — | + +--- + +## 四、项目角色分类 + +### 主链路参与者 + +| 项目 | 资料上传与处理 | 知识库与知识点管理 | AI 对话与知识库问答 | +|------|-------------|----------------|-----------------| +| iOS | 文件选择、校验、上传、候选审核 | 知识库/知识点/文件夹全界面 | 对话界面、会话管理、流式渲染 | +| 主 API | 上传授权、确认、资料记录、导入任务管理 | 全部 CRUD、权限校验、搜索(部分) | 会话管理、上下文加载、模型路由、SSE 转发、内容安全 | +| COS | 文件存储和预签名 URL | 封面图和文件内容存储 | — | +| 数据库 | UploadedFile/DocumentImport 记录 | KnowledgeBase/Item/Folder/Source 全部 | ChatSession/Message/Citation 记录 | +| DeepSeek | — | — | 模型推理(deepseek-v4-pro) | + +### 上游支撑 + +| 项目 | 资料上传与处理 | 知识库与知识点管理 | AI 对话与知识库问答 | +|------|-------------|----------------|-----------------| +| Python RAG Worker | 文档解析、分块、嵌入、候选生成 | 异步处理,不阻塞知识库 CRUD | 知识库内容供给(KnowledgeItem 来自 RAG 候选审核);不参与对话上下文加载 | +| Qdrant | 向量索引存储 | — | 不参与对话上下文加载;当前仅 Admin RAG 调试页使用 | + +### 下游消费 + +| 项目 | 资料上传与处理 | 知识库与知识点管理 | AI 对话与知识库问答 | +|------|-------------|----------------|-----------------| +| Heavy Runtime | 不参与 | 不参与 | **不直接参与基础对话**(负责异步 AI 分析) | + +### 运维与可观测 + +| 项目 | 资料上传与处理 | 知识库与知识点管理 | AI 对话与知识库问答 | +|------|-------------|----------------|-----------------| +| Admin | 文件管理、导入监控(步骤日志+重试)、候选巡检、分块管理 | KB 查看/删除、来源文件查看、引用追踪 | 会话日志、AI 网关管理、使用统计、成本管理、内容安全审核 | + +--- + +## 五、关键架构发现 + +### 5.1 RAG 聊天的上下文不来自 Qdrant + +所有 5 种 Scope(global、knowledge_base、folder、material、knowledge_item)的对话上下文均直接从 PostgreSQL 的 KnowledgeItem 表加载(最多 30 条,每条截取 500 字符,总计最多 4000 字符)。`loadContextByScope` 完全不调用 Qdrant,不存在任何 Scope 使用向量语义搜索。Qdrant 向量索引当前仅用于 Admin RAG 调试页的向量搜索测试。"RAG Chat"中的"RAG"指的是通过 scope 进行结构化检索(从 KnowledgeItem 表查询),而非向量语义搜索。 + +### 5.2 基础 AI 对话不经过 Heavy Runtime + +对话链路:iOS → API → AiGateway → DeepSeek。Heavy Runtime 负责异步 AI 分析任务(学习状态分析、薄弱点识别、测验生成等),通过独立的作业轮询机制运作。 + +### 5.3 文件上传与处理是完全异步的 + +用户上传文件后立即返回,后续的解析、分块、嵌入、索引、候选生成全部由 Python RAG Worker 异步完成。用户可通过资料详情页查看处理状态。 + +### 5.4 Open-or-create 确保每个范围只有一个活跃会话 + +相同 scopeType + scopeId + userId 下只存在一个未归档未删除的会话。这意味着用户每次从同一知识库进入 AI 对话时,都会恢复之前的对话历史。 + +### 5.5 知识库范围对话不等待 RAG + +即使 Python RAG Worker 尚未完成文档处理,知识库范围对话仍可使用——上下文来自用户已手动添加或已通过候选审核的知识点(KnowledgeItem 表),不需要等待 RAG 的向量索引完成。Qdrant 向量索引不参与任何 Scope 的对话上下文构建。 diff --git a/docs/system-map/ios/00-iOS-C端总览.md b/docs/system-map/ios/00-iOS-C端总览.md new file mode 100644 index 0000000..aabe269 --- /dev/null +++ b/docs/system-map/ios/00-iOS-C端总览.md @@ -0,0 +1,79 @@ +# 知习 iOS C 端总览 + +> **分析范围:** 仅 iOS 项目(AIStudyApp),不包含 API、Rust、RAG、Admin 或其他仓库。 +> **分析日期:** 2026-06-19 +> **分析阶段:** 第一阶段完成 — C 端业务盘点与能力定稿 + +--- + +## 一、项目概况 + +知习(ZhiXi)iOS 是一款 AI 驱动的系统化学习应用,基于 SwiftUI 构建,支持深色/浅色主题。当前版本仅支持 Apple ID 登录。业务主数据以云端 API 为主,部分阅读上下文、上传队列和笔记当前保存在本地。 + +## 二、用户生命周期 + +``` +首次启动 → Splash(会话恢复) + → Welcome(欢迎页) + → Login(Apple ID 登录) + → Onboarding(4 步引导:输入知识 / 主动输出 / AI 分析 / 掌握知识) + → GoalSetup(设定学习目标 / 方法 / 时间) + → 主界面(4 Tab) +``` + +已登录用户再次启动时直接进入主界面。账号被禁用或注销后进入对应状态页。 + +## 三、底部导航(一级模块) + +| Tab | 名称 | 说明 | +|-----|------|------| +| 1 | 学习 | 学习工作台:今日任务、继续学习、复习卡片、自我测试、每周摘要 | +| 2 | 知识库 | 个人知识库管理:创建、导入、搜索、浏览知识点、AI 对话 | +| 3 | 分析 | 学习数据分析:掌握度、阅读趋势、薄弱知识点、学习推荐 | +| 4 | 我的 | 个人中心:资料编辑、设置、通知、学习方法、目标、反馈 | + +## 四、页面总览 + +### 4.1 统计口径 + +本阶段盘点范围包括所有用户可访问的页面、弹窗和确认对话框,按入口类型划分: + +| 入口类型 | 数量 | 说明 | +|---------|------|------| +| 独立 Push 页面(可路由) | 32 | 通过 NavigationStack + Route 枚举跳转的页面 | +| 启动/登录流程页面(不可路由) | 6 | 启动页、欢迎页、登录页、账号状态页、引导页、目标设置页 | +| Sheet / 弹窗 | 6 | 从页面中弹出的非独立页面 | +| 确认弹窗(Alert/ConfirmationDialog) | 8 | 各类确认/输入弹窗 | +| 代码存在但无导航入口的页面 | 2 | AIHomeView(已废弃)、RecallTestPage(无入口) | +| **总计可盘点对象** | **54** | | + +### 4.2 独立 Push 页面完成情况 + +| 完成情况 | 数量 | 占比 | +|---------|------|------| +| 已完成 | 17 | 53% | +| 部分完成 | 8 | 25% | +| 占位实现 | 7 | 22% | +| **合计** | **32** | 100% | + +> "占位实现"指页面框架存在但使用硬编码 mock 数据,未接通后端。 + +## 五、关键发现 + +1. **AI 学习闭环已具雏形:** 知识库 → 阅读 → AI 分析薄弱点 → 主动回忆 → 复习卡片,形成完整的学习链路。 +2. **文档阅读基础设施较完善:** 通过 Rust FFI 支持 Markdown、文本、PDF、EPUB、图片、Office 文件的解析和阅读,具备阅读位置记录、事件上报等能力。 +3. **AI 相关页面 mock 较多:** 回忆测试、薄弱点分析、AI 反馈、今日思考等页面的展示数据均为硬编码,未接入真实 AI 分析结果。 +4. **AI 首页(AIHomeView)未被引用:** 该页面代码完整但未接入任何导航入口,属于废弃页面。 +5. **知识库管理功能较完整:** 创建、导入、知识点增删改查、分类管理、公开库发现、订阅等基础功能已接通 API。 +6. **通知系统有界面但功能有限:** 通知列表可查看和标记已读,但设置页面中通知开关状态存在绑定异常。 +7. **部分功能标注 TODO:** 知识点重命名、移动到文件夹、收藏、知识库管理页、官方知识库筛选等功能未实现。 +8. **无离线模式:** 应用设计为在线优先,无本地数据持久化策略,仅在阅读上下文方面有基础离线缓存。 +9. **部分 API 端点已就绪但 C 端无入口:** WaitlistService(waitlist 加入/统计)API 服务代码完整但无任何页面调用;UserService 账号注销(requestAccountDeletion/cancelDeletion)API 已就绪但设置页未提供注销入口;UserService 设备管理(listDevices/removeDevice)API 已就绪但设置页"登录设备管理"行为空(导航自引用)。 + +## 六、关联文档 + +- [01-iOS页面地图.md](./01-iOS页面地图.md) — 全部页面的详细描述 +- [02-iOS页面功能总表.md](./02-iOS页面功能总表.md) — 页面功能汇总表 +- [03-C端业务能力初步清单.md](./03-C端业务能力初步清单.md) — 第一阶段初步归类(草稿,正式能力以 04 为准) +- [04-C端正式业务能力树.md](./04-C端正式业务能力树.md) — 正式 C 端业务能力三层树(主索引) +- [05-页面与业务能力矩阵.md](./05-页面与业务能力矩阵.md) — 页面与业务能力双向矩阵 diff --git a/docs/system-map/ios/01-iOS页面地图.md b/docs/system-map/ios/01-iOS页面地图.md new file mode 100644 index 0000000..2afd2c6 --- /dev/null +++ b/docs/system-map/ios/01-iOS页面地图.md @@ -0,0 +1,786 @@ +# 01 iOS 页面地图 + +> 按用户可见的页面层级整理,不按代码目录组织。 + +--- + +## 一、启动与登录流程 + +### 1.1 启动页(SplashScreen) + +- **页面作用:** 应用启动时显示品牌标识,后台静默恢复登录会话。 +- **页面入口:** 应用冷启动时的默认展示。 +- **页面组成:** 深色渐变背景、品牌图标(大脑)、"知习"标题、加载指示器。 +- **用户可执行操作:** 无(自动跳转)。 +- **自动执行功能:** 从系统钥匙串读取 Token → 调用 API 校验 → 恢复会话或跳转到登录页。 +- **可跳转页面:** 自动跳转至 Welcome 页(未登录)或主界面(已登录)。 +- **页面主要状态:** 仅展示态。会话恢复中 / 恢复完成自动跳转。 +- **当前完成情况:** 已完成 + +--- + +### 1.2 欢迎页(WelcomePage) + +- **页面作用:** 向新用户介绍产品核心功能,引导进入登录流程。 +- **页面入口:** 未登录用户从启动页自动跳转,或已登录用户退出后进入。 +- **页面组成:** 页面渐变背景、装饰光晕、"AI 驱动"标签、主标题"用 AI 重新定义你的学习方式"、三个功能介绍卡片(主动回忆、费曼解释、AI 分析)、"开始使用"按钮。 +- **用户可执行操作:** 点击"开始使用"进入登录页。 +- **自动执行功能:** 无。 +- **可跳转页面:** LoginPage(登录页)。 +- **页面主要状态:** 仅展示态。 +- **当前完成情况:** 已完成 + +--- + +### 1.3 登录页(LoginPage) + +- **页面作用:** 用户使用 Apple ID 登录应用。 +- **页面入口:** 欢迎页点击"开始使用"。 +- **页面组成:** 页面渐变背景、品牌图标、欢迎文案、"使用 Apple 账号登录以同步学习数据"提示、Sign in with Apple 按钮、错误信息区域、登录中取消按钮覆盖层。 +- **用户可执行操作:** Apple ID 登录、取消登录。 +- **自动执行功能:** 登录成功后自动保存 Token 至钥匙串、切换会话状态。 +- **可跳转页面:** 登录成功 → Onboarding 页(首次)或主界面(已设定目标)。 +- **页面主要状态:** 待登录 / 登录中 / 登录失败(显示错误提示)。 +- **当前完成情况:** 已完成 + +--- + +### 1.4 账号状态页(AccountStatusView) + +- **页面作用:** 当账号被禁用或已注销时,向用户展示状态说明。 +- **页面入口:** 启动时 AuthManager 检测到账号为 disabled 或 deleted 状态。 +- **页面组成:** 页面渐变背景、状态图标、标题文案、说明文字、"返回首页"按钮。 +- **用户可执行操作:** 点击"返回首页"回到未登录状态,可重新登录。 +- **自动执行功能:** 无。 +- **可跳转页面:** 回到 Welcome 页。 +- **页面主要状态:** 禁用态 / 注销态(两种展示略有不同)。 +- **当前完成情况:** 已完成 + +--- + +### 1.5 引导页(OnboardingPage) + +- **页面作用:** 首次登录后展示产品价值,引导用户理解产品核心流程。 +- **页面入口:** 首次登录成功后自动跳转。 +- **页面组成:** 页面渐变背景、4 步引导指示器、步骤标题与说明、"下一步"/"开始使用"按钮、"跳过"链接。四步分别为:输入知识、主动输出、AI 分析、掌握知识。 +- **用户可执行操作:** 点击"下一步"依次浏览、点击"跳过"直接结束。 +- **自动执行功能:** 无。 +- **可跳转页面:** GoalSetupPage(目标设置页)或直接进入主界面(跳过)。 +- **页面主要状态:** 展示第1-4步。 +- **当前完成情况:** 已完成 + +--- + +### 1.6 目标设置页(GoalSetupPage) + +- **页面作用:** 用户设定学习目标、偏好方法和每日学习时间。 +- **页面入口:** Onboarding 完成后自动跳转,或从"我的"→"学习目标设置"进入。 +- **页面组成:** 页面渐变背景、标题"设定你的学习目标"、四个学习目标选项(备考考试/职业技能/通识学习/自定义)、三种学习方法多选(间隔回忆/费曼技巧/AI 分析)、四个每日学习时间选项(15分钟/30分钟/1小时/不限制)、"开始学习"按钮。 +- **用户可执行操作:** 选择学习目标、选择学习方法、选择每日时间、确认进入主界面。 +- **自动执行功能:** 确认后将目标通过 API 保存至用户偏好。 +- **可跳转页面:** 主界面 ContentView。 +- **页面主要状态:** 选择中(单选目标、多选方法、单选时间)/ 已确认。 +- **当前完成情况:** 部分完成(学习目标和方法通过 API 保存;每日学习时长仅保存在本地 @State,缺乏可靠持久化) + +--- + +## 二、学习(底部导航 Tab 1) + +### 2.1 学习主页(StudyHomeView) + +- **页面作用:** 学习工作台,聚合展示今日学习任务、复习卡片、自我测试等学习入口。 +- **页面入口:** 底部导航"学习" Tab(默认选中)。 +- **页面组成:** + - 标题栏:页面标题"学习"(实际未显示明显标题) + - 连续学习天数(火焰图标 + 天数) + - 主操作卡片(动态变化,见下) + - 今日复习卡片(卡片数 + 预计时长) + - 自我测试卡片(可用测验数) + - 每周摘要卡片(本周分钟数 / 复习卡片数 / 活跃天数 / 连续天数) + - 底部"查看完整分析"链接 +- **用户可执行操作:** + - 点击主操作卡片(根据优先级不同,操作不同) + - 点击复习卡片入口 + - 点击自我测试入口 + - 点击每周摘要区域查看详细分析 + - 下拉刷新 +- **自动执行功能:** 页面加载时自动计算优先级最高的学习操作(继续学习 > 今日复习 > 自我测试 > 开始学习 > 空状态引导) +- **可跳转页面:** + - MaterialReaderView(资料阅读,继续学习时) + - ReviewCardView(复习卡片) + - QuizTakerView(自我测试) + - QuizListView(测验列表) + - ActiveRecallView(主动回忆) + - 切换到"知识库" Tab +- **页面主要状态:** 加载中 / 加载失败(错误提示 + 重试按钮)/ 已加载·有任务 / 已加载·空状态。 + > 注:View 支持 error 状态展示,但 ViewModel 中所有 API 调用使用 try? 吞错,error 状态在实际运行中永不可达。 +- **当前完成情况:** 已完成 + +--- + +### 2.2 学习会话页(LearningSessionView) + +- **页面作用:** 专注学习计时器,记录单次学习时长。 +- **页面入口:** 从学习主页或资料阅读页的学习任务入口进入。 +- **页面组成:** 环形计时器(带动画渐变环)、任务信息卡片(任务名称、类型、建议时长 30 分钟、今日已学时长)、提示卡片、底部状态栏"学习中…"、暂停/继续按钮、结束按钮。 +- **用户可执行操作:** 暂停/继续计时、结束学习。 +- **自动执行功能:** 进入页面自动开始计时(1秒精度),学习结束时自动展示庆祝动画。 +- **可跳转页面:** 无(结束学习后展示庆祝动画,用户可返回)。 +- **页面主要状态:** 计时中 / 已暂停 / 学习完成(庆祝动画覆盖层)。 +- **当前完成情况:** 暂未确认(本地计时功能完成,但代码中未发现调用 LearningSessionService API 保存学习记录的代码,学习时长可能不持久化到服务端) + +--- + +### 2.3 复习卡片页(ReviewCardView) + +- **页面作用:** 基于间隔重复的闪卡复习。 +- **页面入口:** 学习主页"今日复习"入口、AI 快捷操作。 +- **页面组成:** 进度条、卡片正面(问题)、卡片反面(答案 + 出处)、自评按钮组("完全不会"/"有点难"/"基本会"/"很简单")。 +- **用户可执行操作:** 点击卡片翻转查看答案、点击自评按钮评分、自动跳至下一张。 +- **自动执行功能:** 评分后自动前进到下一张卡片,全部完成后自动展示庆祝动画。 +- **可跳转页面:** 无。 +- **页面主要状态:** 卡片正面 / 卡片反面(含自评按钮)/ 全部完成(庆祝动画覆盖层)。 +- **当前完成情况:** 占位实现(展示 3 张机器学习相关硬编码卡片,未接通 ReviewViewModel 和 API) + +--- + +### 2.4 主动回忆页(ActiveRecallView) + +- **页面作用:** 用户主动输出知识点内容,由 AI 评估掌握程度。 +- **页面入口:** 学习主页底部链接或 AI 快捷操作。 +- **页面组成:** 进度条、问题卡片(含题目类型标签:语音/文字 和来源)、回答输入区(TextEditor 或语音占位按钮)、提交按钮、提交确认区("下一题"/"查看 AI 分析"按钮)。 +- **用户可执行操作:** 输入文字答案、提交答案、查看 AI 分析、进入下一题。 +- **自动执行功能:** 提交答案后展示"AI 正在分析你的回答…"思考动画覆盖层,全部完成后展示庆祝动画。 +- **可跳转页面:** AIFeedbackPageView(AI 反馈页)。 +- **页面主要状态:** 答题模式 / 答案已提交 / AI 分析中(覆盖层)/ 全部完成(庆祝动画覆盖层)。 +- **当前完成情况:** 占位实现(3 道硬编码机器学习题目,第 3 题标记为语音类型但语音功能未实现) + +--- + +## 三、知识库(底部导航 Tab 2) + +### 3.1 知识库首页(LibraryHomeView) + +- **页面作用:** 展示和管理用户的知识库列表。 +- **页面入口:** 底部导航"知识库" Tab。 +- **页面组成:** 标题"知识库"、搜索按钮、创建按钮、搜索栏、筛选分类横条(全部/我的/已订阅/官方)、知识库卡片列表(封面图、名称、描述、日期、可见性标签、置顶标记)。 +- **用户可执行操作:** + - 点击知识库卡片进入详情 + - 点击搜索按钮进入搜索 + - 点击创建按钮新建知识库 + - 切换筛选分类 + - 下拉刷新 + - 无限滚动加载更多 +- **自动执行功能:** 页面加载时自动拉取知识库列表。 +- **可跳转页面:** + - LibraryDetailPage(知识库详情) + - LibrarySearchView(搜索) + - CreateLibraryPage(创建知识库) +- **页面主要状态:** 加载中 / 各分类的空状态(文案不同)/ 已加载·有数据 / 分页加载更多中 / 刷新中。 +- **当前完成情况:** 部分完成("官方"筛选返回空数组,待后端支持;搜索页仅展示空状态,未实现搜索逻辑) + +--- + +### 3.2 知识库搜索页(LibrarySearchView) + +- **页面作用:** 搜索知识库和知识点。 +- **页面入口:** 知识库首页点击搜索图标。 +- **页面组成:** 搜索输入框、空白搜索区域。 +- **用户可执行操作:** 输入搜索关键词(实际搜索逻辑未实现)。 +- **自动执行功能:** 无。 +- **可跳转页面:** 无。 +- **页面主要状态:** 搜索前空状态。 +- **当前完成情况:** 部分完成(页面框架和输入框已搭建,搜索逻辑未实现) + +--- + +### 3.3 知识库详情页(LibraryDetailPage) + +- **页面作用:** 查看知识库内容,管理知识点和来源文件。 +- **页面入口:** 知识库首页点击知识库卡片。 +- **页面组成:** + - 知识库信息头部(封面、标题、描述、元数据行) + - 两个标签页切换:知识点 Tab / 来源 Tab + - **知识点 Tab:** 知识点列表(类型图标、类型标签、日期、学习进度)、排序菜单、操作菜单、批量选择模式 + - **来源 Tab:** 来源文件列表(含阅读状态标签、删除按钮) + - 底部 AI 对话按钮(知识库范围) + - 文件夹管理入口(Sheet) +- **用户可执行操作:** + - 切换知识点/来源 Tab + - 点击知识点进入详情 + - 长按/滑动删除知识点 + - 批量选择与批量删除 + - 切换排序方式(默认/文件大小/创建时间/更新时间) + - 点击上传导入资料 + - 打开文件夹管理弹窗 + - 点击底部 AI 对话按钮 + - 点击来源文件进入资料阅读 + - 删除来源文件 + - 点击"知识库管理"(操作菜单中存在,但 action 为空 TODO,未实现) +- **自动执行功能:** 页面加载时自动拉取知识点列表和来源列表。 +- **可跳转页面:** + - KnowledgeDetailPage(知识点详情) + - ImportPage(导入资料) + - AddKnowledgePage(添加知识点) + - QuizListView(生成测验) + - AIChatPage(AI 对话,知识库范围) + - MaterialReaderView(资料阅读) + - FolderManageView(文件夹管理,Sheet 弹窗) +- **页面主要状态:** + - 加载中 / 加载失败 + - 知识点 Tab·有数据 / 知识点 Tab·空 + - 来源 Tab·有数据 / 来源 Tab·空 + - 批量选择模式 + - 删除确认弹窗 +- **当前完成情况:** 部分完成(知识点重命名 TODO、移动到文件夹 TODO、知识库管理页 TODO、收藏状态切换 TODO) + +--- + +### 3.4 创建知识库页(CreateLibraryPage) + +- **页面作用:** 创建新的知识库。 +- **页面入口:** 知识库首页点击创建按钮、"我的"页学习资产入口。 +- **页面组成:** 封面图区域(可点击上传)、知识库名称输入框(必填)、描述输入框(必填)、创建按钮。 +- **用户可执行操作:** 从相册选择封面图(自动裁剪为 512×512)、输入名称和描述、点击创建。 +- **自动执行功能:** 封面上传时自动调整图片尺寸。 +- **可跳转页面:** 无(创建成功后返回上一页)。 +- **页面主要状态:** 编辑中(名称/描述为空时按钮禁用)/ 封面上传中 / 创建中。 +- **当前完成情况:** 已完成 + +--- + +### 3.5 添加知识点页(AddKnowledgePage) + +- **页面作用:** 向知识库添加新的知识点。 +- **页面入口:** 知识库详情页操作菜单中的"添加"。 +- **页面组成:** "内容来源"分段选择器(手动 / 文件)、手动模式下的标题输入框和内容编辑器、文件模式下的"选择文件"/"图片"按钮、已选文件列表(可移除)、上传进度指示器、保存按钮。 +- **用户可执行操作:** + - 手动模式:输入标题和内容文字,点击保存。 + - 文件模式:选择文件(PDF/纯文本/图片)、选择照片、移除已选文件、批量保存。 +- **自动执行功能:** 文件模式下自动检测 MIME 类型,大于 2MB 的图片自动压缩,文件上传至腾讯云 COS。 +- **可跳转页面:** 无(保存成功后返回上一页)。 +- **页面主要状态:** 手动模式 / 文件模式 / 文件上传中 / 保存中。 +- **当前完成情况:** 已完成 + +--- + +### 3.6 知识点详情页(KnowledgeDetailPage) + +- **页面作用:** 查看知识点详细内容,支持多种文件格式渲染。 +- **页面入口:** 知识库详情页点击知识点。 +- **页面组成:** 根据内容类型不同展示不同渲染方式: + - URL 型知识点:嵌入 MaterialReaderView 渲染 + - 纯文本知识点:直接文本渲染(支持 Markdown) + - 图片/PDF/Word/Excel/PPT/ePub:对应原生阅读器或系统预览 + - 工具栏菜单(笔记、预览选项、阅读原文按钮) +- **用户可执行操作:** 阅读内容、查看原文、添加笔记、收藏(UI 存在但后端未支持)。 +- **自动执行功能:** 加载知识点内容,自动从 COS 下载文件(带过期 URL 重新获取逻辑)。 +- **可跳转页面:** MaterialReaderView。 +- **页面主要状态:** 加载中 / 错误(显示概要回退文字 + 重试按钮)/ 内容已就绪。 +- **当前完成情况:** 部分完成(收藏切换有 UI 但后端 API 未支持,收藏标记为 TODO) + +--- + +### 3.7 编辑知识点页(EditKnowledgePage) + +- **页面作用:** 编辑知识点标题和内容。 +- **页面入口:** 知识点详情页工具栏菜单。 +- **页面组成:** 标题输入框、内容编辑器、保存按钮。 +- **用户可执行操作:** 修改标题和内容、保存。 +- **自动执行功能:** 无。 +- **可跳转页面:** 无(保存后返回)。 +- **页面主要状态:** 编辑中 / 保存中。 +- **当前完成情况:** 已完成 + +--- + +### 3.8 导入资料页(ImportPage) + +- **页面作用:** 向知识库导入外部资料。 +- **页面入口:** 知识库详情页操作菜单中的"导入"。 +- **页面组成:** 三种导入方式入口:文件导入、相册导入、链接导入。自动检测或提示选择目标知识库。 +- **用户可执行操作:** + - 文件导入:选择 PDF 或纯文本文件 + - 相册导入:选择照片 + - 链接导入:输入 URL(通过弹窗) +- **自动执行功能:** 自动选择第一个知识库,无知识库时提示用户创建。 +- **可跳转页面:** ImportReviewPage(导入候选审核页)。 +- **页面主要状态:** 选择导入方式 / 导入中 / 导入失败(错误横幅)。 +- **当前完成情况:** 已完成 + +--- + +### 3.9 导入候选审核页(ImportReviewPage) + +- **页面作用:** 审核 AI 从导入资料中提取的知识点候选。 +- **页面入口:** 导入资料完成后自动跳转。 +- **页面组成:** 候选知识点列表(含置信度分数)、每条候选可展开查看详情、接受/拒绝按钮、"全部接受"按钮。 +- **用户可执行操作:** 接受单个候选、拒绝单个候选、批量全部接受。 +- **自动执行功能:** 加载该来源的导入候选列表。 +- **可跳转页面:** 无。 +- **页面主要状态:** 加载中 / 无待审核候选 / 有待审核列表。 +- **当前完成情况:** 已完成 + +--- + +### 3.10 发现公开库页(DiscoverView) + +- **页面作用:** 浏览和订阅其他用户公开的知识库。 +- **页面入口:** "我的"页"发现公开库"入口。 +- **页面组成:** 公开知识库列表(标题、描述、知识条目数)、每条右侧有订阅/取消订阅按钮。 +- **用户可执行操作:** 订阅知识库、取消订阅。 +- **自动执行功能:** 加载公开知识库列表。 +- **可跳转页面:** 无。 +- **页面主要状态:** 加载中 / 空(无公开知识库)/ 已加载。 +- **当前完成情况:** 已完成 + +--- + +### 3.11 文件夹管理(FolderManageView) + +- **页面作用:** 管理知识库内的文件夹/分类。 +- **页面入口:** 知识库详情页操作菜单中的"文件夹管理"(以 Sheet 形式弹出)。 +- **页面组成:** 文件夹列表(含名称)、新建按钮、每条可滑动操作(重命名、删除)。 +- **用户可执行操作:** 创建文件夹(通过弹窗输入名称)、重命名文件夹、删除文件夹。 +- **自动执行功能:** 加载该知识库的文件夹列表。 +- **可跳转页面:** 无(Sheet 内操作)。 +- **页面主要状态:** 文件夹列表 / 新建弹窗 / 重命名弹窗。 +- **当前完成情况:** 已完成 + +--- + +## 四、分析(底部导航 Tab 3) + +### 4.1 学习分析页(AnalysisHomeView) + +- **页面作用:** 展示学习数据分析和趋势洞察。 +- **页面入口:** 底部导航"分析" Tab。 +- **页面组成:** + - 标题"学习分析"+ 日期范围筛选("近 7 天") + - 4 个统计徽章:综合掌握 / 总分钟 / 复习卡片 / 活跃天 + - 4 个阅读统计徽章:今日阅读 / 本周阅读 / 已读资料 / 阅读资料 + - 掌握度趋势折线图(含动画) + - 阅读时长趋势柱状图 + - 本周学习活跃柱状图 + - 连续学习统计(当前连续/最长连续/最后活跃) + - 最近学习记录列表(最多 5 条) + - 学习推荐列表(含优先级标签) + - 继续阅读入口 + - AI 综合分析文字摘要 + - 薄弱知识点列表(最多 5 条) +- **用户可执行操作:** + - 点击薄弱知识点查看详情(跳转 WeakPointsPage) + - 点击继续阅读入口(跳转 MaterialReaderView) + - 下拉刷新数据 +- **自动执行功能:** 页面加载时自动并行拉取活动概览、趋势、连续天数、推荐、阅读数据等。 +- **可跳转页面:** + - WeakPointsPage(薄弱知识点详情) + - MaterialReaderView(继续阅读) +- **页面主要状态:** 加载中 / 加载失败(错误提示 + 重试按钮)/ 已加载·有数据 / 部分数据为空时隐藏对应区域。 +- **当前完成情况:** 部分完成(掌握度趋势折线图和每周活跃柱状图使用编译时硬编码的 7 天数据,未从 ViewModel API 数据读取,属于占位实现;其他数据来自 API) + +--- + +## 五、我的(底部导航 Tab 4) + +### 5.1 个人中心页(ProfileView) + +- **页面作用:** 用户个人信息与功能入口集合。 +- **页面入口:** 底部导航"我的" Tab。 +- **页面组成:** + - 顶部导航栏:标题"我的"、发现公开库按钮、通知图标、设置图标 + - 个人资料卡片(头像、昵称、邮箱、活跃天/复习卡片/分钟统计) + - 功能菜单:学习目标设置、复习提醒、学习方法偏好、帮助与反馈 + - 学习资产区域:知识库/条目/卡片计数、发现公开库入口、消息中心入口、存储空间展示 +- **用户可执行操作:** + - 点击资料卡片进入编辑资料 + - 点击各菜单项进入对应子页面 + - 点击通知图标进入通知列表 + - 点击设置图标进入设置 +- **自动执行功能:** 页面加载时自动拉取用户资料、活动摘要、资产和存储统计。 +- **可跳转页面:** + - EditProfilePage(编辑资料) + - GoalSettingDetailView(学习目标设置) + - SettingsView(设置,从复习提醒行进入也是设置) + - MethodPreferenceView(学习方法偏好) + - FeedbackFormView(帮助与反馈) + - CreateLibraryPage(学习资产入口) + - DiscoverView(发现公开库) + - NotificationListView(通知列表/消息中心) +- **页面主要状态:** 加载中 / 已加载(含默认值和占位信息)。 +- **当前完成情况:** 已完成 + +--- + +### 5.2 编辑资料页(EditProfilePage) + +- **页面作用:** 编辑个人资料信息。 +- **页面入口:** 个人中心页点击资料卡片。 +- **页面组成:** + - 头像区域(可点击上传,自动裁剪为正方形 256×256) + - 基本信息区:昵称输入框、学习身份输入框 + - 学习档案区:学习方向输入框、当前目标输入框 + - 个人简介输入框 + - 保存按钮(含加载状态) +- **用户可执行操作:** 从相册选择头像、编辑各文本字段、保存。 +- **自动执行功能:** 头像选择后自动裁剪上传。 +- **可跳转页面:** 无。 +- **页面主要状态:** 加载中(加载现有资料)/ 编辑中 / 头像上传中 / 保存中 / 错误提示。 +- **当前完成情况:** 已完成 + +--- + +### 5.3 设置页(SettingsView) + +- **页面作用:** 应用全局设置。 +- **页面入口:** 个人中心页点击设置图标或"复习提醒"行。 +- **页面组成:** + - 外观与语言区:外观模式选择(跟随系统/深色/浅色)、语言 + - 学习设置区:学习目标(导航)、方法偏好(导航) + - 复习提醒区:提醒开关、提醒时间选择器、间隔天数选择器 + - 通知设置区:复习提醒开关、导入完成通知开关、系统通知开关 + - 数据与存储区:存储空间、iCloud 同步开关 + - 账号区:个人信息、设备管理 + - 帮助与反馈、隐私政策、用户协议 + - 退出登录按钮(带确认弹窗) + - 底部关于信息(版本号) +- **用户可执行操作:** 切换外观模式、设置复习提醒时间和间隔天数、切换通知开关、iCloud 同步开关、退出登录、跳转子页面。 +- **自动执行功能:** 外观模式变更时自动保存至用户偏好 API。 +- **可跳转页面:** + - GoalSettingDetailView(学习目标设置) + - MethodPreferenceView(方法偏好) +- **页面主要状态:** 各开关状态、退出登录确认弹窗。 +- **当前完成情况:** 部分完成(三个通知开关绑定到同一个 $reviewReminder 变量,存在明确 bug;"设备管理"、"隐私政策"、"用户协议"入口无导航目标;"存储空间"行导航目标为 Route.settings 自身,形成无效自引用;"登录设备管理"行同理,导航目标也为 Route.settings 自身) + +--- + +### 5.4 学习目标设置页(GoalSettingDetailView) + +- **页面作用:** 配置学习目标和每日学习时长。 +- **页面入口:** 设置页"学习目标"或"我的"页"学习目标设置"。 +- **页面组成:** 四个学习目标选项(备考考试/职业技能/通识学习/自定义)、四个每日学习时间选项(15分钟/30分钟/1小时/不限制)。 +- **用户可执行操作:** 选择目标和时间,保存。 +- **自动执行功能:** 保存至用户 API。 +- **可跳转页面:** 无。 +- **页面主要状态:** 当前选中态展示。 +- **当前完成情况:** 部分完成(学习目标选择通过 API 保存,但每日学习时长 dailyMins 仅保存在本地 @State 变量,不通过 API 持久化,下次进入恢复默认"30 分钟") + +--- + +### 5.5 学习方法偏好页(MethodPreferenceView) + +- **页面作用:** 配置偏好的学习方式。 +- **页面入口:** 设置页或"我的"页"学习方法偏好"。 +- **页面组成:** 四种方法选项(间隔回忆/费曼技巧/AI分析/主动回忆),多选框形式。 +- **用户可执行操作:** 多选/取消方法,保存。 +- **自动执行功能:** 保存至用户偏好 API。 +- **可跳转页面:** 无。 +- **页面主要状态:** 选中/未选中。 +- **当前完成情况:** 已完成 + +--- + +### 5.6 通知列表页(NotificationListView) + +- **页面作用:** 查看和管理系统通知。 +- **页面入口:** "我的"页通知图标或消息中心入口。 +- **页面组成:** 通知列表按日期分组(今天/本周/更早),每条通知含类型图标、标题、内容、时间、已读/未读状态。顶部"全部已读"按钮。 +- **用户可执行操作:** 点击单条通知标记为已读、点击"全部已读"。 +- **自动执行功能:** 加载通知列表。 +- **可跳转页面:** 无。 +- **页面主要状态:** 加载中 / 有通知 / 无通知。 +- **当前完成情况:** 已完成 + +--- + +### 5.7 帮助与反馈页(FeedbackFormView) + +- **页面作用:** 用户提交反馈和问题报告。 +- **页面入口:** "我的"页"帮助与反馈"、设置页"帮助与反馈"。 +- **页面组成:** 反馈类型选择器(Bug反馈/功能建议/内容问题/其他)、内容输入框、提交按钮。 +- **用户可执行操作:** 选择反馈类型、输入描述文字、提交。 +- **自动执行功能:** 提交至反馈 API。 +- **可跳转页面:** 无。 +- **页面主要状态:** 编辑中 / 提交中 / 已提交(可继续提交新的)。 +- **当前完成情况:** 已完成 + +--- + +## 六、AI 辅助功能(跨模块访问) + +### 6.1 AI 对话页(AIChatPage) + +- **页面作用:** 与 AI 进行学习相关的对话互动。 +- **页面入口:** 知识库详情页底部 AI 对话按钮、AI 反馈页"深入提问"、资料阅读页工具栏 AI 按钮(多处入口,均可附带对话范围上下文)。 +- **页面组成:** + - 对话消息列表(用户消息紫色渐变气泡、AI 消息含思考过程和内容) + - AI 思考过程区(可折叠、含流式输出动画) + - 范围标签(当对话限定在特定知识库/资料时显示) + - 工具栏按钮(新建对话、会话列表) + - 底部输入栏(文字输入框、语音图标(占位)、发送按钮) + - AI 回复完成后显示"复制"和"重新生成"按钮 +- **用户可执行操作:** + - 发送文字消息 + - 查看 AI 思考过程 + - 复制 AI 回复 + - 重新生成回复 + - 新建对话 + - 打开会话列表 Sheet + - 在会话列表中搜索、删除、归档会话 +- **自动执行功能:** 流式接收 AI 回复并实时展示,自动创建或恢复对话会话。 +- **可跳转页面:** 无(页面内操作)。 +- **页面主要状态:** + - 创建会话中 / 会话创建失败 + - 消息列表(含滚动加载历史) + - AI 回复流式输出中(含思考动画) + - 会话列表 Sheet(搜索、筛选、编辑操作) +- **当前完成情况:** 已完成 + +--- + +### 6.2 每日思考页(DailyThinkingPage) + +- **页面作用:** 展示一道每日思考题,用户提交回答后获取 AI 反馈。 +- **页面入口:** AI 反馈页"再来一题"。 +- **页面组成:** 思考题目(硬编码:"Transformer 中的注意力机制")、评估要点提示、回答输入框、"提交获取 AI 反馈"按钮。 +- **用户可执行操作:** 输入答案、提交获取 AI 反馈。 +- **自动执行功能:** 无。 +- **可跳转页面:** AIFeedbackPageView。 +- **页面主要状态:** 回答中 / 提交后跳转。 +- **当前完成情况:** 占位实现(题目硬编码,无 ViewModel,无动态题目来源。注:submitted 状态变量在代码中从未被设置为 true,提交按钮始终可见,可能导致用户重复提交) + +--- + +### 6.3 AI 反馈页(AIFeedbackPageView) + +- **页面作用:** 展示 AI 对用户回答的分析评分和建议。 +- **页面入口:** 主动回忆完成后、每日思考提交后、回忆测试提交后。 +- **页面组成(两阶段):** + - 分析中:动画步骤指示器("解析你的回答结构…"等 4 步,约 5 秒) + - 分析结果:得分圆环、掌握度评价文字、用户原始回答、答对的部分列表、需要完善的内容、参考答案要点、"加入待巩固"按钮、"深入提问"按钮、"再来一题"按钮 +- **用户可执行操作:** 查看分析结果、加入待巩固(跳转学习主页)、深入提问(跳转 AI 对话)、再来一题(跳转每日思考)。 +- **自动执行功能:** 模拟分析过程(5 秒后自动展示结果)。 +- **可跳转页面:** StudyHomeView、AIChatPage、DailyThinkingPage。 +- **页面主要状态:** 分析中 / 分析结果。 +- **当前完成情况:** 占位实现(得分 78/100 硬编码,所有分析文字硬编码,未接通真实 AI 分析 API) + +--- + +### 6.4 薄弱知识点页(WeakPointsPage) + +- **页面作用:** 展示用户的薄弱知识点列表。 +- **页面入口:** 学习分析页薄弱知识点区域"全部"链接。 +- **页面组成:** 薄弱知识点列表,每项含掌握度分数、知识点名称、所属知识库、优先级标签(高/中)。 +- **用户可执行操作:** 查看列表。 +- **自动执行功能:** 无。 +- **可跳转页面:** 无。 +- **页面主要状态:** 展示态。 +- **当前完成情况:** 占位实现(5 个硬编码知识点,主题为贝叶斯定理/正态分布/词根/Covariance/梯度下降,无 ViewModel,未接通 API) + +--- + +### 6.5 AI 首页(AIHomeView) + +- **页面作用:** 原本设计为 AI 功能的聚合首页,包含快速操作入口、每日思考题和 AI 输入。 +- **页面入口:** 代码中无任何页面跳转到此页——该页面未接入导航系统,属于废弃页面。 +- **页面组成:** 日期 + 服务器状态、Hero 区、Rive 动画占位、4 个快捷操作按钮、每日思考卡片、推荐问题列表、底部输入栏。 +- **用户可执行操作:** (理论上的操作,实际不可达) +- **自动执行功能:** 健康检查服务器状态。 +- **可跳转页面:** (理论上)ActiveRecallView、WeakPointsPage、AIChatPage、ReviewCardView、DailyThinkingPage。 +- **页面主要状态:** 服务器在线/检查中/离线。 +- **当前完成情况:** 占位实现(已废弃,无导航入口。Rive 动画标注为占位,推荐问题硬编码) + +--- + +### 6.6 回忆测试页(RecallTestPage) + +- **页面作用:** 用户对特定知识点进行回忆测试,输入理解后提交,获取 AI 反馈。 +- **页面入口:** 代码中无任何页面跳转到此页——Route 枚举中无对应 case,属于代码存在但无导航入口的页面。 +- **页面组成:** 提示文字(硬编码:"请回忆并写下你对「偏差-方差权衡」的理解")、TextEditor 回答输入框、"提交"按钮。 +- **用户可执行操作:** (理论上的操作,实际不可达)输入答案、提交获取 AI 反馈。 +- **自动执行功能:** 无。 +- **可跳转页面:** (理论上)AIFeedbackPageView。 +- **页面主要状态:** 编辑中 / 提交后跳转。 +- **当前完成情况:** 占位实现(无导航入口,题目硬编码,无 ViewModel。注:submitted 状态变量在代码中从未被设置为 true,提交按钮始终可见,可能导致用户重复提交) + +--- + +## 七、测验功能(跨模块访问) + +### 7.1 测验列表页(QuizListView) + +- **页面作用:** 查看知识库下的所有测验,并可以生成新测验。 +- **页面入口:** 知识库详情页操作菜单中的"测验"。 +- **页面组成:** 测验列表(含测验标题等信息)、空状态提示("暂无测验"+"生成测验"按钮)、"生成新测验"按钮。 +- **用户可执行操作:** 生成新测验、点击已有测验进入作答。 +- **自动执行功能:** 加载该知识库的测验列表。 +- **可跳转页面:** QuizTakerView(测验作答)。 +- **页面主要状态:** 加载中 / 空(引导生成)/ 有测验列表 / 生成失败(Toast 提示)。 +- **当前完成情况:** 已完成 + +--- + +### 7.2 测验作答页(QuizTakerView) + +- **页面作用:** 逐题作答。 +- **页面入口:** 测验列表点击测验、学习主页自我测试入口。 +- **页面组成:** 进度条(当前题号/总题数)、题目题干、选项/答案区。支持三种题型:选择题(A/B/C/D 单选)、判断题(正确/错误按钮)、填空题(文本输入)。 +- **用户可执行操作:** 选择题选择答案、判断正误、输入填空答案、上一题/下一题导航、提交全部答案。 +- **自动执行功能:** 提交后自动计算得分。 +- **可跳转页面:** QuizResultView(测验结果)。 +- **页面主要状态:** 答题中 / 提交中。 +- **当前完成情况:** 已完成 + +--- + +### 7.3 测验结果页(QuizResultView) + +- **页面作用:** 展示测验得分和详细答题情况。 +- **页面入口:** 测验作答提交后自动跳转。 +- **页面组成:** 大号得分数字(低于 60 分红色、高于 60 分绿色)、正确/总题数统计、"重新测验"按钮、逐题详细结果(正确/错误标记 + 解析)。 +- **用户可执行操作:** 查看每道题的结果和解析、点击重新测验。 +- **自动执行功能:** 加载测验结果详情。 +- **可跳转页面:** 无(重新测验回到 QuizTakerView 或 QuizListView)。 +- **页面主要状态:** 加载中 / 结果已加载。 +- **当前完成情况:** 已完成 + +--- + +## 八、资料阅读(跨模块访问) + +### 8.1 资料阅读页(MaterialReaderView) + +- **页面作用:** 阅读学习资料,支持多种文件格式。 +- **页面入口:** 学习主页"继续学习"、学习分析页"继续阅读"、知识库详情页来源文件、知识点详情页。 +- **页面组成:** + - 根据文件类型不同展示不同内容: + - Markdown/文本/图片:原生渲染(标题、段落、列表、代码块、引用、表格、图片) + - PDF/Word/Excel:系统预览按钮(QuickLook) + - PowerPoint:外部打开按钮(ShareLink) + - 不支持的格式:提示文字 + - 工具栏按钮:标记已读、AI 对话(资料范围)、资料详情、开始学习会话、知识提取 + - 笔记功能入口(Sheet) + - 解析状态 Toast +- **用户可执行操作:** + - 阅读/滚动内容 + - 标记已读/取消标记 + - 打开 AI 对话(资料范围) + - 查看资料详情 + - 开始学习会话 + - 添加笔记 + - QuickLook 预览(PDF/Office) + - 外部打开(PowerPoint) +- **自动执行功能:** + - 自动记录阅读位置(2 秒防抖上报) + - 自动开始/暂停/恢复阅读会话(前后台切换) + - 自动心跳上报(15 秒间隔) + - 优先恢复上次阅读位置(API > 本地缓存 > 会话位置) + - 文件不存在时自动从 COS 下载 + - 后台时自动导出并上传阅读事件 +- **可跳转页面:** + - AIChatPage(资料范围对话) + - MaterialDetailView(资料详情) + - LearningSessionView(学习会话) +- **页面主要状态:** 加载中 / 加载失败(重试)/ 已加载·按格式渲染 / 解析状态 Toast。 +- **当前完成情况:** 部分完成(核心功能已就位,解析触发使用 60×2s 硬编码轮询,存在改进空间) + +--- + +### 8.2 资料详情页(MaterialDetailView) + +- **页面作用:** 展示资料的元数据、处理状态和学习统计。 +- **页面入口:** 资料阅读页工具栏"信息"按钮。 +- **页面组成:** + - "原始文件"区域:AI 处理状态横幅(处理中/就绪/失败)、文件元数据(名称、格式、大小、上传日期)、阅读进度卡片 + - "学习内容"区域:知识点计数、测验计数 +- **用户可执行操作:** 查看文件信息、查看阅读进度、查看关联学习内容。 +- **自动执行功能:** 并行加载知识库详情、知识点列表、测验列表、阅读进度。 +- **可跳转页面:** 无。 +- **页面主要状态:** + - AI 处理状态:处理中(琥珀色横幅)/ 就绪(绿色横幅)/ 失败(红色横幅) + - 数据加载中 +- **当前完成情况:** 已完成 + +--- + +## 九、弹窗与 Sheet + +### 9.1 快速笔记(QuickNoteSheet) + +- **页面作用:** 在阅读过程中快速添加笔记。 +- **页面入口:** 资料阅读页工具栏笔记按钮(以 Sheet 形式弹出)。 +- **页面组成:** 资料上下文头部、笔记内容 TextEditor(自动聚焦)、取消/保存按钮。 +- **用户可执行操作:** 输入笔记文字、保存或取消。 +- **自动执行功能:** 自动获取当前阅读位置作为笔记锚点。 +- **可跳转页面:** 无(Sheet 内操作)。 +- **页面主要状态:** 编辑中 / 保存后关闭。 +- **当前完成情况:** 已完成 + +--- + +### 9.2 系统预览(QuickLook) + +- **页面作用:** 使用系统 QuickLook 预览 PDF、Word、Excel 等 Office 文件。 +- **页面入口:** 资料阅读页中非原生支持格式的"系统预览"按钮(以 Sheet 形式弹出)。 +- **页面组成:** 系统原生 QLPreviewController。 +- **用户可执行操作:** 系统标准的文件预览操作。 +- **自动执行功能:** 无。 +- **可跳转页面:** 无。 +- **页面主要状态:** 加载中 / 预览中。 +- **当前完成情况:** 已完成 + +--- + +### 9.3 AI 会话列表 Sheet + +- **页面作用:** 浏览和管理历史 AI 对话会话。 +- **页面入口:** AI 对话页工具栏"会话列表"按钮(以 Sheet 形式弹出,支持 .medium 和 .large 展示高度)。 +- **页面组成:** 可搜索会话列表,每条显示会话范围和最后消息时间;支持滑动操作(删除、归档)。 +- **用户可执行操作:** 搜索会话、切换会话、删除会话、归档会话。 +- **自动执行功能:** 根据当前对话范围过滤会话列表。 +- **可跳转页面:** 选择会话后关闭 Sheet 并加载对应对话。 +- **页面主要状态:** 会话列表 / 搜索中 / 空列表。 +- **当前完成情况:** 已完成 + +--- + +### 9.4 封面选择 Sheet + +- **页面作用:** 为知识库选择封面图片。 +- **页面入口:** 创建知识库页封面区域点击(以 Sheet 形式弹出,固定高度 220pt)。 +- **页面组成:** "从相册选择"选项。 +- **用户可执行操作:** 打开系统相册选择图片。 +- **自动执行功能:** 图片自动缩放为 512×512。 +- **可跳转页面:** 无。 +- **页面主要状态:** 选择中。 +- **当前完成情况:** 已完成 + +--- + +### 9.5 链接导入弹窗 + +- **页面作用:** 输入 URL 以导入链接内容。 +- **页面入口:** 导入资料页"链接导入"按钮(以 Alert 形式弹出,含输入框)。 +- **页面组成:** 输入框(URL)、确认/取消按钮。 +- **用户可执行操作:** 输入链接地址、确认导入。 +- **自动执行功能:** 无。 +- **可跳转页面:** 无。 +- **页面主要状态:** 输入中。 +- **当前完成情况:** 已完成 + +--- + +### 9.6 各类确认弹窗 + +以下为各页面中使用的系统 Alert 确认弹窗: + +| 弹窗 | 所在页面 | 触发操作 | +|------|---------|---------| +| 删除知识库确认 | LibraryDetailPage | 操作菜单"删除知识库" | +| 批量删除确认 | LibraryDetailPage | 批量选择后点击删除 | +| 新建文件夹 | FolderManageView | 点击"新建" | +| 重命名文件夹 | FolderManageView | 滑动->重命名 | +| 退出登录确认 | SettingsView | 点击"退出登录" | +| 结束学习确认 | LearningSessionView | 点击"结束"(confirmationDialog) | + +以上确认弹窗均已完成。 diff --git a/docs/system-map/ios/02-iOS页面功能总表.md b/docs/system-map/ios/02-iOS页面功能总表.md new file mode 100644 index 0000000..a02d90e --- /dev/null +++ b/docs/system-map/ios/02-iOS页面功能总表.md @@ -0,0 +1,263 @@ +# 02 iOS 页面功能总表 + +> 按页面逐一列出所有用户可见的功能点。 + +--- + +## 启��与登录 + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 启动 | 启动页 | 自动恢复登录会话 | 自动(应用启动) | 读取钥匙串 Token,调用 API 校验,恢复登录或跳转登录页 | 是 | 已完成 | | +| 登录 | 欢迎页 | 查看产品功能介绍 | 页面展示 | 了解产品核心功能 | 否 | 已完成 | | +| 登录 | 欢迎页 | 进入登录流程 | 点击"开始使用"按钮 | 跳转登录页 | 是 | 已完成 | | +| 登录 | 登录页 | Apple ID 登录 | 点击 Sign in with Apple 按钮 | 调用 Apple 认证,获取 Token,登录成功 | 是 | 已完成 | 支持 nonce 验证 | +| 登录 | 登录页 | 取消登录 | 点击"取消"按钮(登录中时显示) | 取消登录任务 | 否 | 已完成 | | +| 登录 | 账号状态页 | 查看账号状态说明 | 页面展示 | 了解账号被禁用/已注销的原因 | 否 | 已完成 | | +| 登录 | 账号状态页 | 返回登录页 | 点击"返回首页"按钮 | 回到未登录状态 | 是 | 已完成 | | +| 引导 | 引导页 | 浏览产品引导 | 点击"下一步"依次浏览 4 步 | 了解产品核心流程 | 否 | 已完成 | | +| 引导 | 引导页 | 跳过引导 | 点击"跳过"链接 | 直接进入目标设置 | 是 | 已完成 | | +| 引导 | 目标设置页 | 选择学习目标 | 点击四选一目标 | 选中学习目标 | 否 | 已完成 | | +| 引导 | 目标设置页 | 选择学习方法 | 点击多选方法 | 选中学习偏好方法 | 否 | 已完成 | | +| 引导 | 目标设置页 | 选择每日学习时间 | 点击四选一时间 | 选中每日时长 | 否 | 部分完成 | 选择和进入主界面已完成,但每日学习时长仅保存在本地 @State,没有可靠持久化 | +| 引导 | 目标设置页 | 确认并开始学习 | 点击"开始学习"按钮 | 进入主界面 | 是 | 部分完成 | 进入主界面已完成,但每日学习时长未持久化 | + +--- + +## 学习 Tab + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 学习 | 学习主页 | 查看连续学习天数 | 页面展示 | 查看连续天数和火焰图标 | 否 | 已完成 | | +| 学习 | 学习主页 | 继续上次学习 | 点击主操作卡片(优先级最高时) | 跳转到资料阅读页继续阅读 | 是 | 已完成 | 优先级自动计算 | +| 学习 | 学习主页 | 开始今日复习 | 点击主操作卡片或复习卡片 | 跳转复习卡片页 | 是 | 部分完成 | 入口正常,内容页为占位 | +| 学习 | 学习主页 | 进行自我测试 | 点击主操作卡片或测试卡片 | 跳转测验作答页 | 是 | 已完成 | | +| 学习 | 学习主页 | 创建知识库引导 | 点击主操作卡片(空状态时) | 切换到知识库 Tab | 是 | 已完成 | | +| 学习 | 学习主页 | 探索公开知识库 | 点击辅助按钮(空状态时) | 切换到知识库 Tab | 是 | 已完成 | | +| 学习 | 学习主页 | 查看每周摘要 | 页面展示 | 查看本周分钟数、复习卡片数、活跃天数、连续天数 | 否 | 已完成 | | +| 学习 | 学习主页 | 查看完整分析 | 点击底部链接 | 跳转主动回忆页 | 是 | 已完成 | 入口存在,跳转目标为占位页 | +| 学习 | 学习主页 | 下拉刷新 | 手势下拉 | 重新加载学习数据 | 否 | 已完成 | | +| 学习 | 学习会话页 | 专注计时学习 | 自动开始 | 计时学习时长,1 秒精度 | 否 | 暂未确认 | 默认 30 分钟;本地计时完成,但代码中未发现调用 LearningSessionService API 保存学习记录 | +| 学习 | 学习会话页 | 暂停学习 | 点击暂停按钮 | 暂停计时 | 否 | 已完成 | | +| 学习 | 学习会话页 | 继续学习 | 点击继续按钮 | 恢复计时 | 否 | 已完成 | | +| 学习 | 学习会话页 | 结束学习 | 点击结束按钮,确认弹窗 | 结束计时,展示庆祝动画 | 否 | 已完成 | | +| 学习 | 学习会话页 | 查看庆祝动画 | 自动(学习结束时) | 展示学习完成庆祝效果 | 否 | 已完成 | | + +--- + +## 知识库 Tab + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 知识库 | 知识库首页 | 查看知识库列表 | 页面加载 | 查看知识库卡片(封面、名称、描述、日期、标签) | 否 | 已完成 | | +| 知识库 | 知识库首页 | 筛选知识库 | 点击筛选分类(全部/我的/已订阅/官方) | 按分类过滤列表 | 否 | 部分完成 | "官方"筛选返回空数据 | +| 知识库 | 知识库首页 | 搜索知识库 | 点击搜索图标 | 跳转搜索页 | 是 | 部分完成 | 搜索逻辑未实现 | +| 知识库 | 知识库首页 | 创建知识库 | 点击创建按钮 | 跳转创建知识库页 | 是 | 已完成 | | +| 知识库 | 知识库首页 | 查看知识库详情 | 点击知识库卡片 | 跳转知识库详情页 | 是 | 已完成 | | +| 知识库 | 知识库首页 | 下拉刷新 | 手势下拉 | 刷新列表 | 否 | 已完成 | | +| 知识库 | 知识库首页 | 加载更多 | 滚动到底部 | 分页加载更多知识库 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 查看知识库信息 | 页面加载 | 查看封面、标题、描述、元数据 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 浏览知识点列表 | 页面展示(默认 Tab) | 查看知识点列表(类型图标、标签、日期) | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 浏览来源文件列表 | 切换到"来源"Tab | 查看来源文件列表(阅读状态标签) | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 查看知识点详情 | 点击知识点条目 | 跳转知识点详情页 | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 删除知识点 | 滑动/长按删除 | 删除知识点 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 批量删除知识点 | 进入批量选择模式,选中多个,点击删除 | 批量删除选中的知识点 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 批量选择模式 | 点击工具栏"批量选择" | 进入多选模式,可全选和逐选 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 切换排序方式 | 点击排序菜单 | 按默认/文件大小/创建时间/更新时间排序 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 导入资料 | 操作菜单→"上传" | 跳转导入资料页 | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 添加知识点 | 操作菜单→"添加" | 跳转添加知识点页 | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 生成测验 | 操作菜单→"测验" | 跳转测验列表页 | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 管理文件夹 | 操作菜单→"文件夹管理" | 弹出文件夹管理 Sheet | 是(Sheet) | 已完成 | | +| 知识库 | 知识库详情页 | 与 AI 对话 | 点击底部 AI 按钮 | 跳转 AI 对话页(知识库范围) | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 阅读来源文件 | 点击来源文件条目 | 跳转资料阅读页 | 是 | 已完成 | | +| 知识库 | 知识库详情页 | 删除来源文件 | 来源文件滑动删除 | 删除来源文件 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 删除知识库 | 操作菜单→"删除知识库",确认弹窗 | 删除整个知识库 | 否 | 已完成 | | +| 知识库 | 知识库详情页 | 重命名知识点 | (预留菜单项) | TODO,未实现 | 否 | 未完成 | 代码中标注 TODO | +| 知识库 | 知识库详情页 | 移动知识点到文件夹 | (预留菜单项) | TODO,未实现 | 否 | 未完成 | 代码中标注 TODO | +| 知识库 | 知识库详情页 | 知识库管理 | (预留菜单项) | TODO,未实现 | 是 | 未完成 | 代码中标注 TODO | +| 知识库 | 创建知识库页 | 上传封面图 | 点击封面区域→相册选择 | 选中图片自动裁剪为 512×512 | 否 | 已完成 | | +| 知识库 | 创建知识库页 | 输入知识库名称 | 文本输入 | 填写名称 | 否 | 已完成 | 必填 | +| 知识库 | 创建知识库页 | 输入知识库描述 | 文本输入 | 填写描述 | 否 | 已完成 | 必填 | +| 知识库 | 创建知识库页 | 确认创建 | 点击创建按钮 | 调用 API 创建知识库,返回上一页 | 否 | 已完成 | 名称或描述为空时禁用 | +| 知识库 | 添加知识点页 | 手动添加知识点 | 选择"手动"模式,输入标题+内容,保存 | 创建文本型知识点 | 否 | 已完成 | | +| 知识库 | 添加知识点页 | 文件添加知识点 | 选择"文件"模式,选择文件/图片,批量保存 | 上传文件并创建知识点 | 否 | 已完成 | 支持 PDF/文本/图片,图片自动压缩 | +| 知识库 | 添加知识点页 | 移除已选文件 | 点击文件旁的移除按钮 | 从待上传列表中移除该文件 | 否 | 已完成 | | +| 知识库 | 知识点详情页 | 阅读知识点内容 | 页面展示 | 按类型渲染内容(文本/Markdown/文件) | 否 | 已完成 | 支持多种文件格式 | +| 知识库 | 知识点详情页 | 收藏知识点 | 工具栏菜单→"收藏" | 切换收藏状态(UI 已实现) | 否 | 部分完成 | 后端 API 未支持,标记 TODO | +| 知识库 | 知识点详情页 | 添加笔记 | 工具栏菜单→"笔记" | 跳转笔记编辑 | 否 | 已完成 | | +| 知识库 | 知识点详情页 | 查看原文 | 工具栏→"阅读原文"(文本型内容) | 切换到原文模式 | 否 | 已完成 | | +| 知识库 | 知识点详情页 | 系统预览文件 | 自动(平台预览模式) | 使用系统预览查看文件 | 否 | 已完成 | PDF/Word/Excel | +| 知识库 | 编辑知识点页 | 编辑标题 | 文本输入 | 修改标题 | 否 | 已完成 | | +| 知识库 | 编辑知识点页 | 编辑内容 | 文本编辑器 | 修改内容 | 否 | 已完成 | | +| 知识库 | 编辑知识点页 | 保存修改 | 点击保存按钮 | 调用 API 更新知识点 | 否 | 已完成 | | +| 知识库 | 导入资料页 | 文件导入 | 点击"文件导入"→选择文件 | 导入 PDF 或纯文本文件 | 否 | 已完成 | | +| 知识库 | 导入资料页 | 相册导入 | 点击"相册导入"→选择照片 | 从相册导入图片 | 否 | 已完成 | | +| 知识库 | 导入资料页 | 链接导入 | 点击"链接导入"→输入 URL | 导入链接内容 | 否 | 已完成 | 通过 Alert 弹窗输入 URL | +| 知识库 | 导入候选审核页 | 查看导入候选 | 页面加载 | 查看 AI 从导入资料中提取的知识点候选(含置信度) | 否 | 已完成 | | +| 知识库 | 导入候选审核页 | 接受单个候选 | 展开候选→点击"接受" | 接受该知识点 | 否 | 已完成 | | +| 知识库 | 导入候选审核页 | 拒绝单个候选 | 展开候选→点击"拒绝" | 拒绝该知识点 | 否 | 已完成 | | +| 知识库 | 导入候选审核页 | 批量接受全部 | 点击"全部接受"按钮 | 接受所有候选知识点 | 否 | 已完成 | | +| 知识库 | 发现公开库页 | 浏览公开库 | 页面加载 | 查看可订阅的公开知识库列表 | 否 | 已完成 | | +| 知识库 | 发现公开库页 | 订阅知识库 | 点击订阅按钮 | 订阅该知识库 | 否 | 已完成 | | +| 知识库 | 发现公开库页 | 取消订阅 | 点击取消订阅按钮 | 取消订阅 | 否 | 已完成 | | +| 知识库 | 文件夹管理 | 查看文件夹列表 | Sheet 展示 | 查看该知识库的文件夹列表 | 否 | 已完成 | | +| 知识库 | 文件夹管理 | 新建文件夹 | 点击"新建"→输入名称 | 创建新文件夹 | 否 | 已完成 | | +| 知识库 | 文件夹管理 | 重命名文件夹 | 滑动→"重命名"→输入名称 | 修改文件夹名称 | 否 | 已完成 | | +| 知识库 | 文件夹管理 | 删除文件夹 | 滑动→"删除" | 删除文件夹 | 否 | 已完成 | | + +--- + +## 分析 Tab + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 分析 | 学习分析页 | 查看综合掌握度 | 页面展示 | 查看掌握度百分比 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看总学习分钟 | 页面展示 | 查看累计学习时长 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看复习卡片数 | 页面展示 | 查看累计复习卡片数 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看活跃天数 | 页面展示 | 查看活跃学习天数 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看阅读统计 | 页面展示 | 查看今日/本周阅读时长、已读/阅读资料数 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看掌握度趋势图 | 页面展示(含动画) | 查看 7 天掌握度趋势折线图 | 否 | 占位实现 | ZXChartView 使用编译时硬编码的 7 天数据,未接入 ViewModel API 返回的真实趋势数据 | +| 分析 | 学习分析页 | 查看阅读时长趋势 | 页面展示 | 查看阅读时长趋势柱状图 | 否 | 已完成 | 数据来源为 API | +| 分析 | 学习分析页 | 查看每周学习活跃 | 页面展示(含动画) | 查看每周每天学习活跃柱状图 | 否 | 占位实现 | ZXWeekBarChart 使用编译时硬编码的 7 天数据,未接入 ViewModel API 返回的真实 heatmap 数据 | +| 分析 | 学习分析页 | 查看连续学习统计 | 页面展示 | 查看当前连续、最长连续、最后活跃日期 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看最近学习记录 | 页面展示 | 查看最近 5 条学习记录 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看学习推荐 | 页面展示 | 查看 AI 推荐的学习行动(含优先级) | 否 | 已完成 | | +| 分析 | 学习分析页 | 继续阅读 | 点击"继续阅读"卡片 | 跳转资料阅读页 | 是 | 已完成 | | +| 分析 | 学习分析页 | 查看 AI 综合分析 | 页面展示 | 查看 AI 生成的综合学习分析文字 | 否 | 已完成 | 文字由数据动态拼接 | +| 分析 | 学习分析页 | 查看薄弱知识点列表 | 页面展示 | 查看最多 5 个薄弱知识点 | 否 | 已完成 | | +| 分析 | 学习分析页 | 查看全部薄弱知识点 | 点击"全部 N 个"链接 | 跳转薄弱知识点页 | 是 | 已完成 | | +| 分析 | 学习分析页 | 下拉刷新 | 手势下拉 | 重新加载分析数据 | 否 | 已完成 | | + +--- + +## 我的 Tab + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 我的 | 个人中心页 | 查看个人资料 | 页面展示 | 查看头像、昵称、邮箱、学习统计 | 否 | 已完成 | | +| 我的 | 个人中心页 | 编辑个人资料 | 点击资料卡片 | 跳转编辑资料页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 设置学习目标 | 点击"学习目标设置" | 跳转学习目标设置页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 设置复习提醒 | 点击"复习提醒" | 跳转设置页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 设置学习方法偏好 | 点击"学习方法偏好" | 跳转方法偏好页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 帮助与反馈 | 点击"帮助与反馈" | 跳转反馈页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 查看学习资产 | 页面展示 | 查看知识库/条目/卡片数量 | 否 | 已完成 | | +| 我的 | 个人中心页 | 发现公开库 | 点击"发现公开库" | 跳转发现公开库页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 查看消息中心 | 点击"消息中心" | 跳转通知列表页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 查看存储空间 | 页面展示 | 查看已用/总容量 | 否 | 已完成 | | +| 我的 | 个人中心页 | 打开通知列表 | 点击通知图标 | 跳转通知列表页 | 是 | 已完成 | | +| 我的 | 个人中心页 | 打开设置 | 点击设置图标 | 跳转设置页 | 是 | 已完成 | | +| 我的 | 编辑资料页 | 上传头像 | 点击头像→相册选择 | 选择并上传新头像(256×256) | 否 | 已完成 | | +| 我的 | 编辑资料页 | 编辑昵称 | 文本输入 | 修改昵称 | 否 | 已完成 | | +| 我的 | 编辑资料页 | 编辑学习身份 | 文本输入 | 修改学习身份 | 否 | 已完成 | | +| 我的 | 编辑资料页 | 编辑学习方向 | 文本输入 | 修改学习方向 | 否 | 已完成 | | +| 我的 | 编辑资料页 | 编辑当前目标 | 文本输入 | 修改当前目标 | 否 | 已完成 | | +| 我的 | 编辑资料页 | 编辑个人简介 | 文本输入 | 修改个人简介 | 否 | 已完成 | | +| 我的 | 编辑资料页 | 保存资料 | 点击保存按钮 | 调用 API 更新资料 | 否 | 已完成 | | +| 我的 | 设置页 | 切换外观模式 | 点击三种外观选项 | 切换深色/浅色/跟随系统 | 否 | 已完成 | 即时生效并保存至 API | +| 我的 | 设置页 | 设置复习提醒时间 | 选择提醒时间 | 设定每日复习提醒时间 | 否 | 已完成 | | +| 我的 | 设置页 | 设置提醒间隔天数 | 选择间隔天数 | 设定复习间隔(1/2/3/5/7天) | 否 | 已完成 | | +| 我的 | 设置页 | 切换复习提醒开关 | 点击开关 | 开启/关闭复习提醒 | 否 | 已完成 | | +| 我的 | 设置页 | 切换导入完成通知 | 点击开关 | 开启/关闭导入完成通知 | 否 | 部分完成(存在 bug) | 三个通知开关(复习提醒/导入完成/系统通知)全部绑定到同一个 $reviewReminder 变量,需修复为各自独立绑定 | +| 我的 | 设置页 | 切换系统通知 | 点击开关 | 开启/关闭系统通知 | 否 | 部分完成(存在 bug) | 同上,三个通知开关绑定到同一状态变量 | +| 我的 | 设置页 | 切换 iCloud 同步 | 点击开关 | 开启/关闭 iCloud 同步 | 否 | 暂未确认 | 开关 UI 存在但后端实现待确认 | +| 我的 | 设置页 | 查看设备管理 | 点击"设备管理" | 待确认 | 是 | 未完成 | 无导航目标 | +| 我的 | 设置页 | 查看隐私政策 | 点击"隐私政策" | 待确认 | 是 | 未完成 | 无导航目标 | +| 我的 | 设置页 | 查看用户协议 | 点击"用户协议" | 待确认 | 是 | 未完成 | 无导航目标 | +| 我的 | 设置页 | 退出登录 | 点击"退出登录",确认弹窗 | 清除 Token,回到未登录状态 | 是 | 已完成 | | +| 我的 | 学习目标设置页 | 修改学习目标 | 点击目标选项 | 选中新学习目标并保存 | 否 | 已完成 | | +| 我的 | 学习目标设置页 | 修改每日时长 | 点击时长选项 | 选中新时长(仅本地 @State,不通过 API 持久化) | 否 | 部分完成 | UI 选择完成,但选择结果不通过 API 保存,下次进入恢复默认"30 分钟" | +| 我的 | 方法偏好页 | 切换学习方法 | 点击复选框 | 选中/取消学习方法并保存 | 否 | 已完成 | 支持多选 | +| 我的 | 通知列表页 | 查看通知列表 | 页面展示 | 按日期分组查看通知 | 否 | 已完成 | | +| 我的 | 通知列表页 | 标记单条已读 | 点击通知条目 | 该通知标记为已读 | 否 | 已完成 | | +| 我的 | 通知列表页 | 全部标记已读 | 点击"全部已读"按钮 | 所有通知标记为已读 | 否 | 已完成 | | +| 我的 | 反馈页 | 选择反馈类型 | 点击类型选项 | 选中反馈类型(Bug/建议/内容/其他) | 否 | 已完成 | | +| 我的 | 反馈页 | 输入反馈内容 | 文本编辑器 | 填写反馈描述 | 否 | 已完成 | | +| 我的 | 反馈页 | 提交反馈 | 点击提交按钮 | 调用 API 提交反馈 | 否 | 已完成 | | + +--- + +## AI 辅助功能 + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| AI | AI 对话页 | 发送学习问题 | 输入文字,点击发送 | AI 回复(流式输出) | 否 | 已完成 | | +| AI | AI 对话页 | 查看 AI 思考过程 | 页面展示(可折叠) | 了解 AI 推理过程 | 否 | 已完成 | 含流式动画 | +| AI | AI 对话页 | 复制 AI 回复 | 点击"复制"按钮 | 复制到剪贴板 | 否 | 已完成 | | +| AI | AI 对话页 | 重新生成回复 | 点击"重新生成"按钮 | AI 重新生成回复 | 否 | 已完成 | | +| AI | AI 对话页 | 新建对话 | 点击工具栏新建按钮 | 创建新的对话会话 | 否 | 已完成 | | +| AI | AI 对话页 | 查看会话列表 | 点击工具栏会话列表按钮 | 弹出会话列表 Sheet | 否 | 已完成 | | +| AI | AI 对话页 | 切换历史会话 | 点击会话列表中的条目 | 加载该会话的消息历史 | 否 | 已完成 | | +| AI | AI 对话页 | 搜索会话 | 在会话列表中输入搜索词 | 过滤会话列表 | 否 | 已完成 | | +| AI | AI 对话页 | 删除会话 | 滑动→删除 | 删除该会话 | 否 | 已完成 | | +| AI | AI 对话页 | 归档会话 | 滑动→归档 | 归档该会话 | 否 | 已完成 | | +| AI | AI 对话页 | 置顶/取消置顶会话 | 左滑→置顶/取消置顶 | 切换会话置顶状态 | 否 | 已完成 | | +| AI | AI 对话页 | 查看对话范围标签 | 页面展示 | 了解当前对话限定范围(知识库/资料等) | 否 | 已完成 | | +| AI | 每日思考页 | 查看每日思考题 | 页面展示 | 查看今日 AI 出的思考题 | 否 | 占位实现 | 题目硬编码 | +| AI | 每日思考页 | 提交回答 | 输入答案,点击"提交获取 AI 反馈" | 跳转 AI 反馈页 | 是 | 占位实现 | | +| AI | AI 反馈页 | 查看 AI 分析步骤 | 自动(5 秒动画) | 展示分析进度动画 | 否 | 占位实现 | 硬编码等待 5 秒 | +| AI | AI 反馈页 | 查看分析评分 | 页面展示 | 查看得分圆环和掌握度评价 | 否 | 占位实现 | 得分 78/100 硬编码 | +| AI | AI 反馈页 | 查看答对/答错分析 | 页面展示 | 查看答对部分和需要完善的内容列表 | 否 | 占位实现 | 分析文字硬编码 | +| AI | AI 反馈页 | 加入待巩固 | 点击"加入待巩固"按钮 | 跳转学习主页 | 是 | 占位实现 | | +| AI | AI 反馈页 | 深入提问 | 点击"深入提问"按钮 | 跳转 AI 对话页 | 是 | 已完成 | | +| AI | AI 反馈页 | 再来一题 | 点击"再来一题"按钮 | 跳转每日思考页 | 是 | 已完成 | | +| AI | 薄弱知识点页 | 查看薄弱知识点列表 | 页面展示 | 查看掌握度低的易错知识点(含优先级) | 否 | 占位实现 | 5 个硬编码条目,未接 API | +| AI | AI 首页 | (已废弃) | 无入口 | — | — | 占位实现 | 页面代码完整但未接入任何导航 | +| AI | 回忆测试页 | 查看回忆测试题 | 页面展示 | 查看回忆测试题目 | 否 | 占位实现 | 题目硬编码"偏差-方差权衡" | +| AI | 回忆测试页 | 提交回答获取 AI 反馈 | 输入答案,点击"提交"按钮 | 跳转 AI 反馈页 | 是 | 占位实现 | 无导航入口,代码存在但未接入 Route 枚举 | + +--- + +## 测验功能 + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 测验 | 测验列表页 | 查看测验列表 | 页面加载 | 查看该知识库的所有测验 | 否 | 已完成 | | +| 测验 | 测验列表页 | 生成新测验 | 点击"生成新测验"按钮 | 调用 AI 生成测验 | 否 | 已完成 | 失败时 Toast 提示 | +| 测验 | 测验列表页 | 开始作答 | 点击已有测验 | 跳转测验作答页 | 是 | 已完成 | | +| 测验 | 测验作答页 | 回答选择题 | 点击 A/B/C/D 选项 | 选中答案,视觉反馈 | 否 | 已完成 | | +| 测验 | 测验作答页 | 回答判断题 | 点击正确/错误按钮 | 选中答案 | 否 | 已完成 | | +| 测验 | 测验作答页 | 回答填空题 | 输入文字答案 | 填写答案 | 否 | 已完成 | | +| 测验 | 测验作答页 | 题目导航 | 点击上一题/下一题 | 切换题目 | 否 | 已完成 | | +| 测验 | 测验作答页 | 提交全部答案 | 点击提交按钮(最后一题) | 提交所有答案,跳转结果页 | 是 | 已完成 | | +| 测验 | 测验结果页 | 查看得分 | 页面展示 | 查看总分和正确/总题数 | 否 | 已完成 | 低于 60 分红色,以上绿色 | +| 测验 | 测验结果页 | 查看逐题详情 | 页面展示 | 查看每道题的正确/错误标记和解析 | 否 | 已完成 | | +| 测验 | 测验结果页 | 重新测验 | 点击"重新测验"按钮 | 重新进入作答 | 是 | 已完成 | | + +--- + +## 复习功能 + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 复习 | 复习卡片页 | 翻转卡片 | 点击卡片 | 卡片翻转显示答案和出处 | 否 | 占位实现 | 3 张硬编码卡片 | +| 复习 | 复习卡片页 | 自评掌握度 | 点击四个等级按钮 | 记录自评,自动进入下一张 | 否 | 占位实现 | | +| 复习 | 复习卡片页 | 查看进度 | 页面展示 | 查看当前进度条 | 否 | 占位实现 | | +| 复习 | 复习卡片页 | 完成庆祝 | 自动(全部卡片完成后) | 展示庆祝动画覆盖层 | 否 | 占位实现 | | +| 复习 | 主动回忆页 | 文字作答 | 输入文字答案,点击提交 | 提交答案 | 否 | 占位实现 | 3 道硬编码问题 | +| 复习 | 主动回忆页 | 语音作答 | 点击语音图标(占位) | 未实现 | 否 | 占位实现 | 仅展示占位 UI | +| 复习 | 主动回忆页 | 查看下一题 | 点击"下一题"按钮 | 进入下一道问题 | 否 | 占位实现 | | +| 复习 | 主动回忆页 | 查看 AI 分析 | 点击"查看 AI 分析"按钮(末题) | 跳转 AI 反馈页 | 是 | 占位实现 | | + +--- + +## 资料阅读 + +| 所属模块 | 所属页面 | 功能名称 | 触发方式 | 功能结果 | 是否跨页面 | 当前完成情况 | 备注 | +|---------|---------|---------|---------|---------|-----------|------------|------| +| 阅读 | 资料阅读页 | 阅读 Markdown 内容 | 页面展示 | 渲染 Markdown(标题/段落/列表/代码/引用/表格/图片) | 否 | 已完成 | Rust FFI | +| 阅读 | 资料阅读页 | 阅读文本内容 | 页面展示 | 渲染纯文本内容 | 否 | 已完成 | | +| 阅读 | 资料阅读页 | 查看图片 | 页面展示 | 显示图片内容 | 否 | 已完成 | | +| 阅读 | 资料阅读页 | 系统预览 PDF/Office | 点击"系统预览"按钮 | 弹出 QuickLook Sheet | 是(Sheet) | 已完成 | | +| 阅读 | 资料阅读页 | 外部打开文件 | 点击"外部打开"(PPT 等) | 通过系统分享打开 | 否 | 已完成 | | +| 阅读 | 资料阅读页 | 标记已读 | 点击工具栏标记按钮 | 切换已读/未读状态 | 否 | 已完成 | 本地缓存 + 事件上报 | +| 阅读 | 资料阅读页 | AI 对话 | 点击工具栏 AI 按钮 | 跳转 AI 对话页(资料范围) | 是 | 已完成 | | +| 阅读 | 资料阅读页 | 查看资料详情 | 点击工具栏信息按钮 | 跳转资料详情页 | 是 | 已完成 | | +| 阅读 | 资料阅读页 | 开始学习会话 | 点击工具栏学习按钮 | 启动学习计时会话 | 否 | 已完成 | | +| 阅读 | 资料阅读页 | 添加笔记 | 点击工具栏笔记按钮 | 弹出快速笔记 Sheet | 是(Sheet) | 已完成 | 自动记录锚点位置 | +| 阅读 | 资料阅读页 | 恢复阅读位置 | 自动 | 恢复到上次阅读位置 | 否 | 已完成 | 优先级:API > 本地 > 会话 | +| 阅读 | 资料阅读页 | 自动旋转/暂停阅读会话 | 自动(前台/后台切换) | 管理阅读会话状态 | 否 | 已完成 | | +| 阅读 | 快速笔记 Sheet | 创建笔记 | 输入文字,点击保存 | 保存笔记(本地 UserDefaults 存储) | 否 | 已完成 | 含锚点信息 | +| 阅读 | 资料详情页 | 查看 AI 处理状态 | 页面展示 | 查看文件 AI 处理进度(处理中/就绪/失败) | 否 | 已完成 | | +| 阅读 | 资料详情页 | 查看文件元数据 | 页面展示 | 查看文件名、格式、大小、上传日期 | 否 | 已完成 | | +| 阅读 | 资料详情页 | 查看阅读进度 | 页面展示 | 查看已读时长、阅读会话数等 | 否 | 已完成 | | +| 阅读 | 资料详情页 | 查看学习内容统计 | 页面展示 | 查看关联的知识点数和测验数 | 否 | 已完成 | | diff --git a/docs/system-map/ios/03-C端业务能力初步清单.md b/docs/system-map/ios/03-C端业务能力初步清单.md new file mode 100644 index 0000000..543a84c --- /dev/null +++ b/docs/system-map/ios/03-C端业务能力初步清单.md @@ -0,0 +1,297 @@ +# 03 C 端业务能力初步清单 + +> **本文档为第一阶段初步归类结果。正式业务能力分类以《04-C端正式业务能力树.md》为准。本文档仅用于保留盘点过程,不作为后续系统地图的主索引。** + +> 基于 iOS 页面功能进行归并,形成业务能力目录。 +> 本阶段仅分析 iOS 项目,不涉及 API、Rust、RAG 或 Admin 仓库。 + +--- + +## 1. 账号与用户 + +**能力说明:** 用户注册、登录、会话管理、账号状态管理、个人资料维护。 + +**关联页面:** +- 启动页(会话恢复) +- 登录页(Apple ID 登录) +- 账号状态页(禁用/注销展示) +- 编辑资料页(昵称、头像、学习身份、方向、目标、简介) +- 设置页(退出登录、账号信息) + +**当前完成度:** 部分完成。核心登录和个人资料维护已完成。以下功能缺失或未接入:设备管理无 C 端入口、账号注销无 C 端入口(API 已就绪)、隐私政策和用户协议页面未接入。 + +--- + +## 2. 新手引导与目标设定 + +**能力说明:** 首次使用时的产品价值传递、学习目标和偏好配置。 + +**关联页面:** +- 欢迎页(功能介绍) +- 引导页(4 步产品引导) +- 目标设置页(学习目标/方法/时间) +- 学习目标设置页(后续修改) +- 方法偏好页(后续修改) + +**当前完成度:** 部分完成。引导流程和目标设置 UI 已完成,但每日学习时长 dailyMins 仅保存在本地 @State 变量,不通过 API 持久化,用户下次进入恢复默认值。 + +--- + +## 3. 知识库管理 + +**能力说明:** 知识库的创建、浏览、搜索、筛选、订阅、删除,以及知识库级别的操作入口。 + +**关联页面:** +- 知识库首页(列表、筛选、搜索、创建入口) +- 知识库搜索页(搜索,待完善) +- 创建知识库页(封面、名称、描述) +- 发现公开库页(浏览、订阅/取消订阅) +- 知识库详情页(部分操作:删除知识库、文件夹管理入口) + +**当前完成度:** 部分完成。搜索逻辑未实现,官方知识库筛选未支持,知识库管理页未实现。 + +--- + +## 4. 知识点管理 + +**能力说明:** 知识点是知识库的基本单元,支持增删改查、多种添加方式(手动/文件/图片/链接)、收藏、笔记。 + +**关联页面:** +- 知识库详情页·知识点 Tab(列表、排序、删除、批量删除、批量选择) +- 添加知识点页(手动、文件、图片) +- 知识点详情页(查看、收藏、笔记、原文) +- 编辑知识点页(修改标题和内容) + +**当前完成度:** 部分完成。收藏功能后端 API 未支持,重命名 TODO,移动到文件夹 TODO。 + +--- + +## 5. 资料上传 + +**能力说明:** 将外部文件(PDF、文本、图片、链接)上传至知识库,支持多种导入方式,AI 自动提取知识点候选。 + +**关联页面:** +- 导入资料页(文件导入、相册导入、链接导入) +- 导入候选审核页(审核 AI 提取的知识点候选:接受/拒绝/全部接受) + +**当前完成度:** 已完成。 + +--- + +## 6. 文档阅读 + +**能力说明:** 阅读学习资料,支持 Markdown、纯文本、PDF、EPUB、图片、Word、Excel、PowerPoint 等多种格式,具备阅读位置记录与恢复、阅读行为跟踪能力。 + +**关联页面:** +- 资料阅读页(多种格式渲染、标记已读、阅读位置恢复、阅读会话管理) +- 资料详情页(文件 AI 处理状态、元数据、阅读进度、关联学习内容统计) +- 系统预览(QuickLook,PDF/Office) +- 外部打开(ShareLink,PPT) + +**当前完成度:** 已完成(核心阅读功能)。解析触发使用了 60×2s 硬编码轮询。 + +--- + +## 7. 阅读笔记 + +**能力说明:** 在阅读过程中快速创建笔记,自动记录锚点位置(材料/段落/行/页)。 + +**关联页面:** +- 快速笔记 Sheet(创建笔记、自动锚点记录) +- 知识点详情页(从知识点进入笔记) + +**当前完成度:** 已完成。笔记存储在本地 UserDefaults。 + +--- + +## 8. 学习信息收集 + +**能力说明:** 收集用户在学习过程中的行为数据(阅读行为、学习时长、阅读位置、标记已读等),经客户端缓冲、批量上传、服务端聚合后,用于学习分析和继续学习推荐。这是学习数据管道的上位业务能力,包含以下子能力: + +- **阅读行为采集:** 在资料阅读过程中自动跟踪用户的阅读事件(打开/关闭/翻页/心跳/标记已读),由 Rust Document Runtime V2 会话管理驱动,含崩溃恢复和离线重试队列。 +- **专注学习会话:** 用户主动开始的计时学习,跟踪学习时长。 +- **本地事件队列:** iOS 端通过本地上传队列管理阅读事件的暂存、去重和重试。 +- **上传与重试:** 将阅读事件批量上传至服务端,含网络恢复自动重试机制。 +- **服务端聚合:** 服务端将原始阅读事件聚合为学习会话、资料阅读进度、每日学习活动和学 习记录。 + +**关联页面:** +- 资料阅读页(阅读行为采集、阅读会话管理、位置记录、心跳上报、标记已读) +- 学习会话页(专注计时、暂停、结束) +- 分析页(学习摘要、趋势、连续统计等消费端展示) +- 学习主页(继续学习推荐、每周摘要) + +**当前完成度:** 部分完成。阅读行为采集(Rust FFI V2 + 本地上传队列 + 服务端聚合)已完成;专注学习会话(LearningSessionView)的本地计时已完成,但代码中未发现调用 LearningSessionService API 保存学习记录的代码,服务端持久化暂未确认。 + +--- + +## 9. 继续学习 + +**能力说明:** 根据用户最近的学习状态,智能推荐下一步学习任务(继续阅读、今日复习、自我测试、开始学习)。 + +**关联页面:** +- 学习主页(优先级算法:继续学习 > 今日复习 > 自我测试 > 开始学习 > 空状态) +- 分析页(继续阅读入口) + +**当前完成度:** 已完成。 + +--- + +## 10. AI 对话 + +**能力说明:** 与 AI 进行学习相关的自然语言对话,支持流式回复、思考过程展示、多会话管理、范围限定(知识库/资料/全局)。 + +**关联页面:** +- AI 对话页(发送消息、流式接收、思考过程、复制、重新生成、新建会话、会话列表与管理) +- AI 会话列表 Sheet(搜索、切换、删除、归档) + +**当前完成度:** 已完成。 + +--- + +## 11. 主动回忆与 AI 反馈 + +**能力说明:** 用户对知识点进行主动输出(文字或语音回答),由 AI 评估掌握程度并给出评分、分析和改进建议。主动回忆 → AI 反馈是一个连续的用户体验流程。 + +**关联页面:** +- 主动回忆页(文字作答、语音作答占位、提交、AI 分析覆盖层、庆祝动画) +- AI 反馈页(分析动画、得分、答对/答错拆解、参考答案、加入待巩固、深入提问、再来一题) +- 每日思考页(查看思考题、提交回答获取 AI 反馈) +- 回忆测试页(查看测试题、提交获取 AI 反馈,无导航入口) +- 薄弱知识点页(薄弱点列表含掌握度分数和优先级) +- 分析页(AI 综合分析文字摘要) + +**当前完成度:** 占位实现。主动回忆页使用 3 道硬编码问题,语音回答为占位 UI;AI 反馈页得分和文字硬编码(78/100);薄弱知识点页 5 条数据硬编码;每日思考页和回忆测试页题目硬编码。上述页面均未接通真实 AI 分析 API。 + +--- + +## 12. 学习分析 + +**能力说明:** 以图表和数字形式展示用户的学习数据分析结果,包括掌握度趋势、阅读趋势、连续学习统计、学习推荐等。 + +**关联页面:** +- 学习分析页(统计徽章、掌握度趋势图、阅读时长趋势图、每周活跃图、连续统计、学习记录、学习推荐) + +**当前完成度:** 部分完成。API 数据已接入,但掌握度趋势图和每周活跃柱状图的图表数据为硬编码 mock,未使用 API 返回的真实数据渲染。 + +--- + +## 13. 题目与测验 + +**能力说明:** AI 根据知识库内容生成测验题目,支持选择题、判断题、填空题,用户逐题作答,查看得分和逐题解析。 + +**关联页面:** +- 测验列表页(查看、生成) +- 测验作答页(选择/判断/填空、导航、提交) +- 测验结果页(得分、逐题详情、重新测验) + +**当前完成度:** 已完成。 + +--- + +## 14. 间隔复习 + +**能力说明:** 基于间隔重复算法,以闪卡形式帮助用户复习知识点,用户自评掌握程度以调整复习计划。 + +**关联页面:** +- 复习卡片页(翻转卡片、自评四个等级、进度条、庆祝动画) + +**当前完成度:** 占位实现。使用 3 张硬编码卡片,未接通 ReviewViewModel 和 API。ReviewViewModel 和 ReviewPlanViewModel 代码已就绪。 + +--- + +## 15. 存储空间管理 + +**能力说明:** 展示用户的存储空间使用情况和学习资产统计。注:当前代码中无会员/订阅/付费墙/内购实现。 + +**关联页面:** +- 个人中心页(存储空间展示、学习资产统计) +- 设置页(iCloud 同步开关,待确认) + +**当前完成度:** 部分完成。存储展示基本完成,iCloud 同步实际后端能力待确认。 + +--- + +## 16. 消息与通知 + +**能力说明:** 系统通知的接收、列表查看、已读标记,以及通知偏好设置。 + +**关联页面:** +- 通知列表页(分组展示、标记已读、全部已读) +- 设置页(复习提醒、导入完成通知、系统通知开关) + +**当前完成度:** 部分完成。通知开关绑定存在疑似 bug(多个开关共用同一个状态变量)。 + +--- + +## 17. 设置与合规 + +**能力说明:** 应用外观、语言、学习偏好、复习提醒、数据同步等全局设置,以及隐私政策、用户协议等合规入口。 + +**关联页面:** +- 设置页(外观切换、复习提醒、通知、存储、iCloud 同步、退出登录) +- 设置页合规入口(隐私政策、用户协议——导航未接入) + +**当前完成度:** 部分完成。隐私政策、用户协议、设备管理页面入口无导航目标。 + +--- + +## 18. 帮助与反馈 + +**能力说明:** 用户提交 Bug 反馈、功能建议、内容问题等。 + +**关联页面:** +- 反馈页(选择反馈类型、输入描述、提交) + +**当前完成度:** 已完成。 + +--- + +## 能力汇总 + +| 序号 | 能力名称 | 完成度 | 关键缺失 | +|------|---------|--------|---------| +| 1 | 账号与用户 | 部分完成 | 设备管理无入口、账号注销无 C 端入口、合规页面未接入 | +| 2 | 新手引导与目标设定 | 部分完成 | 每日学习时长缺乏可靠持久化 | +| 3 | 知识库管理 | 部分完成 | 搜索逻辑、官方库筛选、KB管理页 | +| 4 | 知识点管理 | 部分完成 | 收藏 API、重命名、移动到文件夹 | +| 5 | 资料上传 | 已完成 | — | +| 6 | 文档阅读 | 已完成 | 解析触发轮询可优化 | +| 7 | 阅读笔记 | 已完成 | 笔记存储在本地 UserDefaults | +| 8 | 学习信息收集 | 部分完成 | 阅读行为采集已完成;LearningSessionView 服务端持久化暂未确认 | +| 9 | 继续学习 | 已完成 | — | +| 10 | AI 对话 | 已完成 | — | +| 11 | 主动回忆与 AI 反馈 | 占位实现 | 全部数据硬编码,语音未实现,未接真实 AI API | +| 12 | 学习分析 | 部分完成 | 图表数据为 mock(占位实现) | +| 13 | 题目与测验 | 已完成 | — | +| 14 | 间隔复习 | 占位实现 | 全部数据硬编码,未接 API | +| 15 | 存储空间管理 | 部分完成 | iCloud 同步待确认 | +| 16 | 消息与通知 | 部分完成 | 通知开关绑定 bug | +| 17 | 设置与合规 | 部分完成 | 合规页面入口缺失 | +| 18 | 帮助与反馈 | 已完成 | — | + +--- + +## 业务能力依赖关系(初步) + +``` +账号与用户 + └─ 新手引导与目标设定 + └─ 知识库管理 + ├─ 知识点管理 + │ └─ 阅读笔记(知识点详情页笔记入口) + ├─ 资料上传 → 文档阅读 + │ ├─ 阅读笔记 + │ ├─ 学习信息收集(阅读行为采集 → 服务端聚合) + │ │ └─ 学习分析 + │ ├─ AI 对话(资料范围对话) + │ └─ 题目与测验(解析完成后进入测验) + └─ AI 对话(知识库范围对话) + ├─ 继续学习 → 文档阅读 / 题目与测验 + │ └─ 主动回忆与 AI 反馈 → 间隔复习(加入待巩固) + ├─ 学习分析 + └─ 存储空间管理 +``` + +--- + +> **下一阶段待办:** 扩展到 API、Rust、RAG、Admin 仓库的业务能力分析。 diff --git a/docs/system-map/ios/04-C端正式业务能力树.md b/docs/system-map/ios/04-C端正式业务能力树.md new file mode 100644 index 0000000..f124ee6 --- /dev/null +++ b/docs/system-map/ios/04-C端正式业务能力树.md @@ -0,0 +1,259 @@ +# 04 C 端正式业务能力树 + +> 基于 iOS 页面地图和功能总表,按业务领域→业务能力→子能力的三层结构整理。 +> 不按代码目录组织,不写代码文件路径、类名。 + +--- + +## 1. 账号与用户 + +**能力说明:** 用户注册登录、会话管理、账号状态处理、个人资料维护。 + +``` +账号与用户 +├── 注册与登录 +│ ├── Apple ID 登录(含 nonce 验证) +│ ├── 自动会话恢复(Keychain Token → API 校验) +│ └── Token 刷新(401 自动重试) +├── 账号状态管理 +│ ├── 账号禁用展示 +│ └── 账号注销展示 +├── 个人资料维护 +│ ├── 头像上传与裁剪 +│ ├── 昵称编辑 +│ ├── 学习身份/方向/目标编辑 +│ └── 个人简介编辑 +└── 账号安全与设备 + ├── 登录设备查看(API 已就绪,C 端入口未实现) + ├── 移除登录设备(API 已就绪,C 端入口未实现) + └── 账号注销(API 已就绪,C 端入口未实现) +``` + +**当前完成度:** 部分完成 + +- 已完成:Apple ID 登录、会话恢复、Token 刷新、账号禁用/注销展示、个人资料查看与编辑 +- 未完成:登录设备查看/移除无 C 端入口(API 已就绪)、账号注销无 C 端入口(API 已就绪)、隐私政策和用户协议页面未接入 + +--- + +## 2. 内容获取与管理 + +**能力说明:** 用户构建和管理个人学习知识库的完整能力,包括知识库的创建浏览、知识点的增删改查、外部资料的导入。 + +``` +内容获取与管理 +├── 知识库管理 +│ ├── 创建知识库(封面、名称、描述) +│ ├── 浏览知识库列表(无限滚动分页) +│ ├── 筛选知识库(全部/我的/已订阅/官方) +│ ├── 搜索知识库(搜索逻辑未实现) +│ ├── 查看知识库详情(双 Tab:知识点 + 来源文件) +│ ├── 删除知识库 +│ ├── 订阅/取消订阅公开知识库 +│ └── 发现公开知识库 +├── 知识点管理 +│ ├── 手动添加知识点(标题 + 内容) +│ ├── 文件添加知识点(PDF/文本/图片,自动上传 COS) +│ ├── 查看知识点详情(多格式渲染:文本/Markdown/文件) +│ ├── 编辑知识点(标题 + 内容) +│ ├── 删除知识点(单个 + 批量) +│ ├── 排序知识点(默认/大小/创建时间/更新时间) +│ ├── 收藏知识点(UI 已实现,后端 API 未支持) +│ ├── 重命名知识点(TODO) +│ └── 移动知识点到文件夹(TODO) +├── 资料上传 +│ ├── 文件导入(PDF/纯文本 → COS 上传) +│ ├── 相册导入(图片 → 压缩 → COS 上传) +│ ├── 链接导入(输入 URL) +│ └── 导入候选审核(AI 提取知识点 → 接受/拒绝/批量接受) +└── 文件夹管理 + ├── 创建文件夹 + ├── 重命名文件夹 + └── 删除文件夹 +``` + +**当前完成度:** 部分完成 + +- 已完成:创建知识库、列表浏览、详情查看、知识点增删改查、批量操作、资料导入(三种方式)、导入候选审核、文件夹管理、公开库订阅 +- 未完成:搜索逻辑、官方筛选、收藏 API、重命名、移动到文件夹、知识库管理页 + +--- + +## 3. 学习执行 + +**能力说明:** 用户执行学习行为本身的能力,包括阅读资料、收集学习行为数据、做笔记。 + +``` +学习执行 +├── 文档阅读 +│ ├── 多格式渲染(Markdown/文本/图片/EPUB/PDF/Word/Excel/PPT) +│ ├── 系统预览(QuickLook,PDF/Word/Excel) +│ ├── 外部打开(ShareLink,PPT) +│ ├── 标记已读/取消标记 +│ ├── 阅读位置记录与恢复(API → 本地 → 会话三级优先级) +│ ├── 阅读会话管理(打开/暂停/恢复/关闭,前后台自动切换) +│ ├── 资料详情查看(AI 处理状态、文件元数据、阅读进度) +│ └── 触发知识提取(解析,60×2s 轮询) +├── 学习信息收集 +│ ├── 阅读行为采集(Rust FFI V2:material_opened/closed/position_changed/heartbeat/marked_as_read) +│ ├── 专注学习会话(计时器、暂停/继续/结束、庆祝动画) +│ ├── 本地上传队列(事件暂存、去重、崩溃恢复) +│ └── 上传与重试(批量上传、网络恢复自动重试、401 暂停) +└── 阅读笔记 + ├── 创建笔记(自动记录锚点位置) + └── 查看笔记(知识点详情页笔记入口) +``` + +**当前完成度:** 部分完成 + +- 已完成:文档多格式渲染、阅读位置记录恢复、阅读会话管理、阅读行为采集(Rust FFI V2 + 上传队列)、阅读笔记 +- 暂未确认:专注学习会话的 API 持久化(LearningSessionView 本地计时完成,服务端保存待确认) +- 待优化:解析触发使用硬编码 60×2s 轮询 + +--- + +## 4. AI 学习辅助 + +**能力说明:** AI 作为学习伙伴,通过对话、主动回忆、分析反馈等方式辅助用户学习。 + +``` +AI 学习辅助 +├── AI 对话 +│ ├── 发送学习问题(流式接收 AI 回复) +│ ├── 查看 AI 思考过程(可折叠,含流式动画) +│ ├── 复制/重新生成 AI 回复 +│ ├── 多会话管理(新建、切换、搜索、删除、归档、置顶) +│ └── 对话范围限定(知识库/资料/全局) +└── 主动回忆与 AI 反馈 + ├── 主动回忆(文字作答、语音作答占位) + ├── 每日思考(查看思考题、提交回答) + ├── 回忆测试(代码存在但无导航入口) + ├── AI 分析反馈(评分、答对/答错拆解、参考答案、加入待巩固) + └── 薄弱知识点展示(掌握度分数、优先级标签) +``` + +**当前完成度:** 部分完成 + +- 已完成:AI 对话全部功能(流式对话、思考过程、会话管理、范围限定) +- 占位实现:主动回忆(硬编码问题)、AI 反馈(得分 78/100 硬编码)、每日思考(硬编码题目)、薄弱知识点(硬编码数据)、回忆测试(无入口 + 硬编码) + +--- + +## 5. 测验与复习 + +**能力说明:** 通过 AI 生成测验和基于间隔重复的复习,帮助用户巩固知识。 + +``` +测验与复习 +├── 题目与测验 +│ ├── AI 生成测验(基于知识库内容) +│ ├── 测验作答(选择题/判断题/填空题) +│ ├── 测验结果(得分、逐题详情与解析) +│ └── 重新测验 +└── 间隔复习 + ├── 闪卡翻转(正面问题 → 反面答案) + ├── 自评掌握度(四个等级) + └── 完成庆祝 +``` + +**当前完成度:** 测验已完成;间隔复习为占位实现 + +- 已完成:测验生成、作答(三种题型)、结果展示、重新测验 +- 占位实现:间隔复习(硬编码卡片,未接通 API) +- 注:ReviewViewModel 和 ReviewPlanViewModel 代码已就绪,但未与 View 连接 + +--- + +## 6. 学习结果与分析 + +**能力说明:** 展示学习数据分析结果,并提供智能的下一步学习推荐。 + +``` +学习结果与分析 +├── 学习分析 +│ ├── 统计徽章(掌握度/总分钟/复习卡片/活跃天/阅读统计) +│ ├── 趋势图表(掌握度趋势、阅读时长趋势、每周活跃) +│ ├── 连续学习统计(当前连续/最长连续/最后活跃) +│ ├── 学习记录列表(最近 5 条) +│ ├── AI 综合分析(文字摘要) +│ └── 学习推荐(优先级标签) +└── 继续学习 + └── 优先级算法(继续学习 > 未完成会话 > 今日复习 > 自我测试 > 开始学习 > 空状态引导) +``` + +**当前完成度:** 部分完成 + +- 已完成:统计徽章、阅读时长趋势图、连续统计、学习记录、学习推荐、继续学习算法、AI 综合分析文字 +- 占位实现:掌握度趋势折线图(硬编码数据)、每周活跃柱状图(硬编码数据) + +--- + +## 7. 消息与设置 + +**能力说明:** 管理应用全局设置、通知偏好和系统通知查看。 + +``` +消息与设置 +├── 设置与应用偏好 +│ ├── 外观切换(深色/浅色/跟随系统,即时生效 API 保存) +│ ├── 复习提醒设置(提醒时间 + 间隔天数) +│ ├── 通知开关(复习提醒/导入完成/系统通知) +│ ├── 存储空间展示 +│ ├── iCloud 同步开关(待确认) +│ └── 退出登录 +├── 消息与通知 +│ ├── 通知列表(按日期分组:今天/本周/更早) +│ ├── 标记已读(单条 + 全部) +│ └── 按类型显示图标颜色(10+ 种类型) +└── 学习偏好配置 + ├── 学习目标设置(4 选 1,API 保存) + ├── 每日学习时长(4 选 1,仅本地 @State,不持久化) + └── 学习方法偏好(多选,API 保存) +``` + +**当前完成度:** 部分完成 + +- 已完成:外观切换、复习提醒设置、通知列表与已读标记、学习目标保存、方法偏好保存、退出登录 +- 存在 bug:三个通知开关绑定到同一状态变量 +- 待确认:iCloud 同步实际后端能力 +- 部分完成:每日学习时长不持久化 + +--- + +## 8. 合规与支持 + +**能力说明:** 用户反馈提交和合规相关页面入口。 + +``` +合规与支持 +├── 帮助与反馈 +│ ├── 选择反馈类型(Bug/建议/内容/其他) +│ ├── 输入反馈内容 +│ └── 提交反馈 +├── 隐私政策(入口未接入) +└── 用户协议(入口未接入) +``` + +**当前完成度:** 部分完成 + +- 已完成:帮助与反馈 +- 未完成:隐私政策页面、用户协议页面 + +--- + +## 业务能力汇总表 + +| 序号 | 业务领域 | 业务能力数 | 完成度 | 关键缺失 | +|------|---------|-----------|--------|---------| +| 1 | 账号与用户 | 4 | 部分完成 | 设备管理无入口、账号注销无入口、合规页面未接入 | +| 2 | 内容获取与管理 | 4 | 部分完成 | 搜索逻辑、官方库筛选、KB管理页、收藏API、重命名、移动到文件夹 | +| 3 | 学习执行 | 3 | 部分完成 | LearningSessionView API持久化暂未确认 | +| 4 | AI 学习辅助 | 2 | 部分完成 | 主动回忆与AI反馈全部硬编码 | +| 5 | 测验与复习 | 2 | 部分完成 | 间隔复习硬编码未接API | +| 6 | 学习结果与分析 | 2 | 部分完成 | 图表数据为占位实现 | +| 7 | 消息与设置 | 3 | 部分完成 | 通知开关bug、合规入口缺失、每日时长不持久化 | +| 8 | 合规与支持 | 1(+2) | 部分完成 | 隐私政策、用户协议入口未接入 | + +--- + +> **阶段划分说明:** 本能力树为 C 端视角。跨项目的完整能力展开仅对"文档阅读"和"学习信息收集"两个能力进行了试点分析(见 capabilities/ 目录)。 diff --git a/docs/system-map/ios/05-页面与业务能力矩阵.md b/docs/system-map/ios/05-页面与业务能力矩阵.md new file mode 100644 index 0000000..dea1e23 --- /dev/null +++ b/docs/system-map/ios/05-页面与业务能力矩阵.md @@ -0,0 +1,133 @@ +# 05 页面与业务能力矩阵 + +> 双向矩阵:每个页面关联的业务能力 / 每个业务能力涉及的页面。 + +--- + +## 一、页面 → 业务能力 + +| 页面 | 业务领域 | 主要关联业务能力 | +|------|---------|----------------| +| 启动页 | 账号与用户 | 注册与登录(会话恢复) | +| 欢迎页 | 账号与用户 | 注册与登录(引导入口) | +| 登录页 | 账号与用户 | 注册与登录(Apple ID 登录) | +| 账号状态页 | 账号与用户 | 账号状态管理 | +| 引导页 | 账号与用户 | 注册与登录(首次引导) | +| 目标设置页 | 账号与用户 | 个人资料维护、学习偏好配置 | +| 学习主页 | 学习执行、学习结果与分析 | 继续学习、学习分析 | +| 学习会话页 | 学习执行 | 学习信息收集(专注学习会话) | +| 复习卡片页 | 测验与复习 | 间隔复习 | +| 主动回忆页 | AI 学习辅助 | 主动回忆与 AI 反馈 | +| 知识库首页 | 内容获取与管理 | 知识库管理 | +| 知识库搜索页 | 内容获取与管理 | 知识库管理(搜索) | +| 知识库详情页 | 内容获取与管理、AI 学习辅助 | 知识库管理、知识点管理、文件夹管理、AI 对话 | +| 创建知识库页 | 内容获取与管理 | 知识库管理(创建) | +| 添加知识点页 | 内容获取与管理 | 知识点管理 | +| 知识点详情页 | 内容获取与管理、学习执行 | 知识点管理、文档阅读、阅读笔记 | +| 编辑知识点页 | 内容获取与管理 | 知识点管理 | +| 导入资料页 | 内容获取与管理 | 资料上传 | +| 导入候选审核页 | 内容获取与管理 | 资料上传(导入候选审核) | +| 发现公开库页 | 内容获取与管理 | 知识库管理(订阅/发现) | +| 文件夹管理 Sheet | 内容获取与管理 | 文件夹管理 | +| 学习分析页 | 学习结果与分析 | 学习分析 | +| 个人中心页 | 账号与用户、消息与设置 | 个人资料维护、存储空间管理、消息与通知 | +| 编辑资料页 | 账号与用户 | 个人资料维护 | +| 设置页 | 消息与设置、合规与支持 | 设置与应用偏好、消息与通知、合规入口 | +| 学习目标设置页 | 消息与设置 | 学习偏好配置(学习目标) | +| 方法偏好页 | 消息与设置 | 学习偏好配置(学习方法) | +| 通知列表页 | 消息与设置 | 消息与通知 | +| 反馈页 | 合规与支持 | 帮助与反馈 | +| AI 对话页 | AI 学习辅助 | AI 对话 | +| AI 对话会话列表 Sheet | AI 学习辅助 | AI 对话(多会话管理) | +| 每日思考页 | AI 学习辅助 | 主动回忆与 AI 反馈 | +| AI 反馈页 | AI 学习辅助 | 主动回忆与 AI 反馈 | +| 薄弱知识点页 | AI 学习辅助 | 主动回忆与 AI 反馈 | +| 回忆测试页(无入口) | AI 学习辅助 | 主动回忆与 AI 反馈 | +| AI 首页(已废弃) | AI 学习辅助 | AI 对话、主动回忆与 AI 反馈 | +| 测验列表页 | 测验与复习 | 题目与测验 | +| 测验作答页 | 测验与复习 | 题目与测验 | +| 测验结果页 | 测验与复习 | 题目与测验 | +| 资料阅读页 | 学习执行、AI 学习辅助 | 文档阅读、学习信息收集、阅读笔记、AI 对话 | +| 资料详情页 | 学习执行 | 文档阅读 | +| 快速笔记 Sheet | 学习执行 | 阅读笔记 | +| 系统预览 Sheet | 学习执行 | 文档阅读(系统预览) | + +--- + +## 二、业务能力 → 页面 + +### 1. 账号与用户 + +| 子能力 | 关联页面 | +|--------|---------| +| 注册与登录 | 启动页、欢迎页、登录页、引导页 | +| 账号状态管理 | 账号状态页 | +| 个人资料维护 | 目标设置页、个人中心页、编辑资料页 | + +### 2. 内容获取与管理 + +| 子能力 | 关联页面 | +|--------|---------| +| 知识库管理 | 知识库首页、知识库搜索页、知识库详情页、创建知识库页、发现公开库页 | +| 知识点管理 | 知识库详情页、添加知识点页、知识点详情页、编辑知识点页 | +| 资料上传 | 导入资料页、导入候选审核页 | +| 文件夹管理 | 文件夹管理 Sheet | + +### 3. 学习执行 + +| 子能力 | 关联页面 | +|--------|---------| +| 文档阅读 | 资料阅读页、资料详情页、知识点详情页、系统预览 Sheet | +| 学习信息收集 | 资料阅读页、学习会话页(自动执行,用户不直接感知此能力) | +| 阅读笔记 | 快速笔记 Sheet、知识点详情页 | + +### 4. AI 学习辅助 + +| 子能力 | 关联页面 | +|--------|---------| +| AI 对话 | AI 对话页、AI 对话会话列表 Sheet、资料阅读页(工具栏 AI 按钮)、知识库详情页(底部 AI 按钮) | +| 主动回忆与 AI 反馈 | 主动回忆页、每日思考页、AI 反馈页、薄弱知识点页、回忆测试页(无入口) | + +### 5. 测验与复习 + +| 子能力 | 关联页面 | +|--------|---------| +| 题目与测验 | 测验列表页、测验作答页、测验结果页 | +| 间隔复习 | 复习卡片页 | + +### 6. 学习结果与分析 + +| 子能力 | 关联页面 | +|--------|---------| +| 学习分析 | 学习分析页 | +| 继续学习 | 学习主页、学习分析页(继续阅读入口) | + +### 7. 消息与设置 + +| 子能力 | 关联页面 | +|--------|---------| +| 设置与应用偏好 | 设置页、个人中心页 | +| 消息与通知 | 通知列表页、个人中心页(消息中心入口)、设置页(通知开关) | +| 学习偏好配置 | 学习目标设置页、方法偏好页、目标设置页 | + +### 8. 合规与支持 + +| 子能力 | 关联页面 | +|--------|---------| +| 帮助与反馈 | 反馈页 | +| 合规入口 | 设置页(隐私政策/用户协议/设备管理,均未接入) | + +--- + +## 三、跨页面业务能力分布 + +以下能力横跨多个页面,说明其完整链路: + +| 业务能力 | 跨页面链路 | +|---------|-----------| +| 文档阅读 | 知识库详情页(来源文件入口)→ 资料阅读页(阅读、笔记、AI 对话)→ 资料详情页(查看元数据)→ 系统预览(PDF/Office) | +| 学习信息收集 | 资料阅读页(阅读行为采集)→ 学习会话页(专注计时)→ 分析页(消费数据展示) | +| AI 对话 | 知识库详情页(知识库范围)→ AI 对话页 → 会话列表 Sheet;资料阅读页(资料范围)→ AI 对话页 | +| 主动回忆与 AI 反馈 | 主动回忆页 → AI 反馈页 → 每日思考页 / AI 对话页 / 学习主页 | +| 资料上传 | 导入资料页(文件/相册/链接)→ 导入候选审核页(审核 AI 提取的知识点) | +| 测验 | 知识库详情页(测验入口)→ 测验列表页 → 测验作答页 → 测验结果页 | diff --git a/docs/system-map/ios/review/00-审查总报告.md b/docs/system-map/ios/review/00-审查总报告.md new file mode 100644 index 0000000..647b9c3 --- /dev/null +++ b/docs/system-map/ios/review/00-审查总报告.md @@ -0,0 +1,242 @@ +# 00 审查总报告 + +> 审查对象:知习 iOS 项目第一阶段系统地图(4 份文档) +> 审查日期:2026-06-19 +> 审查方法:独立代码扫描 → 独立基线建立 → 与已有文档逐项比对 +> 审查范围:AIStudyApp/AIStudyApp/ 目录下全部 64 个 .swift 文件(不含 Tests 和自动生成代码) + +--- + +## 一、审查范围 + +### 1.1 已检查的文件 + +- `AIStudyAppApp.swift` — App 入口、所有页面定义 +- `ContentView.swift` — Tab 根结构、共享组件 +- `Core/Navigation/Route.swift` — 全部路由定义(28 个 case) +- `Core/Auth/AuthManager.swift` — 会话状态机(8 种状态) +- `Core/Models/APIModels.swift` — 全部 54 个 API 模型 +- `Core/Models/AppContext.swift` — 设备/运行时上下文 +- `Core/Network/APIClient.swift` — HTTP 客户端、Token 刷新 +- `Core/Services/APIService.swift` — 全部 18 个服务类 +- `Core/Services/FileUploadService.swift` — 文件上传 +- `Core/Services/ReadingAPI.swift` — 阅读相关 API +- `Core/Services/NetworkMonitor.swift` — 网络状态监控 +- `Core/DesignSystem/DesignTokens.swift` — 设计系统 +- `Core/DesignSystem/ZXToast.swift` — Toast 系统 +- `Core/Security/KeychainHelper.swift` — (已通过 AuthManager 间接审查) +- `Core/Security/LocalCache.swift` — 本地缓存 +- `Core/Security/FileCache.swift` — 文件缓存 +- `Features/Study/` 全部 7 个文件 +- `Features/Library/` 全部 5 个文件 +- `Features/Profile/` 全部 8 个文件 +- `Features/AI/` 全部 10 个文件 +- `Features/Analysis/` 全部 2 个文件 +- `Features/Quiz/` 1 个文件(QuizViews.swift) +- `Features/MaterialReader/` 全部 12 个文件 + +### 1.2 已检查的入口类型 + +- [x] Tab(4 个:学习/知识库/分析/我的) +- [x] Push(NavigationLink via Route,25 个路由目标) +- [x] Sheet(6 个) +- [x] FullScreenCover(未发现) +- [x] Alert(6 个) +- [x] ConfirmationDialog(1 个) +- [x] ContextMenu(1 处) +- [x] Menu(1 处) +- [x] Deep Link(未配置) +- [x] Universal Link(未配置) +- [x] URL Scheme(未配置) +- [x] 通知点击路由(未实现) +- [x] Debug 页面(仅 Route.destination 的 DEBUG 覆盖层) +- [x] 条件渲染页面(基于 session/onboarding/数据状态的 7 种分支) +- [x] iPhone/iPad 差异(仅在 AppContext 中标记 deviceType) +- [x] Feature Flag(未发现) + +### 1.3 未检查的项 + +- .xcodeproj 详细配置(Capabilities、Build Settings) +- .entitlements 文件全文(推送通知、iCloud 等 Capability) +- 第三方依赖(Rive 动画 SDK 等) +- Rust FFI 二进制内部逻辑(ZxDocumentRuntime.xcframework) + +--- + +## 二、独立盘点统计 + +| 统计项 | 数量 | +|--------|------| +| 一级模块(Tab) | 4 | +| 独立 Push 页面(可路由) | 32 | +| Tab 内嵌页面(不可路由) | 6(启动/登录流程页面) | +| Sheet / 弹窗 | 10 | +| 确认弹窗(Alert/ConfirmationDialog) | 8 | +| 代码存在但无导航入口的页面 | 2(AIHomeView, RecallTestPage) | +| 页面功能点 | ~180 | +| API 服务类 | 18 | +| 初步业务能力 | 20 | + +--- + +## 三、审查结论 + +**审查结论:有条件通过** + +### 不满足"通过"的哪些门禁条件? + +| 门禁条件 | 满足? | 说明 | +|---------|--------|------| +| 所有导航入口已检查 | 是 | Tab/Push/Sheet/Alert/条件渲染均检查 | +| 所有用户可访问页面已进入基线 | 是 | 32 个路由页面 + 6 个启动/登录页均已盘点 | +| Sheet/弹窗/隐藏入口已检查 | 是 | 10 个 Sheet + 8 个 Alert + ContextMenu/Menu 均已盘点 | +| 页面功能均进入功能基线 | 是 | ~180 个功能点均已盘点 | +| 页面与业务能力完成双向覆盖检查 | 是 | 见 06-页面能力覆盖矩阵.md | +| Mock/占位/废弃实现没有被误判为已完成 | **否** | 4 处 P0 误判(见第四节) | +| 所有"暂未确认"均被明确列出 | 是 | 3 项暂未确认 | +| 严重遗漏为 0 | **否** | 1 个页面遗漏(RecallTestPage) | +| P0 修正项为 0 | **否** | 4 项 P0 修正 | +| 已有文档和独立基线差异已全部处理 | 是 | 16 项差异全部列入待修正清单 | + +--- + +## 四、严重问题(P0 — 会导致系统地图明显失真) + +### 4.1 功能状态误判-图表数据为占位 + +- **问题:** 文档将"查看掌握度趋势图"和"查看每周学习活跃"均标记为"部分完成" +- **实际:** ZXChartView 和 ZXWeekBarChart 使用完全硬编码的编译时数据,ViewModel 的 API 返回数据被忽略。应标记为"占位实现" +- **影响:** 分析页给人的印象是"图表数据已接入但需优化",实际情况是"图表数据完全未接入 API" + +### 4.2 功能状态误判-每日学习时长不持久化 + +- **问题:** GoalSettingDetailView 的"修改每日时长"标记为"已完成" +- **实际:** dailyMins 只保存在本地 @State 变量,不通过 API 持久化,用户下次进入恢复默认"30 分钟" +- **影响:** 给人"目标设置功能完整"的假象 + +### 4.3 设置页通知开关标记为"暂未确认" + +- **问题:** 三个通知开关绑定 bug 被标记为"暂未确认" +- **实际:** 代码中"复习提醒"、"导入完成通知"、"系统通知"三个 Toggle 全部绑定到同一个 `$reviewReminder`,这是明确的代码 bug +- **影响:** 将确定性 bug 降级为不确定性疑点,降低修正优先级 + +### 4.4 文档页面/弹窗统计数字口径不明确 + +- **问题:** 总览文档称"43 个页面/弹窗",但未说明统计口径 +- **实际:** 独立基线盘点出 38 个 Push 页面 + 10 个 Sheet/弹窗 + 8 个确认弹窗 +- **建议:** 明确统计口径(是否含弹窗?是否含废弃页面?)并更新数字 + +--- + +## 五、一般问题(P1/P2) + +### P1 — 遗漏项(4 项) + +1. 遗漏 RecallTestPage(代码存在,无入口,应为占位实现) +2. 遗漏 AIChatPage 会话置顶/取消置顶功能 +3. 遗漏 WaitlistService API 已就绪但 C 端无入口 +4. 遗漏 UserService 账号注销 API 已就绪但无 C 端入口 + +### P2 — 命名、描述、辅助状态问题(8 项) + +1. 业务能力"会员与额度"命名不准确 → 应改为"存储空间管理" +2. 建议合并"主动回忆"与"AI 学习分析"为一个业务能力 +3. StudyHomeViewModel error 状态永不可达(View 有但 ViewModel 不设置) +4. DailyThinkingPage submitted 变量永不为 true +5. 设置页"存储空间"和"登录设备管理"自引用导航 +6. 知识库详情页"知识库管理"按钮为 TODO +7. 业务能力依赖关系图缺少交叉引用 +8. 文件夹新建/重命名 Alert 未列入确认弹窗表 + +--- + +## 六、遗漏项汇总 + +| 类型 | 数量 | 明细 | +|------|------|------| +| 遗漏页面 | 1 | RecallTestPage | +| 遗漏功能 | 4 | 会话置顶、AIHomeView 子功能、解析触发、MaterialReaderView COS 下载 | +| 遗漏 Sheet/弹窗 | 1 | 文件夹新建/重命名 Alert | +| 遗漏 API-页面入口 | 3 | WaitlistService、账号注销、设备管理 | + +--- + +## 七、错误项汇总 + +| 类型 | 数量 | 明细 | +|------|------|------| +| 状态误判 | 4 | 掌握度趋势图(部分→占位)、每周活跃图(部分→占位)、每日时长(已完成→部分)、通知开关(暂未确认→部分+bug) | +| 命名错误 | 1 | 会员与额度 → 存储空间管理 | +| 分类建议 | 2 | 主动回忆+AI 分析建议合并、能力依赖图缺少交叉引用 | + +--- + +## 八、待确认项 + +| 序号 | 待确认内容 | 原因 | +|------|-----------|------| +| U01 | LearningSessionView 是否调用 API 保存学习记录 | 代码中未发现 LearningSessionService.start/end 的直接调用,但可能在 Rust FFI 或 ViewModel 中有间接调用 | +| U02 | SettingsView iCloud 同步开关实际后端支持情况 | Toggle UI 存在但仅改变本地 @State,无法确认后端是否有对应能力 | +| U03 | 分析页"近 7 天"日期范围筛选是否可切换 | UI 中展示了日期范围标签但未发现切换逻辑 | + +--- + +## 九、修正优先级 + +### P0(4 项)— 影响整体地图正确性 + +1. 分析页图表数据状态修正(部分完成 → 占位实现) +2. 每日学习时长持久化状态修正(已完成 → 部分完成) +3. 设置页通知开关 bug 状态修正(暂未确认 → 部分完成,存在 bug) +4. 总览页统计数字口径明确化 + +### P1(4 项)— 遗漏主要页面或业务能力 + +5. 补充 RecallTestPage 到页面地图和功能表 +6. 补充 AIChatPage 会话置顶功能 +7. 标注 WaitlistService 状态 +8. 标注账号注销 API 状态 + +### P2(8 项)— 命名、描述、辅助状态完善 + +9. 重命名"会员与额度"为"存储空间管理" +10. 考虑合并"主动回忆"与"AI 学习分析" +11-16. 其他描述性补充 + +--- + +## 十、最终判断 + +### 总体评价 + +- **已有文档的代码覆盖率高**(页面覆盖率约 95%,功能覆盖率约 95%) +- **核心流程描述准确**(用户生命周期、Tab 结构、路由系统) +- **Mock/占位实现识别基本正确**(AI 相关页面正确标记为占位实现) + +### 主要不足 + +1. **分析页图表状态被低估**(占位实现被标记为部分完成) +2. **设置页通知 bug 被降级为"暂未确认"** +3. **GoalSettingDetailView 学习时长不持久化未被发现** +4. **1 个代码页面、2 个 API 端点、1 个交互功能的遗漏** + +### 是否可以进入下一阶段? + +**可以进入下一阶段的"跨项目业务能力展开",但建议先完成 4 项 P0 修正。** + +原因: +- 已有文档的整体架构和页面覆盖是准确的,作为后续分析的基础足够可靠 +- P0 问题集中在对少数具体功能的状态判断上,不影响整体地图的结构正确性 +- 未发现系统性的页面遗漏或归类错误 +- Mock/占位/废弃实现的识别框架是正确的,只需修正个别判断 +- P1/P2 问题不阻塞跨项目分析,可在第二阶段的盘点中一并修正 + +### 门禁复查 + +| 门禁 | 修正前 | 修正 P0 后 | +|------|--------|-----------| +| 严重遗漏为 0 | 否(1 项 P1) | 是 | +| P0 修正项为 0 | 否(4 项) | 是 | +| Mock/占位未误判 | 否 | 是(修正 4 处后) | + +**完成 4 项 P0 修正后可达"通过"标准。** diff --git a/docs/system-map/ios/review/01-独立页面基线.md b/docs/system-map/ios/review/01-独立页面基线.md new file mode 100644 index 0000000..4dfdebe --- /dev/null +++ b/docs/system-map/ios/review/01-独立页面基线.md @@ -0,0 +1,314 @@ +# 01 独立页面基线 + +> 本文件不参考已有系统地图文档,完全基于代码扫描独立建立。 +> 扫描日期:2026-06-19 +> 扫描范围:AIStudyApp/AIStudyApp/ 目录下全部 .swift 文件(不含 Tests 和 Generated) + +--- + +## 一、独立盘点统计 + +| 统计项 | 数量 | +|--------|------| +| 一级模块(Tab) | 4 | +| 独立页面(含可路由页面) | 32 | +| Sheet / 弹窗 | 10 | +| 确认弹窗(Alert/ConfirmationDialog) | 8 | +| 页面内嵌子视图(非独立路由) | 2 | +| 代码存在但无入口的页面 | 1 | +| 页面功能点(估算) | ~180 | + +--- + +## 二、应用根结构 + +### 2.1 入口点 + +- `AIStudyAppApp.swift` 是 `@main` 入口。 +- 使用 `WindowGroup`,`UIApplicationSupportsMultipleScenes = false`。 +- 无 URL Scheme、Universal Link、Deep Link 配置(Info.plist 中无相关条目)。 +- 无通知点击路由(未发现 `UNUserNotificationCenter` delegate 或 `onOpenURL`)。 +- 无"恢复上次页面"逻辑(每次启动由 AuthManager 状态决定初始页面)。 + +### 2.2 会话状态机(AuthManager.AppSession) + +``` +unknown → SplashScreen +unauthenticated → PreLoginFlow (WelcomePage → LoginPage) +authenticating / refreshing → SplashScreen +authenticated → ContentView (if hasCompletedOnboarding) else PostLoginOnboardingFlow +disabled → AccountStatusView (禁用) +deleted → AccountStatusView (注销) +expired → PreLoginFlow +``` + +### 2.3 Tab 根结构(ContentView) + +``` +TabView(selection: $selectedTab) + ├─ "学习" (tag: "study") → NavigationStack → StudyHomeView + ├─ "知识库" (tag: "library") → NavigationStack → LibraryHomeView + ├─ "分析" (tag: "analysis") → NavigationStack → AnalysisHomeView + └─ "我的" (tag: "profile") → NavigationStack → ProfileView +``` + +所有 Tab 使用 NavigationStack + `.navigationDestination(for: Route.self)` 统一路由。 + +### 2.4 条件性入口 + +| 条件 | 影响的页面/行为 | +|------|----------------| +| hasCompletedOnboarding = false | 显示 PostLoginOnboardingFlow (OnboardingPage → GoalSetupPage) | +| hasCompletedOnboarding = true | 直接进入 ContentView | +| session = .disabled | 显示 AccountStatusView(禁用) | +| session = .deleted | 显示 AccountStatusView(注销) | +| session = .expired / .unauthenticated | 显示 PreLoginFlow | +| selectedTab 值变化 | StudyHomeView 通过 Binding 接收,可被其他 Tab 修改 | +| 有 continueLearning API 数据 | 学习主页显示"继续上次学习"卡片 | +| reviewCards.count > 0 | 学习主页显示"今日复习"卡片 | +| quizzes.count > 0 | 学习主页显示"资料自测"卡片 | +| knowledgeBases.count > 0 | 学习主页显示"开始学习"卡片 | +| 以上全为空 | 学习主页显示空状态引导 | +| iPhone / iPad | AppContext 中记录 deviceType,但不影响页面布局 | +| Debug / Release | DEBUG 宏仅在 Route.destination 中用于显示页面标签覆盖层 | + +--- + +## 三、完整页面清单(按入口类型分类) + +### 3.1 启动/登录流程页面 + +| 序号 | 页面 | Swift 类型 | 入口方式 | 是否可路由 | +|------|------|-----------|---------|-----------| +| P01 | 启动页 | SplashScreen | 应用冷启动(session = .unknown/.authenticating/.refreshing) | 否 | +| P02 | 欢迎页 | WelcomePage | PreLoginFlow step 0 | 否 | +| P03 | 登录页 | LoginPage | PreLoginFlow step 1 | 否 | +| P04 | 账号禁用页 | AccountStatusView | session = .disabled | 否 | +| P05 | 账号注销页 | AccountStatusView | session = .deleted | 否 | +| P06 | 引导页 | OnboardingPage | PostLoginOnboardingFlow step 0 | 否 | +| P07 | 目标设置页 | GoalSetupPage | PostLoginOnboardingFlow step 1 | 否 | + +### 3.2 学习 Tab 页面(NavigationLink Push) + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P08 | 学习主页 | Route.studyHome | Tab "学习" 默认 | +| P09 | 学习会话页 | Route.learningSession | 资料阅读页工具栏 | +| P10 | 复习卡片页 | Route.reviewCard | 学习主页 / AIHomeView | +| P11 | 主动回忆页 | Route.activeRecall | 学习主页底部链接 / AIHomeView | + +### 3.3 知识库 Tab 页面(NavigationLink Push) + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P12 | 知识库首页 | Tab "知识库" 直接渲染 | Tab "知识库" | +| P13 | 知识库搜索页 | Route.librarySearch | 知识库首页搜索图标 | +| P14 | 知识库详情页 | Route.libraryDetail | 知识库首页卡片点击 | +| P15 | 创建知识库页 | Route.libraryCreate | 知识库首页 + 按钮 / 我的页学习资产 | +| P16 | 添加知识点页 | Route.addKnowledge | 知识库详情页操作菜单"添加" | +| P17 | 知识点详情页 | Route.knowledgeDetail | 知识库详情页点击知识点 | +| P18 | 编辑知识点页 | Route.editKnowledge | 知识点详情页工具栏菜单 | +| P19 | 导入资料页 | Route.libraryImport | 知识库详情页操作菜单"上传" | +| P20 | 导入候选审核页 | Route.importReview | 导入资料完成后 | +| P21 | 发现公开库页 | Route.discoverPublic | 我的页"发现公开库" | + +### 3.4 分析 Tab 页面 + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P22 | 学习分析页 | Tab "分析" 直接渲染 | Tab "分析" | + +### 3.5 我的 Tab 页面 + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P23 | 个人中心页 | Tab "我的" 直接渲染 | Tab "我的" | +| P24 | 编辑资料页 | Route.editProfile | 个人中心页资料卡片 / 设置页 | +| P25 | 设置页 | Route.settings | 个人中心页设置图标 / 复习提醒行 | +| P26 | 学习目标设置页 | Route.goalSetting | 设置页 / 我的页 | +| P27 | 学习方法偏好页 | Route.methodPreference | 设置页 / 我的页 | +| P28 | 通知列表页 | Route.notificationList | 我的页通知图标 / 消息中心 | +| P29 | 帮助与反馈页 | Route.feedbackForm | 我的页 / 设置页 | + +### 3.6 AI 辅助页面(跨模块 Push) + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P30 | AI 对话页 | Route.aiChat | 知识库详情页底部 / 资料阅读页工具栏 / AI 反馈页 | +| P31 | 每日思考页 | Route.dailyThinking | AI 反馈页"再来一题" / AIHomeView | +| P32 | AI 反馈页 | Route.aiFeedback | 主动回忆完成后 / 每日思考提交后 | +| P33 | 薄弱知识点页 | Route.weakPoints | 分析页"全部 N 个"链接 / AIHomeView | + +### 3.7 测验页面 + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P34 | 测验列表页 | Route.quizList | 知识库详情页操作菜单"测验" | +| P35 | 测验作答页 | Route.quizTake | 测验列表点击 / 学习主页自我测试 | +| P36 | 测验结果页 | Route.quizResult | 测验作答提交后 | + +### 3.8 资料阅读页面 + +| 序号 | 页面 | Route 枚举 | 入口 | +|------|------|-----------|------| +| P37 | 资料阅读页 | Route.materialReader | 学习主页"继续学习" / 分析页"继续阅读" / 来源文件 / 知识点详情 | +| P38 | 资料详情页 | Route.materialDetail | 资料阅读页工具栏"信息"按钮 | + +### 3.9 Sheet / 弹窗(非独立 Push 页面) + +| 序号 | 名称 | 类型 | 所在页面 | 入口 | +|------|------|------|---------|------| +| S01 | AI 会话列表 Sheet | .sheet (medium/large) | AIChatPage | 工具栏"会话列表"按钮 | +| S02 | 快速笔记 Sheet | .sheet | MaterialReaderView | 工具栏笔记按钮 | +| S03 | 系统预览 (QuickLook) | .sheet (QLPreviewController) | MaterialReaderView | "系统预览"按钮 | +| S04 | 封面选择 Sheet | .sheet (height 220) | CreateLibraryPage | 封面区域点击 | +| S05 | 文件夹管理 Sheet | .sheet | LibraryDetailPage | 操作菜单"文件夹管理" | +| S06 | 链接导入 Alert | .alert (with TextField) | ImportPage | "链接导入"按钮 | + +### 3.10 确认弹窗(Alert / ConfirmationDialog) + +| 序号 | 名称 | 类型 | 所在页面 | +|------|------|------|---------| +| A01 | 结束学习确认 | ConfirmationDialog | LearningSessionView | +| A02 | 删除知识库确认 | Alert | LibraryDetailPage | +| A03 | 批量删除确认 | Alert | LibraryDetailPage | +| A04 | 新建文件夹 | Alert (with TextField) | FolderManageView | +| A05 | 重命名文件夹 | Alert (with TextField) | FolderManageView | +| A06 | 退出登录确认 | Alert | SettingsView | +| A07 | 新建分类 | Alert (with TextField) | FolderManageView | +| A08 | 链接导入 | Alert (with TextField) | ImportPage | + +### 3.11 代码存在但无入口的页面 + +| 名称 | Swift 类型 | 情况说明 | +|------|-----------|---------| +| AI 首页 | AIHomeView | 完整页面代码,含 NavigationLink 到 AIChatPage/ActiveRecallView/WeakPointsPage/ReviewCardView/DailyThinkingPage,但 Route 中无对应 case,无任何其他页面跳转到此页 | + +--- + +## 四、入口类型检查清单 + +| 入口类型 | 是否检查 | 发现情况 | +|---------|---------|---------| +| Tab | 是 | 4 个:学习、知识库、分析、我的 | +| Push (NavigationLink via Route) | 是 | 约 25 个路由目标 | +| Sheet | 是 | 6 个 Sheet | +| FullScreenCover | 是 | 未发现 | +| Alert | 是 | 6 个 Alert | +| ConfirmationDialog | 是 | 1 个 | +| Popover | 是 | 未发现 | +| ContextMenu | 是 | LibraryDetailPage 知识点行 | +| Menu | 是 | LibraryDetailPage 工具栏 | +| Deep Link | 是 | 未配置 | +| Universal Link | 是 | 未配置 | +| URL Scheme | 是 | 未配置 | +| 通知点击路由 | 是 | 未发现 | +| Debug 页面 | 是 | 仅 DEBUG 标签覆盖层,无专用调试页面 | +| 条件渲染页面 | 是 | 基于 session / onboarding / 数据状态的 7 种分支 | +| iPhone/iPad 差异 | 是 | 仅在 AppContext 记录,无布局差异 | +| Feature Flag | 是 | 未发现 | +| 管理员/内部账号 | 是 | 未发现 | +| 首次启动 vs 非首次 | 是 | hasCompletedOnboarding @AppStorage | + +--- + +## 五、页面跳转关系(基于 Route 枚举和 NavigationLink 分析) + +### 5.1 Tab 内跳转 + +| 源页面 | 目标页面 | Route | +|--------|---------|-------| +| StudyHomeView | MaterialReaderView | .materialReader | +| StudyHomeView | ReviewCardView | .reviewCard | +| StudyHomeView | QuizTakerView | .quizTake | +| StudyHomeView | QuizListView | .quizList | +| StudyHomeView | ActiveRecallView | .activeRecall | +| StudyHomeView | 切换到 library Tab | selectedTab 绑定 | +| LibraryHomeView | LibrarySearchView | .librarySearch | +| LibraryHomeView | CreateLibraryPage | .libraryCreate | +| LibraryHomeView | LibraryDetailPage | .libraryDetail | +| LibraryDetailPage | KnowledgeDetailPage | .knowledgeDetail | +| LibraryDetailPage | EditKnowledgePage | .editKnowledge | +| LibraryDetailPage | ImportPage | .libraryImport | +| LibraryDetailPage | AddKnowledgePage | .addKnowledge | +| LibraryDetailPage | QuizListView | .quizList | +| LibraryDetailPage | AIChatPage | .aiChat | +| LibraryDetailPage | MaterialReaderView | .materialReader | +| LibraryDetailPage | FolderManageView (Sheet) | - | +| CreateLibraryPage | 封面选择 Sheet | - | +| AddKnowledgePage | (文件选择器/相册) | 系统组件 | +| KnowledgeDetailPage | MaterialReaderView | .materialReader | +| KnowledgeDetailPage | QuickLook (Sheet) | - | +| KnowledgeDetailPage | QuickNoteSheet | - | +| ImportPage | ImportReviewPage | .importReview | +| ImportPage | (文件选择器/相册/链接Alert) | 系统组件 | +| AnalysisHomeView | WeakPointsPage | .weakPoints | +| AnalysisHomeView | MaterialReaderView | .materialReader | +| ProfileView | EditProfilePage | .editProfile | +| ProfileView | GoalSettingDetailView | .goalSetting | +| ProfileView | SettingsView | .settings | +| ProfileView | MethodPreferenceView | .methodPreference | +| ProfileView | FeedbackFormView | .feedbackForm | +| ProfileView | CreateLibraryPage | .libraryCreate | +| ProfileView | DiscoverView | .discoverPublic | +| ProfileView | NotificationListView | .notificationList | +| SettingsView | GoalSettingDetailView | .goalSetting | +| SettingsView | MethodPreferenceView | .methodPreference | +| SettingsView | EditProfilePage | .editProfile | +| SettingsView | FeedbackFormView | .feedbackForm | + +### 5.2 跨模块跳转 + +| 源页面 | 目标页面 | 触发方式 | +|--------|---------|---------| +| ActiveRecallView | AIFeedbackPageView | 提交完所有回答后"查看 AI 分析" | +| AIFeedbackPageView | StudyHomeView | "加入待巩固" | +| AIFeedbackPageView | AIChatPage | "深入提问" | +| AIFeedbackPageView | DailyThinkingPage | "再来一题" | +| DailyThinkingPage | AIFeedbackPageView | 提交回答后 | +| MaterialReaderView | AIChatPage | 工具栏 AI 按钮 | +| MaterialReaderView | MaterialDetailView | 工具栏信息按钮 | +| MaterialReaderView | LearningSessionView | 工具栏学习按钮 | +| MaterialReaderView | QuickNoteSheet | 工具栏笔记按钮 | +| AIHomeView | AIChatPage | NavigationLink(页面自身无入口) | +| AIHomeView | ActiveRecallView | NavigationLink(页面自身无入口) | +| AIHomeView | WeakPointsPage | NavigationLink(页面自身无入口) | +| AIHomeView | ReviewCardView | NavigationLink(页面自身无入口) | +| AIHomeView | DailyThinkingPage | NavigationLink(页面自身无入口) | + +--- + +## 六、API 服务清单(每个对应一组后端端点) + +| 服务类 | 主要端点 | 被哪些页面使用 | +|--------|---------|--------------| +| AuthService | /auth/apple, /auth/refresh, /auth/logout | LoginPage, AuthManager | +| UserService | /users/me (GET/PATCH), /users/me/preferences, /users/me/profile, /users/me/deletion-request, /users/me/devices, /users/me/assets-summary, /users/me/storage | ProfileView, EditProfilePage, SettingsView, GoalSettingDetailView, MethodPreferenceView | +| KnowledgeBaseService | /knowledge-bases (CRUD), /knowledge-bases/subscribed, /knowledge-bases/:id/subscribe | LibraryHomeView, LibraryDetailPage, CreateLibraryPage, DiscoverView, StudyHomeView | +| KnowledgeItemService | /knowledge-items (CRUD, batch-delete) | LibraryDetailPage, AddKnowledgePage, KnowledgeDetailPage, EditKnowledgePage | +| KnowledgeFolderService | /knowledge-bases/:id/folders (CRUD) | FolderManageView | +| KnowledgeSourceService | /knowledge-bases/:id/sources (CRUD, parse) | LibraryDetailPage, MaterialReaderView | +| DocumentImportService | /imports (create, status) | ImportPage | +| ImportCandidateService | /import-candidates (list, accept, reject, batch-accept) | ImportReviewPage | +| QuizService | /quizzes (generate, list, detail, start, submit, results, history) | QuizListView, QuizTakerView, QuizResultView | +| RagChatService | /rag-chat/sessions (CRUD, messages, stream) | AIChatPage | +| ActiveRecallService | /active-recalls (list, submit) | ActiveRecallView | +| AIAnalysisService | /ai-analysis | (ViewModel 中有调用,但 ActiveRecallView 使用硬编码数据) | +| ReviewService | /reviews (due, submit, generate-cards) | ReviewCardView (View 中硬编码,ViewModel 调用 API) | +| FocusItemService | /focus-items (list, update, complete) | AnalysisHomeView (via ActivityViewModel) | +| ActivityService | /activity (summary, heatmap, trend, streak, recommendations) | AnalysisHomeView, ProfileView, StudyHomeView | +| LearningSessionService | /learning-sessions (list, start, end) | LearningSessionView, StudyHomeView | +| ReadingAPIService | /learning/reading-events/batch, /materials/:id/reading-progress, /learning/continue, /learning/summary, /learning/trend, /learning/records | MaterialReaderView, StudyHomeView, AnalysisHomeView | +| FileUploadService | /files/upload-url, /files/complete, /files/:id | CreateLibraryPage, AddKnowledgePage, ImportPage, EditProfilePage | +| FeedbackService | /feedback | FeedbackFormView | +| NotificationService | /notifications (list, markRead, markAllRead, preferences, push-token) | NotificationListView, SettingsView | +| WaitlistService | /waitlist | (API 定义存在,iOS 代码中未发现使用入口) | + +--- + +## 七、免责说明 + +- 本基线完全基于对 AIStudyApp/AIStudyApp/ 目录下全部 64 个 .swift 文件的逐文件阅读建立。 +- 未检查 .xcassets、.entitlements、.xcodeproj 中的详细配置。 +- iOS 推送通知的深度链接处理在代码中未发现,但可能在 Capabilities 中配置(未检查 .entitlements 文件全文)。 +- WaitlistService 代码存在但未在任何 View 或 ViewModel 中使用,判定为无 C 端入口。 diff --git a/docs/system-map/ios/review/02-独立功能基线.md b/docs/system-map/ios/review/02-独立功能基线.md new file mode 100644 index 0000000..b173765 --- /dev/null +++ b/docs/system-map/ios/review/02-独立功能基线.md @@ -0,0 +1,537 @@ +# 02 独立功能基线 + +> 完全基于代码扫描独立建立,不参考已有系统地图文档。 +> 每项功能标注:已完成 / 部分完成 / 占位实现 / 未完成 / 暂未确认 + +--- + +## 一、启动与登录流程 + +### P01 启动页 (SplashScreen) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 展示品牌标识 | 已完成 | 渐变背景 + 大脑图标 + "知习" + ProgressView | +| 自动恢复登录会话 | 已完成 | AuthManager.restoreSession() 读取 Keychain Token → /users/me 校验 | +| Token 刷新 | 已完成 | /auth/refresh 端点,APIClient 401 自动重试 | +| 会话过期处理 | 已完成 | session = .expired → PreLoginFlow | +| 账号禁用/注销检测 | 已完成 | /users/me 返回特定 errorCode → 切到对应 AccountStatusView | + +### P02 欢迎页 (WelcomePage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 产品功能介绍 | 已完成 | "AI 驱动"标签 + 主标题 + 3 个 FeatureRow(主动回忆、费曼解释、AI 分析) | +| 进入登录 | 已完成 | "开始使用" → LoginPage | + +### P03 登录页 (LoginPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| Apple ID 登录 | 已完成 | SignInWithAppleButton → AuthService.appleLogin | +| nonce 验证 | 已完成 | SHA256(nonce) 传入 Apple 请求 | +| 登录中取消 | 已完成 | 取消按钮 + Task.cancel() | +| 登录错误提示 | 已完成 | 红色错误横幅,显示具体错误信息 | +| Token 存储 | 已完成 | KeychainHelper.save | + +### P04/P05 账号状态页 (AccountStatusView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 禁用状态展示 | 已完成 | icon + title + message + "返回首页" | +| 注销状态展示 | 已完成 | 同上,文案不同 | +| 返回首页 | 已完成 | onBackToLogin → session = .unauthenticated | + +### P06 引导页 (OnboardingPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 4 步引导浏览 | 已完成 | 输入知识 / 主动输出 / AI 分析 / 掌握知识 | +| 跳过引导 | 已完成 | "跳过" → onContinue | +| 步骤指示器 | 已完成 | 4 个圆角矩形进度条 | + +### P07 目标设置页 (GoalSetupPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 选择学习目标(4 选 1) | 已完成 | 备考考试/职业技能/通识学习/自定义 | +| 选择学习方法(多选) | 已完成 | 间隔回忆/费曼技巧/AI 分析 | +| 选择每日学习时间(4 选 1) | 已完成 | 15分钟/30分钟/1小时/不限制 | +| 确认并开始 | 已完成 | "开始学习" → onComplete(true) → hasCompletedOnboarding = true | + +--- + +## 二、学习 Tab (StudyHomeView + 子页面) + +### P08 学习主页 (StudyHomeView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看连续学习天数 | 已完成 | streakDays 从 API 获取,火焰图标 + "X 天连续" | +| 继续上次学习 | 已完成 | MainAction.continueSession → MaterialReaderView,优先级最高 | +| 今日复习入口 | 部分完成 | 入口正常 → ReviewCardView,但 ReviewCardView 使用硬编码数据 | +| 资料自测入口 | 已完成 | MainAction.selfTest → QuizTakerView | +| 空状态引导(创建/探索知识库) | 已完成 | 切换到 library Tab | +| 查看每周摘要 | 已完成 | 本周分钟/复习卡片/活跃天数/连续天数 | +| 查看完整分析 | 已完成 | → Route.activeRecall(目标页为占位实现) | +| 下拉刷新 | 已完成 | .refreshable | +| 加载状态 | 已完成 | ProgressView | +| 错误状态 | 部分完成 | View 支持 error 状态,但 ViewModel 永远不会设置 error(所有 API 用 try? 吞错) | +| 优先级自动计算 | 已完成 | 继续学习 > 未完成会话 > 今日复习 > 自测 > 开始学习 > 空状态 | + +### P09 学习会话页 (LearningSessionView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 专注计时(1 秒精度) | 已完成 | Timer.publish(every: 1) | +| 环形进度动画 | 已完成 | Circle.trim + AngularGradient 动画,上限 30 分钟 | +| 暂停/继续 | 已完成 | isRunning/isPaused 切换 | +| 结束学习(含确认弹窗) | 已完成 | ConfirmationDialog → 结束并保存 | +| 庆祝动画 | 已完成 | ZXCelebrationView | +| 学习时长保存到 API | 暂未确认 | LearningSessionView 不直接调用 API,也未发现调用 LearningSessionService.start/end 的代码 | + +### P10 复习卡片页 (ReviewCardView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 卡片翻转 | 占位实现 | 点击翻转动画正常,但使用 3 张硬编码 ReviewCardItem | +| 自评四个等级 | 占位实现 | "完全不会"/"有点难"/"基本会"/"很简单"按钮 | +| 进度条 | 占位实现 | 正常展示但基于硬编码数据 | +| 完成庆祝 | 占位实现 | ZXCelebrationView | +| 调用 Review API | 未完成 | ReviewViewModel.loadDueCards() 被调用但结果被忽略,View 使用硬编码 ReviewCardItem | + +### P11 主动回忆页 (ActiveRecallView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 文字作答 | 占位实现 | TextEditor + 提交按钮,但使用 3 道硬编码 RecallQuestion | +| 语音作答 | 占位实现 | 展示麦克风图标和提示文字,无实际录音功能 | +| 提交答案 | 占位实现 | 本地状态更新,不调用 API | +| AI 分析动画 | 占位实现 | ZXThinkingOverlay 展示,2 秒后自动消失 | +| 查看 AI 分析结果 | 占位实现 | → AIFeedbackPageView(本身为占位实现) | +| 庆祝动画 | 占位实现 | ZXCelebrationView | +| 题目来源标签 | 占位实现 | 展示硬编码来源文字 | + +--- + +## 三、知识库 Tab + +### P12 知识库首页 (LibraryHomeView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看知识库列表 | 已完成 | LibraryViewModel.loadKnowledgeBases() → KnowledgeBaseService.list() | +| 筛选分类(全部/我的/已订阅/官方) | 部分完成 | "官方"筛选返回空数组(TODO 注释:等后端支持) | +| 搜索入口 | 部分完成 | 搜索按钮 → LibrarySearchView(搜索逻辑未实现) | +| 创建知识库入口 | 已完成 | + 按钮 → CreateLibraryPage | +| 查看知识库详情 | 已完成 | 卡片点击 → LibraryDetailPage | +| 下拉刷新 | 已完成 | .refreshable | +| 无限滚动分页 | 已完成 | ZXLoadMoreFooter | +| 知识库卡片:封面/名称/描述/日期/置顶/公开 | 已完成 | ZLibraryCard 完整展示 | + +### P13 知识库搜索页 (LibrarySearchView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 搜索输入框 | 已完成 | TextField 已搭建 | +| 搜索逻辑 | 未完成 | query 变化时不触发任何 API 调用,结果区域始终为空 | +| 空状态提示 | 已完成 | "搜索知识点、知识库或标签" | + +### P14 知识库详情页 (LibraryDetailPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看知识库信息头部 | 已完成 | 封面/标题/描述/来源/文件数/创建/更新日期 | +| 知识点列表(Tab 0) | 已完成 | KnowledgeItemService.list() | +| 知识点排序 | 已完成 | 默认/文件大小/创建时间/更新时间 | +| 来源文件列表(Tab 1) | 已完成 | KnowledgeSourceService.list() | +| 来源文件阅读状态标签 | 已完成 | "已读"/"阅读中" | +| 查看知识点详情 | 已完成 | → KnowledgeDetailPage | +| 删除单个知识点 | 已完成 | contextMenu 删除 → KnowledgeItemService.delete() | +| 批量选择/删除 | 已完成 | isSelectMode + batchDeleteItems | +| 导入资料入口 | 已完成 | 操作菜单 → ImportPage | +| 添加知识点入口 | 已完成 | 操作菜单 → AddKnowledgePage | +| 生成测验入口 | 已完成 | 操作菜单 → QuizListView | +| 文件夹管理入口 | 已完成 | 操作菜单 → FolderManageView Sheet | +| AI 对话入口 | 已完成 | 底部 AI 按钮 → AIChatPage (知识库范围) | +| 删除来源文件 | 已完成 | 来源文件行删除按钮 | +| 删除知识库 | 已完成 | 确认弹窗 → KnowledgeBaseService.delete() | +| 知识点重命名 | 未完成 | contextMenu 中有"重命名"按钮,但 action 为空(// TODO: rename) | +| 移动到文件夹 | 未完成 | contextMenu 中有"移动到"按钮,但 action 为空(// TODO: move to folder) | +| 知识库管理页 | 未完成 | 操作菜单"知识库管理"按钮 action 为空(// TODO: knowledge base management page) | + +### P15 创建知识库页 (CreateLibraryPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 上传封面图 | 已完成 | PhotosPicker → 裁剪 512x512 → COS 上传 | +| 输入名称(必填) | 已完成 | TextField + 必填校验 | +| 输入描述(必填) | 已完成 | TextEditor + 必填校验 | +| 创建知识库 | 已完成 | KnowledgeBaseService.create() → Toast 反馈 | + +### P16 添加知识点页 (AddKnowledgePage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 手动模式(标题+内容) | 已完成 | TextField + TextEditor → KnowledgeItemService.create() | +| 文件模式(选择文件) | 已完成 | fileImporter → COS 上传 → 创建知识点 | +| 图片模式(选择照片) | 已完成 | PhotosPicker → JPEG 压缩 → COS 上传 → 创建知识点 | +| 多文件批量添加 | 已完成 | 支持多选,逐个上传,显示进度 | +| 移除已选文件 | 已完成 | xmark 按钮 → 从 selectedFiles 移除 | + +### P17 知识点详情页 (KnowledgeDetailPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| URL 型知识点渲染 | 已完成 | COS 下载 → 本地缓存 → MaterialReaderView 嵌入 | +| 纯文本渲染 | 已完成 | 直接 Text 渲染 | +| 文件类型自动检测 | 已完成 | 从扩展名/MIME 推断 MaterialType | +| COS 过期 URL 重取 | 已完成 | 检测 XML → 重新 fetch item → 获取新签名 URL | +| 错误状态(含摘要回退) | 已完成 | 显示错误 + 摘要文字 + 重试按钮 | +| 阅读原文件 | 已完成 | NavigationLink → MaterialReaderView | +| 笔记入口 | 已完成 | 工具栏菜单 → showNoteSheet | +| 系统预览(PDF/Word/Excel) | 已完成 | 工具栏菜单 → QuickLook | +| 收藏切换 | 部分完成 | isFavorited 状态切换有 UI,但 toggleFavorite() 中有 TODO 注释:后端 API 未支持 | + +### P18 编辑知识点页 (EditKnowledgePage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 修改标题 | 已完成 | TextField → KnowledgeItemService.update() | +| 修改内容 | 已完成 | TextEditor → KnowledgeItemService.update() | +| 保存 | 已完成 | "保存修改"按钮 → API 调用 | + +### P19 导入资料页 (ImportPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 文件导入(PDF/纯文本) | 已完成 | fileImporter → COS 上传 → KnowledgeSourceService.add() | +| 相册导入 | 部分完成 | PhotosPicker → COS 上传 → DocumentImportService.create(),但未发现后续 AI OCR 处理流程 | +| 链接导入 | 已完成 | Alert 弹窗输入 URL → DocumentImportService.create() | +| 自动选择目标知识库 | 已完成 | 加载第一个知识库,无则提示创建 | +| 导入错误提示 | 已完成 | 红色错误横幅 | +| 导入进度提示 | 已完成 | statusMessage + ProgressView | + +### P20 导入候选审核页 (ImportReviewPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看候选列表(含置信度) | 已完成 | ImportCandidateService.listBySource() | +| 展开查看候选详情 | 已完成 | expandedId 切换 | +| 接受单个候选 | 已完成 | ImportCandidateService.accept() | +| 拒绝单个候选 | 已完成 | ImportCandidateService.reject() | +| 批量全部接受 | 已完成 | ImportCandidateService.batchAccept() | +| 空候选状态 | 已完成 | "没有待审批的候选" | + +### P21 发现公开库页 (DiscoverView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看公开知识库列表 | 已完成 | KnowledgeBaseService.discover() | +| 订阅知识库 | 已完成 | KnowledgeBaseService.subscribe() | +| 取消订阅 | 已完成 | KnowledgeBaseService.unsubscribe() | +| 空状态 | 已完成 | "暂无公开知识库" | + +### S05 文件夹管理 Sheet (FolderManageView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看文件夹列表 | 已完成 | KnowledgeFolderService.list() | +| 新建文件夹 | 已完成 | Alert 输入 → KnowledgeFolderService.create() | +| 重命名文件夹 | 已完成 | Swipe → Alert 输入 → KnowledgeFolderService.update() | +| 删除文件夹 | 已完成 | Swipe 删除 → KnowledgeFolderService.delete() | + +--- + +## 四、分析 Tab + +### P22 学习分析页 (AnalysisHomeView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 综合掌握度 | 已完成 | ActivityService.summary().dailyAverage | +| 总学习分钟 | 已完成 | ActivityService.summary().totalMinutes | +| 复习卡片数 | 已完成 | ActivityService.summary().totalCardsReviewed | +| 活跃天数 | 已完成 | ActivityService.summary().activeDays | +| 今日/本周阅读统计 | 已完成 | ReadingAPIService.getLearningSummary() | +| 掌握度趋势折线图 | 占位实现 | ZXChartView 使用硬编码数据 [(一,0.62)...(今,0.78)],未使用 API | +| 阅读时长趋势柱状图 | 已完成 | 使用 API 返回的 LearningTrendResponse.series | +| 本周学习活跃柱状图 | 占位实现 | ZXWeekBarChart 使用硬编码数据,未使用 API | +| 连续学习统计 | 已完成 | ActivityService.streak() | +| 最近学习记录(5 条) | 已完成 | ReadingAPIService.getLearningRecords() | +| 学习推荐(3 条) | 已完成 | ActivityService.recommendations() | +| 继续阅读入口 | 已完成 | → MaterialReaderView | +| AI 综合分析文字 | 已完成 | 动态拼接 summary 数据 | +| 薄弱知识点列表(5 条) | 已完成 | FocusItemService.list() | +| 查看全部薄弱知识点 | 已完成 | → WeakPointsPage(目标页为占位实现) | +| 下拉刷新 | 已完成 | .refreshable | +| 日期范围筛选 | 暂未确认 | "近 7 天" 标签展示但无实际切换逻辑 | + +--- + +## 五、我的 Tab + +### P23 个人中心页 (ProfileView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看个人资料(头像/昵称/邮箱) | 已完成 | UserService.myProfile() | +| 查看学习统计(活跃天/卡片/分钟) | 已完成 | ActivityService.summary() | +| 查看学习资产(库/条目/卡片计数) | 已完成 | UserService.fetchAssets() | +| 查看存储空间 | 已完成 | UserService.fetchStorage() | +| 编辑资料入口 | 已完成 | → EditProfilePage | +| 学习目标设置入口 | 已完成 | → GoalSettingDetailView | +| 复习提醒入口 | 已完成 | → SettingsView | +| 学习方法偏好入口 | 已完成 | → MethodPreferenceView | +| 帮助与反馈入口 | 已完成 | → FeedbackFormView | +| 发现公开库入口 | 已完成 | → DiscoverView | +| 消息中心入口 | 已完成 | → NotificationListView | +| 通知图标入口 | 已完成 | → NotificationListView | +| 设置图标入口 | 已完成 | → SettingsView | +| 创建知识库入口(学习资产行) | 已完成 | → CreateLibraryPage | + +### P24 编辑资料页 (EditProfilePage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 上传头像 | 已完成 | PhotosPicker → 256x256 裁剪 → COS 上传 | +| 编辑昵称 | 已完成 | TextField | +| 编辑学习身份 | 已完成 | TextField | +| 编辑学习方向 | 已完成 | TextField | +| 编辑当前目标 | 已完成 | TextField | +| 编辑个人简介 | 已完成 | TextEditor | +| 保存 | 已完成 | UserService.updateProfile() + updateProfileDetail() | + +### P25 设置页 (SettingsView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 切换外观模式 | 已完成 | system/dark/light 循环切换 → UserService.updatePreferences() | +| 语言显示 | 已完成 | 展示"简体中文" | +| 学习目标设置入口 | 已完成 | → GoalSettingDetailView | +| 方法偏好入口 | 已完成 | → MethodPreferenceView | +| 复习提醒开关 | 已完成 | Toggle + 条件显示提醒时间/间隔天数选择器 | +| 复习提醒时间选择 | 已完成 | SegmentedPicker: 08:00/12:00/18:00/20:00/21:00 | +| 间隔天数选择 | 已完成 | SegmentedPicker: 1/2/3/5/7 天 | +| 通知开关 | 部分完成 | 三个通知开关(复习提醒/导入完成/系统通知)全部绑定到同一个 $reviewReminder 变量,疑似 bug | +| 存储空间展示 | 已完成 | profileVM.formattedStorage | +| iCloud 同步开关 | 暂未确认 | Toggle UI 存在,切换仅改变本地 @State,未调用任何 API | +| 个人资料入口 | 已完成 | → EditProfilePage | +| 设备管理入口 | 未完成 | "登录设备管理"行 → Route.settings(指向自身),无实际设备管理页面 | +| 帮助与反馈入口 | 已完成 | → FeedbackFormView | +| 隐私政策入口 | 未完成 | "隐私政策"行无任何导航动作(无 NavigationLink/Button action) | +| 用户协议入口 | 未完成 | "用户协议"行无任何导航动作 | +| 退出登录 | 已完成 | 确认弹窗 → authManager.signOut() | +| 版本号展示 | 已完成 | "知习 v1.0" | + +### P26 学习目标设置页 (GoalSettingDetailView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 选择学习目标 | 已完成 | 4 选 1 → UserService.updateProfileDetail(currentGoal) | +| 选择每日学习时长 | 部分完成 | 4 选 1 UI 存在,但 dailyMins 只保存在本地 @State,不通过 API 持久化 | + +### P27 学习方法偏好页 (MethodPreferenceView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 多选学习方法 | 已完成 | 4 种方法多选 → UserService.updatePreferences(preferredMethods) | +| 保存 | 已完成 | "保存"按钮 → API 调用 | + +### P28 通知列表页 (NotificationListView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看通知列表(按日期分组) | 已完成 | NotificationService.list(),分组为今天/本周/更早 | +| 按类型显示图标和颜色 | 已完成 | 10+ 种通知类型映射 | +| 标记单条已读 | 已完成 | NotificationService.markRead() | +| 全部标记已读 | 已完成 | NotificationService.markAllRead() | +| 下拉刷新 | 已完成 | .refreshable | +| 空状态 | 已完成 | "暂无通知" | + +### P29 帮助与反馈页 (FeedbackFormView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 选择反馈类型 | 已完成 | Bug 反馈/功能建议/内容问题/其他 | +| 输入反馈内容 | 已完成 | TextEditor | +| 提交反馈 | 已完成 | FeedbackService.submit() | + +--- + +## 六、AI 辅助功能 + +### P30 AI 对话页 (AIChatPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 发送文字消息 | 已完成 | → RagChatService.sendMessageStream() | +| 流式接收 AI 回复 | 已完成 | AsyncThrowingStream SSE 解析 | +| 查看 AI 思考过程(可折叠) | 已完成 | ThinkingSection 组件 | +| 复制 AI 回复 | 已完成 | UIPasteboard.general.string | +| 重新生成回复 | 已完成 | onRegenerate → vm.send() | +| 新建对话 | 已完成 | vm.createNewSession() | +| 会话列表 Sheet | 已完成 | .sheet 展示 ChatSession 列表 | +| 切换历史会话 | 已完成 | vm.loadSession(id) | +| 搜索会话 | 已完成 | 会话列表中有搜索功能 | +| 删除会话 | 已完成 | swipe → RagChatService.deleteSession() | +| 归档会话 | 已完成 | swipe → UpdateChatSessionRequest(isArchived: true) | +| 置顶/取消置顶 | 已完成 | swipe → UpdateChatSessionRequest(isPinned:) | +| 对话范围标签 | 已完成 | scopeLabel 显示在消息列表顶部 | +| 创建会话中状态 | 已完成 | ProgressView + "正在准备 AI 助手..." | +| 会话创建失败状态 | 已完成 | 错误图标 + 文字 | + +### P31 每日思考页 (DailyThinkingPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看思考题目 | 占位实现 | 题目硬编码:"解释'注意力机制'在 Transformer 中的作用" | +| 输入回答 | 已完成 | TextEditor | +| 提交获取 AI 反馈 | 占位实现 | → AIFeedbackPageView(本身为占位实现)。注意:submitted 状态变量从未被设置为 true,提交按钮始终可见 | + +### P32 AI 反馈页 (AIFeedbackPageView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| AI 分析进度动画 | 占位实现 | 4 步动画 + 硬编码 5 秒等待 | +| 得分展示 | 占位实现 | 78/100 硬编码,圆环进度 0.78 | +| 掌握度评价 | 占位实现 | "良好掌握" 硬编码 | +| 答对/答错分析 | 占位实现 | 2 条硬编码文字 | +| 加入待巩固 | 占位实现 | → StudyHomeView | +| 深入提问 | 已完成 | → AIChatPage(AIChatPage 本身已完成) | +| 再来一题 | 已完成 | → DailyThinkingPage(DailyThinkingPage 本身为占位实现) | + +### P33 薄弱知识点页 (WeakPointsPage) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看薄弱知识点列表 | 占位实现 | 5 个硬编码 ZXWeakRow(贝叶斯定理/正态分布/词根/Covariance/梯度下降) | +| 优先级标签 | 占位实现 | 硬编码"高"/"中"优先级 | + +### (废弃)AI 首页 (AIHomeView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 服务器状态检查 | 已完成 | APIClient.shared.request("/") 健康检查 | +| 快速操作入口 | 已完成 | 4 个 NavigationLink 到 activeRecall/weakPoints/aiChat/reviewCard | +| 每日思考卡片 | 占位实现 | 硬编码题目 | +| 推荐问题列表 | 占位实现 | 3 条硬编码推荐文字 | +| 底部输入栏 | 已完成 | 输入 → NavigationLink 到 AIChatPage | +| 整体页面 | 占位实现 | **代码完整但无任何导航入口**,Route 枚举中无对应 case,无任何页面跳转到此 | + +--- + +## 七、测验功能 + +### P34 测验列表页 (QuizListView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看测验列表 | 已完成 | QuizService.list(knowledgeBaseId:) | +| 生成新测验 | 已完成 | QuizService.generate(),失败时 Toast | +| 空状态引导 | 已完成 | "暂无测验" + "生成测验"按钮 | +| 开始作答 | 已完成 | → QuizTakerView | + +### P35 测验作答页 (QuizTakerView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 选择题作答(A/B/C/D) | 已完成 | 选项按钮,选中高亮 | +| 判断题作答 | 已完成 | "正确"/"错误"按钮 | +| 填空题作答 | 已完成 | TextField | +| 上一题/下一题导航 | 已完成 | 按钮导航 | +| 进度条 | 已完成 | GeometryReader 进度条 | +| 提交答案 | 已完成 | QuizService.submit() | +| 提交失败 Toast | 已完成 | ZXToastManager.shared.error("提交失败") | + +### P36 测验结果页 (QuizResultView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看得分 | 已完成 | 大号数字,>=60 绿色,<60 红色 | +| 查看正确/总题数 | 已完成 | "答对 X/Y 题" | +| 查看逐题详情(正确/错误标记+解析) | 已完成 | ForEach 遍历 answers | +| 重新测验 | 已完成 | → QuizTakerView | + +--- + +## 八、资料阅读 + +### P37 资料阅读页 (MaterialReaderView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| Markdown 渲染 | 已完成 | Rust FFI parseMarkdown → DocumentBlockView | +| 纯文本渲染 | 已完成 | Rust FFI parseText → DocumentBlockView | +| 图片显示 | 已完成 | UIImage + 元信息 | +| PDF/Word/Excel 系统预览 | 已完成 | QuickLook Sheet | +| PowerPoint 外部打开 | 已完成 | ShareLink | +| 不支持格式提示 | 已完成 | "暂不支持此格式" | +| 标记已读 | 已完成 | 本地 MarkedReadStore + 事件上报 | +| AI 对话(资料范围) | 已完成 | → AIChatPage 带 ChatEntryContext(.material) | +| 查看资料详情 | 已完成 | → MaterialDetailView | +| 开始学习会话 | 已完成 | → LearningSessionView | +| 添加笔记 | 已完成 | → QuickNoteSheet,含锚点记录 | +| 恢复阅读位置 | 已完成 | API → 本地 → 会话 三级优先级 | +| 自动记录阅读位置(2s 防抖) | 已完成 | reportScrollPosition | +| 前后台会话管理 | 已完成 | scenePhase → pause/resume | +| 心跳上报(15s) | 已完成 | Rust FFI | +| COS 自动下载 | 已完成 | 文件不存在时自动从 COS 下载 | +| 解析触发 | 部分完成 | 60×2s 硬编码轮询,硬编码超时逻辑 | +| 阅读进度标记 | 已完成 | API reading-progress 查询 | + +### P38 资料详情页 (MaterialDetailView) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| AI 处理状态横幅 | 已完成 | 处理中(琥珀色)/就绪(绿色)/失败(红色) | +| 文件元数据展示 | 已完成 | 文件名、格式、大小、上传日期 | +| 阅读进度卡片 | 已完成 | 阅读状态 + 累计阅读时长 | +| 知识点/测验计数 | 已完成 | statBox 展示 | + +--- + +## 九、弹窗与 Sheet + +### S01 AI 会话列表 Sheet + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 查看会话列表 | 已完成 | RagChatService.listSessions() | +| 切换会话 | 已完成 | 点击 → vm.loadSession() | +| 搜索会话 | 已完成 | 搜索输入 | +| 删除会话 | 已完成 | swipe 删除 | +| 归档会话 | 已完成 | swipe 归档 | +| 置顶/取消置顶 | 已完成 | swipe 置顶 | +| 新建会话 | 已完成 | + 按钮 | + +### S02 快速笔记 Sheet (QuickNoteSheet) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| 输入笔记文字 | 已完成 | TextEditor(自动聚焦) | +| 保存笔记 | 已完成 | UserDefaults 存储,含锚点信息 | +| 取消 | 已完成 | dismiss() | + +### S03 系统预览 (QuickLook) + +| 功能 | 状态 | 判定依据 | +|------|------|---------| +| PDF/Office 预览 | 已完成 | QLPreviewController | + +--- + +## 十、统计 + +| 统计项 | 已完成 | 部分完成 | 占位实现 | 未完成 | 暂未确认 | +|--------|--------|---------|---------|--------|---------| +| 启动/登录功能 | 16 | 0 | 0 | 0 | 0 | +| 学习 Tab 功能 | 8 | 2 | 6 | 1 | 1 | +| 知识库 Tab 功能 | 30 | 3 | 0 | 3 | 0 | +| 分析 Tab 功能 | 12 | 0 | 2 | 0 | 1 | +| 我的 Tab 功能 | 24 | 2 | 0 | 3 | 1 | +| AI 辅助功能 | 12 | 0 | 10 | 0 | 0 | +| 测验功能 | 11 | 0 | 0 | 0 | 0 | +| 资料阅读功能 | 17 | 1 | 0 | 0 | 0 | +| Sheet/弹窗功能 | 9 | 0 | 0 | 0 | 0 | +| **总计** | **139** | **8** | **18** | **7** | **3** | diff --git a/docs/system-map/ios/review/03-页面差异清单.md b/docs/system-map/ios/review/03-页面差异清单.md new file mode 100644 index 0000000..8f5470d --- /dev/null +++ b/docs/system-map/ios/review/03-页面差异清单.md @@ -0,0 +1,189 @@ +# 03 页面差异清单 + +> 将独立页面基线(review/01-独立页面基线.md)与已有文档(01-iOS页面地图.md)逐项比对。 + +--- + +## 一、文档已覆盖且正确的页面(一致项) + +以下页面在文档中描述正确,与代码实现一致: + +| 文档章节 | 文档页面名 | 代码类型 | 判定 | +|---------|-----------|---------|------| +| 1.1 | 启动页 (SplashScreen) | SplashScreen | 一致 | +| 1.2 | 欢迎页 (WelcomePage) | WelcomePage | 一致 | +| 1.3 | 登录页 (LoginPage) | LoginPage | 一致 | +| 1.4 | 账号状态页 (AccountStatusView) | AccountStatusView | 一致 | +| 1.5 | 引导页 (OnboardingPage) | OnboardingPage | 一致 | +| 1.6 | 目标设置页 (GoalSetupPage) | GoalSetupPage | 一致 | +| 2.1 | 学习主页 (StudyHomeView) | StudyHomeView | 一致 | +| 2.2 | 学习会话页 (LearningSessionView) | LearningSessionView | 一致 | +| 2.3 | 复习卡片页 (ReviewCardView) | ReviewCardView | 一致 | +| 2.4 | 主动回忆页 (ActiveRecallView) | ActiveRecallView | 一致 | +| 3.1 | 知识库首页 (LibraryHomeView) | LibraryHomeView | 一致 | +| 3.2 | 知识库搜索页 (LibrarySearchView) | LibrarySearchView | 一致 | +| 3.3 | 知识库详情页 (LibraryDetailPage) | LibraryDetailPage | 一致 | +| 3.4 | 创建知识库页 (CreateLibraryPage) | CreateLibraryPage | 一致 | +| 3.5 | 添加知识点页 (AddKnowledgePage) | AddKnowledgePage | 一致 | +| 3.6 | 知识点详情页 (KnowledgeDetailPage) | KnowledgeDetailPage | 一致 | +| 3.7 | 编辑知识点页 (EditKnowledgePage) | EditKnowledgePage | 一致 | +| 3.8 | 导入资料页 (ImportPage) | ImportPage | 一致 | +| 3.9 | 导入候选审核页 (ImportReviewPage) | ImportReviewPage | 一致 | +| 3.10 | 发现公开库页 (DiscoverView) | DiscoverView | 一致 | +| 3.11 | 文件夹管理 (FolderManageView) | FolderManageView | 一致 | +| 4.1 | 学习分析页 (AnalysisHomeView) | AnalysisHomeView | 一致 | +| 5.1 | 个人中心页 (ProfileView) | ProfileView | 一致 | +| 5.2 | 编辑资料页 (EditProfilePage) | EditProfilePage | 一致 | +| 5.3 | 设置页 (SettingsView) | SettingsView | 一致 | +| 5.4 | 学习目标设置页 (GoalSettingDetailView) | GoalSettingDetailView | 一致 | +| 5.5 | 学习方法偏好页 (MethodPreferenceView) | MethodPreferenceView | 一致 | +| 5.6 | 通知列表页 (NotificationListView) | NotificationListView | 一致 | +| 5.7 | 帮助与反馈页 (FeedbackFormView) | FeedbackFormView | 一致 | +| 6.1 | AI 对话页 (AIChatPage) | AIChatPage | 一致 | +| 6.2 | 每日思考页 (DailyThinkingPage) | DailyThinkingPage | 一致 | +| 6.3 | AI 反馈页 (AIFeedbackPageView) | AIFeedbackPageView | 一致 | +| 6.4 | 薄弱知识点页 (WeakPointsPage) | WeakPointsPage | 一致 | +| 6.5 | AI 首页 (AIHomeView) | AIHomeView | 一致(正确标记为废弃) | +| 7.1 | 测验列表页 (QuizListView) | QuizListView | 一致 | +| 7.2 | 测验作答页 (QuizTakerView) | QuizTakerView | 一致 | +| 7.3 | 测验结果页 (QuizResultView) | QuizResultView | 一致 | +| 8.1 | 资料阅读页 (MaterialReaderView) | MaterialReaderView | 一致 | +| 8.2 | 资料详情页 (MaterialDetailView) | MaterialDetailView | 一致 | +| 9.1 | 快速笔记 (QuickNoteSheet) | QuickNoteSheet | 一致 | +| 9.2 | 系统预览 (QuickLook) | QuickLookPreview | 一致 | +| 9.3 | AI 会话列表 Sheet | AIChatPage 内 Sheet | 一致 | +| 9.4 | 封面选择 Sheet | CreateLibraryPage 内 Sheet | 一致 | +| 9.5 | 链接导入弹窗 | ImportPage 内 Alert | 一致 | +| 9.6 | 各类确认弹窗 | 多个 Alert/ConfirmationDialog | 一致 | + +**一致页面数:43 个(含 6 个 Sheet/弹窗)** + +--- + +## 二、代码存在但文档遗漏的页面 + +### 遗漏 1:RecallTestPage + +- **代码位置:** `Features/AI/RecallTestPage.swift` +- **页面作用:** 独立的回忆测试页面,用户输入对特定知识点的理解,提交后跳转 AI 反馈页。 +- **入口:** 代码中有 Route 定义但**未被任何 NavigationLink 引用**。Route 枚举中有 `aiFeedback` case,但未发现 `recallTest` case。 +- **实际状态:** 代码存在但无导航入口(类似 AIHomeView 的情况)。 +- **应出现在:** 01-iOS页面地图.md → 第六章 AI 辅助功能 +- **建议补到位置:** 新增 6.6 节"回忆测试页(RecallTestPage)" +- **建议状态:** 占位实现(无导航入口 + 题目硬编码) + +### 遗漏 2:Route.studyHome 独立页面 + +- **代码位置:** Route.swift `case studyHome` +- **说明:** Route 中定义了 `studyHome` 路由目标(指向 StudyHomeView(selectedTab: .constant("study"))),可被 NavigationLink 跳转到学习主页的独立副本。虽然与 Tab 1 的学习主页渲染同一 View,但路由跳转会 push 一个新的 NavigationStack 副本。 +- **文档处理:** 文档将 StudyHomeView 仅归入 Tab 页面,未提及它也可作为 Push 路由目标。 +- **建议:** 在页面跳转关系中标注 StudyHomeView 可被 Route.studyHome 推入导航栈。 + +--- + +## 三、文档记录但当前不可访问的页面 + +无。所有文档记录的页面在代码中均有对应的入口。 + +--- + +## 四、文档记录为"已完成",但实际为"部分完成"或"占位实现"的页面 + +| 文档页面 | 文档状态 | 实际状态 | 差异说明 | +|---------|---------|---------|---------| +| 学习会话页 (2.2) | 已完成 | 暂未确认 | 文档称"已完成"。页面计时功能完成,但**未发现调用 LearningSessionService.start/end 保存学习记录到 API 的代码**,学习时长仅在本地计时。 | +| 复习卡片页 (2.3) | 占位实现 | 占位实现 | 状态一致,但文档说 ReviewViewModel 和 ReviewPlanViewModel 代码已就绪。实际情况:ReviewCardView 完全忽略 ViewModel 的数据,使用不同类型的硬编码结构体 ReviewCardItem。 | +| 主动回忆页 (2.4) | 占位实现 | 占位实现 | 状态一致。 | +| 知识库首页 (3.1) | 部分完成 | 部分完成 | 状态一致。 | +| 知识库详情页 (3.3) | 部分完成 | 部分完成 | 状态一致。 | +| 学习分析页 (4.1) | 部分完成 | 部分完成 | 状态一致。但需补充:**每日学习时长(dailyMins)保存逻辑缺失**(GoalSettingDetailView 中 dailyMins 仅保存在本地 @State)。 | +| 设置页 (5.3) | 部分完成 | 部分完成 | 状态一致。需补充:"存储空间"行 → Route.settings(自引用),"登录设备管理" → Route.settings(自引用),均无实际导航目标。 | +| AI 反馈页 (6.3) | 占位实现 | 占位实现 | 状态一致。 | +| 薄弱知识点页 (6.4) | 占位实现 | 占位实现 | 状态一致。 | +| 资料阅读页 (8.1) | 部分完成 | 部分完成 | 状态一致。 | +| 每日思考页 (6.2) | 占位实现 | 占位实现 | 状态一致。但需补充:`submitted` 状态变量从未被设置为 true,提交按钮始终可见(这可能导致 UI 行为异常)。 | + +--- + +## 五、文档重复记录的页面 + +无发现。文档每个页面只记录一次。 + +--- + +## 六、页面名称不同但实际为同一个页面的情况 + +无发现。文档页面名称与代码类型名称一一对应。 + +--- + +## 七、页面被错误归入业务模块的情况 + +| 页面 | 文档归类 | 建议归类 | 原因 | +|------|---------|---------|------| +| 创建知识库页 | 知识库 Tab | 正确 | 入口来自知识库首页和我的页 | +| 学习会话页 | 学习 Tab | 正确 | 入口来自资料阅读页 | +| 主动回忆页 | 学习 Tab | 正确 | 入口来自学习主页 | + +无严重归类错误。 + +--- + +## 八、Sheet、弹窗、隐藏入口遗漏检查 + +### 已记录的 Sheet/弹窗(9.1-9.6) + +| 文档项目 | 覆盖情况 | +|---------|---------| +| 快速笔记 (9.1) | 已覆盖 | +| 系统预览 (9.2) | 已覆盖 | +| AI 会话列表 Sheet (9.3) | 已覆盖 | +| 封面选择 Sheet (9.4) | 已覆盖 | +| 链接导入弹窗 (9.5) | 已覆盖 | +| 各类确认弹窗 (9.6) | 已覆盖 6 个中的 6 个 | + +### 遗漏的 Sheet/弹窗 + +| 遗漏项 | 所在页面 | 说明 | +|--------|---------|------| +| 文件夹新建/重命名 Alert | FolderManageView | "新建分类" + "重命名"两个带 TextField 的 Alert,文档在 9.6 确认弹窗表格中未列出 | + +建议在 9.6 确认弹窗表格中补充: +- 新建分类(FolderManageView) +- 重命名分类(FolderManageView) + +--- + +## 九、页面入口和跳转关系错误 + +| 错误位置 | 文档描述 | 实际代码 | 严重程度 | +|---------|---------|---------|---------| +| 学习主页"查看完整分析" → ActiveRecallView | 文档:跳转主动回忆页 | 代码:`Route.activeRecall` → ActiveRecallView | **正确**(但主动回忆页为占位实现) | +| 学习主页"自我测试" → QuizTakerView | 文档:跳转测验作答页 | 代码:MainAction.selfTest → Route.quizTake(quizId:) | **正确** | +| 学习主页"自我测试"小卡片 → QuizListView | 文档未明确 | 代码:Route.quizList(knowledgeBaseId: "") | **需补充**,知识库 ID 为空字符串可能导致异常 | +| 设置页"复习提醒" → SettingsView | 文档:跳转设置页(从我的页复习提醒行) | 代码:`Route.settings` → SettingsView | **正确但奇怪**:从设置页的"复习提醒"行再次跳转 SettingsView 形成自引用 | + +--- + +## 十、页面状态遗漏 + +| 遗漏状态 | 所在页面 | 说明 | +|---------|---------|------| +| LearningSessionView 未保存学习记录到 API | 学习会话页 | 文档标记为"已完成",但缺少 API 持久化,用户在分析页看不到本次学习数据 | +| StudyHomeViewModel 永不为 error | 学习主页 | error 状态代码存在但 ViewModel 中所有 API 调用用 try? 吞错,error 状态永不可达 | +| DailyThinkingPage submitted 永不为 true | 每日思考页 | 提交按钮始终可见,可能导致用户重复提交 | +| GoalSettingDetailView dailyMins 不持久化 | 学习目标设置页 | 每日时长选择不通过 API 保存,下次进入恢复默认"30 分钟" | + +--- + +## 十一、总体评估 + +| 评估维度 | 结果 | +|---------|------| +| 文档页面覆盖率 | 43/45 (95.6%) — 遗漏 RecallTestPage + studyHome 路由 | +| 页面状态准确率 | 38/43 (88.4%) — 5 个页面状态描述与代码存在差异 | +| Sheet/弹窗覆盖率 | 8/9 (88.9%) — 遗漏 1 个确认弹窗组合 | +| 跳转关系准确率 | 基本正确,1 处需补充说明 | +| 页面状态描述完整度 | 需补充 4 处状态遗漏 | + +**结论:页面地图文档整体质量较高,覆盖率 95%+。主要问题集中在页面完成状态的部分误判,以及个别状态的遗漏。** diff --git a/docs/system-map/ios/review/04-功能差异清单.md b/docs/system-map/ios/review/04-功能差异清单.md new file mode 100644 index 0000000..d2d5918 --- /dev/null +++ b/docs/system-map/ios/review/04-功能差异清单.md @@ -0,0 +1,140 @@ +# 04 功能差异清单 + +> 将独立功能基线(review/02-独立功能基线.md)与已有文档(02-iOS页面功能总表.md)逐项比对。 + +--- + +## 一、功能遗漏清单 + +### 遗漏 1:学习主页 selfTestSmallCard → QuizListView (kbId="") + +- **文档覆盖:** 文档记录"进行自我测试"功能(点击主操作卡片或测试卡片) +- **遗漏:** 文档未说明 smallCard 跳转 QuizListView 时 knowledgeBaseId 为空字符串,可能导致不正确的行为 +- **应补到:** 02-iOS页面功能总表.md → 学习 Tab → "进行自我测试" +- **建议补充说明:** "注:辅助卡片自测入口使用空 knowledgeBaseId,可能在 quizList 中显示空列表" + +### 遗漏 2:GoalSettingDetailView 每日学习时长不持久化 + +- **文档覆盖:** 文档 5.4 节记录 GoalSettingDetailView 的"修改每日时长"功能为"已完成" +- **实际:** dailyMins 只保存在本地 @State 变量,未通过 API 持久化 +- **应补到:** 02-iOS页面功能总表.md → 我的 Tab → "修改每日时长" +- **建议状态修正:** 已完成为 → 部分完成(UI 完成,数据不持久化) + +### 遗漏 3:RecallTestPage 功能未记录 + +- **文档覆盖:** 未记录 +- **实际:** RecallTestPage 代码存在(Features/AI/RecallTestPage.swift),含: + - 查看回忆测试题(硬编码) + - 输入回答 + - 提交获取 AI 反馈(→ AIFeedbackPageView) +- **建议补到:** 02-iOS页面功能总表.md → AI 辅助功能 → 新增"回忆测试页"行 +- **建议状态:** 占位实现(无导航入口,题目硬编码) + +### 遗漏 4:AIChatPage 置顶/取消置顶会话 + +- **文档覆盖:** 文档记录"删除会话"和"归档会话" +- **遗漏:** 未记录置顶/取消置顶功能(swipeActions(edge: .leading)) +- **应补到:** 02-iOS页面功能总表.md → AI 辅助功能 → AI 对话页 +- **建议新增行:** "置顶/取消置顶会话 | 左滑→置顶/取消置顶 | 切换会话置顶状态" + +### 遗漏 5:MaterialReaderView 解析触发 + 轮询 + +- **文档覆盖:** 文档在"阅读 Markdown 内容"等行标注已完成 +- **遗漏:** 文档未将"触发 AI 知识提取(解析)"作为独立功能记录,工具栏 brain 按钮触发 60×2s 轮询是一个重要功能 +- **建议补到:** 02-iOS页面功能总表.md → 资料阅读 → 新增行 +- **建议新增行:** "触发知识提取 | 点击工具栏大脑按钮 | 提交解析任务,轮询进度(60×2s) | 部分完成 | 轮询使用硬编码次数和间隔" + +### 遗漏 6:AIHomeView 的全部功能(虽已废弃) + +- **文档覆盖:** 文档记录了 AIHomeView 为占位实现/已废弃,但功能总表中将其合并入一行"AI 首页(已废弃)" +- **遗漏:** 该页面内有具体的子功能(服务器状态检查、快速操作入口、每日思考卡片、推荐问题列表),但功能总表未展开 +- **评估:** 这对于已废弃页面是合理的简化处理,不做强制修正要求 + +--- + +## 二、功能状态误判 + +| 文档功能 | 文档状态 | 实际状态 | 判定依据 | +|---------|---------|---------|---------| +| 学习会话-专注计时学习 | 已完成 | 暂未确认 | 本地计时完成,但未发现调用 LearningSessionService API 保存学习记录 | +| 学习主页-开始今日复习 | 部分完成 | 部分完成 | 入口正常,ReviewCardView 为占位实现。文档正确标记。 | +| 学习主页-查看完整分析 | 已完成 | 已完成 | 入口存在,跳转到 ActiveRecallView(本身为占位实现)。**文档正确标记了跳转目标的状态,但入口本身已完成。** | +| 学习主页-探索公开知识库 | 已完成 | 已完成 | 切换到 library Tab | +| 分析页-查看掌握度趋势图 | 部分完成 | 占位实现 | **应为占位实现**,ZXChartView 使用完全硬编码的 7 天数据 `[("一", 0.62)...]`,ViewModel 的 trend 数据被忽略 | +| 分析页-查看每周学习活跃 | 部分完成 | 占位实现 | **应为占位实现**,ZXWeekBarChart 使用完全硬编码数据,ViewModel 的 heatmap 数据被忽略 | +| 分析页-查看 AI 综合分析 | 已完成 | 已完成 | 动态拼接 API 数据,非 AI 生成 | +| 分析页-查看全部薄弱知识点 | 已完成 | 已完成 | 跳转到 WeakPointsPage(本身为占位实现) | +| 设置页-切换导入完成通知 | 暂未确认 | 部分完成 | 三个通知开关全部绑定到同一个 $reviewReminder 变量,是明确的 **bug** 而非待确认 | +| 设置页-切换系统通知 | 暂未确认 | 部分完成 | 同上 | +| 设置页-切换 iCloud 同步 | 暂未确认 | 暂未确认 | 仅改变本地 @State,无 API 调用 | +| GoalSettingDetailView-修改每日时长 | 已完成 | 部分完成 | dailyMins 不持久化 | +| 每日思考页-提交回答 | 占位实现 | 占位实现 | 状态一致,但 submitted 变量 bug 未记录 | + +--- + +## 三、自动触发功能遗漏 + +文档功能总表主要记录了用户主动触发的功能,以下自动触发功能在文档中有部分遗漏: + +| 自动功能 | 文档覆盖 | 建议 | +|---------|---------|------| +| MaterialReaderView 进入时自动恢复阅读位置 | 已覆盖("恢复阅读位置"行) | — | +| MaterialReaderView 前后台切换暂停/恢复会话 | 已覆盖 | — | +| MaterialReaderView 自动从 COS 下载文件 | 未明确记录 | 建议在"阅读 Markdown 内容"备注中补充 | +| MaterialReaderView COS 过期 URL 重取 | 未明确记录 | 建议补充 | +| 学习主页优先级自动计算 | 已覆盖 | — | +| StudyHomeViewModel 错误状态永不可达 | 未记录 | 建议在备注中说明 ViewModel 的 try? 吞错行为 | + +--- + +## 四、搜索、筛选、排序、分页等辅助功能检查 + +| 功能 | 页面 | 文档覆盖 | 备注 | +|------|------|---------|------| +| 知识库搜索 | LibraryHomeView | 已覆盖(但标为部分完成) | 搜索页搜索逻辑未实现 | +| 知识库分类筛选 | LibraryHomeView | 已覆盖 | 4 个分类 chips | +| 知识库分页加载 | LibraryHomeView | 已覆盖 | 无限滚动 | +| 知识点排序 | LibraryDetailPage | 已覆盖 | 4 种排序 | +| 知识点批量选择 | LibraryDetailPage | 已覆盖 | | +| 会话搜索 | AIChatPage Sheet | 已覆盖 | | +| 通知列表无筛选 | NotificationListView | 未记录筛选 | 无筛选功能,合理 | +| 测验列表无筛选 | QuizListView | 未记录筛选 | 无筛选功能,合理 | + +--- + +## 五、API 调用存在但无页面入口 + +### WaitlistService + +- **API 端点:** /waitlist (POST), /waitlist/stats (GET) +- **代码存在:** APIService.swift 中 WaitlistService 类完整定义 +- **页面入口:** 无任何 View 或 ViewModel 调用 WaitlistService +- **文档记录:** 文档未提及 waitlist 功能 +- **建议:** 在系统地图中标注"Waitlist API 已就绪但 C 端无入口"(或在总览中标注为后端预留能力) + +### UserService.requestAccountDeletion / cancelDeletion + +- **API 端点:** /users/me/deletion-request (POST/DELETE) +- **页面入口:** 无任何页面调用这两个方法 +- **文档记录:** 未提及注销账号功能 +- **建议:** 补充到设置页的未完成功能列表 + +### UserService.listDevices / removeDevice + +- **API 端点:** /users/me/devices (GET/DELETE) +- **页面入口:** 设置页有"登录设备管理"行但无导航目标(→ Route.settings 自引用) +- **建议:** 标注为"API 已就绪,设备管理页面未实现" + +--- + +## 六、总体评估 + +| 评估维度 | 结果 | +|---------|------| +| 功能总表覆盖率 | 约 95%,遗漏约 6 个功能点 | +| 功能状态准确率 | 约 90%,7 个功能的状态需要修正 | +| 自动触发功能覆盖 | 基本完整,2 处建议补充 | +| 辅助功能覆盖 | 完整 | +| API-页面映射完整性 | 3 个 API 有端点无页面入口需标注 | + +**结论:功能总表文档覆盖较全面,主要问题是若干功能的状态标记偏乐观(部分图表数据被标记为"部分完成"但实际为"占位实现"),以及少数自动触发功能和 API-页面不一致未记录。** diff --git a/docs/system-map/ios/review/05-业务能力归类审查.md b/docs/system-map/ios/review/05-业务能力归类审查.md new file mode 100644 index 0000000..5f1c146 --- /dev/null +++ b/docs/system-map/ios/review/05-业务能力归类审查.md @@ -0,0 +1,272 @@ +# 05 业务能力归类审查 + +> 审查对象:已有文档 `03-C端业务能力初步清单.md` +> 审查方法:先独立归类,再与文档比对 + +--- + +## 一、独立业务能力归类 + +基于代码扫描独立建立的业务能力清单: + +### 能力 1:账号注册与登录 + +- **代码依据:** Apple ID 登录(LoginPage)、会话恢复(SplashScreen/AuthManager)、Token 刷新(APIClient)、账号禁用/注销状态处理(AccountStatusView) +- **用户目标:** 使用 Apple ID 安全登录,会话自动恢复 +- **关联页面:** P01, P03, P04, P05 +- **独立判定:** 已存在,核心流程完整 + +### 能力 2:新手引导与目标设定 + +- **代码依据:** WelcomePage → OnboardingPage → GoalSetupPage 流程 +- **用户目标:** 首次使用时了解产品价值,设定个性化学习目标 +- **关联页面:** P02, P06, P07, P26, P27 +- **独立判定:** 已存在 + +### 能力 3:个人资料维护 + +- **代码依据:** EditProfilePage(头像/昵称/身份/方向/目标/简介)+ ProfileView(查看) +- **用户目标:** 维护个人档案信息 +- **关联页面:** P23, P24 +- **独立判定:** 已存在 + +### 能力 4:知识库浏览与管理 + +- **代码依据:** LibraryHomeView(列表/筛选/分页)、LibraryDetailPage(详情/排序/删除)、CreateLibraryPage(创建)、DiscoverView(公开库发现/订阅) +- **用户目标:** 创建、浏览、管理个人知识库,发现和订阅公开知识库 +- **关联页面:** P12, P14, P15, P21 +- **独立判定:** 已存在。部分功能未完成(官方库筛选、KB 管理页、搜索逻辑) + +### 能力 5:知识点管理 + +- **代码依据:** LibraryDetailPage 知识点 Tab(列表/排序/删除/批量操作)、AddKnowledgePage(手动/文件/图片添加)、KnowledgeDetailPage(查看)、EditKnowledgePage(编辑) +- **用户目标:** 在知识库中增删改查知识点 +- **关联页面:** P14, P16, P17, P18 +- **独立判定:** 已存在。收藏 API 未支持、重命名/移动到文件夹为 TODO + +### 能力 6:资料上传与处理 + +- **代码依据:** ImportPage(文件/相册/链接导入)、ImportReviewPage(AI 候选审批) +- **用户目标:** 将外部资料导入知识库,审核 AI 提取的知识点 +- **关联页面:** P19, P20 +- **独立判定:** 已存在 + +### 能力 7:文档阅读 + +- **代码依据:** MaterialReaderView(多格式渲染/位置恢复/标记已读)、MaterialDetailView(处理状态/元数据)、QuickLook(系统预览)、ShareLink(外部打开) +- **用户目标:** 阅读学习资料,支持多种格式 +- **关联页面:** P37, P38, S03 +- **独立判定:** 已存在 + +### 能力 8:阅读笔记 + +- **代码依据:** QuickNoteSheet(创建笔记/自动锚点记录) +- **用户目标:** 在阅读过程中记笔记 +- **关联页面:** S02 +- **独立判定:** 已存在。本地存储(UserDefaults),未同步到服务端 + +### 能力 9:阅读行为跟踪 + +- **代码依据:** ReadingRuntimeSessionManager + ReadingEventCollector + ReadingPositionStore +- **用户目标:** 自动记录阅读行为,用于分析 +- **关联页面:** P37(自动执行) +- **独立判定:** 已存在 + +### 能力 10:学习信息收集 + +- **代码依据:** LearningSessionView(计时)、MaterialReaderView(阅读会话) +- **用户目标:** 记录学习时长和阅读行为 +- **关联页面:** P09, P37 +- **独立判定:** 已存在。但 LearningSessionView 未发现 API 保存调用,需确认学习会话数据是否真正被收集 + +### 能力 11:继续学习 + +- **代码依据:** StudyHomeView 优先级算法(ContinueLearningResponse → MainAction.continueSession) +- **用户目标:** 从上次中断处继续学习 +- **关联页面:** P08 +- **独立判定:** 已存在 + +### 能力 12:AI 对话 + +- **代码依据:** AIChatPage(流式对话/思考过程/多会话管理/范围限定) +- **用户目标:** 与 AI 进行学习相关对话 +- **关联页面:** P30, S01 +- **独立判定:** 已存在 + +### 能力 13:题目与测验 + +- **代码依据:** QuizListView(查看/生成)、QuizTakerView(作答/提交)、QuizResultView(结果/解析) +- **用户目标:** 通过测验检验学习效果 +- **关联页面:** P34, P35, P36 +- **独立判定:** 已存在 + +### 能力 14:学习分析 + +- **代码依据:** AnalysisHomeView(统计徽章/趋势图/连续统计/学习记录/推荐/薄弱点) +- **用户目标:** 查看学习数据分析和趋势 +- **关联页面:** P22 +- **独立判定:** 已存在。掌握度趋势图和每周活跃图为占位实现 + +### 能力 15:主动回忆与 AI 反馈 + +- **代码依据:** ActiveRecallView → AIFeedbackPageView 链路 +- **用户目标:** 主动输出知识,获得 AI 评估反馈 +- **关联页面:** P11, P32, P31 +- **独立判定:** 占位实现(全部使用硬编码数据) + +### 能力 16:间隔复习 + +- **代码依据:** ReviewCardView(闪卡翻转/自评) +- **用户目标:** 基于间隔重复的闪卡复习 +- **关联页面:** P10 +- **独立判定:** 占位实现(硬编码数据,未接通 API) + +### 能力 17:学习会话计时 + +- **代码依据:** LearningSessionView(专注计时/暂停/结束/庆祝) +- **用户目标:** 记录专注学习时长 +- **关联页面:** P09 +- **独立判定:** 部分完成(本地计时完成,API 持久化待确认) + +### 能力 18:消息与通知 + +- **代码依据:** NotificationListView(分组展示/已读标记)、SettingsView(通知开关) +- **用户目标:** 接收系统通知,管理通知偏好 +- **关联页面:** P28, P25 +- **独立判定:** 已存在。通知开关存在绑定 bug + +### 能力 19:设置与应用偏好 + +- **代码依据:** SettingsView(外观/语言/复习提醒/通知/存储/iCloud/退出登录) +- **用户目标:** 管理应用全局设置 +- **关联页面:** P25, P26, P27 +- **独立判定:** 已存在。合规页面入口缺失、设备管理未实现 + +### 能力 20:帮助与反馈 + +- **代码依据:** FeedbackFormView(类型选择/内容输入/提交) +- **用户目标:** 提交问题和建议 +- **关联页面:** P29 +- **独立判定:** 已存在 + +### 能力 21:存储空间管理 + +- **代码依据:** ProfileView 存储空间展示 + SettingsView iCloud 同步开关 +- **用户目标:** 了解和控制存储使用 +- **关联页面:** P23, P25 +- **独立判定:** 部分存在(展示完成,iCloud 同步待确认) + +--- + +## 二、与已有文档的能力对比 + +### 完全一致的能力(14 项) + +| 序号 | 独立能力 | 文档能力 | 判定 | +|------|---------|---------|------| +| 1 | 账号注册与登录 | 1. 账号与用户 | 一致 | +| 2 | 新手引导与目标设定 | 2. 新手引导与目标设定 | 一致 | +| 3 | 知识库浏览与管理 | 3. 知识库管理 | 一致 | +| 4 | 知识点管理 | 4. 知识点管理 | 一致 | +| 5 | 资料上传与处理 | 5. 资料上传 | 一致 | +| 6 | 文档阅读 | 6. 文档阅读 | 一致 | +| 7 | 阅读笔记 | 7. 阅读笔记 | 一致 | +| 8 | 阅读行为跟踪 | 8. 阅读行为跟踪 | 一致 | +| 9 | 学习信息收集 | 9. 学习信息收集 | 一致 | +| 10 | 继续学习 | 10. 继续学习 | 一致 | +| 11 | AI 对话 | 11. AI 对话 | 一致 | +| 12 | 题目与测验 | 14. 题目与测验 | 一致 | +| 13 | 帮助与反馈 | 20. 帮助与反馈 | 一致 | +| 14 | 设置与应用偏好 | 19. 设置与合规 | 基本一致 | + +### 需要调整的能力(6 项) + +| 独立能力 | 文档对应 | 问题 | 建议 | +|---------|---------|------|------| +| 个人资料维护 | 合并入"1. 账号与用户" | 文档将个人资料维护合并入账号与用户能力。独立判定认为这是可接受的归类,但边界稍显模糊。 | 可保持现状,或拆分出"个人资料维护"子能力 | +| 主动回忆与 AI 反馈 | 15. 主动回忆 + 12. AI 学习分析 | 文档将"主动回忆"和"AI 学习分析"分为两个独立能力。独立判定认为主动回忆 → AI 反馈是一个连续流程,不应强行拆分。 | 建议将"15. 主动回忆"与"12. AI 学习分析"合并为"主动回忆与 AI 反馈" | +| 间隔复习 | 16. 间隔复习 | 一致 | — | +| 学习分析 | 13. 学习分析 | 一致 | — | +| 学习会话计时 | 无独立条目 | 文档将学习会话计时合并入"9. 学习信息收集"。独立判定认为学习会话计时是一个有独立 UI 的用户行为,宜作为独立能力或子能力。 | 建议在"学习信息收集"能力下明确标注"学习会话计时"子项 | +| 消息与通知 | 18. 消息与通知 | 一致 | — | +| 存储空间管理 | 合并入"17. 会员与额度" | 文档将其归入"会员与额度"。独立判定认为当前代码中无会员/订阅/付费功能,命名为"会员与额度"不准确。 | 建议重命名为"存储与额度"或"存储空间管理" | + +### 文档有但未发现代码支持的能力(1 项) + +| 文档能力 | 判定 | 说明 | +|---------|------|------| +| 17. 会员与额度 | 未发现会员/订阅相关代码 | 代码中无内购、订阅、付费墙、会员等级等实现。存储展示和 iCloud 同步开关存在,但被描述为"会员与额度"不准确。 | + +--- + +## 三、能力归类质量检查 + +### 以技术模块命名检查 + +| 文档能力名 | 是否以技术模块命名 | 判定 | +|-----------|-----------------|------| +| 账号与用户 | 否 | 通过 | +| 知识库管理 | 否 | 通过 | +| 阅读行为跟踪 | 边缘 | 偏技术,建议改为"阅读进度同步"或保持 | +| AI 对话 | 否 | 通过 | +| AI 学习分析 | 否 | 通过 | + +### 闭环拆分过度/不足检查 + +| 文档能力 | 问题 | +|---------|------| +| 主动回忆 + AI 学习分析 | 拆分过度。主动回忆提交 → AI 反馈是一个连续用户体验,不应分为两个能力 | +| 阅读行为跟踪 + 学习信息收集 | 边界模糊。两者都涉及数据收集,调用相同的底层 FFI 和 API | +| 文档阅读 + 阅读笔记 + 阅读行为跟踪 | 三个能力高度耦合在 MaterialReaderView 中,是否过度拆分值得商榷 | + +### 按页面名称命名检查 + +| 文档能力 | 是否直接使用页面名 | 判定 | +|---------|-----------------|------| +| 继续学习 | 否(StudyHomeView 的功能,非页面名) | 通过 | +| 题目与测验 | 否 | 通过 | +| 主动回忆 | 是(与页面同名) | **建议改为"主动回忆与 AI 评估"** | + +--- + +## 四、文档业务能力依赖关系图审查 + +文档中的依赖关系图: + +``` +账号与用户 + └─ 新手引导与目标设定 + └─ 知识库管理 + ├─ 知识点管理 + ├─ 资料上传 → 文档阅读 + │ ├─ 阅读笔记 + │ └─ 阅读行为跟踪 → 学习信息收集 + └─ 题目与测验 + ├─ AI 对话 + ├─ 继续学习 → 主动回忆 / 间隔复习 / 文档阅读 + │ └─ AI 学习分析 + └─ 学习分析 + └─ AI 学习分析 +``` + +审查意见: +1. "AI 对话"应在"知识库管理"下有分支(知识库范围对话)。 +2. "AI 对话"也应在"文档阅读"下有分支(资料范围对话)。 +3. "题目与测验"应在"文档阅读"下有分支(从资料阅读触发解析后进入测验)。 +4. "阅读笔记"也应关联到"知识点管理"(知识点详情页有笔记入口)。 +5. "主动回忆 → AI 学习分析 → 间隔复习"应形成环路(分析后加入待巩固)。 +6. "学习分析"应在"学习信息收集"之后,而非独立于信息收集。 + +--- + +## 五、总体评估 + +| 评估维度 | 结果 | +|---------|------| +| 能力数量合理度 | 20 项基本合理,建议合并"主动回忆"与"AI 学习分析" | +| 能力命名准确度 | 17/20 准确,1 个偏技术(阅读行为跟踪),1 个以页面命名(主动回忆),1 个不准确(会员与额度) | +| 能力边界清晰度 | 阅读相关 3 个能力(文档阅读/阅读笔记/阅读行为跟踪)边界可讨论 | +| 依赖关系准确度 | 基本正确,若干分支缺失 | +| 遗漏能力 | 无重大遗漏,学习会话计时建议作为子能力标注 | + +**结论:业务能力归类文档整体合理,主要问题是"会员与额度"命名不准确(当前无会员功能)、"主动回忆"与"AI 学习分析"建议合并、依赖关系图缺少几个交叉引用。** diff --git a/docs/system-map/ios/review/06-页面能力覆盖矩阵.md b/docs/system-map/ios/review/06-页面能力覆盖矩阵.md new file mode 100644 index 0000000..22dbe15 --- /dev/null +++ b/docs/system-map/ios/review/06-页面能力覆盖矩阵.md @@ -0,0 +1,104 @@ +# 06 页面能力覆盖矩阵 + +> 双向覆盖检查:页面→能力 + 能力→页面 + +--- + +## 一、页面→能力覆盖(每个页面至少归属一个业务能力) + +| 页面 | 归属业务能力 | 主要功能 | 文档是否覆盖 | 状态判断是否正确 | +|------|------------|---------|------------|----------------| +| P01 启动页 | 账号注册与登录 | 自动恢复会话 | 是 | 是 | +| P02 欢迎页 | 新手引导与目标设定 | 产品介绍、引导登录 | 是 | 是 | +| P03 登录页 | 账号注册与登录 | Apple ID 登录 | 是 | 是 | +| P04/P05 账号状态页 | 账号注册与登录 | 禁用/注销状态展示 | 是 | 是 | +| P06 引导页 | 新手引导与目标设定 | 4 步产品引导 | 是 | 是 | +| P07 目标设置页 | 新手引导与目标设定 | 设定目标/方法/时间 | 是 | 是 | +| P08 学习主页 | 继续学习、学习分析 | 优先级算法、今日任务、每周摘要 | 是 | 是 | +| P09 学习会话页 | 学习信息收集 | 专注计时 | 是 | 状态偏乐观(API 保存待确认) | +| P10 复习卡片页 | 间隔复习 | 闪卡翻转、自评 | 是 | 是(标记为占位实现) | +| P11 主动回忆页 | 主动回忆与 AI 反馈 | 文字/语音作答 | 是 | 是(标记为占位实现) | +| P12 知识库首页 | 知识库浏览与管理 | 列表/筛选/分页 | 是 | 是 | +| P13 知识库搜索页 | 知识库浏览与管理 | 搜索 | 是 | 是 | +| P14 知识库详情页 | 知识库浏览与管理、知识点管理 | 双 Tab/排序/批量操作/删除 | 是 | 是 | +| P15 创建知识库页 | 知识库浏览与管理 | 创建知识库 | 是 | 是 | +| P16 添加知识点页 | 知识点管理 | 手动/文件/图片添加 | 是 | 是 | +| P17 知识点详情页 | 知识点管理、文档阅读 | 查看/渲染/收藏/笔记 | 是 | 部分(收藏 API 未支持) | +| P18 编辑知识点页 | 知识点管理 | 编辑标题/内容 | 是 | 是 | +| P19 导入资料页 | 资料上传与处理 | 文件/相册/链接导入 | 是 | 是 | +| P20 导入候选审核页 | 资料上传与处理 | 候选审批 | 是 | 是 | +| P21 发现公开库页 | 知识库浏览与管理 | 浏览/订阅公开库 | 是 | 是 | +| P22 学习分析页 | 学习分析 | 统计/趋势图/记录/推荐/薄弱点 | 是 | 部分(趋势图为占位) | +| P23 个人中心页 | 个人资料维护、设置与应用偏好 | 资料/菜单/资产/存储 | 是 | 是 | +| P24 编辑资料页 | 个人资料维护 | 头像/昵称/身份/目标 | 是 | 是 | +| P25 设置页 | 设置与应用偏好、消息与通知 | 外观/复习/通知/存储/退出 | 是 | 部分(通知开关 bug,合规入口缺失) | +| P26 学习目标设置页 | 新手引导与目标设定 | 修改目标/时长 | 是 | 否(dailyMins 不持久化,文档标已完成) | +| P27 方法偏好页 | 新手引导与目标设定 | 多选方法 | 是 | 是 | +| P28 通知列表页 | 消息与通知 | 查看/标记已读/全部已读 | 是 | 是 | +| P29 帮助与反馈页 | 帮助与反馈 | 选择类型/输入/提交 | 是 | 是 | +| P30 AI 对话页 | AI 对话 | 流式对话/会话管理 | 是 | 是 | +| P31 每日思考页 | 主动回忆与 AI 反馈 | 查看题目/提交回答 | 是 | 是(标记为占位) | +| P32 AI 反馈页 | 主动回忆与 AI 反馈 | 分析评分/建议/导航 | 是 | 是(标记为占位) | +| P33 薄弱知识点页 | 学习分析 | 查看薄弱点列表 | 是 | 是(标记为占位) | +| (废) AIHomeView | AI 对话、主动回忆、间隔复习、学习分析 | 快速操作/思考题/推荐 | 是(标记为废弃) | 是 | +| P34 测验列表页 | 题目与测验 | 查看/生成测验 | 是 | 是 | +| P35 测验作答页 | 题目与测验 | 选择/判断/填空作答 | 是 | 是 | +| P36 测验结果页 | 题目与测验 | 得分/逐题详情/重测 | 是 | 是 | +| P37 资料阅读页 | 文档阅读、阅读笔记、阅读行为跟踪、学习信息收集、AI 对话 | 多格式渲染/位置恢复/标记已读/AI/笔记 | 是 | 是 | +| P38 资料详情页 | 文档阅读 | AI 处理状态/元数据/进度 | 是 | 是 | +| S01 会话列表 Sheet | AI 对话 | 会话搜索/切换/删除/归档/置顶 | 是 | 遗漏置顶功能 | +| S02 快速笔记 Sheet | 阅读笔记 | 创建笔记/锚点记录 | 是 | 是 | +| S03 系统预览 | 文档阅读 | PDF/Office 预览 | 是 | 是 | +| S04 封面选择 Sheet | 知识库浏览与管理 | 相册选择封面 | 是 | 是 | +| S05 文件夹管理 Sheet | 知识库浏览与管理 | 文件夹 CRUD | 是 | 是 | +| (无入口) RecallTestPage | 主动回忆与 AI 反馈 | 回忆测试 | 否 | 遗漏 | +| (无入口) WaitlistService | 未归类 | waitlist 加入/统计 | 否 | 遗漏(API 存在但无 C 端入口) | + +--- + +## 二、能力→页面覆盖(每个能力是否有实际页面入口) + +| 业务能力 | 有页面入口? | 关联页面 | 遗漏关联页面 | 错误关联 | +|---------|------------|---------|------------|---------| +| 账号注册与登录 | 是 | P01,P03,P04,P05 | 无 | 无 | +| 新手引导与目标设定 | 是 | P02,P06,P07,P26,P27 | 无 | 无 | +| 知识库浏览与管理 | 是 | P12,P14,P15,P21,S04,S05 | 遗漏 P13(搜索页) | 无 | +| 知识点管理 | 是 | P14,P16,P17,P18 | 无 | 无 | +| 资料上传与处理 | 是 | P19,P20 | 无 | 无 | +| 文档阅读 | 是 | P17,P37,P38,S03 | 无 | 无 | +| 阅读笔记 | 是 | S02,P37 | 遗漏 P17(知识点详情页笔记入口) | 无 | +| 阅读行为跟踪 | 是(自动) | P37 | 无 | 无 | +| 学习信息收集 | 是(自动) | P09,P37 | 无 | 无 | +| 继续学习 | 是 | P08,P22 | 无 | 无 | +| AI 对话 | 是 | P30,S01,P37 | 遗漏 P14(知识库范围 AI 对话) | 无 | +| 题目与测验 | 是 | P34,P35,P36 | 无 | 无 | +| 学习分析 | 是 | P22,P33 | 无 | 无 | +| 主动回忆与 AI 反馈 | 是(占位) | P11,P31,P32 | 遗漏 RecallTestPage | 无 | +| 间隔复习 | 是(占位) | P10 | 无 | 无 | +| 学习会话计时 | 是 | P09 | 无 | 无 | +| 消息与通知 | 是 | P28,P25 | 无 | 无 | +| 设置与应用偏好 | 是 | P25,P26,P27 | 无 | 无 | +| 帮助与反馈 | 是 | P29 | 无 | 无 | +| 存储空间管理 | 是 | P23,P25 | 无 | 无 | +| 会员与额度(文档命名) | — | — | 无实际会员/订阅代码 | 文档将存储+资产归入此项不准确 | + +--- + +## 三、无法归类的页面或功能 + +| 对象 | 问题 | 建议 | +|------|------|------| +| WaitlistService | API 完整但无 C 端入口 | 在系统地图中标注为"后端已就绪,C 端未接入" | +| RecallTestPage | 代码存在但无导航入口 | 归类到"主动回忆与 AI 反馈",标注为占位实现 | +| AIHomeView | 已废弃,无法归类到实际能力 | 保持现状,作为废弃页面参考 | +| UserService.requestAccountDeletion | API 存在但无页面入口 | 在"账号与用户"能力中标注"账号注销 API 已就绪,C 端入口未实现" | + +--- + +## 四、双向覆盖检查结论 + +- **页面→能力:** 43/43 个可访问页面均已归属至少一个业务能力。RecallTestPage(无入口)未归属。 +- **能力→页面:** 19/20 个能力有实际页面入口。"会员与额度"能力无实际会员/订阅代码支持。 +- **遗漏关联页面:** 5 处(知识库搜索页、知识点详情页笔记入口、知识库范围 AI 对话、RecallTestPage、WaitlistService) +- **错误关联:** 无 +- **状态判断错误:** 2 处(学习会话 API 保存、GoalSetting dailyMins 持久化) diff --git a/docs/system-map/ios/review/07-待修正文档清单.md b/docs/system-map/ios/review/07-待修正文档清单.md new file mode 100644 index 0000000..2bc0da0 --- /dev/null +++ b/docs/system-map/ios/review/07-待修正文档清单.md @@ -0,0 +1,150 @@ +# 07 待修正文档清单 + +> 列出所有需要在已有系统地图文档中修正的条目,按优先级排序。 + +--- + +## P0 — 影响整体地图正确性(必须修正) + +### P0-1:每日学习时长不持久化 → 02-iOS页面功能总表 + +- **涉及文档:** 02-iOS页面功能总表.md +- **位置:** 我的 Tab → "修改每日时长" +- **当前状态:** 已完成 +- **修正为:** 部分完成 +- **原因:** GoalSettingDetailView 中 dailyMins 只保存在本地 @State 变量,未通过 API 持久化。用户下次进入设置页时恢复默认值"30 分钟"。 +- **备注栏补充:** "UI 选择完成,但选择结果不通过 API 保存" + +### P0-2:分析页图表数据为占位实现 → 02-iOS页面功能总表 + +- **涉及文档:** 02-iOS页面功能总表.md +- **位置:** 分析 Tab → "查看掌握度趋势图" 和 "查看每周学习活跃" +- **当前状态:** 部分完成 +- **修正为:** 占位实现 +- **原因:** ZXChartView 使用硬编码 `[("一", 0.62), ...]` 数据,ZXWeekBarChart 使用硬编码 `[("一", 0.3), ...]` 数据。两组数据均未从 ViewModel 的 API 数据读取,属于完全占位实现。 +- **备注栏补充:** "图表组件使用编译时硬编码的 7 天数据,未接入 ViewModel API 返回的真实数据" + +### P0-3:设置页通知开关绑定 bug → 02-iOS页面功能总表 + +- **涉及文档:** 02-iOS页面功能总表.md +- **位置:** 我的 Tab → "切换导入完成通知"、"切换系统通知" +- **当前状态:** 暂未确认 +- **修正为:** 部分完成(存在 bug) +- **原因:** SettingsView 中"复习提醒"、"导入完成通知"、"系统通知"三个 Toggle 全部绑定到同一个 `$reviewReminder` 变量(见 SettingsView.swift:61-65)。这不是"待确认",而是明确的代码 bug。 +- **修正状态描述:** "三个通知开关绑定到同一状态变量,需修复为各自独立绑定" + +### P0-4:文档声称的页面总数与实际不符 + +- **涉及文档:** 00-iOS-C端总览.md +- **位置:** 第四节"页面总览" +- **当前描述:** "共盘点出 43 个页面/弹窗"(已完成 19 + 部分完成 13 + 占位实现 7 + 暂未确认 1 + 未完成 3) +- **实际:** 独立基线盘点出 38 个独立 Push 页面 + 10 个 Sheet/弹窗 + 8 个确认弹窗 + 1 个废弃页面 = 总计约 47 个可盘点对象(含弹窗) +- **说明:** 文档的"43"如果指页面+弹窗,则遗漏了 RecallTestPage(代码存在无入口)、部分 Alert 弹窗。建议明确统计口径并更新数字。 + +--- + +## P1 — 遗漏主要页面或业务能力 + +### P1-1:遗漏 RecallTestPage + +- **涉及文档:** 01-iOS页面地图.md, 02-iOS页面功能总表.md +- **遗漏对象:** RecallTestPage (Features/AI/RecallTestPage.swift) +- **应补到位置:** 01 第六章 AI 辅助功能,新增 6.6 节"回忆测试页" +- **建议状态:** 占位实现(无导航入口 + 题目硬编码) +- **功能表补充:** 查看回忆测试题、输入回答、提交获取 AI 反馈(→ AIFeedbackPageView) + +### P1-2:遗漏 AIChatPage 会话置顶功能 + +- **涉及文档:** 02-iOS页面功能总表.md +- **遗漏对象:** AI 对话页 → 会话列表 Sheet → 左滑置顶/取消置顶 +- **应补到位置:** AI 辅助功能 → AI 对话页 +- **新增行:** "置顶/取消置顶会话 | 左滑→置顶/取消置顶 | 切换会话置顶状态 | 已完成" + +### P1-3:遗漏 WaitlistService API 已就绪但 C 端无入口 + +- **涉及文档:** 00-iOS-C端总览.md 或 03-C端业务能力初步清单.md +- **遗漏对象:** WaitlistService(/waitlist POST, /waitlist/stats GET) +- **说明:** API 服务代码完整但无任何 View/ViewModel 调用。应标注为"后端已就绪,C 端入口未实现"。 + +### P1-4:遗漏账号注销 API 已就绪但无入口 + +- **涉及文档:** 03-C端业务能力初步清单.md → 账号与用户 +- **遗漏对象:** UserService.requestAccountDeletion() 和 cancelDeletion() +- **说明:** API 端点 /users/me/deletion-request POST/DELETE 已就绪,但设置页及其他页面均未提供注销账号入口。 +- **建议:** 在"账号与用户"能力中补充"账号注销 API 已就绪,C 端入口未实现" + +--- + +## P2 — 命名、描述、辅助状态问题 + +### P2-1:业务能力"会员与额度"命名不准确 → 03 + +- **涉及文档:** 03-C端业务能力初步清单.md +- **当前命名:** 17. 会员与额度 +- **修正为:** 存储空间管理(或"存储与额度") +- **原因:** 代码中无任何会员/订阅/付费墙/内购实现。该能力实际包含的功能仅为存储空间展示和学习资产统计。 + +### P2-2:建议合并"主动回忆"与"AI 学习分析" → 03 + +- **涉及文档:** 03-C端业务能力初步清单.md +- **当前:** 15. 主动回忆 和 12. AI 学习分析 为两个独立能力 +- **建议:** 合并为"主动回忆与 AI 反馈" +- **原因:** 主动回忆 → AI 反馈是一个连续用户体验流程,不应拆分为两个独立业务能力 + +### P2-3:StudyHomeViewModel 错误状态永不可达 → 01 + +- **涉及文档:** 01-iOS页面地图.md +- **位置:** 2.1 学习主页 → 页面主要状态 +- **当前描述:** "加载中 / 错误 / 已加载·有任务 / 已加载·空状态" +- **补充说明:** "注:View 支持 error 状态展示,但 ViewModel 中所有 API 调用使用 try? 吞错,error 状态在实际运行中永不可达" + +### P2-4:DailyThinkingPage submitted 变量 bug → 01 + +- **涉及文档:** 01-iOS页面地图.md +- **位置:** 6.2 每日思考页 +- **补充说明:** "注:submitted 状态变量在代码中从未被设置为 true,提交按钮始终可见,可能导致用户重复提交" + +### P2-5:设置页自引用导航 → 01 + +- **涉及文档:** 01-iOS页面地图.md +- **位置:** 5.3 设置页 +- **当前描述:** "存储空间"行和"登录设备管理"行 → Route.settings +- **补充说明:** "存储空间"和"登录设备管理"导航目标均为 Route.settings(指向设置页自身),形成无效的自引用 + +### P2-6:知识库详情页操作菜单"知识库管理"按钮 → 01 + +- **涉及文档:** 01-iOS页面地图.md +- **位置:** 3.3 知识库详情页 +- **当前描述:** 用户可执行操作中未包含此按钮 +- **补充说明:** 操作菜单中存在"知识库管理"按钮,但 action 为空(// TODO),属未实现功能 + +### P2-7:业务能力依赖关系图缺少交叉引用 → 03 + +- **涉及文档:** 03-C端业务能力初步清单.md +- **位置:** "业务能力依赖关系(初步)" +- **补充以下分支:** + - AI 对话 → 知识库管理(知识库范围对话) + - AI 对话 → 文档阅读(资料范围对话) + - 文档阅读 → 题目与测验(解析完成后进入测验) + - 阅读笔记 → 知识点管理(知识点详情页笔记入口) + - 主动回忆 → 间隔复习(AI 分析后加入待巩固 → 安排间隔复习) + - 学习分析 → 学习信息收集(分析依赖信息收集数据) + +### P2-8:文件夹新建/重命名 Alert 未列入确认弹窗表 → 01 + +- **涉及文档:** 01-iOS页面地图.md 9.6 节"各类确认弹窗"表格 +- **补充行:** + - 新建分类 | FolderManageView | 点击"新建" + - 重命名分类 | FolderManageView | 滑动→重命名 + +--- + +## 修正优先级汇总 + +| 优先级 | 数量 | 影响范围 | +|--------|------|---------| +| P0 | 4 | 状态误判会导致整体地图失真 | +| P1 | 4 | 遗漏主要页面/功能/API 入口 | +| P2 | 8 | 命名、描述、辅助状态完善 | + +**总计待修正项:16 项** diff --git a/docs/system-map/review/07-内容与对话能力审查报告.md b/docs/system-map/review/07-内容与对话能力审查报告.md new file mode 100644 index 0000000..27c6d24 --- /dev/null +++ b/docs/system-map/review/07-内容与对话能力审查报告.md @@ -0,0 +1,475 @@ +# 内容与对话能力审查报告 + +> 审查日期:2026-06-19 +> 审查范围:4 份跨项目能力文档 +> 审查方法:独立扫描所有相关仓库代码 → 独立还原三条业务链路 → 与文档逐项比对 + +--- + +## 1. 审查范围 + +### 1.1 已检查的仓库与模块 + +| 仓库 | 已检查的模块/文件 | 检查深度 | +|------|-----------------|---------| +| **iOS (AIStudyApp)** | 全部 64 个 .swift 文件(Features/AI, Features/Library, Features/MaterialReader, Features/Quiz, Features/Profile, Features/Study, Core/) | 逐文件阅读 | +| **主 API (api-server)** | Prisma schema (2221 行完整模型)、rag-chat.service.ts、document-import.service.ts、knowledge-base.service.ts、knowledge-source.service.ts、knowledge-items.service.ts、files.service.ts、import-candidate 模块 | 逐文件阅读 | +| **Python RAG Worker** | 全部 10 个 .py 文件(main.py, config.py, api_client.py, parser.py, chunker.py, embedder.py, indexer.py, candidate_generator.py, reranker.py, pipelines/import_pipeline.py) | 逐文件阅读 | +| **Admin (admin-projects)** | App.tsx 路由、全部 ~40 个页面组件、全部 service 模块 | Agent 全面探索 | +| **Prisma Schema** | 全部 120+ 数据模型定义 | 逐模型检查 | +| **COS** | 通过 files.service.ts 和 Python RAG Worker 的 download_file 间接检查 | 间接验证 | +| **Qdrant** | 通过 indexer.py 的 upsert_points / search / mark_deleted 间接检查 | 间接验证 | +| **Rust Document Runtime** | 检查文档声称的参与环节 | 确认不参与上传/处理/AI对话链路 | +| **Heavy Runtime** | 检查文档声称的参与环节 | 确认不参与基础对话链路 | + +### 1.2 已检查的文档 + +- `03-资料上传与处理.md` +- `04-知识库与知识点管理.md` +- `05-AI对话与知识库问答.md` +- `06-内容与对话项目矩阵.md` + +--- + +## 2. 审查方法 + +### 2.1 独立还原方法 + +1. **链路一(资料上传与处理):** 从 iOS 文件选择入口 → API 预签名 URL → COS PUT → 确认上传 → KnowledgeSource 创建 → DocumentImport 入队 → Python RAG Worker 轮询/认领/下载/解析/分块/嵌入/索引/候选生成 → 候选审核 → 各状态位更新,逐环节检查代码调用链。 +2. **链路二(知识库与知识点管理):** 从 Prisma 数据模型出发,检查 KnowledgeBase/KnowledgeItem/KnowledgeSource/KnowledgeFolder/DocumentImport/ImportCandidate 之间的关系、CRUD 实现、权限校验、级联删除行为。 +3. **链路三(AI 对话与知识库问答):** 从 rag-chat.service.ts 出发,检查会话 open-or-create、5 种 scope 的上下文加载、AiGateway 路由、SSE 流式传输、Citation 生成,逐行核对代码与文档描述。 + +### 2.2 双向覆盖检查方法 + +- **文档→代码:** 对文档中每一项关于"已完成"的声明,在代码中寻找对应的实现证据。 +- **代码→文档:** 从代码中扫描出的所有 API 端点、服务方法和 Admin 页面,反向检查是否在文档中有对应记录。 + +### 2.3 跨文档一致性检查方法 + +- 逐份文档提取关于同一项目职责、同一业务对象、同一状态的描述,进行横向比对。 + +--- + +## 3. 独立还原的真实业务链路 + +### 3.1 链路一:资料上传与处理 + +**基于代码的独立还原:** + +``` +1. iOS 文件选择 → ImportPage / AddKnowledgePage +2. iOS → POST /files/upload-url (filename, mimeType, sizeBytes) +3. API 内容安全检查文件名 → COS 生成预签名 PUT URL (1h 有效) +4. iOS 直接 PUT 文件到 COS +5. iOS → POST /files/complete (objectKey) → API headObject 验证 → 创建 UploadedFile 记录 +6. iOS → POST /knowledge-bases/:id/sources (fileId, type, title, ...) +7. KnowledgeSourceService.addSource(): + - 创建 KnowledgeSource 记录 (parseStatus/indexStatus/learningStatus = "pending") + - 自动创建 DocumentImport 记录 (status = "QUEUED") + - Redis 状态初始化 (key: job:document-import:{id}:status/progress/message) + - 入队到 'document-import' 队列 +8. Python RAG Worker (每 5s 轮询): + - GET /internal/rag/jobs/next → 获取 QUEUED 任务 + - POST /internal/rag/jobs/{id}/claim → 认领 + - 启动心跳 (每 30s POST /internal/rag/jobs/{id}/heartbeat) + - run_import(): + a. DOWNLOADING: 从 COS 下载文件 + b. PARSING: parse_document(file_path, mime_type) + - PDF → PyMuPDF 文本提取 / OCR 回退 (SiliconFlow Qwen3-VL) + - DOCX → python-docx + - TXT/MD → 直接读取 + - CSV/XLSX → pandas → Markdown table + - Images → SiliconFlow Qwen3-VL OCR + c. CLEANING: (当前为占位——无实际清洗逻辑) + d. CHUNKING: 递归字符分割 (512 tokens, 64 overlap, 中文句子边界保护) + e. EMBEDDING: SiliconFlow BAAI/bge-m3 (1024维, 批次50, 重试2次) + f. INDEXING: Qdrant upsert_points + API save_chunks (KnowledgeChunk 记录) + g. GENERATING_CANDIDATES: DeepSeek deepseek-chat (temperature 0.3) 非致命步骤 + h. COMPLETED: update_job_status("COMPLETED", {progress: 100}) +9. 用户审核候选 → ImportCandidateService.accept/reject/batch-accept +10. 接受候选 → API 创建 KnowledgeItem (itemType: ai_generated) +``` + +**关键确认:** +- parseStatus/indexStatus/learningStatus 三者独立追踪,由 Python RAG Worker 在管线不同阶段更新 +- 候选生成是非致命步骤——即使失败,解析和索引仍可成功 +- 原文件在 RAG 完成前即可阅读(MaterialReaderView 直接渲染文件,不等待 RAG) +- Admin 导入监控页 (ImportMonitor.tsx) 支持查看步骤日志和重试 + +### 3.2 链路二:知识库与知识点管理 + +**基于代码的独立还原:** + +``` +数据对象关系 (Prisma Schema): +KnowledgeBase + ├── KnowledgeSource[] (1:N, 含 parseStatus/indexStatus/learningStatus) + ├── KnowledgeItem[] (1:N, 含 parentId 树状结构) + ├── KnowledgeFolder[] (1:N, 含 parentId 树状结构) + ├── KnowledgeChunk[] (1:N, 含 externalVectorId → Qdrant) + ├── ImportCandidate[] (1:N, 含 status: PENDING/ACCEPTED/REJECTED) + ├── KnowledgeBaseSubscription[] (1:N, userId+KBId 唯一约束) + └── Quiz[] (1:N) + +KnowledgeSource + ├── file: UploadedFile (1:1) + ├── items: KnowledgeItem[] (1:N, 通过 sourceId) + ├── chunks: KnowledgeChunk[] (1:N) + └── candidates: ImportCandidate[] (1:N) + +核心权限: +- KB 创建: 每用户最多 20 个 (MAX_KNOWLEDGE_BASE_COUNT) +- KB 所有权: userId 匹配校验,非所有者对私有 KB 返回 404 +- KB 删除: 仅所有者,软删除 (deletedAt) +- 知识点删除: 所有者校验,itemCount 自动维护 +- 来源资料删除: KnowledgeSourceService.remove() 无所有权检查 (代码缺陷) +- 文件夹更新/删除: updateFolder/deleteFolder 无显式所有权检查 +- 订阅: 不可订阅自己的 KB,KB 必须为公开且未删除 + +当前未实现的功能: +- "官方"知识库: ownerType 字段存在,但无实际官方 KB 创建逻辑 +- 搜索: 仅 discover 端点支持 LIKE 查询 (title/description),无全文搜索 +- 收藏: Favorite 表存在但有 iOS 端 TODO 标记 +- 重命名/移动到文件夹: iOS contextMenu action 为空 +- 知识库管理页: iOS 操作菜单按钮 action 为空 +``` + +### 3.3 链路三:AI 对话与知识库问答 + +**基于代码的独立还原(rag-chat.service.ts 逐行分析):** + +``` +五种 Scope 类型及上下文加载: + +1. global: + - 上下文: 空 (直接返回 isEmpty: true) + - 代码: loadContextByScope → case 'global' → { text: '', citations: [], isEmpty: true } + - iOS 入口: 从 AI 反馈页"深入提问"→ AIChatPage (context: nil) + +2. knowledge_base: + - 上下文: prisma.knowledgeItem.findMany({ knowledgeBaseId: kbId, deletedAt: null }) + - 查询: PostgreSQL KnowledgeItem 表 (非 Qdrant!) + - 限制: 30 条, 每条约 500 字符, 总计最多 4000 字符 + - iOS 入口: 知识库详情页底部 AI 对话按钮 + +3. material: + - 上下文: prisma.knowledgeItem.findMany({ knowledgeBaseId: kbId, sourceRef: scopeId }) + - 查询: PostgreSQL KnowledgeItem 表, 按 sourceRef 过滤 + - iOS 入口: 资料阅读页工具栏 AI 按钮 + +4. knowledge_item: + - 上下文: prisma.knowledgeItem.findMany({ id: scopeId }) + - 查询: PostgreSQL KnowledgeItem 表, 单条知识点 + - iOS 入口: 知识点详情页工具栏菜单 (代码中 scopeType=knowledge_item 存在但 iOS 入口待确认) + +5. folder: + - 上下文: prisma.knowledgeItem.findMany({ knowledgeBaseId: kbId, parentId: scopeId }) + - 查询: PostgreSQL KnowledgeItem 表, 按父文件夹过滤 + +会话机制: +- open-or-create: 相同 scopeType + scopeId + userId 复用未删除未归档会话 +- forceCreate: 跳过查找,强制创建新会话 +- ScopeSnapshot: 每条消息保存 { scopeType, scopeId, parentKnowledgeBaseId } +- Citation: 从 context.citations 前 5 个提取 (chunkId = item.id, sourceTitle, excerptText) +- 自动标题: 首次消息截取前 40 字符 + +模型调用: +- AiGateway.generate() / generateStream() +- tier: 'primary' → DeepSeek deepseek-v4-pro +- promptKey: 'rag-chat', promptVersion: 'v1' +- 流式: SSE 逐块转发 (type: 'content' | 'thinking' | 'error' | 'done') +- 无 Heavy Runtime 参与 + +内容安全: +- 输入检查: this.safety?.check(content, { contentType: 'rag_input' }) +- AI 输出: 不检查 (仅输入被检查) + +Qdrant 参与: 无。知识库范围对话的上下文完全来自 PostgreSQL KnowledgeItem 表。 +``` + +--- + +## 4. 总体结论 + +**审查结论:有条件通过** + +### 不满足"通过"的关键原因 + +| 门禁条件 | 满足? | 说明 | +|---------|--------|------| +| P0 问题为零 | **否** | 1 项 P0(见第 5 节) | +| 没有将未实现功能标记为已完成 | 是 | 文档对未完成项标记基本准确 | +| 没有错误描述项目职责 | 是 | 项目角色分配正确 | +| 没有错误描述数据流向 | 是 | 数据流描述与代码一致 | +| 没有把 RAG 作为原文件阅读前置条件 | 是 | 文档正确指出 RAG 不阻塞阅读 | +| 没有把 Heavy Runtime 默认写入基础对话链 | 是 | 文档正确指出 Heavy Runtime 不参与 | +| 上传/解析/索引/学习提取/候选审核状态已明确区分 | 是 | 五种状态分别描述 | +| 知识库/来源资料/知识点/文件夹/订阅关系清晰 | 是 | 关系描述基本准确 | +| 四类对话 Scope 的实际状态清晰 | 是 | 五种 Scope 的上下文来源均正确描述 | +| 所有暂未确认项均已明确标记 | 是 | 7 项暂未确认均已列出 | + +--- + +## 5. P0 严重问题 + +### P0-1:文档 05 声称知识库对话"不通过 Qdrant 向量搜索"——实际确认正确,但资料范围的 Qdrant 语义检索被标注为"暂未确认",而代码中明确未启用 + +- **涉及文档:** 05-AI对话与知识库问答.md 第 3.3 节 +- **文档当前描述:** "如果 Python RAG Worker 已完成向量索引,可通过 Qdrant 进行语义检索补充上下文(具体是否启用 Qdrant 取决于 API 实现,当前代码中资料范围上下文的加载方式与知识库范围类似,以 KnowledgeItem 为主)" +- **实际情况:** rag-chat.service.ts 的 `loadContextByScope` 方法中,`case 'material'` 仅查询 `prisma.knowledgeItem.findMany({ sourceRef: scopeId })`,**完全不涉及 Qdrant**。Qdrant 的 `search()` 函数虽然在 indexer.py 中已实现,但在 rag-chat.service.ts 中零引用。 +- **影响:** 文档暗示资料范围对话"可能"使用 Qdrant 语义检索,给读者造成该功能存在但不稳定的印象。实际上该功能**未被实现**——资料范围对话从不调用 Qdrant。 +- **建议修正:** 将第 3.3 节中关于 Qdrant 的描述改为明确结论:"资料范围对话的上下文**完全来自 PostgreSQL KnowledgeItem 表**,不涉及 Qdrant 向量搜索。Qdrant 语义检索已实现但**未集成到对话链路**。" +- **修正优先级:** P0 — 涉及核心数据流向描述 + +--- + +## 6. P1 主要问题 + +### P1-1:文档 03 声称"API 验证文件类型(8 种)和大小(最大 20MB)" —— files.service.ts 中未发现验证 + +- **涉及文档:** 03-资料上传与处理.md 第 5 节"主 API" +- **文档描述:** "验证文件类型(PDF/TXT/Markdown/CSV/XLSX/DOCX/PNG/JPEG/WebP)和大小(最大 20MB)" +- **实际情况:** files.service.ts 的 `requestUploadUrl()` 方法仅执行内容安全检查(文件名敏感词),未进行文件类型白名单校验或大小检查。类型/大小校验可能在 Controller 层的 DTO 或 Guard 中进行。 +- **建议修正:** 若校验确实存在(需进一步确认 DTO/Guard),补充具体位置;若不存在,修正为"暂未确认"或标注实际校验范围。 +- **修正优先级:** P1 + +### P1-2:文档 03 声称"清理"步骤在管线中执行——实际为空操作 + +- **涉及文档:** 03-资料上传与处理.md 第 3 节用户主流程 +- **文档描述:** 流程中包含"清洗"步骤 +- **实际情况:** import_pipeline.py 第 63 行 `await update_job_status(job_id, "CLEANING", ...)` 仅设置状态和进度百分比,**无任何实际文本清洗逻辑**。注释为 `# 3. 清洗` 但之后立即进入分块阶段。 +- **建议修正:** 在管线描述中标注"清洗步骤当前为占位(仅更新状态,无实际逻辑)"。 +- **修正优先级:** P1 + +### P1-3:文档 04 声称"文件夹创建时间步创建 folder 类型的 KnowledgeItem"——但更新文件夹名称时 KnowledgeItem 标题不更新 + +- **涉及文档:** 04-知识库与知识点管理.md 第 4.7 节 +- **文档描述:** 文件夹操作包括重命名 +- **实际情况:** `createFolder()` 同步创建 folder 类型的 KnowledgeItem(标题 = 文件夹名称),且 `deleteFolder()` 也同步删除 KnowledgeItem。但 `updateFolder()` 仅更新 KnowledgeFolder 记录,**不同步更新对应的 KnowledgeItem 标题**,导致重命名后文件夹和对应 KnowledgeItem 的标题不一致。 +- **建议修正:** 在文档中标注"重命名文件夹时,对应的 folder 类型 KnowledgeItem 标题不会同步更新"。 +- **修正优先级:** P1 + +### P1-4:文档 04 缺失对文件夹创建数量限制的描述 + +- **涉及文档:** 04-知识库与知识点管理.md +- **遗漏:** 代码中未发现文件夹创建数量的上限限制,也未发现每 KB 的文件夹数量限制。 +- **建议:** 标注为"文件夹创建数量无明确限制"。 +- **修正优先级:** P1 + +--- + +## 7. P2 一般问题 + +### P2-1:文档 03 中"RAG 解析失败"一节描述 PDF OCR 为"回退"——与实际代码顺序相反 + +- **文档描述:** "PDF 通过 PyMuPDF + OCR 回退" +- **实际代码 (parser.py):** PDF 先检查 `pdf_needs_ocr()` (<50 字符/页),若需要 OCR 则先用 PyMuPDF 提取文本,若结果 <100 字符才用 SiliconFlow OCR。顺序是:PyMuPDF 文本提取 → 不够则 OCR,而非"OCR 回退"。 +- **建议修正:** 改为"PDF 优先文本提取,不足时 OCR 补充"。 +- **修正优先级:** P2 + +### P2-2:文档 03 声称 Admin "RAG 调试"为"已完成"——实际为基础实现 + +- **涉及文档:** 03-资料上传与处理.md 第 11 节完成状态表 +- **文档状态:** "Admin RAG 调试 | 已完成 | 向量搜索测试" +- **实际 Admin 代码:** KnowledgeOps.tsx 的 rag-debug Tab 仅有一个搜索输入框和按钮,结果通过 `message.info()` toast 展示,无结构化表格。页面注释:"完整 RAG 管道在 M3 阶段完善"。 +- **建议修正:** 状态从"已完成"改为"部分完成",备注"基础 UI 可用,结果展示为 toast 而非结构化表格"。 +- **修正优先级:** P2 + +### P2-3:文档 05 中 Qdrant 和 Python RAG Worker 的角色描述在两个文档中略有差异 + +- **文档 03 描述:** Python RAG Worker 是"主链路参与者" +- **文档 05 描述:** Python RAG Worker 是"上游支撑(间接参与)" +- **分析:** 从单个文档看均正确——文档 03 中 Worker 确为主链路(上传处理必须经过它),文档 05 中 Worker 为支撑(对话不依赖它)。但读者跨文档阅读时可能困惑。 +- **建议:** 在文档 06 项目矩阵中已正确区分两场景的角色。无需修改正文,但建议在 05 文档中增加一句"Worker 在对话链路中的角色与在上传链路中不同"。 +- **修正优先级:** P2 + +### P2-4:文档 04 中"API 知识库数量限制"的实际值是硬编码的 + +- **文档描述:** "每用户最多 20 个" +- **代码验证:** `MAX_KNOWLEDGE_BASE_COUNT` 从 constants 文件导入,其值未在当前打开的代码中显示,但文档声称 20 与 iOS 早期审查发现一致。 +- **建议:** 准确。无需修改。 +- **修正优先级:** 无需修正 + +--- + +## 8. 遗漏项 + +### 8.1 遗漏入口 + +无重大遗漏。文档 03 的 C 端入口表覆盖了 iOS 所有上传入口。 + +### 8.2 遗漏功能 + +| 遗漏项 | 应出现在 | 说明 | +|--------|---------|------| +| KnowledgeSourceService.triggerParse() | 03 文档第 8 节"系统自动修改"或第 9 节"修改入口" | 该端点支持管理员触发重新解析,文档在 Admin 操作中提到了"触发重新解析"但未描述其具体实现(创建新 DocumentImport 并入队) | +| ChatSession.knowledgeItemIds 字段 | 05 文档第 7.1 节 | Prisma 中 ChatSession 有 knowledgeItemIds Json? 字段(默认 []),但 rag-chat.service.ts 中使用 knowledgeItemIds 的实际行为未在文档中描述 | +| Folder scope 对话 | 05 文档第 3 节 | 代码中明确支持 scopeType='folder',但文档仅提了 4 种 scope(global/knowledge_base/material/knowledge_item),遗漏了 folder | + +### 8.3 遗漏业务对象 + +| 遗漏对象 | 说明 | +|---------|------| +| SourceReference | Prisma 中定义的 SourceReference 模型(关联 KnowledgeSource/KnowledgeChunk,追踪 AI 产物引用来源),Admin 中有引用追踪功能,但文档 03 第 7 节数据对象清单中遗漏 | + +### 8.4 遗漏异常恢复 + +| 遗漏场景 | 应出现在 | 说明 | +|---------|---------|------| +| Worker 心跳超时后任务回收的具体机制 | 03 文档第 10.5 节 | 文档提到"心跳超过 5 分钟的 CLAIMED 任务被重置为 QUEUED",但未描述哪个组件执行此回收(API 定时任务?Worker 自身?) | + +--- + +## 9. 错误项 + +### 9.1 文档 03 第 10.6 节"RAG 解析失败"描述 + +- **文档描述:** "Worker 处理:解析阶段失败 → 任务标记 FAILED" +- **实际代码:** import_pipeline.py 中异常捕获后调用 `update_job_status(job_id, "FAILED_RETRYABLE", ...)`,不是 "FAILED"(无后缀)。状态字符串的差异可能影响重试逻辑。 +- **建议修正:** 将文档中的 "FAILED" 改为 "FAILED_RETRYABLE",或统一描述为"失败(可重试)"。 + +### 9.2 文档 05 第 3.4 节"知识点范围"描述 + +- **文档描述:** 关联页面中有"知识点详情页 → 工具栏菜单(如有)" +- **实际代码:** KnowledgeDetailPage 的工具栏菜单在 `vm.detectedType` 存在且 previewMode 为 nativeReader 或 platformPreview 时才显示,且菜单中仅有"笔记"和"预览"选项,**未发现直接跳转到 AI 对话页的入口**。知识点范围的 AI 对话入口在 iOS 端可能不存在。 +- **建议修正:** 将"知识点详情页"从 C 端入口表中移除,或将 iOS 入口标记为"暂未确认"。 + +--- + +## 10. 跨文档冲突 + +### 冲突 1:导入任务状态命名 + +| 文档 | 状态描述 | 实际代码 | +|------|---------|---------| +| 03 第 4.2 节 | 文本解析状态 "pending → processing → complete/failed" | parseStatus 的可能值为 "pending"(默认),但 Worker 不更新 parseStatus,仅更新 job status 为 "PARSING" | +| 03 第 4.3 节 | 向量索引状态 "pending → processing → complete/failed" | 同样,indexStatus 为 KnowledgeSource 字段,默认 "pending",Worker 不直接更新它 | + +**分析:** 文档描述的状态流转(pending → processing → complete/failed)是设计意图,但 Python RAG Worker 代码中只通过 `update_job_status()` 更新 Redis 状态,KnowledgeSource 的三个状态字段(parseStatus/indexStatus/learningStatus)的更新逻辑在 API 内部的 `/internal/rag/jobs/{id}/status` 处理中——该端点代码未在本轮审查中阅读。 + +**建议:** 标注为"暂未确认 — KnowledgeSource 状态字段的更新逻辑在 API 内部端点中,需进一步检查 `/internal/rag/jobs/{id}/status` 的处理代码"。 + +### 冲突 2:Admin 角色描述 + +| 文档 | 描述 | +|------|------| +| 03 第 5 节 | Admin 标注为"运维与可观测" | +| 05 第 5 节 | Admin 标注为"运维与可观测" | +| 06 项目矩阵 | Admin 全部标注为"运维可观测" | + +**分析:** 一致,无冲突。 + +### 冲突 3:无其他关键冲突 + +经逐项比对,03/04/05/06 四份文档之间无其他关键冲突。同一项目职责在不同文档中的描述基本一致,同一业务对象名称一致,同一能力的完成状态标记一致。 + +--- + +## 11. 暂未确认项 + +| 序号 | 内容 | 原因 | 后续需检查 | +|------|------|------|-----------| +| U01 | API 文件类型/大小校验的具体位置 | files.service.ts 中未发现,可能在 DTO/Guard/Pipe 层 | files.controller.ts 和 DTO 定义 | +| U02 | KnowledgeSource 三个状态字段的实际更新逻辑 | Python RAG Worker 通过 `/internal/rag/jobs/{id}/status` 更新,但该端点的处理代码未阅读 | API 内部 RAG job status 处理端点 | +| U03 | 导入任务自动重试(最多 3 次)的实际实现 | 文档声称 API 自动重试,但 Worker 仅标记 FAILED_RETRYABLE,重试调度逻辑的位置未确认 | API 的 job 重试调度逻辑 | +| U04 | 孤儿文件自动清理 (file-cleanup) 的实际执行策略 | file-cleanup.processor.ts 文件存在,但未阅读 | file-cleanup.processor.ts 的具体实现 | +| U05 | 处理中删除源时 Worker 是否检查软删除标志 | 文档标注为"暂未确认" | Python RAG Worker 在处理前是否查询 source 的 deletedAt | +| U06 | 用户自定义 API Key 在对话中的实际使用 | 文档 05 声称支持用户自定义 DeepSeek Key,AiGateway 代码未阅读 | AiGateway 的 credential 选择逻辑 | +| U07 | 流式响应中断时已生成部分内容的保存行为 | rag-chat.service.ts 的 sendMessageStream 在 fullContent 非空时才保存,中断时机影响是否保存 | 需实际测试 | + +--- + +## 12. 完成度调整建议 + +| 业务能力或子能力 | 文档当前状态 | 审查建议状态 | 调整原因 | +|----------------|------------|------------|---------| +| 资料范围 Qdrant 语义检索 | 暂未确认 (05) | 未完成 | rag-chat.service.ts 完全不调用 Qdrant | +| Admin RAG 调试 | 已完成 (03) | 部分完成 | UI 为基础实现,结果显示为 toast,代码注释"完整 RAG 管道在 M3 阶段完善" | +| 文本清洗步骤 | 已完成 (03 隐含) | 占位实现 | import_pipeline.py 中 CLEANING 状态后无实际逻辑 | +| 文件夹 Scope 对话 | 未提及 (05) | 已完成 | rag-chat.service.ts 中 folder case 已完整实现 | +| 知识点范围对话 iOS 入口 | 暂未确认 (05) | 未完成 | iOS KnowledgeDetailPage 工具栏未发现 AI 对话入口 | +| API 文件类型校验 | 已完成 (03) | 暂未确认 | files.service.ts 中未发现校验逻辑 | +| SourceReference 数据对象 | 遗漏 (03 第 7 节) | 已存在 | Prisma 中已定义,Admin 中有引用追踪功能 | +| Python RAG Worker 在对话中的角色 | 间接参与 (05) | 准确 | 不直接参与对话流程 | + +--- + +## 13. 文档修正清单 + +### 03-资料上传与处理.md + +| 章节 | 当前内容 | 修正方向 | +|------|---------|---------| +| 第 3 节流程 | "清洗"步骤 | 标注"清洗步骤当前为占位(无实际逻辑)" | +| 第 5 节主 API | "验证文件类型(8 种)和大小(最大 20MB)" | 若未找到校验位置,改为暂未确认 | +| 第 7.4 节 | 数据对象清单遗漏 SourceReference | 补充 SourceReference 对象描述 | +| 第 10.6 节 | "任务标记 FAILED" | 改为 "FAILED_RETRYABLE" | +| 第 10.2 节 | "PyMuPDF + OCR 回退" | 改为 "PyMuPDF 文本提取优先,不足时 OCR 补充" | +| 第 11 节状态表 | Admin RAG 调试 = 已完成 | 改为"部分完成",备注基础 UI | +| 第 11 节 | 孤儿文件清理 = 暂未确认 | 保持,但补充 file-cleanup.processor.ts 引用 | +| 第 11 节 | 处理中删除源 = 暂未确认 | 保持 | + +### 04-知识库与知识点管理.md + +| 章节 | 当前内容 | 修正方向 | +|------|---------|---------| +| 第 4.7 节 | 文件夹重命名 | 补充"重命名文件夹时,对应 folder 类型 KnowledgeItem 标题不同步更新" | +| 第 3 节业务对象关系 | Folder → 同步创建 folder 类型 KnowledgeItem | 补充 updateFolder 不同步的说明 | +| 第 10 节状态表 | 来源资料删除权限 = 暂未确认 | 确认为"存在缺陷——无所有权检查" | + +### 05-AI对话与知识库问答.md + +| 章节 | 当前内容 | 修正方向 | +|------|---------|---------| +| 第 2 节 C 端入口 | 知识点详情页 → 工具栏菜单 | 移除或标记为暂未确认(iOS 端未发现入口) | +| 第 3 节对话范围 | 仅列 4 种 scope | 补充 folder scope(代码已实现) | +| 第 3.3 节资料范围 | Qdrant 语义检索"可能"使用 | 明确改为"不使用 Qdrant——上下文完全来自 PostgreSQL KnowledgeItem 表" | +| 第 10 节状态表 | Qdrant 语义检索 = 暂未确认 | 改为"未完成——Qdrant 向量搜索未集成到对话链路" | + +### 06-内容与对话项目矩阵.md + +| 章节 | 当前内容 | 修正方向 | +|------|---------|---------| +| 三、Qdrant 行"资料范围语义检索时使用" | "资料范围语义检索时使用" | 与文档 05 保持一致——标注为"未启用" | + +--- + +## 14. 审查门禁结果 + +| 门禁条件 | 结果 | 说明 | +|---------|------|------| +| 三条业务链路已独立还原 | 满足 | 逐链路从代码验证 | +| 所有相关仓库已检查 | 满足 | iOS、API、Python RAG Worker、Admin、Prisma Schema、COS、Qdrant 均已检查 | +| 页面和调用入口已检查 | 满足 | iOS 全部入口 + API 全部端点 | +| API 和异步任务已检查 | 满足 | REST API + Queue + Python Worker 管线 | +| 数据对象关系已检查 | 满足 | Prisma Schema 全部 120+ 模型关系 | +| 权限与删除影响已检查 | 满足 | 软删除级联行为、所有权校验 | +| 异常与恢复已检查 | 满足 | 上传失败、Worker 失败、RAG 未完成、模型调用失败等 | +| Admin 查询和操作入口已检查 | 满足 | 40+ Admin 页面全部盘点 | +| 双向覆盖检查已完成 | 满足 | 文档→代码 + 代码→文档 | +| 跨文档一致性检查已完成 | 满足 | 4 份文档逐项比对 | +| P0 问题为零 | **不满足** | 1 项 P0:文档 05 资料范围 Qdrant 语义检索状态描述不准确 | +| 未确认项已明确记录 | 满足 | 7 项暂未确认均已列出 | + +--- + +## 15. 是否可以进入下一阶段 + +### 结论:可以进入下一阶段(AI 学习分析、主动回忆、题目与复习能力整理),但建议先完成 1 项 P0 修正。 + +**P0 阻塞项:** 文档 05 关于资料范围 Qdrant 语义检索的描述需修正——代码中 rag-chat.service.ts 完全不调用 Qdrant,文档暗示"可能启用"会造成误解。 + +**P1 问题(4 项)不阻塞下一阶段:** +1. API 文件类型/大小校验位置待确认 +2. 文本清洗步骤为空操作 +3. 文件夹重命名不同步 KnowledgeItem 标题 +4. 文件夹创建数量无限制 + +**P2 问题(4 项)不阻塞:** 命名修正和细节补充可在后续阶段一并处理。 + +**当前文档的整体可靠性评价:** +- 三条业务链路的主流程描述与代码一致 +- 项目职责分配正确(Rust Document Runtime 和 Heavy Runtime 的角色描述准确) +- 数据对象关系基本正确 +- 完成状态标记在核心链路上准确,边缘功能有少量偏差 +- 跨文档一致性良好,无关键矛盾