panatgithub_AnkiHeadingSync/docs/settings-page-cardization-gap-report.md
Dusk 0fdf9c8ef3 重构设置页为五卡片并统一识别配置 / Cardize settings page and unify recognition config
重构设置页采用五个卡片外壳,提升布局稳定性和局部刷新体验;通过 cardTypeConfigs 驱动各卡片的识别配置,并完成初步的功能测试与验证。 / Refactored settings page into five cards for better stability and partial refresh; unified recognition configurations via cardTypeConfigs with initial testing and verification.
2026-04-24 12:12:10 +08:00

144 lines
No EOL
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设置页卡片化差距审计
本文以本轮“设置页卡片化 + 局部刷新 + 设置驱动卡片识别配置”任务合同为唯一验收基准,对当前仓库做真实实现审计。
## 1. 当前设置页仍是单入口整页重建
- 设置页入口位于 `src/presentation/settings/PluginSettingTab.ts`
- `display()` 里直接执行 `containerEl.empty()`,随后把所有设置项重新创建。
- 多个普通交互会再次调用 `this.display()`,包括:
- 语义 QA 标记变更
- note type 切换
- Anki 字段加载
- 字段映射保存
- 文件级 deck 开关
- 范围模式切换
- 文件夹树勾选
- 文件夹树展开/收起
- 这与“稳定卡片外壳 + 卡片内部局部刷新”的任务目标直接冲突,也是当前页面跳动和滚动漂移的根因。
## 2. 现有 UI 结构与目标 5 卡片结构不一致
- 当前设置页是按顺序平铺的 imperative render没有稳定分区壳层。
- 不存在折叠卡片,也没有设置页实例级展开状态。
- deck、scope、mapping、semantic preview 等内容都混在一个 `display()` 流程里。
- 不满足“5 张可折叠卡片、默认展开 1/5、默认折叠 2/3/4”的要求。
## 3. 第一张卡片的数据模型还没有成为识别真源
- 当前设置模型只保留旧的离散字段:
- `qaHeadingLevel`
- `clozeHeadingLevel`
- `qaGroupMarker`
- `semanticQaMarker`
- `qaNoteType`
- `clozeNoteType`
- `semanticQaNoteType`
- `noteFieldMappings`
- 运行时识别入口仍是 `src/domain/manual-sync/services/CardIndexingService.ts`
- 先按 `qaHeadingLevel/clozeHeadingLevel` 把标题判成 `basic/cloze`
- 再仅在 `basic` 分支内部,用 `qaGroupMarker/semanticQaMarker` 特判 QA Group 与 Semantic QA
- 当前不存在统一的“4 行配置 -> 识别匹配规则 -> 运行时类型”的结构。
- 因此即便只改 UI也无法让表格真正驱动同步识别。
## 4. 当前识别规则不足以支持新任务合同
- `CardIndexingService` 只支持:
- 一个 QA/basic 标题级别
- 一个 cloze 标题级别
- basic 上的两个 marker 分流
- 当前不支持:
- `enabled` 控制识别开关
- 同一标题级别下多行配置的优先级匹配
- 同级默认行(空 extra marker回退
- 保存时检测“同级多个启用默认行”并阻止保存
- 现有 `validatePluginSettings()` 还显式禁止 `qaHeadingLevel === clozeHeadingLevel`,这与新合同允许同级依赖 extra marker 分流的方向冲突。
## 5. 现有字段映射能力可复用,但需要换接入方式
- `noteFieldMappings`、`NoteFieldMappingService`、Anki note model 读取接口、字段详情读取接口都已存在,可复用。
- 但当前 UI 采用“每个 section 单独选择 note type、单独读取字段、再单独点保存映射”的流程。
- 这与新的直接编辑表格、自动保存、按需 debounce 保存不一致。
- QA Group 12 已经有独立的托管模型链路:
- `QaGroupModelDefinition`
- `QaGroupSyncService`
- 这说明 QA Group 行不应该被硬塞进普通 `noteFieldMappings` 保存流程;该行应显示为托管模型/托管字段。
## 6. 第二、三、四张卡片已有局部能力基础,但刷新策略不对
- “同步内容”相关设置已经存在,但散落在整页 render 中。
- 范围设置已经具备:
- `scopeMode`
- 文件夹树纯函数
- lazy load
- 缓存字段 `folderTree` / `hasLoadedFolderTree` / `folderTreeLoadPromise`
- deck 设置已经具备完整字段和按钮能力。
- 但 scope、deck 的普通交互仍回到整页 `display()`,所以已有能力还没有被组织成局部刷新架构。
## 7. 文件夹树缓存已存在,但缺少局部刷新按钮
- 当前文件夹树只在 `scopeMode !== all` 时触发加载。
- 已有缓存字段能支撑“按展开时加载”和“重复打开不重复遍历”。
- 但没有局部“刷新文件夹列表”入口。
- 加载完成后仍调用整页 `display()`,不满足“只刷新 card 3 / tree region”的目标。
## 8. Anki 模板加载路径存在,但还是 section 级旧交互
- 当前已有:
- `listNoteModels()`
- `getNoteModelDetails(modelName)`
- 但交互仍是:先刷新 note types再按 section 读取字段。
- 新合同要求 card 1 提供一个统一按钮,一次刷新模板列表,并补齐当前表格已选模板的字段选项。
- 当前状态字段 `availableNoteModels`、`loadedModelDetails`、`draftMappings` 可部分复用,但需要调整成表格行驱动。
## 9. 迁移链路尚未实现
- `mergePluginSettings()` 目前只做默认值合并,不会从旧字段构建新识别配置。
- `normalizePluginSettings()` 当前只处理 backlink label 标准化。
- `DataJsonPluginConfigRepository.load()` / `save()` 会依赖 `mergePluginSettings()``validatePluginSettings()`,所以迁移和兼容必须落在设置模型层,而不是仅在 UI 层补丁。
## 10. 现有测试缺口
- 设置页测试目前主要覆盖:
- note type / field mapping
- scope tree 交互
- deck 开关
- 还没有覆盖:
- 5 卡片结构
- 默认展开状态
- 表格直编 + debounce 自动保存
- 普通交互不触发整页重建
- 新识别规则与冲突阻止保存
- 旧设置迁移到新识别结构后行为保持不变
## 11. 可复用与必须替换
可复用:
- `noteFieldMappings``NoteFieldMappingService`
- `listNoteModels()` / `getNoteModelDetails()`
- QA Group 托管模型链路
- scope tree 纯函数与缓存字段
- deck 设置字段与插入模板能力
- `PluginSettingTab` 现有各段业务渲染逻辑中的具体设置项语义
必须替换或重组:
- `PluginSettingTab.display()` 的整页重建模式
- 运行时基于旧离散字段的识别分派方式
- 设置模型里缺失的新识别配置与迁移逻辑
- 设置页测试夹具中无法表达“局部清空/局部重绘”的部分
## 12. 结论
当前仓库具备完成本任务的大部分业务能力,但缺少三个关键骨架:
1. 稳定卡片壳层与局部 render 机制
2. 新的卡片识别配置模型及其向旧字段的兼容迁移
3. 让运行时识别直接消费新配置的匹配逻辑
因此本轮实现应聚焦于:
- 先在设置模型层建立新配置与迁移
- 再改运行时识别入口
- 最后将设置页重组为 5 张稳定卡片并接入局部刷新