本 skill 适用于从零搭建纯前端、零后端的刷题/备考类 H5 应用,并期望一键部署到 CloudStudio 或 COS 等静态托管服务。凡符合上述场景的考试备考工具(考研、公考、医师资格、法考、语言证书、企业培训等),均可直接复用本框架,通过前置问答配置后快速生成可运行的生产级应用。 模块清单(按需启用) 备考中心 Dashboard(默认落地页:欢迎语 + 模块入口卡) 每日一练(确定性种子抽题,按日更新) 章节刷题(按章浏览,进度按 savedAt 恢复) 模拟题 / 真题模考(计时、交卷、成
QQ( QQ).是一项面向实际任务的技能,主要用于Overview. 零建构,零后端,纯前端 H5 考试预览应用程序的可重复使用的蓝图.;使用它来: 为任何考试建立新的预览系统, 或者将一个主题选项概括化。
从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
A reusable blueprint for zero-build, zero-backend, pure-frontend H5 exam-prep apps. Use it to stand up a new prep system for any exam, or to generalize a subject-specific one. It favors silent progress resume (no popups), mobile-friendly folding navigation, a structured exam-result page, and a simple single-file loading architecture (questions.json with 3-tier retry fetch). Concrete subject rules (question bank, whitelist) live in the consuming project.
硬性规则:本 skill 被调用来「从零搭建 / 生成」一个新的备考系统时,agent 的第一条回复 MUST 是前置问题,用
AskUserQuestion呈现下方 Q1–Q10。问询确认前,禁止读取模板、禁止写文件、禁止部署。 ⚠️ 反模式教训:曾跳过这步直接开工,导致多处凭默认猜(白名单示例账号、科目划分、模块范围都是 agent 自作主张)。无论用户多急,都必须先问;用户说「直接按默认搭」等同默认确认全部「默认值」项,但仍需先把问题列出来、拿到确认再开工。 这是本 skill 的「前置问题」约定——每次新系统都必须走一遍,不是一次性文档。
Before scaffolding or refactoring, collect the following. Do not start development/deployment
until all required params for the chosen branch are confirmed. Use AskUserQuestion (one or
several calls). Reasonable defaults may be proposed but must be marked「默认值」.
| # | Question | Why it matters |
|---|---|---|
| Q1 | 目标考试类型与名称?(考研 / 公考 / 医师资格 / 法律职业 / 语言证书 / 企业培训 / 其他) | 决定科目划分、题型枚举、考点结构 |
| Q2 | 需要构建多少个考试科目?各科目名称? | 数据按科目组织;单科目时全局自动隐藏科目筛选框 |
| Q3 | 题型清单?(单选 / 多选 / 判断 / 填空 / 简答 / 论述 / 作文 等) | 客观题系统判分;主观题只展示采分点 + 参考答案,不判分 |
| Q4 | 启用哪些功能模块?逐项勾选 | 动态隐藏未启用模块入口;关闭模块保留历史数据,仅隐藏入口 |
模块清单(逐项确认启用 / 关闭):
Q6 — 白名单数据源(三选一,手机号 SHA-256 哈希比对,白名单不存明文):
gen-hash.html 或 crypto.js 生成 SHA-256 哈希后写入 whitelist.jsonwhitelist.json无论选哪种,最终生成
data/whitelist.json={ "entries": [{ "hash": "sha256hex", "name": "昵称" }] }(兼容旧格式{ "hashes": [...] })。用户登录时手机号经 SHA-256 哈希后与白名单哈希比对,昵称自动从白名单读取,无需用户手填昵称。登录弹窗副标题统一为「输入手机号(仅本地记录,不上传),系统生成你的专属学习档案」。白名单仅存哈希值,不存明文手机号(合规要求)。
Q7 — 是否需要 AI 离线预生成题目?
questions.json;运行时无 AI 调用部署方式:默认 CloudStudio sandbox(无需询问)。 用
workbuddy_cloudstudio_deploy部署干净dist/(只含index.html+css/+js/+data/)。 仅当用户主动要求自定义域名 / 长期稳定链接时才考虑腾讯云 COS,且必须先读references/cos-pitfalls.md(5 层 bug 链:createReadStream 空文件、CDN 忽略查询参数、裸路径死循环等)。
| # | Question | Default |
|---|---|---|
| Q8 | 主题色色值 / 色系? | --c-primary 蓝紫渐变(可改绿/橙等) |
| Q9 | 是否提供配套材料(大纲 / 教材 / 真题 / 讲义)? | 无 |
| Q10 | 登录后落地页? | 备考中心 dashboard(欢迎语 + 日期 + 模块入口卡);dashboard 未登录也可访问,其他模块需登录 |
AskUserQuestion 一次性或分批问,但当前分支所需参数必须全部确认。15 real bugs were found and fixed in production. Read references/pitfalls.md for full
root-cause + fix. Each has a copy-paste template in references/templates/. Summary:
| # | Bug | Template / Fix |
|---|---|---|
| P1 | Whitelist login fails on file:// + race |
auth-whitelist-guard.js + app openLogin guard |
| P2 | Modal won't close (stale JS cache) | CSS .hidden,[hidden]{display:none!important} + ?v=N on assets |
loadIndex 并发覆盖 |
已移除 — 无分片/IDB 即无此问题 | |
| P4 | Bare App global (jsdom crash) |
Always QuizApp.App; never bare App |
| P5 | knowledge.json written broken (un-escaped quotes) |
Generate JSON via script (json.dump), never LLM-stream |
| P6 | Mistakes delete-not-conquer; subjective/blank leak in | storage-mistake-conquer.js + quiz-submit-conquer.js |
| P7 | Per-page subject dropdowns ≠ global selector | app-global-subject.js |
| 已移除 — 无 IndexedDB 缓存 | ||
| P9 | HTTP 缓存毒化 data/*.json → 硬刷新仍空 |
fetchJSON:{cache:'no-store'} + URL ?_=Date.now() |
| P10 | 真机错误全丢失(无 unhandledrejection 监听) |
app.js init 首行加全局 error/unhandledrejection 监听 |
| 已移除 — 数据一次全量加载,无需 prefetch | ||
| P12 | 空题静默无恢复入口 | render() 空态改 state-box 含「刷新页面」「重置缓存并刷新」 |
| P13 | startPaper 前置操作 S(null → 白屏) | 不要提前设 S.xxx,全部走 startItems 的 opts |
| P14 | 错题本收藏按钮 ReferenceError: q is not defined | wireCard 不要引用外部局部变量 q,用 rec.questionData |
| P15 | 路由时未开始答题即调 stopTimer() → 崩 | stopTimer() 首行加 if(S && S.timer) 空守卫 |
(function (global) {
var App = { /* router, dashboard, login, renderUser */ };
global.QuizApp = global.QuizApp || {};
global.QuizApp.App = App;
})(window);
Split feature code into one file per module to keep each under ~400 lines.
js/app.js — router, dashboard (备考中心, default landing page), login dialog, renderUser (top-right greeting).js/idb.js — DataStore manager (loadData / getSubject / getChapter / findQuestion). Single questions.json fetch with 3-tier retry.js/quiz.js — daily/chapter/mock/exam modes, renderExamComplete (result page), gradeExamSilent (exam exit guard).js/knowledge.js — single-card knowledge view with localStorage progress, sidebar chapter linkage, 3D flip (pure click).js/review.js — shared module for 错题本 + 收藏夹 (single-question paged view with prev/next; no chapter filter).js/auth.js — phone-number whitelist login (SHA-256 hashed compare), auto nickname from whitelist.js/storage.js — LocalStorage wrapper, per-user isolation prefix, progress persistence.js/crypto.js — pure-JS SHA-256 for whitelist compare + user isolation prefix (template: references/templates/crypto-sha256.js).Data.subjects[] // e.g. one subject, or grouped by exam section
└─ chapters[] // chapters / units / topics
└─ questions[] // { id, type, question, options:[{label,text}], answer, analysis,
// scoringPoints:[{score,point}], referenceAnswer }
Keep progress separate from content: persist progress to LocalStorage keyed by user + module + chapter.
Desktop: #sidebar fixed left, #main flex right. Mobile: #sidebar is a fixed left drawer triggered by #railToggle,
with #railOverlay as backdrop. 章节筛选抽屉已移除——侧栏两级导航替代.
All data lives in one file: data/questions.json. DataStore.loadData() fetches it once
(with 3-tier retry: cache-bust → clean URL → 800ms delayed retry) and populates
Data.subjects / Data.mockPapers / Data.realPapers. The promise is cached — subsequent
calls return the same result.
INDEX_VER. One file, one fetch.questions arrays inline — read from DataStore.getChapter() directly.DataStore.loadData().then(...) — fire-and-forget on first call, instant after.js/idb.js is ~60 lines (retry logic + query helpers). No references/architecture.md needed.ensureSubject, ensureChapter, loadIndex, or INDEX_VER — these are removed.DEFAULT_ROUTE = 'dashboard' — 登录后(及未登录时)首先进入备考中心,结构如下:
👋 你好,{昵称} + 今日日期/星期 + 「开始每日一练 →」CTA(仅登录态)。关键点:
count != null ? count : questions.length(直接从 questions 数组计算)。科目下拉放在 #sidebar 内(brand 下方、nav 上方),全站唯一入口。所有模块按所选科目呈现数据。
index.html: 内 下方放 。
桌面端侧栏常驻,科目下拉始终可见;移动端侧栏是抽屉,科目下拉随抽屉出现。
js/app.js:App.currentSubject + getSubject()/setSubject() 是全局唯一科目来源;
renderGlobalSubject() 渲染 #subjbar( + ),单科目时 bar.hidden=true 自动隐藏。
- 各页面无独立的章节筛选(章节下拉框已全部移除)。侧栏两级导航中点击章节子项即切换内容。
- 模块内科目锁定:进入模块后
renderGlobalSubject(true) → select disabled + 🔒 科目·锁定,
回备考中心才可切换。
Standard module breakdown
Module
Purpose
Resume behavior
每日一练 (daily)
deterministic seeded subset per day
silent resume by date key
章节刷题 (chapter)
browse by chapter cards (direct entry)
no next-button; tap card → practice
模拟题 (mock)
full timed paper
exam flow
真题模考 (real-exam)
past papers
exam flow
错题本 (mistakes)
wrong-question review (single-question paged)
prev/next buttons; no chapter filter
收藏夹 (favorites)
bookmarked review (single-question paged)
prev/next buttons; no chapter filter
知识卡 (knowledge)
single flashcard + localStorage progress
sidebar chapter click → switch chapter cards
考试模式 · 关键行为
- 提交后不显示答案:考试中提交只记录答案并自动跳到下一题;最后一题提交后停住,显示「已提交,等待交卷」。
- 实现要点:
renderBody 对错着色 guard !S.isExam;renderQuestion 仅在 !S.isExam 时渲染 reveal(正确答案/解析);submit 考试分支执行 S.idx++; render() 自动跳题。
- 答案仅在交卷后可见:点击「交卷」→ 确认 →
renderExamComplete 展示成绩单。
考试题号面板
- 考试页面左侧
.exam-palette(grid 排列题号按钮),点击可跳转任意题。
- 题号三态:当前
.current(蓝底白字)、已答 .answered(浅蓝)、未答(灰)。按钮 data-pidx 存索引。
两级可折叠侧栏导航
#sidebar 中章节刷题、知识卡、模拟题、真题模考四个模块改为 .has-sub > .nav-parent + .nav-sub 结构。
- 点击父项展开/折叠(切换
.open class);子项直接启动章节/试卷。buildSidebar() 在 loadData() 后构建。
- 各页面不再有独立的章节筛选下拉框(错题本、收藏夹、知识卡等均已移除
chapterFilterHTML/wireChapterFilter)。
答案回顾 · 单题浏览模式(结果页按钮)
- 结果页两个按钮:「逐题回顾」「错题回顾」(+「返回备考中心」)。
- 点击后进入
Quiz.reviewBrowse(items, view, onBack)——每页一道题,答题界面格式(q-card),
选项已着色 disabled、reveal 直接展开(正确答案+解析+采分点),下一题翻页逐题查看。
- 最后一题显示「返回结果 →」按钮(
onBack 回调),点后回到成绩报告页。
- 错题回顾若无错题 toasts「本次没有错题 🎉」。
- 实现:回顾按钮保存当前
S.items/S.answers 快照,传给 reviewBrowse;onBack→恢复快照→renderExamComplete()。
模块 UI 重设计模式(知识卡 / 收藏夹 / 错题本 / 章节刷题)
重设计这几个复习模块时沉淀的通用模式,复用即可避免返工。原型定稿后再实现(原型仅作确认,不在原型里写业务代码)。
通用原则(每次重设计必守)
- 配色对齐全局主色:只用 App 的
--c-primary / --c-success / --c-danger / --c-warn / --c-bg / --c-surface / --c-line 等 token,不要另起一套色板(否则会出现"原型色调与主色调不一致",需返工)。
- 模块内不做科目筛选:科目选择唯一入口在侧栏
#subjbar(brand 下方)。桌面端常驻可见;移动端侧栏抽屉打开时可见。模块内锁定(select disabled + 🔒 科目·锁定),回备考中心切。
- 解析用内联抽屉(
渐进披露),不用 modal:点「解析」就地展开 .reveal(display:none → .show),减少弹窗打断;revealBody(rec) 组装「正确答案 + 解析 + 采分点」。
- 纯点击交互(不做键盘/ARIA):用户明确要求去掉键盘 ← → / 空格、ARIA、
tabindex、focus-visible、44px 强制触控。所有交互只保留点击(卡片翻面 = onclick 翻面;上一张/下一张 = 按钮 onclick)。动画仍用 prefers-reduced-motion 关闭 .flashcard-inner 等过渡。
- 性能:收藏/错题记录已存
questionData(localStorage),重练直接用 Quiz.startItems(items, {mode:'list'}) 成卷(items 形如 {q, subjectId, chapterId})。
- 尺寸自适应(流体布局):容器
max-width:min(1200px,100%);侧栏/rail 宽度 clamp();环形图尺寸 clamp();避免写死 px 值。闪卡用 flex:1 撑满整页——PC 上 min-height:calc(100vh-170px)、移动端 min-height:max(320px,calc(100vh-200px))。
知识卡 · 单卡视图 + 进度记忆
- 每页只显示一张闪卡(
.kb-single),上一张/下一张按钮翻页,不跳转。
- 浏览位置存入 localStorage(
kb_prog_{sid}),退出再进恢复上次章节和卡片索引。
- 侧栏知识卡章节子项点击 →
Knowledge.setChapter(cid) → 切到对应章节第一张卡。
- 3D 翻转纯点击(
card.onclick → inner.classList.add('flipped')),不做键盘/ARIA。
- 实现:
Knowledge.render → loadData() → 读 localStorage 恢复进度 → 按 _selChapter 过滤知识点列表 → 渲染单卡 + 上下页按钮。
章节刷题 · 全宽章节卡片 + 点击直接入答题
- 去掉中间"章节概览卡"那一步,改成点击卡片直接调
launchChapter(sid, cid) 进入答题页。
- PC 桌面:
.rail-wide 网格容器(display:grid; grid-template-columns:repeat(auto-fill,minmax(240px,1fr))),每张卡片纵向展示章节名 + x/y 题 + 进度条 + CTA 按钮;hover 上浮 + 变色。
- 移动端:
.rail-wide 的 grid 被媒体查询覆盖(.rail 走固定左抽屉),卡片在移动端左抽屉内纵向堆叠,选完自动折叠(classList.remove('open') + 遮罩隐藏)。
- 卡片结构: