# 架构文档 ## 1. 系统总览 ``` ┌─────────────────────────────────────────────────────┐ │ 用户浏览器 │ │ ┌───────────────────────────────────────────────┐ │ │ │ index.html (单文件 SPA) │ │ │ │ ┌─────────┐ ┌──────────┐ ┌─────────────┐ │ │ │ │ │ 导航栏 │ │ 做题区域 │ │ 导入模态框 │ │ │ │ │ │ │ │ [复制题目]│ │ [提示词模板] │ │ │ │ │ └────┬────┘ └─────┬────┘ └──────┬──────┘ │ │ │ └───────┼─────────────┼──────────────┼──────────┘ │ └──────────┼─────────────┼──────────────┼─────────────┘ │ fetch │ fetch │ JSON.parse ▼ ▼ ▼ ┌─────────────────────────────────────────────────────┐ │ topics/ (数据层) │ │ ├── index.json ← 主题索引 │ │ └── {topic-slug}/ │ │ ├── meta.json ← 主题元信息(稳定) │ │ ├── fill_blank.json ← 填空题集 │ │ └── single_choice.json ← 单选题集 │ └─────────────────────────────────────────────────────┘ ▲ │ git push / pull ▼ ┌─────────────────────────────────────────────────────┐ │ Agent / LLM (生成层) │ │ ├── Claude Code Skill (generate / validate) │ │ ├── LLM + 提示词模板 (schema/prompt-template.md) │ │ └── JSON Schema 校验 (schema/question.schema.json) │ └─────────────────────────────────────────────────────┘ ``` ## 2. 目录结构 ``` examination/ ├── index.html # 前端入口(单文件 SPA) ├── topics/ # 题目数据 │ ├── index.json # 主题索引 │ └── {topic-slug}/ # 主题目录 │ ├── meta.json # 主题元信息 │ ├── fill_blank.json # 填空题 │ ├── single_choice.json # 单选题 │ ├── multiple_choice.json # 多选题(可选) │ ├── true_false.json # 判断题(可选) │ ├── short_answer.json # 简答题(可选) │ ├── code_reading.json # 代码阅读题(可选) │ └── scenario.json # 场景分析题(可选) ├── schema/ # Schema 与模板 │ ├── question.schema.json # 题目 JSON Schema(Draft-07) │ ├── prompt-template.md # LLM 生成提示词模板 │ └── templates/ # 各题型示例 │ ├── single_choice.json │ ├── multiple_choice.json │ ├── true_false.json │ ├── fill_blank.json │ ├── short_answer.json │ ├── code_reading.json │ └── scenario.json ├── docs/ # 文档 │ ├── requirements.md # 需求文档 │ └── architecture.md # 架构文档(本文件) ├── .gitignore # 排除 .ref/ └── README.md ``` ## 3. 数据模型 ### 3.1 主题索引 — `topics/index.json` ```json { "version": "1.0.0", "updated": "2026-09-02", "topics": [ { "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 } } } ] } ] } ``` - `topics[]` — 顶层主题列表,每个主题是一个手风琴(Accordion)分区 - `slug` / `name` / `description` — 主题标识与展示信息 - `subtopics[]` — 子主题列表,隶属于该顶层主题 - `path` — 子主题数据目录路径 - `stats` — 题目数量统计 - 前端以 Accordion 形式渲染:默认全部折叠,同时只展开一个 ### 3.2 主题元信息 — `topics/{slug}/meta.json` ```json { "slug": "gc-jvm", "name": "GC / JVM / 三色标记", "description": "JVM 堆内存模型、GC 算法、三色标记法、垃圾收集器", "tags": ["jvm", "gc", "heap"], "difficulty_range": [1, 5], "schema_version": "1.0.0", "question_files": ["fill_blank", "single_choice"], "stats": { "total": 20, "by_type": { "fill_blank": 10, "single_choice": 10 } } } ``` - `question_files` 列出该主题包含的题型文件名(不含 `.json` 后缀) - 前端根据此列表动态加载对应的题目文件 - `stats` 在每次生成/追加题目后由 Agent 更新 ### 3.3 题目文件 — `topics/{slug}/{type}.json` ```json { "topic": "gc-jvm", "type": "fill_blank", "schema_version": "1.0.0", "generated": "2026-09-02T00:00:00Z", "questions": [ /* 题目数组 */ ] } ``` 每种题型一个文件,支持多 Agent 并行写入不同题型文件而无冲突。 ### 3.4 题目对象 #### 公共字段(所有题型必有) | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `id` | string | ✅ | 格式 `{type_short}-{seq}`,如 `fb-001` | | `type` | enum | ✅ | 题型标识 | | `difficulty` | integer | ✅ | 1-5 | | `tags` | string[] | ✅ | 细粒度知识点标签 | | `question` | string | ✅ | 题干 | | `explanation` | string | ✅ | 解析 | | `source` | string | ❌ | 来源 | | `related` | string[] | ❌ | 关联题目 id | #### 填空题 (`fill_blank`) ```json { "answer": ["老", "Old"], "answer_rule": "any" } ``` - `answer`: string[],可接受的答案列表 - `answer_rule`: `"any"`(任一匹配) | `"all"`(全部匹配) | `"ordered"`(按序匹配) #### 单选题 (`single_choice`) ```json { "options": { "A": "选项A", "B": "选项B", "C": "选项C", "D": "选项D" }, "answer": "B" } ``` #### 多选题 (`multiple_choice`) ```json { "options": { "A": "...", "B": "...", "C": "...", "D": "..." }, "answer": ["A", "C"] } ``` #### 判断题 (`true_false`) ```json { "answer": true } ``` #### 简答题 (`short_answer`) ```json { "answer": "参考答案文本", "keywords": ["关键词1", "关键词2"], "scoring_rubric": "评分标准说明" } ``` #### 代码阅读题 (`code_reading`) ```json { "code": "int x = 1;\nprintf(\"%d\", x);", "language": "c", "sub_questions": [ { "index": 1, "type": "single_choice", "question": "...", "options": {...}, "answer": "A", "explanation": "..." } ] } ``` #### 场景分析题 (`scenario`) ```json { "context": "一个电商系统在高峰期出现超卖问题...", "code": null, "sub_questions": [ { "index": 1, "type": "short_answer", "question": "...", "answer": "...", "keywords": [...], "explanation": "..." } ] } ``` ### 3.5 ID 编码规则 ``` {type_short}-{sequence} fb - 001 ``` | type_short | 题型 | |------------|------| | `sc` | single_choice | | `mc` | multiple_choice | | `tf` | true_false | | `fb` | fill_blank | | `sa` | short_answer | | `cr` | code_reading | | `sn` | scenario | ## 4. 前端架构 ### 4.1 页面结构 ``` ┌──────────────────────────────────────────┐ │ Header: 🎯 CS 知识应试强化 [🌙/☀️] │ ├────────────┬─────────────────────────────┤ │ Sidebar │ Main Content │ │ │ │ │ ▼ 去哪儿.. │ ┌─ Tabs ─────────────────┐ │ │ · gc-jvm │ │ 全部 | 填空 | 选择 |.. │ │ │ · ai-so │ └────────────────────────┘ │ │ · ai-mm │ ┌─ Toolbar ──────────────┐ │ │ ▶ 其他主题 │ │ 重置 全部显示 提交全部 │ │ │ │ └────────────────────────┘ │ │ │ ┌─ Question Card ────────┐ │ │ ──────── │ │ #1 [📋复制] ★★★ │ │ │ 📥 导入 │ │ 题干 [____] │ │ │ │ │ [检查] [显示答案] │ │ │ │ │ 💡 解析... │ │ │ │ └────────────────────────┘ │ └────────────┴─────────────────────────────┘ ▼ = 展开中 ▶ = 折叠中(Accordion 模式) ``` ### 4.2 数据流 ``` 页面加载 │ ▼ fetch topics/index.json ──→ 渲染侧边栏 Accordion(默认全折叠) │ │ 用户展开某主题 + 点击子主题 ▼ fetch topics/{slug}/meta.json ──→ 获取 question_files 列表 │ ▼ fetch topics/{slug}/{type}.json (并行) ──→ 合并 questions 数组 │ ▼ renderQuiz() ──→ 渲染 Tab 栏 + 按当前 Tab 过滤题目卡片 │ │ 用户交互(选择/输入/检查/显示答案/切换 Tab/复制题目) ▼ answers / activeTab 状态更新 ──→ re-render 复制题目流程: 用户点击 [📋 复制题目] ──→ copyQuestionPrompt(qId) ──→ 按题型组织提示词(题干 + 选项/代码/子问题) ──→ navigator.clipboard.writeText() ──→ 按钮变为 ✅ 已复制 导入提示词流程: 用户打开导入弹窗 ──→ 点击 [📋 复制 AI 生成提示词] ──→ 选择题型 ──→ 预览提示词模板 ──→ 复制到剪贴板 ──→ 粘贴到外部 AI ──→ 获取 JSON ──→ 粘贴回导入框 ``` ### 4.3 状态管理 ```javascript // 题型配置(常量) const QUESTION_TYPES = { fill_blank: { label: '填空', color: '--type-fill_blank' }, single_choice: { label: '选择', color: '--type-single_choice' }, // ... }; // 应用状态 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 题型配置与渲染 题型颜色通过 CSS 变量定义在 `:root` 中,新增题型只需: 1. 在 `QUESTION_TYPES` 添加配置 2. 在 `:root` 添加 `--type-{name}` 变量 3. CSS 自动生效(通过 `.q-card.type-{name}` 规则) | 题型 | 渲染方式 | 判定逻辑 | 边框颜色变量 | |------|----------|----------|--------------| | fill_blank | 题干中的 `______` 替换为 `` | `matchFillAnswer()` 根据 `answer_rule` 匹配 | `--type-fill_blank` | | single_choice | 选项列表,radio 样式 | `value === answer` | `--type-single_choice` | | multiple_choice | 选项列表,checkbox 样式 | 数组比较 | `--type-multiple_choice` | | true_false | 两个大按钮 | `value === answer` | `--type-true_false` | | short_answer | `