内容正文:
AI技术在教学中的应用初探
汇报人:连建华
1
开场与AI概览
01
2
从粉笔到智能助手
传统化学教学痛点
面对高中化学教学面临备课耗时、实验风险高、成绩分析繁琐以及班级管理细碎等痛点,这些问题长期困扰着教师,制约了教学效率的提升。
AI技术的赋能作用
AI技术的出现为化学教学带来了新的突破,它能够全流程渗透教学环节,重塑教师的工作格局,帮助教师从重复性工作中解放出来,从而更专注于教学设计和学生关怀。
3
利用AI快速开场视频
几秒钟后,你就能得到一段有图片、配音和背景音乐的视频了。这个功能非常适合用来制作课堂导入视频,既节省时间,又能保证视频的质量。
AI焕新备课流程
02
6
利用AI生成教学设计初稿
场景:设计《氧化还原反应》一课的教案。
工具:DeepSeek、Kimi、豆包
操作步骤:
输入提示词:“请为高中化学《氧化还原反应》一节设计一份教案,需包含教学目标、重难点、教学过程(导入、新知讲解、巩固练习、小结)和课后作业。”
AI生成初稿后,教师根据学情和教学风格进行修改和优化。
优势:节省备课时间,提供多样化的教学思路。
7
利用AI快速制作课件
场景:制作《元素周期表》的PPT课件。
工具:豆包、腾讯元宝等生成大纲,Kimi+生成PPT
扣子智能体,WPS AI
操作步骤:
输入提示词:“请生成一份高中化学鲁科版选择性必修2《原子结构模型》的PPT大纲,包含研究的历史、玻尔的原子结构模型、量子力学对原子核外电子一点状态的描述。”
提高课件制作效率
我们可以直接将AI生成的内容复制到PPT中,并在此基础上搭配图表和动画效果,从而大大提高课件制作的效率,确保课堂教学内容的逻辑性和专业性。
8
https://www.coze.cn/
AI重塑实验教学
03
10
酸性氢氧燃料电池的工作原理 微观实验升级方案
提示词:
你是一位高级程序员,设计用html格式输出的酸性氢氧燃料电池的工作原理的动画。 要求是编写一个微观动画(循环播放)完整的可视化元素:左侧灰色多孔负极和右侧黑色多孔正极,中间蓝色H2SO4电解质溶液区域,使用质子交换膜。 外电路:导线连接正负极,中间有灯泡。 详细的反应过程是: 负极反应:H2分子吸附、分解为H+和电子。 正极反应:O2分子吸附、与电子和通过质子交换膜的H+反应生成H2O。 离子迁移:H+向正极移动。 电子流动:金色电子从负极出发沿导线移动,灯泡亮起来。 需要丰富的视觉效果。
场景:设计《酸性氢氧燃料电池的工作原理》微观动画。
工具:DeepSeek
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>酸性氢氧燃料电池工作原理</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a2a3a, #0d1b2a);
color: #e0e0e0;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.container {
max-width: 1200px;
width: 100%;
text-align: center;
}
h1 {
margin: 20px 0;
font-size: 2.5rem;
color: #4fc3f7;
text-shadow: 0 0 10px rgba(79, 195, 247, 0.5);
}
.subtitle {
margin-bottom: 30px;
font-size: 1.2rem;
color: #b0bec5;
}
.animation-container {
position: relative;
width: 100%;
height: 600px;
background: #0a141f;
border-radius: 10px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.7);
overflow: hidden;
margin-bottom: 30px;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
.controls {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 30px;
flex-wrap: wrap;
}
button {
padding: 12px 25px;
font-size: 1rem;
background: #1565c0;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
button:hover {
background: #1976d2;
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.4);
}
button:active {
transform: translateY(0);
}
.explanation {
background: rgba(30, 40, 50, 0.7);
border-radius: 10px;
padding: 20px;
margin-top: 20px;
text-align: left;
max-width: 800px;
margin: 0 auto;
}
.explanation h2 {
color: #4fc3f7;
margin-bottom: 15px;
border-bottom: 1px solid #37474f;
padding-bottom: 10px;
}
.reaction {
display: flex;
justify-content: space-between;
margin: 20px 0;
flex-wrap: wrap;
}
.reaction-box {
flex: 1;
min-width: 300px;
background: rgba(20, 30, 40, 0.8);
border-radius: 8px;
padding: 15px;
margin: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.reaction-box h3 {
color: #81d4fa;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.reaction-box h3::before {
content: "•";
margin-right: 8px;
color: #4fc3f7;
}
.legend {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
margin-top: 20px;
}
.legend-item {
display: flex;
align-items: center;
margin: 5px;
}
.color-box {
width: 20px;
height: 20px;
margin-right: 8px;
border-radius: 3px;
}
.footer {
margin-top: 30px;
color: #78909c;
font-size: 0.9rem;
}
@media (max-width: 768px) {
h1 {
font-size: 2rem;
}
.animation-container {
height: 500px;
}
.reaction {
flex-direction: column;
}
}
</style>
</head>
<body>
<div class="container">
<h1>酸性氢氧燃料电池工作原理</h1>
<p class="subtitle">微观动画演示 - 酸性电解质(H₂SO₄)环境下的氢氧燃料电池</p>
<div class="animation-container">
<canvas id="fuelCellCanvas"></canvas>
</div>
<div class="controls">
<button id="playPauseBtn">暂停动画</button>
<button id="resetBtn">重置动画</button>
<button id="slowBtn">慢速播放</button>
<button id="normalBtn">正常速度</button>
</div>
<div class="explanation">
<h2>工作原理说明</h2>
<div class="reaction">
<div class="reaction-box">
<h3>负极反应(氢气氧化)</h3>
<p>H₂ → 2H⁺ + 2e⁻</p>
<p>氢气分子在负极催化剂表面吸附并分解为质子和电子。</p>
</div>
<div class="reaction-box">
<h3>正极反应(氧气还原)</h3>
<p>O₂ + 4H⁺ + 4e⁻ → 2H₂O</p>
<p>氧气分子在正极催化剂表面与质子和电子反应生成水。</p>
</div>
</div>
<div class="reaction">
<div class="reaction-box">
<h3>质子迁移</h3>
<p>H⁺ 通过质子交换膜从负极迁移到正极。</p>
</div>
<div class="reaction-box">
<h3>电子流动</h3>
<p>电子通过外电路从负极流向正极,驱动外部负载(灯泡)。</p>
</div>
</div>
<div class="legend">
<div class="legend-item">
<div class="color-box" style="background-color: #b0b0b0;"></div>
<span>负极(多孔石墨)</span>
</div>
<div class="legend-item">
<div class="color-box" style="background-color: #303030;"></div>
<span>正极(多孔石墨)</span>
</div>
<div class="legend-item">
<div class="color-box" style="background-color: #1e88e5;"></div>
<span>电解质(H₂SO₄溶液)</span>
</div>
<div class="legend-item">
<div class="color-box" style="background-color: #ffd54f;"></div>
<span>电子</span>
</div>
<div class="legend-item">
<div class="color-box" style="background-color: #e57373;"></div>
<span>质子(H⁺)</span>
</div>
<div class="legend-item">
<div class="color-box" style="background-color: #81c784;"></div>
<span>水分子(H₂O)</span>
</div>
</div>
</div>
<div class="footer">
<p>酸性氢氧燃料电池工作原理动画演示 | 修正版</p>
</div>
</div>
<script>
// 获取Canvas元素和上下文
const canvas = document.getElementById('fuelCellCanvas');
const ctx = canvas.getContext('2d');
// 设置Canvas尺寸
function resizeCanvas() {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
}
// 初始化时设置尺寸
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 动画控制变量
let animationId = null;
let isPlaying = true;
let animationSpeed = 1;
// 燃料电池组件尺寸
const cellWidth = canvas.width * 0.9;
const cellHeight = canvas.height * 0.5;
const cellX = (canvas.width - cellWidth) / 2;
const cellY = canvas.height * 0.3;
// 电极尺寸
const electrodeWidth = cellWidth * 0.1;
const anodeX = cellX;
const cathodeX = cellX + cellWidth - electrodeWidth;
// 质子交换膜尺寸
const membraneWidth = cellWidth * 0.02;
const membraneX = cellX + cellWidth / 2 - membraneWidth / 2;
// 导线路径点 - 从电极正上方出发
const wirePath = {
// 负极导线路径
anodeStart: { x: anodeX + electrodeWidth/2, y: cellY - 10 },
anodeToBulb: { x: cellX + cellWidth * 0.3, y: cellY - 80 },
// 灯泡位置
bulb: { x: canvas.width / 2, y: cellY - 120 },
// 正极导线路径
cathodeToBulb: { x: cellX + cellWidth * 0.7, y: cellY - 80 },
cathodeEnd: { x: cathodeX + electrodeWidth/2, y: cellY - 10 }
};
// 灯泡参数
const bulbRadius = 25;
// 粒子类
class Particle {
constructor(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.active = true;
}
draw() {
if (!this.active) return;
ctx.save();
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.restore();
}
}
// 电子类 - 严格沿导线流动
class Electron extends Particle {
constructor(x, y) {
super(x, y, 5, '#ffd54f');
this.pathProgress = 0; // 0到100,表示在导线上的进度
this.speed = 1.5;
}
update() {
if (!this.active) return;
this.pathProgress += this.speed * animationSpeed;
if (this.pathProgress <= 50) {
// 负极到灯泡段
const t = this.pathProgress / 50;
this.x = wirePath.anodeStart.x + (wirePath.anodeToBulb.x - wirePath.anodeStart.x) * t;
this.y = wirePath.anodeStart.y + (wirePath.anodeToBulb.y - wirePath.anodeStart.y) * t;
} else if (this.pathProgress <= 100) {
// 灯泡到正极段
const t = (this.pathProgress - 50) / 50;
this.x = wirePath.anodeToBulb.x + (wirePath.cathodeEnd.x - wirePath.anodeToBulb.x) * t;
this.y = wirePath.anodeToBulb.y + (wirePath.cathodeEnd.y - wirePath.anodeToBulb.y) * t;
} else {
// 电子到达正极,参与反应
this.active = false;
// 触发水分子生成
createWaterMolecule(this.x, cellY + 10);
}
}
}
// 质子类
class Proton extends Particle {
constructor(x, y) {
super(x, y, 6, '#e57373');
this.speedX = 1.2;
}
update() {
if (!this.active) return;
// 质子向正极移动
this.x += this.speedX * animationSpeed;
// 质子到达正极区域
if (this.x > cathodeX - 10) {
this.active = false;
}
}
}
// 水分子类
class Water extends Particle {
constructor(x, y) {
super(x, y, 8, '#81c784');
this.speedY = 0.5;
this.lifetime = 200; // 水分子存在时间
}
update() {
if (!this.active) return;
// 水分子向下移动(沉入溶液)
this.y += this.speedY * animationSpeed;
this.lifetime -= animationSpeed;
// 水分子逐渐消失
if (this.lifetime < 50) {
this.radius = 8 * (this.lifetime / 50);
}
if (this.lifetime <= 0) {
this.active = false;
}
}
}
// 氢气分子类
class Hydrogen extends Particle {
constructor(x, y) {
super(x, y, 10, '#90caf9');
this.speedX = -0.8;
this.oscillation = Math.random() * Math.PI * 2;
}
update() {
if (!this.active) return;
// 氢气向负极移动
this.x += this.speedX * animationSpeed;
this.oscillation += 0.05;
this.y += Math.sin(this.oscillation) * 0.3;
// 氢气到达负极表面
if (this.x < anodeX + electrodeWidth + 15) {
this.active = false;
// 生成质子和电子
createProtonAndElectron(this.x, this.y);
}
}
}
// 氧气分子类
class Oxygen extends Particle {
constructor(x, y) {
super(x, y, 12, '#ffab91');
this.speedX = 0.6;
this.oscillation = Math.random() * Math.PI * 2;
}
update() {
if (!this.active) return;
// 氧气在正极区域移动
this.x += this.speedX * animationSpeed;
this.oscillation += 0.05;
this.y += Math.sin(this.oscillation) * 0.3;
// 氧气循环移动
if (this.x > cathodeX + 30) {
this.x = cathodeX - 40;
}
}
}
// 粒子数组
let electrons = [];
let protons = [];
let waters = [];
let hydrogens = [];
let oxygens = [];
// 灯泡状态
let bulbBrightness = 0;
let bulbGlow = 0;
// 创建质子和电子
function createProtonAndElectron(x, y) {
// 创建质子(在电解质溶液中)
protons.push(new Proton(x, y));
// 创建电子(在导线上)
electrons.push(new Electron(wirePath.anodeStart.x, wirePath.anodeStart.y));
// 添加新的氢气分子
hydrogens.push(new Hydrogen(
anodeX + electrodeWidth + 80 + Math.random() * 50,
cellY + 30 + Math.random() * (cellHeight - 60)
));
}
// 创建水分子
function createWaterMolecule(x, y) {
waters.push(new Water(x, y));
// 添加新的氧气分子
oxygens.push(new Oxygen(
cathodeX - 40 - Math.random() * 30,
cellY + 30 + Math.random() * (cellHeight - 60)
));
}
// 初始化粒子
function initParticles() {
electrons = [];
protons = [];
waters = [];
hydrogens = [];
oxygens = [];
// 初始化氢气分子(在负极区域)
for (let i = 0; i < 6; i++) {
hydrogens.push(new Hydrogen(
anodeX + electrodeWidth + 50 + Math.random() * 80,
cellY + 30 + Math.random() * (cellHeight - 60)
));
}
// 初始化氧气分子(在正极区域)
for (let i = 0; i < 4; i++) {
oxygens.push(new Oxygen(
cathodeX - 40 - Math.random() * 50,
cellY + 30 + Math.random() * (cellHeight - 60)
));
}
bulbBrightness = 0;
bulbGlow = 0;
}
// 绘制燃料电池
function drawFuelCell() {
// 绘制背景
ctx.fillStyle = '#0a141f';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制电池外壳
ctx.strokeStyle = '#78909c';
ctx.lineWidth = 3;
ctx.strokeRect(cellX - 5, cellY - 5, cellWidth + 10, cellHeight + 10);
// 绘制电解质区域
const gradient = ctx.createLinearGradient(cellX, cellY, cellX, cellY + cellHeight);
gradient.addColorStop(0, '#0d47a1');
gradient.addColorStop(1, '#1565c0');
ctx.fillStyle = gradient;
ctx.fillRect(cellX, cellY, cellWidth, cellHeight);
// 绘制电解质纹理
ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
for (let i = 0; i < 50; i++) {
const x = cellX + Math.random() * cellWidth;
const y = cellY + Math.random() * cellHeight;
const size = Math.random() * 4 + 1;
ctx.fillRect(x, y, size, size);
}
// 绘制负极(灰色多孔)
const anodeGradient = ctx.createLinearGradient(anodeX, cellY, anodeX + electrodeWidth, cellY);
anodeGradient.addColorStop(0, '#909090');
anodeGradient.addColorStop(1, '#b0b0b0');
ctx.fillStyle = anodeGradient;
ctx.fillRect(anodeX, cellY, electrodeWidth, cellHeight);
// 绘制负极孔隙
ctx.fillStyle = '#707070';
for (let i = 0; i < 25; i++) {
const x = anodeX + Math.random() * electrodeWidth;
const y = cellY + Math.random() * cellHeight;
const size = Math.random() * 6 + 3;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
// 绘制正极(黑色多孔)
const cathodeGradient = ctx.createLinearGradient(cathodeX, cellY, cathodeX + electrodeWidth, cellY);
cathodeGradient.addColorStop(0, '#202020');
cathodeGradient.addColorStop(1, '#404040');
ctx.fillStyle = cathodeGradient;
ctx.fillRect(cathodeX, cellY, electrodeWidth, cellHeight);
// 绘制正极孔隙
ctx.fillStyle = '#101010';
for (let i = 0; i < 25; i++) {
const x = cathodeX + Math.random() * electrodeWidth;
const y = cellY + Math.random() * cellHeight;
const size = Math.random() * 6 + 3;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
// 绘制质子交换膜
ctx.fillStyle = '#f5f5f5';
ctx.fillRect(membraneX, cellY, membraneWidth, cellHeight);
// 绘制膜上的纹理
ctx.fillStyle = '#e0e0e0';
for (let i = 0; i < 20; i++) {
const y = cellY + Math.random() * cellHeight;
const height = Math.random() * 8 + 4;
ctx.fillRect(membraneX, y, membraneWidth, height);
}
// 绘制外电路导线
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 4;
// 负极导线
ctx.beginPath();
ctx.moveTo(wirePath.anodeStart.x, wirePath.anodeStart.y);
ctx.lineTo(wirePath.anodeToBulb.x, wirePath.anodeToBulb.y);
ctx.lineTo(wirePath.bulb.x, wirePath.bulb.y);
ctx.stroke();
// 正极导线
ctx.beginPath();
ctx.moveTo(wirePath.bulb.x, wirePath.bulb.y);
ctx.lineTo(wirePath.cathodeToBulb.x, wirePath.cathodeToBulb.y);
ctx.lineTo(wirePath.cathodeEnd.x, wirePath.cathodeEnd.y);
ctx.stroke();
// 绘制灯泡发光效果
if (bulbBrightness > 0) {
bulbGlow += 0.1;
const glowSize = bulbRadius * (1.5 + Math.sin(bulbGlow) * 0.3);
const glowGradient = ctx.createRadialGradient(
wirePath.bulb.x, wirePath.bulb.y, bulbRadius,
wirePath.bulb.x, wirePath.bulb.y, glowSize
);
glowGradient.addColorStop(0, `rgba(255, 255, 200, ${bulbBrightness * 0.8})`);
glowGradient.addColorStop(1, 'rgba(255, 255, 200, 0)');
ctx.fillStyle = glowGradient;
ctx.beginPath();
ctx.arc(wirePath.bulb.x, wirePath.bulb.y, glowSize, 0, Math.PI * 2);
ctx.fill();
}
// 绘制灯泡
ctx.fillStyle = `rgba(255, 255, 200, ${bulbBrightness})`;
ctx.beginPath();
ctx.arc(wirePath.bulb.x, wirePath.bulb.y, bulbRadius, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#cccccc';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(wirePath.bulb.x, wirePath.bulb.y, bulbRadius, 0, Math.PI * 2);
ctx.stroke();
// 绘制灯泡底座
ctx.fillStyle = '#aaaaaa';
ctx.fillRect(wirePath.bulb.x - 15, wirePath.bulb.y + bulbRadius, 30, 10);
// 绘制标签
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.fillText('负极', anodeX + electrodeWidth / 2, cellY - 15);
ctx.fillText('正极', cathodeX + electrodeWidth / 2, cellY - 15);
ctx.fillText('质子交换膜', membraneX + membraneWidth / 2, cellY - 35);
ctx.fillText('H₂SO₄电解质', cellX + cellWidth / 2, cellY + cellHeight + 25);
// 绘制反应方程式
ctx.font = '14px Arial';
ctx.fillText('H₂ → 2H⁺ + 2e⁻', anodeX + electrodeWidth / 2, cellY + cellHeight + 50);
ctx.fillText('O₂ + 4H⁺ + 4e⁻ → 2H₂O', cathodeX + electrodeWidth / 2, cellY + cellHeight + 50);
}
// 更新和绘制粒子
function updateParticles() {
// 更新氢气分子
hydrogens = hydrogens.filter(h => h.active);
hydrogens.forEach(h => h.update());
// 更新质子
protons = protons.filter(p => p.active);
protons.forEach(p => p.update());
// 更新电子
electrons = electrons.filter(e => e.active);
electrons.forEach(e => e.update());
// 更新灯泡亮度(基于电子数量)
bulbBrightness = Math.min(0.8, electrons.length / 8);
// 更新水分子
waters = waters.filter(w => w.active);
waters.forEach(w => w.update());
// 更新氧气分子
oxygens = oxygens.filter(o => o.active);
oxygens.forEach(o => o.update());
}
// 绘制所有粒子
function drawParticles() {
// 绘制氢气分子
hydrogens.forEach(h => h.draw());
// 绘制氧气分子
oxygens.forEach(o => o.draw());
// 绘制质子
protons.forEach(p => p.draw());
// 绘制电子
electrons.forEach(e => e.draw());
// 绘制水分子
waters.forEach(w => w.draw());
}
// 动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFuelCell();
updateParticles();
drawParticles();
if (isPlaying) {
animationId = requestAnimationFrame(animate);
}
}
// 初始化动画
initParticles();
animate();
// 控制按钮事件
document.getElementById('playPauseBtn').addEventListener('click', function() {
isPlaying = !isPlaying;
this.textContent = isPlaying ? '暂停动画' : '继续动画';
if (isPlaying) {
animate();
} else {
cancelAnimationFrame(animationId);
}
});
document.getElementById('resetBtn').addEventListener('click', function() {
initParticles();
});
document.getElementById('slowBtn').addEventListener('click', function() {
animationSpeed = 0.5;
});
document.getElementById('normalBtn').addEventListener('click', function() {
animationSpeed = 1;
});
</script>
</body>
</html>
酸碱中和反应 微观动画
提示词:
请用 HTML + CSS + JavaScript 写一个 酸碱中和反应的动态可视化代码,具体要求:
离子:H⁺(红色,标‘H⁺’)、OH⁻(蓝色,标‘OH⁻’)、Na⁺(紫色,标‘Na⁺’)、Cl⁻(绿色,标‘Cl⁻’)。
反应过程:H⁺ 和 OH⁻ 从屏幕两侧移动到中间,碰撞后结合成 H₂O(标‘H₂O’)。
游离离子:Na⁺ 和 Cl⁻ 保持游离,在背景中缓慢移动。
交互:加一个 ‘开始反应’按钮,点击后触发动画。
标注:显示 ‘H⁺ + OH⁻ → H₂O’ 的化学方程式。
输出:完整可运行的 HTML文件代码(含CSS+JS),并注释关键部分。
场景:设计《酸碱中和反应》微观动画。
工具:腾讯元宝出提示词、DeepSeek写代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>酸碱中和反应动态可视化</title>
<style>
body {
font-family: 'Arial', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f5f5f5;
margin: 0;
padding: 20px;
}
h1 {
color: #333;
margin-bottom: 10px;
}
.equation {
font-size: 24px;
margin-bottom: 20px;
padding: 10px 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.container {
position: relative;
width: 800px;
height: 400px;
margin-bottom: 20px;
border: 2px solid #ddd;
border-radius: 5px;
overflow: hidden;
background-color: #fff;
}
canvas {
display: block;
}
.controls {
margin-top: 10px;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #45a049;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.legend {
display: flex;
justify-content: center;
margin-top: 20px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
margin: 0 15px;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 5px;
}
</style>
</head>
<body>
<h1>酸碱中和反应动态可视化</h1>
<div class="equation">H⁺ + OH⁻ → H₂O</div>
<div class="container">
<canvas id="reactionCanvas" width="800" height="400"></canvas>
</div>
<div class="controls">
<button id="startButton">开始反应</button>
<button id="resetButton" disabled>重置</button>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background-color: #ff4444;"></div>
<span>H⁺ (氢离子)</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #4444ff;"></div>
<span>OH⁻ (氢氧根离子)</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #aa44ff;"></div>
<span>Na⁺ (钠离子)</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #44ff44;"></div>
<span>Cl⁻ (氯离子)</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background-color: #cccccc;"></div>
<span>H₂O (水分子)</span>
</div>
</div>
<script>
// 获取Canvas元素和上下文
const canvas = document.getElementById('reactionCanvas');
const ctx = canvas.getContext('2d');
// 获取按钮元素
const startButton = document.getElementById('startButton');
const resetButton = document.getElementById('resetButton');
// 定义离子和分子
const ions = {
hPlus: { x: 100, y: 200, color: '#ff4444', label: 'H⁺', radius: 20, speed: 2, targetX: 400 },
ohMinus: { x: 700, y: 200, color: '#4444ff', label: 'OH⁻', radius: 20, speed: 2, targetX: 400 },
naPlus: { x: 200, y: 100, color: '#aa44ff', label: 'Na⁺', radius: 15, speed: 0.5, direction: 1 },
clMinus: { x: 600, y: 300, color: '#44ff44', label: 'Cl⁻', radius: 15, speed: 0.5, direction: 1 }
};
// 水分子
let waterMolecule = null;
// 动画状态
let animationId = null;
let reactionStarted = false;
let reactionComplete = false;
// 绘制离子
function drawIon(ion) {
ctx.beginPath();
ctx.arc(ion.x, ion.y, ion.radius, 0, Math.PI * 2);
ctx.fillStyle = ion.color;
ctx.fill();
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.stroke();
// 绘制标签
ctx.font = '16px Arial';
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(ion.label, ion.x, ion.y);
}
// 绘制水分子
function drawWaterMolecule() {
if (!waterMolecule) return;
ctx.beginPath();
ctx.arc(waterMolecule.x, waterMolecule.y, waterMolecule.radius, 0, Math.PI * 2);
ctx.fillStyle = waterMolecule.color;
ctx.fill();
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.stroke();
// 绘制标签
ctx.font = '16px Arial';
ctx.fillStyle = '#fff';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(waterMolecule.label, waterMolecule.x, waterMolecule.y);
}
// 更新离子位置
function updateIons() {
// 更新H⁺和OH⁻的位置(向中间移动)
if (reactionStarted && !reactionComplete) {
if (ions.hPlus.x < ions.hPlus.targetX) {
ions.hPlus.x += ions.hPlus.speed;
}
if (ions.ohMinus.x > ions.ohMinus.targetX) {
ions.ohMinus.x -= ions.ohMinus.speed;
}
// 检查是否碰撞
const distance = Math.sqrt(
Math.pow(ions.hPlus.x - ions.ohMinus.x, 2) +
Math.pow(ions.hPlus.y - ions.ohMinus.y, 2)
);
if (distance < ions.hPlus.radius + ions.ohMinus.radius) {
reactionComplete = true;
// 创建水分子
waterMolecule = {
x: (ions.hPlus.x + ions.ohMinus.x) / 2,
y: (ions.hPlus.y + ions.ohMinus.y) / 2,
color: '#cccccc',
label: 'H₂O',
radius: 25
};
}
}
// 更新游离离子的位置(随机移动)
ions.naPlus.y += ions.naPlus.speed * ions.naPlus.direction;
if (ions.naPlus.y <= ions.naPlus.radius || ions.naPlus.y >= canvas.height - ions.naPlus.radius) {
ions.naPlus.direction *= -1;
}
ions.clMinus.y += ions.clMinus.speed * ions.clMinus.direction;
if (ions.clMinus.y <= ions.clMinus.radius || ions.clMinus.y >= canvas.height - ions.clMinus.radius) {
ions.clMinus.direction *= -1;
}
}
// 绘制背景网格(模拟溶液环境)
function drawBackground() {
// 绘制浅蓝色背景
ctx.fillStyle = 'rgba(200, 230, 255, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制网格线
ctx.strokeStyle = 'rgba(200, 230, 255, 0.5)';
ctx.lineWidth = 1;
// 垂直线
for (let x = 0; x < canvas.width; x += 40) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
// 水平线
for (let y = 0; y < canvas.height; y += 40) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
// 主动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制背景
drawBackground();
// 更新离子位置
updateIons();
// 绘制游离离子
drawIon(ions.naPlus);
drawIon(ions.clMinus);
// 绘制反应离子或水分子
if (!reactionComplete) {
drawIon(ions.hPlus);
drawIon(ions.ohMinus);
} else {
drawWaterMolecule();
}
// 继续动画
animationId = requestAnimationFrame(animate);
}
// 开始动画
function startAnimation() {
if (!reactionStarted) {
reactionStarted = true;
startButton.disabled = true;
resetButton.disabled = false;
animate();
}
}
// 重置动画
function resetAnimation() {
// 停止当前动画
if (animationId) {
cancelAnimationFrame(animationId);
}
// 重置离子位置
ions.hPlus.x = 100;
ions.ohMinus.x = 700;
ions.naPlus.y = 100;
ions.clMinus.y = 300;
// 重置状态
reactionStarted = false;
reactionComplete = false;
waterMolecule = null;
// 重置按钮状态
startButton.disabled = false;
resetButton.disabled = true;
// 重绘初始状态
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBackground();
drawIon(ions.hPlus);
drawIon(ions.ohMinus);
drawIon(ions.naPlus);
drawIon(ions.clMinus);
}
// 初始化
function init() {
// 绘制初始状态
drawBackground();
drawIon(ions.hPlus);
drawIon(ions.ohMinus);
drawIon(ions.naPlus);
drawIon(ions.clMinus);
// 添加事件监听器
startButton.addEventListener('click', startAnimation);
resetButton.addEventListener('click', resetAnimation);
}
// 页面加载完成后初始化
window.addEventListener('load', init);
</script>
</body>
</html>
https://www.bukenghezi.com/
AI精准成绩分析
04
17
期中数据一键诊断
AI快速分析成绩数据
将年级化学期中考试成绩表上传至DeepSeek,豆包等AI能够快速输出平均分、及格率、优秀率等关键数据,并精准定位各班级的薄弱知识点,为教师提供直观的数据支持。
18
个性化学习建议批量生成
AI生成个性化学习建议
通过将学生的分数与错题输入Kimi,AI能够基于错因分析为每位学生生成个性化的学习建议,包括对应的知识讲解链接和变式练习题,真正实现因材施教。
19
个性化成绩单批量生成
Excel表格输入相应的数据
我个人觉得最好用的是:豆包
AI赋能班级管理
05
21
智能座位表优化策略
AI生成座位方案
输入学生的身高、视力、性格和成绩等信息后,AI能够利用组合算法自动生成多版座位方案,兼顾纪律和学习帮扶需求,为班主任提供科学的决策依据。
班主任微调确认
班主任可以在AI生成的座位方案基础上,根据实际情况进行实时拖拽微调,并查看冲突提示,几分钟内完成原本需要半天思考的排座任务,提高工作效率。
22
场景:设计《座位表》
工具:DeepSeek
提示词:你是高中班主任,想要制作一份可以支持excel表格导入学生名单,支持设置教室列数和行数的可以拖拽调换位置移动的座位表。排座位规则按身高顺序由矮到高或视力由高度近视到视力良好;附加规则男女平衡分布、成绩名次互补的功能。并且将男生女生分别用淡蓝和淡粉色表示,空位显示“空”用灰色表示。最后需要有导出编排后的座位表功能。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能座位编排系统</title>
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: "Microsoft YaHei", sans-serif;
}
body {
background-color: #f5f7fa;
padding: 20px;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #2c3e50;
border-bottom: 2px solid #3498db;
padding-bottom: 10px;
}
.control-panel {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
.panel-section {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #3498db;
}
h2 {
font-size: 18px;
margin-bottom: 15px;
color: #2c3e50;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, select, button {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
button {
background: #3498db;
color: white;
border: none;
cursor: pointer;
transition: background 0.3s;
font-weight: bold;
}
button:hover {
background: #2980b9;
}
.file-upload {
background: #ecf0f1;
padding: 10px;
border-radius: 4px;
text-align: center;
border: 2px dashed #bdc3c7;
cursor: pointer;
margin-bottom: 10px;
}
.file-upload:hover {
background: #dfe6e9;
}
.classroom-container {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
}
.blackboard {
width: 80%;
background: #2c3e50;
color: white;
text-align: center;
padding: 15px;
border-radius: 10px 10px 0 0;
margin-bottom: 20px;
font-size: 20px;
font-weight: bold;
}
.seats-grid {
display: grid;
gap: 10px;
width: 100%;
margin-bottom: 30px;
}
.seat {
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
text-align: center;
cursor: move;
transition: all 0.3s;
min-height: 80px;
display: flex;
flex-direction: column;
justify-content: center;
}
.seat.male {
background-color: #d6eaf8;
}
.seat.female {
background-color: #fadbd8;
}
.seat.empty {
background-color: #ecf0f1;
color: #7f8c8d;
}
.seat.dragging {
opacity: 0.5;
transform: scale(0.95);
}
.student-name {
font-weight: bold;
margin-bottom: 5px;
}
.student-info {
font-size: 12px;
color: #666;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 15px;
margin-top: 20px;
}
.action-buttons button {
width: auto;
padding: 10px 20px;
}
.export-btn {
background: #27ae60;
}
.export-btn:hover {
background: #219653;
}
.print-btn {
background: #e67e22;
}
.print-btn:hover {
background: #d35400;
}
.student-list {
margin-top: 20px;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
}
.student-item {
padding: 5px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
}
@media print {
.control-panel, .action-buttons {
display: none;
}
.seat {
border: 1px solid #000;
break-inside: avoid;
}
}
</style>
</head>
<body>
<div class="container">
<h1>智能座位编排系统</h1>
<div class="control-panel">
<div class="panel-section">
<h2>数据导入</h2>
<div class="form-group">
<div class="file-upload" id="fileUpload">
<p>点击上传Excel或TXT文件</p>
<input type="file" id="fileInput" accept=".xlsx,.xls,.txt" style="display: none;">
</div>
<div id="fileName">未选择文件</div>
</div>
<div class="form-group">
<label for="classLayout">教室布局(行×列)</label>
<div style="display: flex; gap: 10px;">
<input type="number" id="rows" placeholder="行数" min="1" max="10" value="6">
<input type="number" id="cols" placeholder="列数" min="1" max="10" value="8">
</div>
</div>
<button id="generateSeats">生成座位表</button>
</div>
<div class="panel-section">
<h2>排序规则</h2>
<div class="form-group">
<label for="sortRule">主要排序规则</label>
<select id="sortRule">
<option value="height">按身高(由矮到高)</option>
<option value="vision">按视力(由高度近视到良好)</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="genderBalance" checked> 男女平衡分布
</label>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="scoreComplement" checked> 成绩名次互补
</label>
</div>
<button id="autoArrange">智能编排座位</button>
</div>
</div>
<div class="classroom-container">
<div class="blackboard">讲台</div>
<div class="seats-grid" id="seatsGrid">
<!-- 座位将通过JavaScript动态生成 -->
</div>
</div>
<div class="action-buttons">
<button class="export-btn" id="exportBtn">导出座位表</button>
<button class="print-btn" id="printBtn">打印座位表</button>
</div>
<div class="student-list" id="studentList">
<!-- 学生列表将通过JavaScript动态生成 -->
</div>
</div>
<script>
// 示例学生数据
let students = [
{ id: 1, name: "张三", gender: "male", height: 165, vision: 4.8, score: 85 },
{ id: 2, name: "李四", gender: "female", height: 158, vision: 5.0, score: 92 },
{ id: 3, name: "王五", gender: "male", height: 172, vision: 4.5, score: 78 },
{ id: 4, name: "赵六", gender: "female", height: 160, vision: 4.9, score: 88 },
{ id: 5, name: "钱七", gender: "male", height: 168, vision: 4.7, score: 95 },
{ id: 6, name: "孙八", gender: "female", height: 155, vision: 5.1, score: 82 },
{ id: 7, name: "周九", gender: "male", height: 170, vision: 4.6, score: 79 },
{ id: 8, name: "吴十", gender: "female", height: 162, vision: 4.8, score: 90 },
{ id: 9, name: "郑十一", gender: "male", height: 166, vision: 4.9, score: 87 },
{ id: 10, name: "王十二", gender: "female", height: 159, vision: 5.0, score: 93 },
{ id: 11, name: "李十三", gender: "male", height: 174, vision: 4.4, score: 76 },
{ id: 12, name: "张十四", gender: "female", height: 157, vision: 4.7, score: 84 },
{ id: 13, name: "刘十五", gender: "male", height: 169, vision: 4.8, score: 89 },
{ id: 14, name: "陈十六", gender: "female", height: 161, vision: 5.0, score: 91 },
{ id: 15, name: "杨十七", gender: "male", height: 167, vision: 4.6, score: 80 },
{ id: 16, name: "黄十八", gender: "female", height: 156, vision: 4.9, score: 86 }
];
// 座位安排数据
let seatArrangement = [];
let draggedSeat = null;
// DOM元素
const fileUpload = document.getElementById('fileUpload');
const fileInput = document.getElementById('fileInput');
const fileName = document.getElementById('fileName');
const rowsInput = document.getElementById('rows');
const colsInput = document.getElementById('cols');
const generateSeatsBtn = document.getElementById('generateSeats');
const sortRuleSelect = document.getElementById('sortRule');
const genderBalanceCheckbox = document.getElementById('genderBalance');
const scoreComplementCheckbox = document.getElementById('scoreComplement');
const autoArrangeBtn = document.getElementById('autoArrange');
const seatsGrid = document.getElementById('seatsGrid');
const exportBtn = document.getElementById('exportBtn');
const printBtn = document.getElementById('printBtn');
const studentList = document.getElementById('studentList');
// 初始化
document.addEventListener('DOMContentLoaded', function() {
// 绑定事件
fileUpload.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileUpload);
generateSeatsBtn.addEventListener('click', generateSeats);
autoArrangeBtn.addEventListener('click', autoArrangeSeats);
exportBtn.addEventListener('click', exportSeatMap);
printBtn.addEventListener('click', printSeatMap);
// 初始生成座位表
generateSeats();
updateStudentList();
});
// 处理文件上传
function handleFileUpload(event) {
const file = event.target.files[0];
if (!file) return;
fileName.textContent = file.name;
const reader = new FileReader();
reader.onload = function(e) {
const data = e.target.result;
if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
// 处理Excel文件
processExcelFile(data);
} else if (file.name.endsWith('.txt')) {
// 处理TXT文件
processTxtFile(data);
}
};
reader.readAsBinaryString(file);
}
// 处理Excel文件
function processExcelFile(data) {
try {
const workbook = XLSX.read(data, { type: 'binary' });
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
const jsonData = XLSX.utils.sheet_to_json(firstSheet);
students = jsonData.map((row, index) => ({
id: index + 1,
name: row.姓名 || row.name || `学生${index+1}`,
gender: row.性别 === '女' || row.gender === 'female' ? 'female' : 'male',
height: parseInt(row.身高 || row.height) || 160 + Math.floor(Math.random() * 20),
vision: parseFloat(row.视力 || row.vision) || (4.5 + Math.random() * 0.6).toFixed(1),
score: parseInt(row.成绩 || row.score) || 60 + Math.floor(Math.random() * 40)
}));
generateSeats();
updateStudentList();
} catch (error) {
alert('Excel文件处理出错: ' + error.message);
}
}
// 处理TXT文件
function processTxtFile(data) {
try {
const lines = data.split('
');
students = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;
// 假设TXT格式为: 姓名,性别,身高,视力,成绩
const parts = line.split(',');
if (parts.length >= 3) {
students.push({
id: i + 1,
name: parts[0] || `学生${i+1}`,
gender: parts[1] === '女' ? 'female' : 'male',
height: parseInt(parts[2]) || 160 + Math.floor(Math.random() * 20),
vision: parseFloat(parts[3]) || (4.5 + Math.random() * 0.6).toFixed(1),
score: parseInt(parts[4]) || 60 + Math.floor(Math.random() * 40)
});
}
}
generateSeats();
updateStudentList();
} catch (error) {
alert('TXT文件处理出错: ' + error.message);
}
}
// 生成座位表
function generateSeats() {
const rows = parseInt(rowsInput.value) || 6;
const cols = parseInt(colsInput.value) || 8;
const totalSeats = rows * cols;
// 初始化座位安排
seatArrangement = [];
for (let i = 0; i < totalSeats; i++) {
if (i < students.length) {
seatArrangement.push(students[i]);
} else {
seatArrangement.push(null); // 空座位
}
}
renderSeats(rows, cols);
}
// 渲染座位表
function renderSeats(rows, cols) {
seatsGrid.innerHTML = '';
seatsGrid.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
for (let i = 0; i < rows * cols; i++) {
const seat = document.createElement('div');
seat.className = 'seat';
seat.dataset.index = i;
if (seatArrangement[i]) {
const student = seatArrangement[i];
seat.classList.add(student.gender);
seat.innerHTML = `
<div class="student-name">${student.name}</div>
<div class="student-info">身高: ${student.height}cm</div>
<div class="student-info">视力: ${student.vision}</div>
<div class="student-info">成绩: ${student.score}</div>
`;
} else {
seat.classList.add('empty');
seat.textContent = '空';
}
// 添加拖拽功能
seat.draggable = true;
seat.addEventListener('dragstart', handleDragStart);
seat.addEventListener('dragover', handleDragOver);
seat.addEventListener('drop', handleDrop);
seat.addEventListener('dragend', handleDragEnd);
seatsGrid.appendChild(seat);
}
}
// 拖拽功能实现
function handleDragStart(e) {
draggedSeat = this;
this.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
}
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
}
function handleDrop(e) {
e.preventDefault();
if (draggedSeat !== this) {
const fromIndex = parseInt(draggedSeat.dataset.index);
const toIndex = parseInt(this.dataset.index);
// 交换座位
[seatArrangement[fromIndex], seatArrangement[toIndex]] =
[seatArrangement[toIndex], seatArrangement[fromIndex]];
renderSeats(parseInt(rowsInput.value), parseInt(colsInput.value));
}
}
function handleDragEnd() {
this.classList.remove('dragging');
draggedSeat = null;
}
// 智能编排座位
function autoArrangeSeats() {
const rows = parseInt(rowsInput.value) || 6;
const cols = parseInt(colsInput.value) || 8;
const totalSeats = rows * cols;
const sortRule = sortRuleSelect.value;
const genderBalance = genderBalanceCheckbox.checked;
const scoreComplement = scoreComplementCheckbox.checked;
// 复制学生数组
let sortedStudents = [...students];
// 按规则排序
if (sortRule === 'height') {
sortedStudents.sort((a, b) => a.height - b.height);
} else if (sortRule === 'vision') {
sortedStudents.sort((a, b) => a.vision - b.vision);
}
// 如果需要成绩互补,则按蛇形排列
if (scoreComplement) {
// 先按成绩排序
sortedStudents.sort((a, b) => b.score - a.score);
// 蛇形排列
let snakeArranged = [];
for (let i = 0; i < rows; i++) {
const row = sortedStudents.slice(i * cols, (i + 1) * cols);
if (i % 2 === 1) {
row.reverse(); // 奇数行反转,形成蛇形
}
snakeArranged = snakeArranged.concat(row);
}
sortedStudents = snakeArranged;
}
// 如果需要男女平衡
if (genderBalance) {
const males = sortedStudents.filter(s => s.gender === 'male');
const females = sortedStudents.filter(s => s.gender === 'female');
// 交替排列男女
let balanced = [];
const maxLength = Math.max(males.length, females.length);
for (let i = 0; i < maxLength; i++) {
if (i < males.length) balanced.push(males[i]);
if (i < females.length) balanced.push(females[i]);
}
sortedStudents = balanced;
}
// 初始化座位安排
seatArrangement = [];
for (let i = 0; i < totalSeats; i++) {
if (i < sortedStudents.length) {
seatArrangement.push(sortedStudents[i]);
} else {
seatArrangement.push(null); // 空座位
}
}
renderSeats(rows, cols);
}
// 更新学生列表
function updateStudentList() {
studentList.innerHTML = '';
students.forEach(student => {
const item = document.createElement('div');
item.className = 'student-item';
item.innerHTML = `
<span>${student.name}</span>
<span>${student.gender === 'male' ? '男' : '女'}</span>
<span>身高: ${student.height}cm</span>
<span>视力: ${student.vision}</span>
<span>成绩: ${student.score}</span>
`;
studentList.appendChild(item);
});
}
// 导出座位表
function exportSeatMap() {
const rows = parseInt(rowsInput.value) || 6;
const cols = parseInt(colsInput.value) || 8;
let csvContent = "座位表
";
for (let i = 0; i < rows; i++) {
let rowContent = "";
for (let j = 0; j < cols; j++) {
const index = i * cols + j;
const student = seatArrangement[index];
rowContent += (student ? student.name : "空") + (j < cols - 1 ? "," : "");
}
csvContent += rowContent + "
";
}
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement("a");
const url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", "座位表.csv");
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// 打印座位表
function printSeatMap() {
window.print();
}
</script>
</body>
</html>
早读签到
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生签到系统</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Ma+Shan+Zheng&family=ZCOOL+QingKe+HuangYou&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: KaiTi, STKaiti, "楷体", serif;
}
body {
background: linear-gradient(135deg, #c9dfc9 0%, #a7c8a7 100%);
color: #333;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
overflow: hidden;
border: 2px solid #4caf50;
}
header {
background: #4caf50;
color: white;
padding: 20px;
text-align: center;
border-bottom: 2px solid #3e8e41;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.header-top {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-bottom: 10px;
}
h1 {
font-family: 'Ma Shan Zheng', cursive;
font-size: 2.8rem;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
margin-bottom: 10px;
letter-spacing: 2px;
flex: 1;
text-align: center;
}
.header-controls {
display: flex;
gap: 10px;
}
.withdraw-btn {
background: #ff6b6b;
color: white;
border: none;
padding: 10px 15px;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
font-weight: bold;
transition: all 0.3s;
white-space: nowrap;
}
.withdraw-btn:hover {
background: #ff5252;
transform: translateY(-2px);
}
.withdraw-btn:disabled {
background: #cccccc;
cursor: not-allowed;
transform: none;
}
.current-time-header {
font-size: 1.2rem;
background: rgba(255, 255, 255, 0.2);
padding: 5px 10px;
border-radius: 5px;
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
}
.main-content {
display: flex;
padding: 20px;
gap: 20px;
}
.left-panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
.right-panel {
flex: 2;
display: flex;
flex-direction: column;
gap: 20px;
}
.panel {
background: white;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
padding: 20px;
border: 2px solid #4caf50;
}
.panel-title {
font-size: 1.4rem;
color: #2e7d32;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px dashed #4caf50;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: bold;
}
.panel-content {
min-height: 200px;
max-height: 400px;
overflow-y: auto;
}
.student-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 15px;
}
.student-card {
background: #f0f4ff;
border-radius: 50%;
width: 80px;
height: 80px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
position: relative;
margin: 0 auto;
}
.student-card:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.15);
}
.student-card.checked-in {
background: #e6f7ee;
border: 2px solid #34c759;
}
.student-card.checked-in:hover {
background: #d4f3e3;
}
.student-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
font-size: 1.2rem;
font-weight: bold;
}
.student-card.checked-in .student-avatar {
background: #34c759;
}
.student-name {
font-weight: 600;
font-size: 0.8rem;
text-align: center;
margin-top: 5px;
color: #2e7d32;
}
.checkin-time {
font-size: 0.7rem;
color: #777;
margin-top: 5px;
}
.controls {
display: flex;
flex-direction: column;
gap: 15px;
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
font-weight: 600;
font-size: 0.9rem;
color: #2e7d32;
}
input, button {
padding: 12px 15px;
border-radius: 8px;
border: 1px solid #ddd;
font-size: 1rem;
font-family: KaiTi, STKaiti, "楷体", serif;
}
input[type="file"] {
padding: 10px;
}
input[type="datetime-local"] {
padding: 11px;
}
button {
background: #4caf50;
color: white;
border: none;
cursor: pointer;
transition: background 0.3s;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
font-weight: bold;
}
button:hover {
background: #3e8e41;
transform: translateY(-2px);
}
button.secondary {
background: #ff9800;
}
button.secondary:hover {
background: #f57c00;
}
.stats {
display: flex;
justify-content: space-around;
margin-top: 15px;
padding-top: 15px;
border-top: 1px dashed #4caf50;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 1.8rem;
font-weight: bold;
color: #2e7d32;
}
.stat-label {
font-size: 0.9rem;
color: #2e7d32;
}
.deadline-warning {
color: #ff9500;
font-weight: 600;
margin-top: 10px;
}
.deadline-passed {
color: #ff3b30;
font-weight: 600;
margin-top: 10px;
}
.file-input-container {
position: relative;
overflow: hidden;
display: inline-block;
width: 100%;
}
.file-input-button {
background: #4caf50;
color: white;
padding: 12px 15px;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
text-align: center;
transition: background 0.3s;
font-weight: bold;
}
.file-input-button:hover {
background: #3e8e41;
}
.file-input {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.import-feedback {
margin-top: 10px;
padding: 10px;
border-radius: 5px;
background: #f8f9fa;
font-size: 0.9rem;
}
.import-success {
color: #28a745;
border-left: 3px solid #28a745;
}
.import-error {
color: #dc3545;
border-left: 3px solid #dc3545;
}
.name-only-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.name-item {
background: #f0f4ff;
padding: 8px 15px;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
/* 增大字体 */
font-size: 1.2rem;
font-weight: bold;
}
.name-item:hover {
background: #e0e8ff;
transform: translateY(-2px);
}
.name-item.checked-in {
background: #e6f7ee;
border: 1px solid #34c759;
}
.name-item.disabled {
opacity: 0.6;
cursor: not-allowed;
/* 截止时间后红色显示 */
background: #ffebee;
color: #d32f2f;
border: 1px solid #f44336;
}
@media (max-width: 768px) {
.main-content {
flex-direction: column;
}
.header-top {
flex-direction: column;
gap: 10px;
}
h1 {
font-size: 2.2rem;
}
.current-time-header {
margin-top: 10px;
}
.student-grid {
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}
.student-card {
width: 70px;
height: 70px;
}
.student-avatar {
width: 40px;
height: 40px;
font-size: 1rem;
}
.student-name {
font-size: 0.7rem;
}
.name-only-list {
justify-content: center;
}
/* 移动端调整字体大小 */
.name-item {
font-size: 1rem;
}
.header-controls {
width: 100%;
justify-content: center;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="header-top">
<h1>学生签到系统</h1>
<div class="header-controls">
<button class="withdraw-btn" id="withdraw-checkin" disabled>
<i class="fas fa-undo"></i> 误签撤回
</button>
<div class="current-time-header">
<span>⏰</span>当前时间:<span id="current-time">--:--:--</span>
</div>
</div>
</div>
<p class="subtitle">简单高效的课堂签到管理工具</p>
</header>
<div class="main-content">
<div class="left-panel">
<div class="panel">
<div class="panel-title">
<span>控制面板</span>
</div>
<div class="controls">
<div class="control-group">
<label>导入学生名单</label>
<div class="file-input-container">
<div class="file-input-button">
<i class="fas fa-file-import"></i> 选择文件 (CSV/TXT)
</div>
<input type="file" id="file-import" class="file-input" accept=".csv,.txt">
</div>
<small>支持CSV或文本格式,每行一个学生姓名</small>
<div id="import-feedback" class="import-feedback" style="display: none;"></div>
</div>
<div class="control-group">
<label for="deadline-time">设置签到截止时间</label>
<input type="datetime-local" id="deadline-time">
</div>
<button id="set-deadline">
<i class="fas fa-clock"></i> 应用截止时间
</button>
<button id="reset-checkins" class="secondary">
<i class="fas fa-redo"></i> 重置签到
</button>
<button id="export-data" class="secondary">
<i class="fas fa-download"></i> 导出签到数据
</button>
</div>
</div>
<div class="panel">
<div class="panel-title">
<span>签到统计</span>
</div>
<div class="stats">
<div class="stat-item">
<div class="stat-value" id="total-count">0</div>
<div class="stat-label">总人数</div>
</div>
<div class="stat-item">
<div class="stat-value" id="checked-in-count">0</div>
<div class="stat-label">已签到</div>
</div>
<div class="stat-item">
<div class="stat-value" id="not-checked-in-count">0</div>
<div class="stat-label">未签到</div>
</div>
</div>
<div id="deadline-info">
<!-- 截止时间信息将在这里显示 -->
</div>
</div>
</div>
<div class="right-panel">
<div class="panel">
<div class="panel-title">
<span>待签到区</span>
<span id="waiting-count">0 人</span>
</div>
<div class="panel-content">
<div class="name-only-list" id="waiting-area">
<!-- 待签到学生将在这里显示 -->
<div style="width: 100%; text-align: center; padding: 20px; color: #777;">
暂无学生数据,请导入名单
</div>
</div>
</div>
</div>
<div class="panel">
<div class="panel-title">
<span>已签到区</span>
<span id="checked-in-count-title">0 人</span>
</div>
<div class="panel-content">
<div class="student-grid" id="checked-in-area">
<!-- 已签到学生将在这里显示 -->
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 学生数据
let students = [];
let deadline = null;
let isCheckinDisabled = false;
// 初始化页面
document.addEventListener('DOMContentLoaded', function() {
// 设置截止时间按钮事件
document.getElementById('set-deadline').addEventListener('click', setDeadline);
// 重置签到按钮事件
document.getElementById('reset-checkins').addEventListener('click', resetCheckins);
// 导出数据按钮事件
document.getElementById('export-data').addEventListener('click', exportData);
// 文件导入事件
document.getElementById('file-import').addEventListener('change', handleFileImport);
// 误签撤回按钮事件
document.getElementById('withdraw-checkin').addEventListener('click', withdrawCheckin);
// 更新时间
setInterval(updateTime, 1000);
updateTime();
// 初始渲染
renderStudents();
updateStats();
});
// 更新时间显示
function updateTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
document.getElementById('current-time').textContent = `${hours}:${minutes}:${seconds}`;
// 检查是否超过截止时间
if (deadline && new Date() > deadline) {
if (!isCheckinDisabled) {
disableCheckin();
}
} else {
if (isCheckinDisabled) {
enableCheckin();
}
}
}
// 禁用签到功能
function disableCheckin() {
isCheckinDisabled = true;
// 禁用所有未签到的学生
const nameItems = document.querySelectorAll('.name-item:not(.checked-in)');
nameItems.forEach(item => {
item.classList.add('disabled');
});
}
// 启用签到功能
function enableCheckin() {
isCheckinDisabled = false;
// 启用所有学生
const nameItems = document.querySelectorAll('.name-item');
nameItems.forEach(item => {
item.classList.remove('disabled');
});
}
// 渲染学生列表
function renderStudents() {
const waitingArea = document.getElementById('waiting-area');
const checkedInArea = document.getElementById('checked-in-area');
// 清空区域
waitingArea.innerHTML = '';
checkedInArea.innerHTML = '';
if (students.length === 0) {
waitingArea.innerHTML = '<div style="width: 100%; text-align: center; padding: 20px; color: #777;">暂无学生数据,请导入名单</div>';
// 禁用撤回按钮
document.getElementById('withdraw-checkin').disabled = true;
return;
}
// 计算已签到和未签到人数
let checkedInCount = 0;
// 渲染每个学生
students.forEach((student, index) => {
if (student.checkedIn) {
checkedInCount++;
const card = createStudentCard(student, true, index);
checkedInArea.appendChild(card);
} else {
const nameItem = createNameItem(student);
waitingArea.appendChild(nameItem);
}
});
// 更新计数显示
document.getElementById('waiting-count').textContent = `${students.length - checkedInCount} 人`;
document.getElementById('checked-in-count-title').textContent = `${checkedInCount} 人`;
// 根据是否有已签到的学生启用或禁用撤回按钮
document.getElementById('withdraw-checkin').disabled = checkedInCount === 0;
}
// 创建学生卡片(用于已签到区)
function createStudentCard(student, isCheckedIn, index) {
const card = document.createElement('div');
card.className = isCheckedIn ? 'student-card checked-in' : 'student-card';
// 使用HSL颜色模型生成不同颜色
const hue = (index * 137.508) % 360; // 使用黄金角近似值分布颜色
// 创建头像/圆圈
const avatar = document.createElement('div');
avatar.className = 'student-avatar';
avatar.style.backgroundColor = `hsl(${hue}, 70%, 65%)`;
// 获取姓氏首字母作为头像
const firstChar = student.name.charAt(0);
avatar.textContent = firstChar;
// 创建姓名显示
const nameDiv = document.createElement('div');
nameDiv.className = 'student-name';
nameDiv.textContent = student.name;
card.appendChild(avatar);
card.appendChild(nameDiv);
if (isCheckedIn && student.checkInTime) {
const timeElem = document.createElement('div');
timeElem.className = 'checkin-time';
timeElem.textContent = formatTime(student.checkInTime);
card.appendChild(timeElem);
// 添加皇冠图标
const crown = document.createElement('div');
crown.style.position = 'absolute';
crown.style.top = '-8px';
crown.style.right = '-5px';
crown.style.fontSize = '1.4rem';
crown.textContent = '👑';
card.appendChild(crown);
}
return card;
}
// 创建姓名项(用于待签到区)
function createNameItem(student) {
const nameItem = document.createElement('div');
nameItem.className = 'name-item';
nameItem.textContent = student.name;
if (isCheckinDisabled) {
nameItem.classList.add('disabled');
} else {
nameItem.onclick = function() {
checkInStudent(student.name);
};
}
return nameItem;
}
// 学生签到
function checkInStudent(studentName) {
// 检查是否已过截止时间
if (isCheckinDisabled) {
alert('已超过签到截止时间,无法签到!');
return;
}
const student = students.find(s => s.name === studentName);
if (student && !student.checkedIn) {
// 更新学生状态
student.checkedIn = true;
student.checkInTime = new Date();
// 重新渲染
renderStudents();
// 更新统计信息
updateStats();
// 检查是否全部签到
if (students.every(s => s.checkedIn)) {
setTimeout(() => {
alert('所有同学都已签到!新学期快乐!');
}, 500);
}
}
}
// 误签撤回功能
function withdrawCheckin() {
// 获取所有已签到的学生
const checkedInStudents = students.filter(s => s.checkedIn);
if (checkedInStudents.length === 0) {
alert('当前没有已签到的学生!');
return;
}
// 创建选择列表
let listHtml = '<div style="max-height: 200px; overflow-y: auto; margin: 10px 0;">';
checkedInStudents.forEach(student => {
listHtml += `
<div style="display: flex; justify-content: space-between; padding: 8px; border-bottom: 1px solid #eee;">
<span>${student.name}</span>
<span>${formatDateTime(student.checkInTime)}</span>
</div>
`;
});
listHtml += '</div>';
// 使用自定义确认对话框
const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.style.top = '0';
modal.style.left = '0';
modal.style.width = '100%';
modal.style.height = '100%';
modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
modal.style.display = 'flex';
modal.style.justifyContent = 'center';
modal.style.alignItems = 'center';
modal.style.zIndex = '1000';
modal.innerHTML = `
<div style="background: white; padding: 20px; border-radius: 10px; width: 90%; max-width: 400px;">
<h3 style="margin-bottom: 15px; color: #2e7d32;">选择要撤回的签到</h3>
${listHtml}
<div style="display: flex; justify-content: space-between; margin-top: 20px;">
<button id="cancel-withdraw" style="padding: 8px 16px; background: #ccc; border: none; border-radius: 5px; cursor: pointer;">取消</button>
<button id="withdraw-latest" style="padding: 8px 16px; background: #ff6b6b; color: white; border: none; border-radius: 5px; cursor: pointer;">撤回最后一次签到</button>
</div>
</div>
`;
document.body.appendChild(modal);
// 添加事件监听器
document.getElementById('cancel-withdraw').addEventListener('click', function() {
document.body.removeChild(modal);
});
document.getElementById('withdraw-latest').addEventListener('click', function() {
// 找到最后一次签到
const latestCheckin = [...students].filter(s => s.checkedIn)
.sort((a, b) => new Date(b.checkInTime) - new Date(a.checkInTime))[0];
if (latestCheckin) {
latestCheckin.checkedIn = false;
latestCheckin.checkInTime = null;
// 重新渲染
renderStudents();
updateStats();
alert(`已成功撤回 ${latestCheckin.name} 的签到!`);
}
document.body.removeChild(modal);
});
}
// 更新统计信息
function updateStats() {
const total = students.length;
const checkedIn = students.filter(s => s.checkedIn).length;
const notCheckedIn = total - checkedIn;
document.getElementById('total-count').textContent = total;
document.getElementById('checked-in-count').textContent = checkedIn;
document.getElementById('not-checked-in-count').textContent = notCheckedIn;
// 更新截止时间信息
updateDeadlineInfo();
}
// 设置截止时间
function setDeadline() {
const deadlineInput = document.getElementById('deadline-time').value;
if (deadlineInput) {
deadline = new Date(deadlineInput);
updateDeadlineInfo();
alert(`已设置签到截止时间为: ${formatDateTime(deadline)}`);
// 检查当前时间是否已超过截止时间
if (new Date() > deadline) {
disableCheckin();
}
} else {
alert('请先选择日期和时间!');
}
}
// 更新截止时间信息显示
function updateDeadlineInfo() {
const deadlineInfo = document.getElementById('deadline-info');
if (deadline) {
const now = new Date();
let html = '';
if (now > deadline) {
html = `<div class="deadline-passed">
<i class="fas fa-exclamation-circle"></i>
已超过签到截止时间: ${formatDateTime(deadline)}
</div>`;
} else {
// 计算剩余时间
const timeLeft = deadline - now;
const hoursLeft = Math.floor(timeLeft / (1000 * 60 * 60));
const minutesLeft = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
html = `<div class="deadline-warning">
<i class="fas fa-clock"></i>
签到截止时间: ${formatDateTime(deadline)}<br>
剩余时间: ${hoursLeft}小时${minutesLeft}分钟
</div>`;
}
deadlineInfo.innerHTML = html;
} else {
deadlineInfo.innerHTML = '<div>未设置签到截止时间</div>';
}
}
// 重置签到
function resetCheckins() {
if (confirm('确定要重置所有签到记录吗?')) {
students.forEach(student => {
student.checkedIn = false;
student.checkInTime = null;
});
renderStudents();
updateStats();
enableCheckin();
alert('签到记录已重置!');
}
}
// 导出数据
function exportData() {
if (students.length === 0) {
alert('没有学生数据可导出!');
return;
}
let exportContent = "姓名,签到状态,签到时间
";
students.forEach(student => {
exportContent += `${student.name},${student.checkedIn ? '已签到' : '未签到'},${student.checkInTime ? formatDateTime(student.checkInTime) : 'N/A'}
`;
});
// 创建下载链接
const blob = new Blob([exportContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
const date = new Date().toISOString().slice(0, 10);
link.setAttribute("href", url);
link.setAttribute("download", `签到记录_${date}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
alert('签到数据已导出!');
}
// 处理文件导入
function handleFileImport(event) {
const file = event.target.files[0];
const feedback = document.getElementById('import-feedback');
if (!file) {
return;
}
// 检查文件类型
const isValidType = ['text/csv', 'text/plain'].includes(file.type) ||
file.name.endsWith('.csv') ||
file.name.endsWith('.txt');
if (!isValidType) {
feedback.style.display = 'block';
feedback.className = 'import-feedback import-error';
feedback.innerHTML = '<i class="fas fa-exclamation-circle"></i> 错误:请选择CSV或文本文件';
return;
}
const reader = new FileReader();
reader.onload = function(e) {
try {
const content = e.target.result;
const lines = content.split(/\r
|
/);
const importedStudents = [];
// 处理每一行
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// 跳过空行和标题行
if (!line || line === '姓名' || line === '名字' || line === 'name' || line === '姓名,学号') {
continue;
}
// 处理CSV格式(简单处理,仅取第一个逗号前的部分)
let name = line;
if (line.includes(',')) {
name = line.split(',')[0].trim();
}
if (name) {
importedStudents.push({
id: i + 1,
name: name,
checkedIn: false,
checkInTime: null
});
}
}
if (importedStudents.length === 0) {
feedback.style.display = 'block';
feedback.className = 'import-feedback import-error';
feedback.innerHTML = '<i class="fas fa-exclamation-circle"></i> 错误:文件中未找到有效学生姓名';
return;
}
// 更新学生列表
students = importedStudents;
// 更新UI
renderStudents();
updateStats();
// 显示成功消息
feedback.style.display = 'block';
feedback.className = 'import-feedback import-success';
feedback.innerHTML = `<i class="fas fa-check-circle"></i> 成功导入 ${importedStudents.length} 名学生`;
} catch (error) {
feedback.style.display = 'block';
feedback.className = 'import-feedback import-error';
feedback.innerHTML = '<i class="fas fa-exclamation-circle"></i> 错误:文件读取失败';
console.error('File import error:', error);
}
};
reader.onerror = function() {
feedback.style.display = 'block';
feedback.className = 'import-feedback import-error';
feedback.innerHTML = '<i class="fas fa-exclamation-circle"></i> 错误:文件读取失败';
};
reader.readAsText(file);
}
// 格式化时间
function formatTime(date) {
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
}
// 格式化日期时间
function formatDateTime(date) {
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${formatTime(date)}`;
}
</script>
</body>
</html>
25
AI创新场景与总结
06
26
化学助手与智能命题
AI支持课后答疑与命题
DeepSeek与Kimi等AI工具能够在课后为学生提供即时的化学知识解释,同时具备根据输入的知识点生成差异化练习题或整套试卷的智能命题功能,为学生自主学习和复习提供了有力支持。
27
感谢您的指导
THANK YOU FOR GUIDANCE
28
$