console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>5以内口算卡片</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;font-family:system-ui,sans-serif}
body{background:#f7f9fc;padding:16px;min-height:100vh}
.title{text-align:center;font-size:22px;font-weight:bold;margin-bottom:12px;color:#222}
.info-row{display:flex;justify-content:space-between;color:#444;font-size:15px;margin-bottom:10px}
.card{background:#fff;border-radius:20px;box-shadow:0 4px 12px #00000015;padding:24px 16px}
.q-box{text-align:center;font-size:48px;font-weight:bold;margin:16px 0 24px;color:#111;min-height:70px}
canvas{display:block;width:100%;height:220px;border:2px solid #dde3ee;border-radius:16px;background:#fff;touch-action:none}
.tip{text-align:center;font-size:22px;font-weight:bold;height:40px;margin:12px 0;line-height:40px}
.right{color:#27ae60}
.wrong{color:#e74c3c}
.btns{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:14px}
button{padding:12px 6px;border:none;border-radius:12px;font-size:16px;color:white;background:#3478f6}
button.gray{background:#8898aa}
button.green{background:#27ae60}
.reset-btn{background:#9b59b6;margin-top:10px;width:100%}
</style>
</head>
<body>
<div class="title">5以内口算卡片</div>
<div class="info-row">
<div id="progressText"></div>
<div id="scoreText">对:0 错:0</div>
</div>
<div class="card">
<div class="q-box" id="question"></div>
<canvas id="board"></canvas>
<div class="tip" id="tip"></div>
<div class="btns">
<button class="gray" onclick="clearPad()">擦除</button>
<button class="green" onclick="checkAnswer()">判分</button>
<button onclick="nextQ()">下一题</button>
</div>
<button class="reset-btn" onclick="resetAll()">重新从头洗牌开始</button>
</div>
<script>
const canvas=document.getElementById('board'),ctx=canvas.getContext('2d');
const tip=document.getElementById('tip'),questionDom=document.getElementById('question');
const progressDom=document.getElementById('progressText'),scoreDom=document.getElementById('scoreText');
let w,h,drawing=false,currentItem=null,rightCount=0,wrongCount=0;
const questionList=[
{q:"0+0=",ans:0},{q:"1+0=",ans:1},{q:"0+1=",ans:1},
{q:"2+0=",ans:2},{q:"1+1=",ans:2},{q:"0+2=",ans:2},
{q:"3+0=",ans:3},{q:"2+1=",ans:3},{q:"1+2=",ans:3},{q:"0+3=",ans:3},
{q:"4+0=",ans:4},{q:"3+1=",ans:4},{q:"2+2=",ans:4},{q:"1+3=",ans:4},{q:"0+4=",ans:4},
{q:"5+0=",ans:5},{q:"4+1=",ans:5},{q:"3+2=",ans:5},{q:"2+3=",ans:5},{q:"1+4=",ans:5},{q:"0+5=",ans:5},
{q:"0-0=",ans:0},{q:"1-0=",ans:1},{q:"1-1=",ans:0},
{q:"2-0=",ans:2},{q:"2-1=",ans:1},{q:"2-2=",ans:0},
{q:"3-0=",ans:3},{q:"3-1=",ans:2},{q:"3-2=",ans:1},{q:"3-3=",ans:0},
{q:"4-0=",ans:4},{q:"4-1=",ans:3},{q:"4-2=",ans:2},{q:"4-3=",ans:1},{q:"4-4=",ans:0},
{q:"5-0=",ans:5},{q:"5-1=",ans:4},{q:"5-2=",ans:3},{q:"5-3=",ans:2},{q:"5-4=",ans:1},{q:"5-5=",ans:0},
];
let remainPool=[];
function shuffle(a){const b=[...a];for(let i=b.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[b[i],b[j]]=[b[j],b[i]];}return b;}
function resetAll(){remainPool=shuffle(questionList);rightCount=0;wrongCount=0;updateScore();nextQ();}
function updateScore(){scoreDom.innerText="对:"+rightCount+" 错:"+wrongCount;}
function resize(){w=canvas.clientWidth;h=canvas.clientHeight;canvas.width=w;canvas.height=h;ctx.lineCap='round';ctx.lineJoin='round';ctx.lineWidth=6;ctx.strokeStyle='#222';}
window.addEventListener('resize',resize);resize();
canvas.onpointerdown=e=>{e.preventDefault();drawing=true;const p=getPos(e);ctx.beginPath();ctx.moveTo(p.x,p.y);};
canvas.onpointermove=e=>{if(!drawing)return;e.preventDefault();const p=getPos(e);ctx.lineTo(p.x,p.y);ctx.stroke();};
canvas.onpointerup=canvas.onpointercancel=()=>drawing=false;
function getPos(e){const r=canvas.getBoundingClientRect();return{x:e.clientX-r.left,y:e.clientY-r.top};}
function clearPad(){ctx.clearRect(0,0,w,h);tip.innerText='';}
function nextQ(){clearPad();if(remainPool.length<=0){tip.innerText="全部题目做完啦!";tip.className="tip right";questionDom.innerText="完成";progressDom.innerText="一轮结束,可以点【重新从头洗牌开始】再来一遍";return;}currentItem=remainPool.pop();questionDom.innerText=currentItem.q;progressDom.innerText="剩余:"+remainPool.length+" / 总共:"+questionList.length;}
function checkAnswer(){const inputVal=prompt("输入手写的答案数字:");if(inputVal===null)return;const num=Number(inputVal);if(isNaN(num)){tip.innerText="请输入有效数字!";tip.className="tip wrong";return;}if(num===currentItem.ans){tip.innerText="答对啦!真棒";tip.className="tip right";rightCount++;}else{tip.innerText="不对,正确答案是:"+currentItem.ans;tip.className="tip wrong";wrongCount++;}updateScore();}
resetAll();
</script>
</body>
</html>