From 10a464eea4907ece9f0349e36e3116de4e589d77 Mon Sep 17 00:00:00 2001 From: wonder Date: Wed, 2 Sep 2026 19:10:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Topic-SubTopic=20?= =?UTF-8?q?=E5=B1=82=E7=BA=A7=E7=BB=93=E6=9E=84=E4=B8=8E=20Accordion=20?= =?UTF-8?q?=E4=BE=A7=E8=BE=B9=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - topics/index.json 重构为嵌套模型(topic → subtopics) - 侧边栏改为 Accordion 交互:默认折叠、同时只展开一个 - 展开/折叠状态通过 localStorage 持久化 - 更新架构文档同步数据模型变更 Co-Authored-By: Claude Code --- docs/architecture.md | 61 ++++++++++++-------- index.html | 121 +++++++++++++++++++++++++++------------ topics/index.json | 133 +++++++++++++++++++++++-------------------- 3 files changed, 191 insertions(+), 124 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 07bdcf3..586a288 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -77,20 +77,29 @@ examination/ "updated": "2026-09-02", "topics": [ { - "slug": "gc-jvm", - "name": "GC / JVM / 三色标记", - "description": "...", - "path": "topics/gc-jvm", - "stats": { - "total": 20, - "by_type": { "fill_blank": 10, "single_choice": 10 } - } + "slug": "qunar-ai-fullstack", + "name": "去哪儿 AI 面 — AI 全栈方向", + "description": "覆盖 JVM/GC、AI Agent 架构、工具链、幻觉治理等核心考察领域", + "subtopics": [ + { + "slug": "gc-jvm", + "name": "GC / JVM / 三色标记", + "description": "...", + "path": "topics/gc-jvm", + "stats": { "total": 20, "by_type": { "fill_blank": 10, "single_choice": 10 } } + } + ] } ] } ``` -前端加载此文件渲染主题列表,`stats` 字段用于展示题目数量。 +- `topics[]` — 顶层主题列表,每个主题是一个手风琴(Accordion)分区 + - `slug` / `name` / `description` — 主题标识与展示信息 + - `subtopics[]` — 子主题列表,隶属于该顶层主题 + - `path` — 子主题数据目录路径 + - `stats` — 题目数量统计 +- 前端以 Accordion 形式渲染:默认全部折叠,同时只展开一个 ### 3.2 主题元信息 — `topics/{slug}/meta.json` @@ -240,19 +249,20 @@ examination/ ├────────────┬─────────────────────────────┤ │ Sidebar │ Main Content │ │ │ │ -│ 📚 主题 │ ┌─ Tabs ─────────────────┐ │ -│ · gc-jvm │ │ 全部 | 填空 | 选择 |.. │ │ -│ · ai-so │ └────────────────────────┘ │ -│ · ai-mm │ ┌─ Toolbar ──────────────┐ │ -│ · ai-he │ │ 重置 全部显示 提交全部 │ │ -│ · ai-at │ └────────────────────────┘ │ +│ ▼ 去哪儿.. │ ┌─ Tabs ─────────────────┐ │ +│ · gc-jvm │ │ 全部 | 填空 | 选择 |.. │ │ +│ · ai-so │ └────────────────────────┘ │ +│ · ai-mm │ ┌─ Toolbar ──────────────┐ │ +│ ▶ 其他主题 │ │ 重置 全部显示 提交全部 │ │ +│ │ └────────────────────────┘ │ │ │ ┌─ Question Card ────────┐ │ -│ ──────── │ │ #1 ★★★ │ │ -│ 📥 导入 │ │ 题干 [____] │ │ +│ ──────── │ │ #1 ★★★ │ │ +│ 📥 导入 │ │ 题干 [____] │ │ │ │ │ [检查] [显示答案] │ │ │ │ │ 💡 解析... │ │ │ │ └────────────────────────┘ │ └────────────┴─────────────────────────────┘ + ▼ = 展开中 ▶ = 折叠中(Accordion 模式) ``` ### 4.2 数据流 @@ -261,9 +271,9 @@ examination/ 页面加载 │ ▼ -fetch topics/index.json ──→ 渲染侧边栏主题列表 +fetch topics/index.json ──→ 渲染侧边栏 Accordion(默认全折叠) │ - │ 用户点击主题 + │ 用户展开某主题 + 点击子主题 ▼ fetch topics/{slug}/meta.json ──→ 获取 question_files 列表 │ @@ -289,12 +299,13 @@ const QUESTION_TYPES = { }; // 应用状态 -let topics = []; // 从 index.json 加载的主题列表 -let currentTopic = null; // 当前选中的主题 slug -let currentQuestions = []; // 当前主题的所有题目(合并自多个题型文件) -let answers = {}; // qId → { value, correct, revealed } -let customQuestions = []; // 通过导入功能临时添加的题目 -let activeTab = 'all'; // 当前 Tab:'all' 或题型名称 +let topicGroups = []; // 顶层主题列表(含 subtopics) +let expandedGroup = null; // 当前展开的顶层主题 slug(Accordion) +let currentTopic = null; // 当前选中的子主题 slug +let currentQuestions = []; // 当前子主题的所有题目 +let answers = {}; // qId → { value, correct, revealed } +let customQuestions = []; // 通过导入功能临时添加的题目 +let activeTab = 'all'; // 当前 Tab:'all' 或题型名称 ``` ### 4.4 题型配置与渲染 diff --git a/index.html b/index.html index b53a84b..cec7f9f 100644 --- a/index.html +++ b/index.html @@ -47,8 +47,20 @@ body { font-family: -apple-system, 'Segoe UI', sans-serif; background: var(--bg) /* Sidebar */ .sidebar-title { font-size: 13px; color: var(--text2); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 12px; padding: 0 8px; } -.topic-list { list-style: none; } -.topic-item { padding: 12px 16px; border-radius: 8px; cursor: pointer; transition: all 0.2s; margin-bottom: 4px; } + +/* Accordion */ +.accordion-section { margin-bottom: 4px; } +.accordion-header { padding: 10px 12px; cursor: pointer; user-select: none; border-radius: 8px; transition: background 0.2s; display: flex; align-items: center; gap: 8px; } +.accordion-header:hover { background: var(--surface2); } +.accordion-header .accordion-info { flex: 1; min-width: 0; } +.accordion-header .accordion-name { font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.accordion-header .accordion-desc { font-size: 11px; color: var(--text2); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.accordion-header .accordion-chevron { font-size: 11px; color: var(--text2); transition: transform 0.2s; flex-shrink: 0; } +.accordion-section.expanded .accordion-chevron { transform: rotate(180deg); } +.accordion-body { list-style: none; overflow: hidden; max-height: 0; opacity: 0; transition: max-height 0.25s ease, opacity 0.2s ease; } +.accordion-section.expanded .accordion-body { max-height: 2000px; opacity: 1; } +.accordion-body .topic-item { padding: 10px 12px 10px 24px; } +.topic-item { padding: 10px 12px; border-radius: 8px; cursor: pointer; transition: all 0.2s; margin-bottom: 2px; } .topic-item:hover { background: var(--surface2); } .topic-item.active { background: var(--accent); color: white; } .topic-item .topic-name { font-size: 14px; font-weight: 600; } @@ -170,8 +182,7 @@ body { font-family: -apple-system, 'Segoe UI', sans-serif; background: var(--bg)