{
  "case_id": "C1",
  "case_name": "汉语拼音学习应用",
  "prompt": "生成一个单页HTML应用，用于学习汉语拼音，要求：\n1. 包含声母、韵母、声调的完整教学\n2. 每个拼音配有：\n   - 标准发音音频\n   - 口型示意图\n   - 笔顺动画\n3. 练习模式：听音选字\n4. 进度追踪和错题本\n5. 适合5-8岁儿童使用",
  "result": {
    "success": true,
    "content": "这是一个为您生成的单页HTML应用（Single Page Application）。为了满足**5-8岁儿童**的需求，设计风格采用了鲜艳的色彩、圆润的按钮和简单的交互。\n\n**使用说明：**\n1.  将以下代码保存为 `.html` 文件（例如 `pinyin_learning.html`）。\n2.  直接用浏览器（推荐 Chrome 或 Edge）打开即可运行。\n3.  **注意**：由于这是一个纯前端演示，音频功能使用了浏览器的 `Web Speech API`（自动发音）。在正式产品中，建议替换为真人录制的 MP3 文件以确保声调完美准确。\n\n```html\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>快乐学拼音 - 儿童版</title>\n    <style>\n        :root {\n            --primary-color: #FF9F43;\n            --secondary-color: #54a0ff;\n            --accent-color: #ff6b6b;\n            --bg-color: #feca57;\n            --card-bg: #ffffff;\n            --text-color: #2f3542;\n            --font-main: \"YouYuan\", \"幼圆\", \"Comic Sans MS\", cursive, sans-serif;\n        }\n\n        * {\n            box-sizing: border-box;\n            user-select: none;\n        }\n\n        body {\n            font-family: var(--font-main);\n            background-color: var(--bg-color);\n            margin: 0;\n            padding: 0;\n            display: flex;\n            flex-direction: column;\n            height: 100vh;\n            overflow: hidden;\n        }\n\n        /* 导航栏 */\n        nav {\n            background-color: #fff;\n            padding: 15px;\n            display: flex;\n            justify-content: center;\n            gap: 20px;\n            box-shadow: 0 4px 10px rgba(0,0,0,0.1);\n            z-index: 10;\n        }\n\n        .nav-btn {\n            background-color: var(--secondary-color);\n            color: white;\n            border: none;\n            padding: 10px 25px;\n            border-radius: 30px;\n            font-size: 1.2rem;\n            cursor: pointer;\n            transition: transform 0.2s, background 0.2s;\n            box-shadow: 0 4px 0 #2e86de;\n        }\n\n        .nav-btn:active, .nav-btn.active {\n            transform: translateY(4px);\n            box-shadow: none;\n            background-color: var(--accent-color);\n            box-shadow: 0 0 0 #c0392b; /* No shadow when pressed/active if using transform */\n        }\n\n        /* 主内容区 */\n        #app {\n            flex: 1;\n            overflow-y: auto;\n            padding: 20px;\n            display: flex;\n            justify-content: center;\n        }\n\n        .section {\n            display: none;\n            width: 100%;\n            max-width: 800px;\n            animation: fadeIn 0.5s;\n        }\n\n        .section.active {\n            display: block;\n        }\n\n        @keyframes fadeIn {\n            from { opacity: 0; transform: translateY(20px); }\n            to { opacity: 1; transform: translateY(0); }\n        }\n\n        /* 学习模块 */\n        .category-title {\n            text-align: center;\n            color: var(--text-color);\n            font-size: 1.5rem;\n            margin: 20px 0 10px;\n            background: rgba(255,255,255,0.5);\n            border-radius: 15px;\n            padding: 5px;\n        }\n\n        .pinyin-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));\n            gap: 15px;\n            padding-bottom: 50px;\n        }\n\n        .pinyin-card {\n            background: var(--card-bg);\n            border-radius: 15px;\n            height: 80px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            font-size: 2rem;\n            font-weight: bold;\n            color: var(--text-color);\n            cursor: pointer;\n            box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n            border-bottom: 5px solid #ddd;\n            transition: all 0.2s;\n        }\n\n        .pinyin-card:hover {\n            transform: translateY(-2px);\n            border-bottom-color: var(--primary-color);\n        }\n\n        /* 弹窗详情 */\n        .modal-overlay {\n            position: fixed;\n            top: 0; left: 0; right: 0; bottom: 0;\n            background: rgba(0,0,0,0.7);\n            display: none;\n            justify-content: center;\n            align-items: center;\n            z-index: 100;\n        }\n\n        .modal {\n            background: white;\n            width: 90%;\n            max-width: 400px;\n            border-radius: 25px;\n            padding: 20px;\n            text-align: center;\n            position: relative;\n            border: 5px solid var(--primary-color);\n        }\n\n        .close-btn {\n            position: absolute;\n            top: 10px;\n            right: 15px;\n            font-size: 2rem;\n            cursor: pointer;\n            color: #aaa;\n        }\n\n        .big-pinyin {\n            font-size: 6rem;\n            color: var(--accent-color);\n            margin: 10px 0;\n            position: relative;\n        }\n\n        /* 笔顺动画模拟 */\n        .stroke-anim {\n            position: absolute;\n            top: 0; left: 0; right: 0; bottom: 0;\n            opacity: 0.3;\n            color: #ddd;\n            z-index: -1;\n        }\n\n        .media-controls {\n            display: flex;\n            justify-content: space-around;\n            margin-top: 20px;\n        }\n\n        .control-btn {\n            background: var(--secondary-color);\n            color: white;\n            border: none;\n            border-radius: 50%;\n            width: 60px;\n            height: 60px;\n            font-size: 1.5rem;\n            cursor: pointer;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n        }\n\n        /* 口型示意图 (CSS模拟) */\n        .mouth-shape {\n            width: 100px;\n            height: 60px;\n            background: #ffcccc;\n            border: 3px solid #ff6b6b;\n            border-radius: 50%; /* 默认圆形 */\n            margin: 10px auto;\n            transition: all 0.3s;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            font-size: 0.8rem;\n            color: #c0392b;\n        }\n\n        /* 练习模式 */\n        .quiz-container {\n            text-align: center;\n            background: white;\n            padding: 30px;\n            border-radius: 20px;\n            box-shadow: 0 5px 15px rgba(0,0,0,0.1);\n        }\n\n        .quiz-score {\n            font-size: 1.5rem;\n            color: var(--secondary-color);\n            margin-bottom: 20px;\n        }\n\n        .listen-btn {\n            background: var(--primary-color);\n            width: 100px;\n            height: 100px;\n            border-radius: 50%;\n            border: none;\n            font-size: 3rem;\n            color: white;\n            margin: 0 auto 30px;\n            cursor: pointer;\n            box-shadow: 0 5px 0 #e67e22;\n            animation: pulse 2s infinite;\n        }\n\n        @keyframes pulse {\n            0% { transform: scale(1); }\n            50% { transform: scale(1.05); }\n            100% { transform: scale(1); }\n        }\n\n        .options-grid {\n            display: grid;\n            grid-template-columns: 1fr 1fr;\n            gap: 20px;\n        }\n\n        .option-btn {\n            background: #f1f2f6;\n            border: 2px solid #dfe4ea;\n            padding: 20px;\n            font-size: 2rem;\n            border-radius: 15px;\n            cursor: pointer;\n        }\n\n        .option-btn.correct { background: #2ed573; color: white; border-color: #2ed573; }\n        .option-btn.wrong { background: #ff4757; color: white; border-color: #ff4757; }\n\n        /* 进度/错题本 */\n        .progress-stats {\n            display: flex;\n            justify-content: space-around;\n            margin-bottom: 20px;\n        }\n\n        .stat-box {\n            background: white;\n            padding: 15px;\n            border-radius: 10px;\n            text-align: center;\n            width: 45%;\n        }\n\n        .mistake-list {\n            list-style: none;\n            padding: 0;\n        }\n\n        .mistake-item {\n            background: white;\n            margin-bottom: 10px;\n            padding: 15px;\n            border-radius: 10px;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            font-size: 1.2rem;\n        }\n\n        .review-btn {\n            background: var(--secondary-color);\n            color: white;\n            border: none;\n            padding: 5px 15px;\n            border-radius: 15px;\n            cursor: pointer;\n        }\n\n    </style>\n</head>\n<body>\n\n<nav>\n    <button class=\"nav-btn active\" onclick=\"switchTab('learn')\">📚 学习</button>\n    <button class=\"nav-btn\" onclick=\"switchTab('practice')\">🎮 练习</button>\n    <button class=\"nav-btn\" onclick=\"switchTab('progress')\">🏆 进度</button>\n</nav>\n\n<div id=\"app\">\n    <!-- 学习模块 -->\n    <div id=\"learn\" class=\"section active\">\n        <div class=\"category-title\">声母 (Initials)</div>\n        <div class=\"pinyin-grid\" id=\"initials-grid\"></div>\n        \n        <div class=\"category-title\">韵母 (Finals)</div>\n        <div class=\"pinyin-grid\" id=\"finals-grid\"></div>\n\n        <div class=\"category-title\">整体认读音节</div>\n        <div class=\"pinyin-grid\" id=\"overall-grid\"></div>\n    </div>\n\n    <!-- 练习模块 -->\n    <div id=\"practice\" class=\"section\">\n        <div class=\"quiz-container\">\n            <div class=\"quiz-score\">得分: <span id=\"score\">0</span></div>\n            <button class=\"listen-btn\" onclick=\"playCurrentQuizAudio()\">🔊</button>\n            <p>点击喇叭听声音，选出正确的拼音</p>\n            <div class=\"options-grid\" id=\"options-container\">\n                <!-- 选项动态生成 -->\n            </div>\n            <button id=\"next-btn\" class=\"nav-btn\" style=\"margin-top:20px; display:none;\" onclick=\"nextQuestion()\">下一题 ➡</button>\n        </div>\n    </div>\n\n    <!-- 进度模块 -->\n    <div id=\"progress\" class=\"section\">\n        <div class=\"progress-stats\">\n            <div class=\"stat-box\">\n                <h3>已学</h3>\n                <h1 id=\"learned-count\" style=\"color:var(--primary-color)\">0</h1>\n            </div>\n            <div class=\"stat-box\">\n                <h3>错题</h3>\n                <h1 id=\"mistake-count\" style=\"color:var(--accent-color)\">0</h1>\n            </div>\n        </div>\n        <div class=\"category-title\">错题本 (点击复习)</div>\n        <ul class=\"mistake-list\" id=\"mistake-list\">\n            <!-- 错题列表 -->\n        </ul>\n        <button class=\"nav-btn\" style=\"width:100%; background:#ff6b6b\" onclick=\"clearMistakes()\">🗑️ 清空错题</button>\n    </div>\n</div>\n\n<!-- 详情弹窗 -->\n<div class=\"modal-overlay\" id=\"modal\">\n    <div class=\"modal\">\n        <span class=\"close-btn\" onclick=\"closeModal()\">×</span>\n        <h2 id=\"modal-title\">拼音详情</h2>\n        \n        <!-- 口型示意 -->\n        <div class=\"mouth-shape\" id=\"mouth-shape\">\n            口型\n        </div>\n        \n        <div class=\"big-pinyin\" id=\"modal-char\">a</div>\n        \n        <!-- 声调演示 -->\n        <div id=\"tone-display\" style=\"font-size: 1.5rem; color: #888; margin-bottom:10px;\">\n            ā á ǎ à\n        </div>\n\n        <div class=\"media-controls\">\n            <button class=\"control-btn\" onclick=\"playDetailAudio()\">🔊</button>\n            <button class=\"control-btn\" onclick=\"animateStroke()\">✏️</button>\n        </div>\n        <p style=\"margin-top:15px; font-size:0.9rem; color:#666;\">点击 🔊 听发音，点击 ✏️ 看笔顺</p>\n    </div>\n</div>\n\n<script>\n    // --- 数据定义 ---\n    const pinyinData = {\n        initials: ['b','p','m','f','d','t','n','l','g','k','h','j','q','x','zh','ch','sh','r','z','c','s','y','w'],\n        finals: ['a','o','e','i','u','ü','ai','ei','ui','ao','ou','iu','ie','üe','er','an','en','in','un','ün','ang','eng','ing','ong'],\n        overall: ['zhi','chi','shi','ri','zi','ci','si','yi','wu','yu','ye','yue','yuan','yin','yun','ying']\n    };\n\n    // 口型数据模拟 (CSS border-radius 和 width/height 变化)\n    const mouthShapes = {\n        'a': { w: '80px', h: '80px', r: '50%', desc: '张大嘴巴' },\n        'o': { w: '60px', h: '60px', r: '50%', desc: '圆圆嘴巴' },\n        'e': { w: '80px', h: '40px', r: '30%', desc: '扁扁嘴巴' },\n        'i': { w: '90px', h: '20px', r: '10px', desc: '牙齿对齐' },\n        'u': { w: '30px', h: '30px', r: '50%', desc: '嘴巴突出' },\n        'ü': { w: '30px', h: '30px', r: '50%', desc: '嘴巴吹笛' },\n        // 默认\n        'default': { w: '60px', h: '40px', r: '40%', desc: '自然口型' }\n    };\n\n    // 状态管理\n    let currentQuizAnswer = '';\n    let score = 0;\n    let mistakes = JSON.parse(localStorage.getItem('pinyinMistakes')) || [];\n    let learned = JSON.parse(localStorage.getItem('pinyinLearned')) || [];\n\n    // --- 初始化 ---\n    function init() {\n        renderGrid('initials-grid', pinyinData.initials);\n        renderGrid('finals-grid', pinyinData.finals);\n        renderGrid('overall-grid', pinyinData.overall);\n        updateStats();\n    }\n\n    function renderGrid(elementId, data) {\n        const container = document.getElementById(elementId);\n        data.forEach(char => {\n            const div = document.createElement('div');\n            div.className = 'pinyin-card';\n            div.innerText = char;\n            div.onclick = () => openDetail(char);\n            container.appendChild(div);\n        });\n    }\n\n    // --- 交互逻辑 ---\n    function switchTab(tabId) {\n        document.querySelectorAll('.section').forEach(el => el.classList.remove('active'));\n        document.querySelectorAll('.nav-btn').forEach(el => el.classList.remove('active'));\n        \n        document.getElementById(tabId).classList.add('active');\n        event.target.classList.add('active');\n\n        if(tabId === 'practice') startQuiz();\n        if(tabId === 'progress') renderMistakes();\n    }\n\n    // --- 学习详情弹窗 ---\n    let currentDetailChar = '';\n\n    function openDetail(char) {\n        currentDetailChar = char;\n        const modal = document.getElementById('modal');\n        document.getElementById('modal-char').innerText = char;\n        document.getElementById('modal-title').innerText = \n            pinyinData.initials.includes(char) ? \"声母学习\" : \"韵母/音节学习\";\n\n        // 设置口型\n        const shape = mouthShapes[char.charAt(0)] || mouthShapes['default'];\n        const mouthEl = document.getElementById('mouth-shape');\n        mouthEl.style.width = shape.w;\n        mouthEl.style.height = shape.h;\n        mouthEl.style.borderRadius = shape.r;\n        mouthEl.innerText = shape.desc;\n\n        // 记录已学\n        if(!learned.includes(char)) {\n            learned.push(char);\n            localStorage.setItem('pinyinLearned', JSON.stringify(learned));\n            updateStats();\n        }\n\n        modal.style.display = 'flex';\n        \n        // 自动播放一次\n        setTimeout(() => playDetailAudio(), 500);\n    }\n\n    function closeModal() {\n        document.getElementById('modal').style.display = 'none';\n    }\n\n    // --- 媒体功能 (音频 & 动画) ---\n    function playDetailAudio() {\n        // 实际项目中应替换为: new Audio(`assets/audio/${currentDetailChar}.mp3`).play();\n        speak(currentDetailChar);\n    }\n\n    function animateStroke() {\n        const el = document.getElementById('modal-char');\n        // 简单的 CSS 动画模拟书写效果 (这里用颜色渐变模拟)\n        el.style.color = '#ddd';\n        setTimeout(() => {\n            el.style.transition = 'color 1s ease';\n            el.style.color = 'var(--accent-color)';\n        }, 100);\n    }\n\n    // 浏览器语音合成 (Fallback)\n    function speak(text) {\n        window.speechSynthesis.cancel();\n        const u = new SpeechSynthesisUtterance(text);\n        u.lang = 'zh-CN';\n        u.rate = 0.8; // 语速稍慢适合儿童\n        window.speechSynthesis.speak(u);\n    }\n\n    // --- 练习模式逻辑 ---\n    function startQuiz() {\n        document.getElementById('next-btn').style.display = 'none';\n        const allPinyin = [...pinyinData.initials, ...pinyinData.finals, ...pinyinData.overall];\n        \n        // 随机选一个答案\n        currentQuizAnswer = allPinyin[Math.floor(Math.random() * allPinyin.length)];\n        \n        // 生成干扰项 (共4个选项)\n        let options = [currentQuizAnswer];\n        while(options.length < 4) {\n            const random = allPinyin[Math.floor(Math.random() * allPinyin.length)];\n            if(!options.includes(random)) options.push(random);\n        }\n        \n        // 打乱顺序\n        options.sort(() => Math.random() - 0.5);\n\n        // 渲染选项\n        const container = document.getElementById('options-container');\n        container.innerHTML = '';\n        options.forEach(opt => {\n            const btn = document.createElement('button');\n            btn.className = 'option-btn';\n            btn.innerText = opt;\n            btn.onclick = () => checkAnswer(btn, opt);\n            container.appendChild(btn);\n        });\n\n        // 自动播放题目音频\n        setTimeout(playCurrentQuizAudio, 500);\n    }\n\n    function playCurrentQuizAudio() {\n        speak(currentQuizAnswer);\n    }\n\n    function checkAnswer(btn, selected) {\n        // 禁用所有按钮防止重复点击\n        const btns = document.querySelectorAll('.option-btn');\n        btns.forEach(b => b.disabled = true);\n\n        if(selected === currentQuizAnswer) {\n            btn.classList.add('correct');\n            score += 10;\n            document.getElementById('score').innerText = score;\n            speak(\"真棒！\");\n        } else {\n            btn.classList.add('wrong');\n            // 标出正确答案\n            btns.forEach(b => {\n                if(b.innerText === currentQuizAnswer) b.classList.add('correct');\n            });\n            addMistake(currentQuizAnswer);\n            speak(\"哎呀，再接再厉\");\n        }\n        \n        document.getElementById('next-btn').style.display = 'inline-block';\n    }\n\n    function nextQuestion() {\n        startQuiz();\n    }\n\n    // --- 进度 & 错题本 ---\n    function addMistake(char) {\n        if(!mistakes.includes(char)) {\n            mistakes.push(char);\n            localStorage.setItem('pinyinMistakes', JSON.stringify(mistakes));\n            updateStats();\n        }\n    }\n\n    function renderMistakes() {\n        const list = document.getElementById('mistake-list');\n        list.innerHTML = '';\n        if(mistakes.length === 0) {\n            list.innerHTML = '<li style=\"text-align:center; color:#888;\">太棒了，没有错题！</li>';\n            return;\n        }\n        \n        mistakes.forEach(char => {\n            const li = document.createElement('li');\n            li.className = 'mistake-item';\n            li.innerHTML = `\n                <span>${char}</span>\n                <button class=\"review-btn\" onclick=\"openDetail('${char}')\">复习 🔊</button>\n            `;\n            list.appendChild(li);\n        });\n    }\n\n    function clearMistakes() {\n        if(confirm('确定要清空错题本吗？')) {\n            mistakes = [];\n            localStorage.setItem('pinyinMistakes', JSON.stringify(mistakes));\n            renderMistakes();\n            updateStats();\n        }\n    }\n\n    function updateStats() {\n        document.getElementById('learned-count').innerText = learned.length;\n        document.getElementById('mistake-count').innerText = mistakes.length;\n    }\n\n    // 启动\n    init();\n\n</script>\n</body>\n</html>\n```\n\n### 功能特点详解：\n\n1.  **针对儿童的UI设计**：\n    *   使用 **幼圆/Comic Sans** 等圆润字体。\n    *   **大按钮、大文字**，方便儿童点击。\n    *   **色彩心理学**：使用明亮的黄色（背景）、橙色（重点）、绿色（正确）、红色（错误）来吸引注意力并提供即时反馈。\n\n2.  **完整教学内容**：\n    *   包含声母、韵母、整体认读音节三个板块。\n    *   **详情弹窗**：点击任意拼音卡片，弹出大字卡。\n    *   **口型示意**：使用 CSS 动态改变形状（圆形、扁形等）来模拟发音时的嘴型（简化版）。\n    *   **笔顺演示**：虽然没有引入复杂的 SVG 动画库（为了保持单文件），但我实现了一个颜色渐变动画来模拟“书写”的视觉反馈。\n\n3.  **听音选字（练习模式）**：\n    *   随机抽取拼音。\n    *   语音自动播放。\n    *   选择正确显示绿色并加分，选择错误显示红色并自动显示正确答案。\n    *   配有简单的正误语音反馈（“真棒”、“再接再厉”）。\n\n4.  **进度追踪与错题本**：\n    *   使用 `localStorage` **本地存储**，刷新页面后进度和错题不会丢失。\n    *   **自动记录**：在练习模式答错的题会自动加入错题本。\n    *   **复习功能**：在错题本中可以直接点击“复习”重新打开教学卡片。\n\n5.  **技术实现**：\n    *   **零依赖**：不需要安装任何库，纯原生 HTML/CSS/JS。\n    *   **Web Speech API**：使用浏览器自带的文字转语音功能，无需下载音频文件即可发音（**注意：** 电脑端的 Chrome/Edge 效果最好，移动端可能依赖系统语音包）。\n\n### 如何进一步优化（给家长的建议）：\n如果您想让这个应用更完美，可以找一些标准的拼音 MP3 文件，创建一个 `audio` 文件夹，然后修改代码中的 `playDetailAudio` 函数，将 `speak(text)` 替换为播放真实音频文件的代码。",
    "model": "gemini-3-pro-preview",
    "usage": {
      "prompt_tokens": 116,
      "completion_tokens": 7702,
      "total_tokens": 7818
    },
    "timestamp": "2025-11-19 13:26:38"
  },
  "needs_screenshot": true,
  "needs_manual_test": true
}