<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>第02讲:找规律画图</title>
<style>
/* ================= 基础重置与全局样式 ================= */
:root {
--primary: #a29bfe; /* 薰衣草紫 */
--primary-dark: #6c5ce7;
--accent: #fdcb6e; /* 奶油黄 */
--success: #00b894; /* 薄荷绿 */
--error: #ff7675; /* 珊瑚红 */
--bg-color: #f0f3f5;
--text-main: #2d3436;
--text-sub: #636e72;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; font-family: "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; }
::-webkit-scrollbar { display: none; }
html, body { margin: 0; padding: 0; background: var(--bg-color); overflow: hidden; height: 100vh; }
/* 动态背景图案 */
body {
background-image: radial-gradient(#dfe6e9 1px, transparent 1px);
background-size: 20px 20px;
}
#app { height: 100vh; max-width: 480px; margin: 0 auto; background: rgba(255,255,255,0.95); display: flex; flex-direction: column; position: relative; box-shadow: 0 0 30px rgba(0,0,0,0.05); }
.content-area { flex: 1; overflow-y: auto; padding-bottom: 90px; scroll-behavior: smooth; padding-top: 10px; }
/* 通用动画类 */
.fade-in { animation: fadeIn 0.4s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
.shake { animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; }
@keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 20%, 80% { transform: translate3d(2px, 0, 0); } 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } 40%, 60% { transform: translate3d(4px, 0, 0); } }
/* ================= 底部导航 (App Bar) ================= */
.bottom-nav {
position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
width: 100%; max-width: 480px; height: 75px;
background: rgba(255, 255, 255, 0.98);
border-top: 1px solid rgba(0,0,0,0.05);
display: flex; justify-content: space-around; align-items: center;
z-index: 9999; box-shadow: 0 -5px 20px rgba(0,0,0,0.03);
backdrop-filter: blur(10px);
padding-bottom: 10px;
}
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; cursor: pointer; padding: 5px; color: #b2bec3; transition: all 0.3s; }
.nav-item.active { color: var(--primary-dark); transform: translateY(-3px); }
.nav-icon { font-size: 24px; margin-bottom: 2px; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); }
.nav-label { font-size: 11px; font-weight: 600; }
/* ================= 页面通用 ================= */
.page-title { font-size: 24px; font-weight: 800; color: var(--text-main); margin: 20px 20px 10px; text-align: center; letter-spacing: 1px; }
.page-subtitle { color: var(--primary-dark); font-size: 16px; margin: 25px 20px 15px; font-weight: 800; display: flex; align-items: center; gap: 8px; }
.page-subtitle::before { content: ''; display: block; width: 4px; height: 16px; background: var(--accent); border-radius: 2px; }
/* ================= 概念页 ================= */
.intro-page { padding: 20px; }
.intro-story {
background: #fff; padding: 20px; border-radius: 20px;
box-shadow: 0 10px 20px rgba(0,0,0,0.05); margin-bottom: 20px;
font-size: 16px; line-height: 1.8; color: var(--text-sub);
}
.concept-list { display: flex; flex-direction: column; gap: 15px; }
.concept-item {
background: white; border-radius: 16px; padding: 15px;
display: flex; align-items: center; gap: 15px;
box-shadow: 0 4px 10px rgba(0,0,0,0.03); transition: transform 0.2s;
}
.concept-item:active { transform: scale(0.98); }
.concept-emoji { font-size: 32px; background: #f0f3ff; padding: 10px; border-radius: 50%; }
.concept-text strong { display: block; color: var(--text-main); font-size: 16px; margin-bottom: 4px; }
.concept-text p { margin: 0; color: var(--text-sub); font-size: 13px; }
.speak-btn {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
color: white; border: none; padding: 15px 40px; border-radius: 50px;
font-size: 16px; font-weight: bold; cursor: pointer; display: block;
margin: 30px auto 0; box-shadow: 0 8px 20px rgba(108, 92, 231, 0.3);
transition: transform 0.2s; width: 80%;
}
.speak-btn:active { transform: scale(0.95); }
/* ================= 演示页 ================= */
.demo-page { padding: 0 15px; }
.tab-nav {
display: flex; background: white; margin: 10px 0 20px;
border-radius: 15px; padding: 5px; box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.tab-item {
flex: 1; padding: 10px; text-align: center; cursor: pointer;
font-weight: 600; color: var(--text-sub); border-radius: 12px;
transition: all 0.3s; font-size: 14px;
}
.tab-item.active { background: #e0e7ff; color: var(--primary-dark); }
.demo-section { display: none; }
.demo-section.active { display: block; animation: fadeIn 0.5s ease; }
.animation-area {
background: #ffffff; border-radius: 24px; padding: 10px;
min-height: 320px; position: relative; overflow: hidden;
box-shadow: inset 0 0 30px rgba(0,0,0,0.02), 0 10px 20px rgba(0,0,0,0.05);
border: 1px solid rgba(0,0,0,0.05); margin-bottom: 20px;
}
.svg-container { width: 100%; height: 100%; min-height: 280px; }
.math-area {
background: white; border-left: 5px solid var(--accent);
border-radius: 0 12px 12px 0; padding: 15px; margin: 10px 0 20px;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.math-formula { font-size: 20px; font-weight: 800; color: var(--text-main); text-align: center; }
.step-explanation {
background: #dfe6e9; padding: 15px; border-radius: 12px;
color: var(--text-main); font-size: 15px; text-align: center;
margin-bottom: 85px; line-height: 1.5; font-weight: 500;
}
.control-bar {
position: fixed; bottom: 85px; left: 50%; transform: translateX(-50%);
width: 90%; max-width: 460px; z-index: 100;
background: rgba(255,255,255,0.9); backdrop-filter: blur(8px);
padding: 10px; border-radius: 20px;
box-shadow: 0 5px 20px rgba(0,0,0,0.15);
display: flex; justify-content: space-between; border: 1px solid rgba(0,0,0,0.05);
}
.step-btn {
background: var(--primary-dark); color: white; border: none;
padding: 12px 25px; border-radius: 15px; font-size: 15px; font-weight: bold;
cursor: pointer; transition: all 0.2s; box-shadow: 0 4px 10px rgba(108, 92, 231, 0.3);
}
.step-btn:disabled { background: #dcdde1; color: #fff; box-shadow: none; cursor: not-allowed; opacity: 0.7; }
.step-btn:active:not(:disabled) { transform: scale(0.95); }
/* ================= 讲解页 ================= */
.explain-page { padding: 20px; }
.example-card {
background: white; border-radius: 20px; padding: 20px; margin-bottom: 20px;
box-shadow: 0 5px 15px rgba(0,0,0,0.05); transition: transform 0.2s;
border: 1px solid #f1f2f6; overflow: hidden;
}
.example-header {
display: flex; justify-content: space-between; align-items: center;
cursor: pointer; padding-bottom: 10px; border-bottom: 1px dashed #eee;
margin-bottom: 10px;
}
.example-title { font-weight: 800; color: var(--primary-dark); font-size: 16px; }
.example-content { display: none; padding-top: 5px; }
.example-content.active { display: block; animation: slideDown 0.3s ease; }
@keyframes slideDown { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } }
.example-answer {
background: #eafff3; padding: 12px; border-radius: 10px;
font-size: 14px; color: var(--text-sub); border-left: 4px solid var(--success); margin-top: 10px;
}
/* ================= 练习/奥数 ================= */
.practice-page { padding: 20px; }
.question-card {
background: white; border-radius: 24px; padding: 25px;
box-shadow: 0 10px 25px rgba(0,0,0,0.08);
}
.question-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 2px solid #f1f2f6; padding-bottom: 15px; }
.question-number { font-weight: 800; color: var(--primary-dark); font-size: 16px; }
.score-display { background: #ffeaa7; color: #d35400; padding: 4px 12px; border-radius: 12px; font-weight: 900; font-size: 14px; }
.question-text { font-size: 18px; line-height: 1.6; color: var(--text-main); margin-bottom: 25px; font-weight: 600; }
.option-btn {
display: block; width: 100%; padding: 16px; margin-bottom: 12px;
text-align: left; border: 2px solid #f1f2f6; border-radius: 16px;
background: white; font-size: 16px; cursor: pointer; transition: all 0.2s;
color: var(--text-sub); position: relative; overflow: hidden;
}
.option-btn:active:not(:disabled) { transform: scale(0.98); background: #f1f2f6; }
.option-btn.correct { background: #eafff3; border-color: var(--success); color: #00b894; font-weight: bold; }
.option-btn.wrong { background: #fff5f5; border-color: var(--error); color: #ff7675; }
.feedback-area {
padding: 15px; border-radius: 12px; margin-bottom: 20px;
font-size: 15px; line-height: 1.6; animation: fadeIn 0.3s;
}
.feedback-correct { background: #eafff3; color: #00b894; border: 1px solid #b8e994; }
.feedback-wrong { background: #fff5f5; color: #d63031; border: 1px solid #ffcccc; }
.next-btn {
background: linear-gradient(135deg, var(--accent) 0%, #fab1a0 100%);
color: #d35400; border: none; padding: 16px; width: 100%; border-radius: 16px;
font-size: 18px; font-weight: 800; cursor: pointer;
box-shadow: 0 8px 20px rgba(253, 203, 110, 0.4);
}
.completion-page { text-align: center; padding: 60px 20px; }
.completion-emoji { font-size: 80px; margin-bottom: 20px; animation: float 3s infinite; }
.final-score { font-size: 48px; font-weight: 900; color: var(--accent); margin: 20px 0 40px; text-shadow: 2px 2px 0px rgba(0,0,0,0.1); }
.restart-btn {
background: linear-gradient(135deg, #00b894 0%, #55efc4 100%);
color: white; border: none; padding: 16px 50px; border-radius: 50px;
font-size: 18px; font-weight: bold; cursor: pointer; box-shadow: 0 10px 20px rgba(0, 184, 148, 0.3);
}
.hint-box { background: #fff7e6; border-left: 5px solid var(--accent); padding: 15px; border-radius: 8px; margin: 15px 0; font-size: 14px; color: #d35400; font-weight: 500; }
.difficulty-badge {
display: inline-block; background: #dfe6e9; color: #636e72;
border-radius: 8px; padding: 3px 8px; font-size: 12px; margin-left: 10px; font-weight: bold;
}
/* ================= 秘籍页 ================= */
.secrets-container { padding: 20px; overflow-x: auto; padding-bottom: 40px; }
.secrets-scroll { display: flex; gap: 20px; }
.secret-card {
flex: 0 0 260px; background: white; border-radius: 24px; padding: 25px;
box-shadow: 0 10px 25px rgba(0,0,0,0.1); display: flex; flex-direction: column;
align-items: center; text-align: center; border-top: 6px solid var(--primary-dark);
}
.secret-card:nth-child(2) { border-top-color: var(--accent); }
.secret-card:nth-child(3) { border-top-color: var(--success); }
.secret-emoji { font-size: 50px; margin-bottom: 15px; }
.secret-title { font-size: 18px; font-weight: 800; color: var(--text-main); margin-bottom: 10px; }
.secret-content { font-size: 14px; line-height: 1.6; color: var(--text-sub); }
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<div v-show="currentPage === 1" class="intro-page fade-in">
<div class="page-title">🔍 找规律画图</div>
<div class="intro-story">
小朋友们,图形宝宝在玩排队游戏呢!它们一会儿换位置,一会儿转圈圈。只要我们找到它们变化的秘密(规律),就能猜出下一个是谁啦!
</div>
<div class="page-subtitle">🌟 核心魔法</div>
<div class="concept-list">
<div class="concept-item">
<div class="concept-emoji">🔄</div>
<div class="concept-text">
<strong>位置移动</strong>
<p>图形像小朋友换座位一样,左跑跑右跑跑。</p>
</div>
</div>
<div class="concept-item">
<div class="concept-emoji">🎡</div>
<div class="concept-text">
<strong>旋转跳跃</strong>
<p>图形像风车一样转圈圈,倒立、躺平、站直。</p>
</div>
</div>
<div class="concept-item">
<div class="concept-emoji">🔁</div>
<div class="concept-text">
<strong>循环重复</strong>
<p>就像唱歌一样,一组动作做完了,再从头开始。</p>
</div>
</div>
</div>
<button class="speak-btn" @click="speak('欢迎学习找规律画图。图形会变换位置,像风车一样旋转,并且规律会循环。')">🎧 听老师讲解</button>
</div>
<div v-show="currentPage === 2" class="demo-page fade-in">
<div class="page-title">🎬 规律演示</div>
<div class="tab-nav">
<div class="tab-item" :class="{active: demoTab === 'position'}" @click="switchDemoTab('position')">🔄 位置变化</div>
<div class="tab-item" :class="{active: demoTab === 'group'}" @click="switchDemoTab('group')">📦 分组规律</div>
</div>
<div class="demo-section" :class="{active: demoTab === 'position'}">
<div class="animation-area">
<svg class="svg-container" viewBox="0 0 400 330" id="position-svg">
<defs>
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="2" dy="2" stdDeviation="2" flood-color="#000" flood-opacity="0.1"/>
</filter>
</defs>
<rect x="50" y="100" width="80" height="80" rx="10" fill="none" stroke="#dfe6e9" stroke-width="2" stroke-dasharray="5,5"/>
<rect x="160" y="100" width="80" height="80" rx="10" fill="none" stroke="#dfe6e9" stroke-width="2" stroke-dasharray="5,5"/>
<rect x="270" y="100" width="80" height="80" rx="10" fill="none" stroke="#dfe6e9" stroke-width="2" stroke-dasharray="5,5"/>
<text x="90" y="200" font-size="14" fill="#b2bec3" text-anchor="middle">1</text>
<text x="200" y="200" font-size="14" fill="#b2bec3" text-anchor="middle">2</text>
<text x="310" y="200" font-size="14" fill="#b2bec3" text-anchor="middle">3</text>
<g id="block-red" filter="url(#dropShadow)">
<rect x="60" y="110" width="60" height="60" rx="10" fill="#ff7675"/>
<text x="90" y="145" font-size="24" fill="white" text-anchor="middle" dominant-baseline="middle">●</text>
</g>
<g id="block-yellow" filter="url(#dropShadow)">
<rect x="170" y="110" width="60" height="60" rx="10" fill="#ffeaa7"/>
<text x="200" y="145" font-size="24" fill="#d35400" text-anchor="middle" dominant-baseline="middle">▲</text>
</g>
<g id="block-blue" filter="url(#dropShadow)">
<rect x="280" y="110" width="60" height="60" rx="10" fill="#74b9ff"/>
<text x="310" y="145" font-size="24" fill="white" text-anchor="middle" dominant-baseline="middle">■</text>
</g>
<text id="q-mark" x="310" y="150" font-size="40" fill="#636e72" text-anchor="middle" opacity="0" font-weight="bold">?</text>
</svg>
</div>
<div class="math-area">
<div class="math-formula" id="position-formula">● ▲ ■</div>
</div>
<div class="step-explanation" id="position-explanation">三个图形排排坐。观察它们怎么换位置。</div>
<div class="control-bar">
<button class="step-btn" @click="prevPositionStep" :disabled="positionStep === 0">◀ 上一步</button>
<button class="step-btn" @click="nextPositionStep" :disabled="positionStep === 3">下一步 ▶</button>
</div>
</div>
<div class="demo-section" :class="{active: demoTab === 'group'}">
<div class="animation-area">
<svg class="svg-container" viewBox="0 0 400 330" id="group-svg">
<g id="shapes-group">
<circle cx="50" cy="150" r="20" fill="#ff7675" />
<rect x="90" y="130" width="40" height="40" fill="#74b9ff" />
<circle cx="170" cy="150" r="20" fill="#ff7675" />
<rect x="210" y="130" width="40" height="40" fill="#74b9ff" />
<circle cx="290" cy="150" r="20" fill="#ff7675" />
<rect id="final-rect" x="330" y="130" width="40" height="40" fill="#74b9ff" opacity="0.2"/>
</g>
<rect id="gbox-1" x="25" y="100" width="110" height="100" rx="10" fill="none" stroke="#00b894" stroke-width="2" stroke-dasharray="5,5" opacity="0"/>
<rect id="gbox-2" x="145" y="100" width="110" height="100" rx="10" fill="none" stroke="#00b894" stroke-width="2" stroke-dasharray="5,5" opacity="0"/>
<text id="g-text" x="200" y="250" text-anchor="middle" font-size="18" fill="#2d3436" opacity="0">一组:圆 + 方</text>
</svg>
</div>
<div class="math-area">
<div class="math-formula" id="group-formula">● ■ ● ■ ● ?</div>
</div>
<div class="step-explanation" id="group-explanation">观察图形重复的规律。</div>
<div class="control-bar">
<button class="step-btn" @click="prevGroupStep" :disabled="groupStep === 0">◀ 上一步</button>
<button class="step-btn" @click="nextGroupStep" :disabled="groupStep === 2">下一步 ▶</button>
</div>
</div>
</div>
<div v-show="currentPage === 3" class="explain-page fade-in">
<div class="page-title">📝 规律详解</div>
<div class="tab-nav">
<div class="tab-item" :class="{active: explainTab === 'basic'}" @click="explainTab = 'basic'">基础规律</div>
<div class="tab-item" :class="{active: explainTab === 'method'}" @click="explainTab = 'method'">解题方法</div>
<div class="tab-item" :class="{active: explainTab === 'example'}" @click="explainTab = 'example'">典型例题</div>
</div>
<div v-show="explainTab === 'basic'">
<div class="example-card">
<div class="example-title">1. 位置循环</div>
<div class="example-content">就像几个小朋友围着圆桌转,每人每次往左移动一个位置。</div>
</div>
<div class="example-card">
<div class="example-title">2. 旋转变化</div>
<div class="example-content">像时钟的指针一样转动。注意是顺时针(往右转)还是逆时针(往左转)。</div>
</div>
</div>
<div v-show="explainTab === 'method'">
<div class="example-card">
<div class="example-title">💡 方法一:找“循环组”</div>
<div class="example-content">把重复出现的一段图形圈起来,这就是一组。看剩下的位置是这一组里的第几个。</div>
</div>
<div class="example-card">
<div class="example-title">🔢 方法二:标数字</div>
<div class="example-content">在图形下面写上1, 2, 3... 看看单数(1,3,5)是什么,双数(2,4,6)是什么。</div>
</div>
</div>
<div v-show="explainTab === 'example'">
<div class="example-card" @click="toggleExample(1)">
<div class="example-header">
<span>⭐ 例题1:基础循环</span>
<span>{{ example1Open ? '▲' : '▼' }}</span>
</div>
<div class="example-content" :class="{active: example1Open}">
<div class="example-question">● ○ ● ○ ● ____</div>
<div class="example-answer">
<strong>答案:○</strong><br>
解析:一个黑圆,一个白圆,两个一组循环。第6个应该是白圆。
</div>
</div>
</div>
<div class="example-card" @click="toggleExample(2)">
<div class="example-header">
<span>🚀 例题2:位置移动</span>
<span>{{ example2Open ? '▲' : '▼' }}</span>
</div>
<div class="example-content" :class="{active: example2Open}">
<div class="example-question">123, 231, 312, ____</div>
<div class="example-answer">
<strong>答案:123</strong><br>
解析:第1个数字跑到最后面去了。123 -> 231 -> 312 -> 123。循环回来了!
</div>
</div>
</div>
</div>
</div>
<div v-show="currentPage === 4" class="practice-page fade-in">
<div v-if="!practiceCompleted">
<div class="question-card">
<div class="question-header">
<span class="question-number">第 {{currentQuestion + 1}}/{{practiceQuestions.length}} 题</span>
<span class="score-display">⭐ {{score}}</span>
</div>
<div class="question-text">{{practiceQuestions[currentQuestion].text}}</div>
<div class="options-container">
<button
v-for="(option, index) in practiceQuestions[currentQuestion].options"
:key="'opt'+index"
class="option-btn"
:class="{
'correct': answered && option.correct,
'wrong': answered && selectedOption === index && !option.correct,
'shake': answered && selectedOption === index && !option.correct
}"
@click="selectOption(index, option.correct)"
:disabled="answered"
>
{{['A.','B.','C.','D.'][index]}} {{option.text}}
</button>
</div>
<div v-if="answered" class="feedback-area" :class="isCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isCorrect"><strong>🎉 答对啦!</strong><br>{{practiceQuestions[currentQuestion].explanation}}</div>
<div v-else><strong>💡 再想一想:</strong><br>{{practiceQuestions[currentQuestion].explanation}}</div>
</div>
<button v-if="answered" class="next-btn" @click="nextQuestion">
{{currentQuestion < practiceQuestions.length - 1 ? '下一题 →' : '完成练习'}}
</button>
</div>
</div>
<div v-else class="completion-page fade-in">
<div class="completion-emoji">🏆</div>
<div class="completion-title">练习完成!</div>
<div class="final-score">+{{score}} 分</div>
<button class="restart-btn" @click="switchPage(5)">挑战奥数题 🚀</button>
</div>
</div>
<div v-show="currentPage === 5" class="practice-page fade-in">
<div v-if="!olympiadCompleted">
<div class="question-card" style="border-top: 5px solid #ff9f43;">
<div class="question-header">
<div>
<span class="question-number">奥数挑战 {{currentOlympiad + 1}}/{{olympiadQuestions.length}}</span>
<span class="difficulty-badge" :class="'difficulty-' + olympiadQuestions[currentOlympiad].difficulty">
{{olympiadQuestions[currentOlympiad].difficultyText}}
</span>
</div>
<span class="score-display">⭐ {{olympiadScore}}</span>
</div>
<div class="question-text">{{olympiadQuestions[currentOlympiad].text}}</div>
<div class="options-container">
<button
v-for="(option, index) in olympiadQuestions[currentOlympiad].options"
:key="'olopt'+index"
class="option-btn"
:class="{
'correct': olympiadAnswered && option.correct,
'wrong': olympiadAnswered && selectedOlympiadOption === index && !option.correct,
'shake': olympiadAnswered && selectedOlympiadOption === index && !option.correct
}"
@click="selectOlympiadOption(index, option.correct)"
:disabled="olympiadAnswered"
>
{{['A.','B.','C.','D.'][index]}} {{option.text}}
</button>
</div>
<div v-if="wrongAttempts > 0 && !olympiadAnswered" class="hint-box fade-in">
<strong>💡 提示:</strong>
{{ wrongAttempts === 1 ? olympiadQuestions[currentOlympiad].hint1 :
(wrongAttempts === 2 ? olympiadQuestions[currentOlympiad].hint2 : olympiadQuestions[currentOlympiad].hint3) }}
</div>
<div v-if="olympiadAnswered" class="feedback-area" :class="isOlympiadCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isOlympiadCorrect"><strong>👏 真棒!</strong><br>{{olympiadQuestions[currentOlympiad].explanation}}</div>
<div v-else><strong>📖 解析:</strong><br>{{olympiadQuestions[currentOlympiad].explanation}}</div>
</div>
<button v-if="olympiadAnswered || wrongAttempts >= 3" class="next-btn" @click="nextOlympiad">
{{currentOlympiad < olympiadQuestions.length - 1 ? '下一题 →' : '查看成绩'}}
</button>
</div>
</div>
<div v-else class="completion-page fade-in">
<div class="completion-emoji">👑</div>
<div class="completion-title">挑战结束!</div>
<div class="final-score">+{{olympiadScore}} 分</div>
<button class="restart-btn" @click="switchPage(6)">查看通关秘籍 🎁</button>
</div>
</div>
<div v-show="currentPage === 6" class="secrets-container fade-in">
<div class="page-title">🗝️ 通关秘籍</div>
<div class="secrets-scroll">
<div class="secret-card">
<div class="secret-emoji">📦</div>
<div class="secret-title">分组法</div>
<div class="secret-content">把重复出现的一段图形圈起来,看这一组有几个,然后数数。</div>
</div>
<div class="secret-card">
<div class="secret-emoji">🔢</div>
<div class="secret-title">单双数法</div>
<div class="secret-content">第1,3,5...是单数位置,第2,4,6...是双数位置。它们可能有不同的规律。</div>
</div>
<div class="secret-card">
<div class="secret-emoji">✏️</div>
<div class="secret-title">标记法</div>
<div class="secret-content">在图形下面标上1, 2, 3...,或者标上颜色文字,更容易发现秘密!</div>
</div>
</div>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item" :class="{active: currentPage === 1}" @click="switchPage(1)">
<div class="nav-icon">💡</div><div class="nav-label">概念</div>
</div>
<div class="nav-item" :class="{active: currentPage === 2}" @click="switchPage(2)">
<div class="nav-icon">🎬</div><div class="nav-label">演示</div>
</div>
<div class="nav-item" :class="{active: currentPage === 3}" @click="switchPage(3)">
<div class="nav-icon">📝</div><div class="nav-label">讲解</div>
</div>
<div class="nav-item" :class="{active: currentPage === 4}" @click="switchPage(4)">
<div class="nav-icon">✏️</div><div class="nav-label">练习</div>
</div>
<div class="nav-item" :class="{active: currentPage === 5}" @click="switchPage(5)">
<div class="nav-icon">🏆</div><div class="nav-label">奥数</div>
</div>
<div class="nav-item" :class="{active: currentPage === 6}" @click="switchPage(6)">
<div class="nav-icon">🎁</div><div class="nav-label">秘籍</div>
</div>
</div>
</div>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/vue.global.prod.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/gsap.min.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/confetti.browser.min.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
currentPage: 1,
demoTab: 'position',
explainTab: 'basic',
positionStep: 0,
groupStep: 0,
example1Open: false,
example2Open: false,
// 练习题
practiceQuestions: [
{ text: "找规律:●○●○●○____", options: [{text: "●", correct: true}, {text: "○", correct: false}, {text: "△", correct: false}, {text: "□", correct: false}], explanation: "一个黑圆,一个白圆,轮流出现。" },
{ text: "找规律:△□○△□○△____", options: [{text: "△", correct: false}, {text: "□", correct: true}, {text: "○", correct: false}, {text: "●", correct: false}], explanation: "△□○为一组,第8个是第二组的中间那个。" },
{ text: "找规律:■■□■■□____", options: [{text: "■", correct: true}, {text: "□", correct: false}, {text: "●", correct: false}, {text: "○", correct: false}], explanation: "两个黑方块,一个白方块。接下来又是黑方块。" },
{ text: "找规律:○●●○●●○____", options: [{text: "○", correct: false}, {text: "●", correct: true}, {text: "□", correct: false}, {text: "△", correct: false}], explanation: "一个圈,两个点。循环开始,接着是点。" },
{ text: "图形移动:左、中、右、左、中、右。下一个在哪里?", options: [{text: "左", correct: true}, {text: "中", correct: false}, {text: "右", correct: false}, {text: "不确定", correct: false}], explanation: "每3个一循环,第7个回到第一个位置。" },
{ text: "找规律:△▽△▽____", options: [{text: "△", correct: true}, {text: "▽", correct: false}, {text: "○", correct: false}, {text: "□", correct: false}], explanation: "正三角和倒三角交替出现。" },
{ text: "找规律:●●●○○●●●○○____", options: [{text: "●", correct: true}, {text: "○", correct: false}, {text: "●或○", correct: false}, {text: "不对", correct: false}], explanation: "3个黑,2个白。接着又是黑。" },
{ text: "找规律:□△□○□△□○____", options: [{text: "□", correct: true}, {text: "△", correct: false}, {text: "○", correct: false}, {text: "●", correct: false}], explanation: "每4个一组:□△□○。第9个是新的一组开始。" }
],
currentQuestion: 0,
answered: false,
selectedOption: null,
isCorrect: false,
score: 0,
practiceCompleted: false,
// 奥数题
olympiadQuestions: [
{ text: "彩灯闪烁:红红绿、红红绿、红红绿。第20盏灯是什么颜色?", options: [{text: "红", correct: true}, {text: "绿", correct: false}, {text: "黄", correct: false}, {text: "蓝", correct: false}], hint1: "每3个一组", hint2: "20除以3", hint3: "余数是2", explanation: "20 ÷ 3 = 6 组 ... 2 个。第2个是红色。", difficulty: 2, difficultyText: "⭐⭐" },
{ text: "方块变色:第1个红色,第2个蓝色,第3个红色,第4个蓝色。第16个是什么颜色?", options: [{text: "红色", correct: false}, {text: "蓝色", correct: true}, {text: "黄色", correct: false}, {text: "绿色", correct: false}], hint1: "单数是红", hint2: "双数是蓝", hint3: "16是双数", explanation: "双数位置都是蓝色。", difficulty: 1, difficultyText: "⭐" },
{ text: "图形旋转:▶变成▼,▼变成◀,◀变成▲,▲变成▶。这是什么规律?", options: [{text: "顺时针90度", correct: true}, {text: "逆时针90度", correct: false}, {text: "翻转", correct: false}, {text: "无规律", correct: false}], hint1: "看箭头方向", hint2: "像时钟一样转", hint3: "右->下->左->上", explanation: "这是顺时针旋转。", difficulty: 3, difficultyText: "⭐⭐⭐" },
{ text: "数字和图形:1△ 2□ 3△ 4□ 5____", options: [{text: "△", correct: true}, {text: "□", correct: false}, {text: "6", correct: false}, {text: "○", correct: false}], hint1: "单数配△", hint2: "双数配□", hint3: "5是单数", explanation: "单数是△,双数是□。", difficulty: 2, difficultyText: "⭐⭐" },
{ text: "小球滚动:A->B->C->B->A。第9秒在哪?", options: [{text: "A", correct: true}, {text: "B", correct: false}, {text: "C", correct: false}, {text: "D", correct: false}], hint1: "A,B,C,B,A,B,C...", hint2: "4个一循环(A,B,C,B)", hint3: "9除以4余1", explanation: "循环是 A, B, C, B。9 ÷ 4 = 2...1。第1个是 A。", difficulty: 3, difficultyText: "⭐⭐⭐" },
{ text: "图案填色:第1、3、5个红,第2、4、6个蓝。第11个什么色?", options: [{text: "红色", correct: true}, {text: "蓝色", correct: false}, {text: "黄色", correct: false}, {text: "绿色", correct: false}], hint1: "单数红", hint2: "双数蓝", hint3: "11是单数", explanation: "单数位置红色。", difficulty: 1, difficultyText: "⭐" },
{ text: "积木搭建:1层1块,2层3块,3层6块,4层10块。5层几块?", options: [{text: "12", correct: false}, {text: "13", correct: false}, {text: "14", correct: false}, {text: "15", correct: true}], hint1: "每层加几块?", hint2: "+2, +3, +4", hint3: "+5", explanation: "10 + 5 = 15块。", difficulty: 2, difficultyText: "⭐⭐" },
{ text: "小动物排队:🐱🐶🐱🐶... 第20个是谁?", options: [{text: "🐱", correct: false}, {text: "🐶", correct: true}, {text: "不确定", correct: false}, {text: "都是", correct: false}], hint1: "2个一组", hint2: "双数是🐶", hint3: "20是双数", explanation: "20是双数,所以是第二个🐶。", difficulty: 2, difficultyText: "⭐⭐" }
],
currentOlympiad: 0,
olympiadAnswered: false,
selectedOlympiadOption: null,
isOlympiadCorrect: false,
wrongAttempts: 0,
olympiadScore: 0,
olympiadCompleted: false
};
},
methods: {
switchPage(page) {
this.stopSpeak();
this.currentPage = page;
window.scrollTo(0,0);
if(page === 2) {
this.positionStep = 0;
this.groupStep = 0;
this.$nextTick(() => { this.runPositionAnimation(); this.runGroupAnimation(); });
}
if(page === 4 && this.practiceCompleted) { this.practiceCompleted=false; this.currentQuestion=0; this.score=0; }
if(page === 5 && this.olympiadCompleted) { this.olympiadCompleted=false; this.currentOlympiad=0; this.olympiadScore=0; }
},
stopSpeak() {
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
const audio = document.getElementById('tts-audio');
if (audio) { audio.pause(); audio.currentTime = 0; }
} else {
if (window.speechSynthesis) { window.speechSynthesis.cancel(); }
}
},
speak(text) {
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
let audio = document.getElementById('tts-audio');
if (!audio) {
audio = document.createElement('audio');
audio.id = 'tts-audio';
audio.style.display = 'none';
document.body.appendChild(audio);
}
const url = `https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/tts.php?text=${encodeURIComponent(text)}&t=${Date.now()}`;
audio.src = url;
audio.play().catch(err => { console.log('语音播放失败:', err); });
} else {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'zh-CN';
utterance.rate = 0.9;
window.speechSynthesis.speak(utterance);
}
},
switchDemoTab(tab) {
this.demoTab = tab;
if(tab === 'position') { this.positionStep = 0; this.$nextTick(() => this.runPositionAnimation()); }
else { this.groupStep = 0; this.$nextTick(() => this.runGroupAnimation()); }
},
toggleExample(num) {
if(num===1) this.example1Open = !this.example1Open;
if(num===2) this.example2Open = !this.example2Open;
},
// 动画:位置变化
runPositionAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
const targets = ['#block-red', '#block-yellow', '#block-blue'];
// Reset
gsap.set(targets, {x: 0, opacity: 1});
gsap.set("#q-mark", {opacity: 0});
gsap.set("#block-blue", {opacity: 1});
if (this.positionStep === 0) {
// Initial
} else if (this.positionStep === 1) {
// Shift 1: Red -> 2, Yellow -> 3, Blue -> 1 (Cyclic shift right visually)
// Or following text: Red(1)->2, Yellow(2)->3, Blue(3)->1
tl.to("#block-red", {x: 110, duration: 0.8, ease: "power2.inOut"}) // 1->2
.to("#block-yellow", {x: 110, duration: 0.8, ease: "power2.inOut"}, "<") // 2->3
.to("#block-blue", {x: -220, duration: 0.8, ease: "power2.inOut"}, "<"); // 3->1
} else if (this.positionStep === 2) {
// Shift 2 from Step 1 positions
// Red is at 2, moves to 3. Yellow at 3, moves to 1. Blue at 1, moves to 2.
gsap.set("#block-red", {x: 110}); gsap.set("#block-yellow", {x: 110}); gsap.set("#block-blue", {x: -220});
tl.to("#block-red", {x: 220, duration: 0.8, ease: "power2.inOut"}) // 2->3
.to("#block-yellow", {x: -110, duration: 0.8, ease: "power2.inOut"}, "<") // 3->1
.to("#block-blue", {x: -110, duration: 0.8, ease: "power2.inOut"}, "<"); // 1->2
} else if (this.positionStep === 3) {
// Question: What's at pos 3? (Red is at 3)
gsap.set("#block-red", {x: 220}); gsap.set("#block-yellow", {x: -110}); gsap.set("#block-blue", {x: -110});
tl.to("#block-red", {opacity: 0, duration: 0.3}) // Hide the answer
.to("#q-mark", {opacity: 1, scale: 1.2, duration: 0.5, ease: "back.out(1.7)"});
}
},
nextPositionStep() { if(this.positionStep < 3) { this.positionStep++; this.runPositionAnimation(); } },
prevPositionStep() { if(this.positionStep > 0) { this.positionStep--; this.runPositionAnimation(); } },
// 动画:分组
runGroupAnimation() {
if (typeof gsap === 'undefined') return;
const tl = gsap.timeline();
// Reset
gsap.set(["#gbox-1", "#gbox-2", "#g-text"], {opacity: 0});
gsap.set("#final-rect", {opacity: 0.2, fill: "#74b9ff"});
if (this.groupStep === 1) {
tl.to(["#gbox-1", "#gbox-2"], {opacity: 1, duration: 0.5, stagger: 0.2})
.to("#g-text", {opacity: 1, y: 240, duration: 0.5});
} else if (this.groupStep === 2) {
gsap.set(["#gbox-1", "#gbox-2", "#g-text"], {opacity: 1});
tl.to("#final-rect", {opacity: 1, duration: 0.5, scale: 1.1, ease: "elastic.out(1, 0.3)"});
}
},
nextGroupStep() { if(this.groupStep < 2) { this.groupStep++; this.runGroupAnimation(); } },
prevGroupStep() { if(this.groupStep > 0) { this.groupStep--; this.runGroupAnimation(); } },
// 练习题逻辑
selectOption(index, correct) {
if (this.answered) return;
this.answered = true;
this.selectedOption = index;
this.isCorrect = correct;
if (correct) {
this.score += 20;
confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } });
}
},
nextQuestion() {
if (this.currentQuestion < this.practiceQuestions.length - 1) {
this.currentQuestion++;
this.answered = false;
this.selectedOption = null;
} else {
this.practiceCompleted = true;
}
},
// 奥数题逻辑
selectOlympiadOption(index, correct) {
if (this.olympiadAnswered) return;
if (correct) {
this.olympiadAnswered = true;
this.selectedOlympiadOption = index;
this.isOlympiadCorrect = true;
this.olympiadScore += 25;
this.wrongAttempts = 0;
confetti({ particleCount: 150, spread: 80, origin: { y: 0.6 } });
} else {
// 震动在CSS类中控制
this.wrongAttempts++;
if (this.wrongAttempts >= 3) {
this.olympiadAnswered = true;
this.selectedOlympiadOption = index;
this.isOlympiadCorrect = false;
}
}
},
nextOlympiad() {
if (this.currentOlympiad < this.olympiadQuestions.length - 1) {
this.currentOlympiad++;
this.olympiadAnswered = false;
this.selectedOlympiadOption = null;
this.wrongAttempts = 0;
} else {
this.olympiadCompleted = true;
}
}
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 AI 生成。
登录后可复制完整代码