feat: 第17课课评完成 + 学生档案更新 + 课评网页模板 + 暑假绩效考核
This commit is contained in:
469
.claude/templates/课评网页模板.html
Normal file
469
.claude/templates/课评网页模板.html
Normal file
@@ -0,0 +1,469 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{第N周}} · {{班级简称}}课评</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;600&display=swap');
|
||||
|
||||
:root {
|
||||
--coral: #e85d4c;
|
||||
--coral-light: #f5a99e;
|
||||
--coral-dark: #c44738;
|
||||
--amber: #f0a84a;
|
||||
--amber-light: #f5d08a;
|
||||
--ink: #2c2420;
|
||||
--ink-soft: #5a524e;
|
||||
--paper: #faf6f1;
|
||||
--paper-warm: #f5efe8;
|
||||
--cream: #fffdf9;
|
||||
--border: #e8e0d8;
|
||||
--shadow-soft: rgba(44, 36, 32, 0.06);
|
||||
--shadow-medium: rgba(44, 36, 32, 0.10);
|
||||
--shadow-card: rgba(44, 36, 32, 0.08);
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
background: var(--paper);
|
||||
min-height: 100vh;
|
||||
color: var(--ink);
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 50%, rgba(240, 168, 74, 0.03) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 20%, rgba(232, 93, 76, 0.02) 0%, transparent 50%),
|
||||
radial-gradient(circle at 50% 80%, rgba(240, 168, 74, 0.02) 0%, transparent 40%);
|
||||
}
|
||||
|
||||
.topbar {
|
||||
position: sticky; top: 0; z-index: 100;
|
||||
background: rgba(250, 246, 241, 0.92); backdrop-filter: blur(16px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 14px 28px; display: flex; justify-content: space-between; align-items: center;
|
||||
}
|
||||
.topbar-title { font-family: 'Noto Serif SC', serif; font-size: 1.05em; font-weight: 600; color: var(--ink); letter-spacing: 0.5px; }
|
||||
.topbar-meta { font-size: 0.8em; color: var(--ink-soft); margin-top: 2px; }
|
||||
.topbar-actions { display: flex; gap: 10px; }
|
||||
.btn { padding: 8px 18px; border-radius: 10px; font-size: 0.85em; font-weight: 500; cursor: pointer; transition: all 0.25s ease; border: none; font-family: inherit; }
|
||||
.btn-outline { background: transparent; border: 1.5px solid var(--border); color: var(--ink-soft); }
|
||||
.btn-outline:hover { border-color: var(--coral); color: var(--coral); background: rgba(232, 93, 76, 0.05); }
|
||||
.btn-success { background: var(--coral); color: white; }
|
||||
.btn-success:hover { background: var(--coral-dark); }
|
||||
.btn-success:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
|
||||
.main { max-width: 680px; margin: 0 auto; padding: 28px 20px 160px; position: relative; }
|
||||
|
||||
.course-hero {
|
||||
background: linear-gradient(135deg, var(--cream) 0%, var(--paper-warm) 100%);
|
||||
border-radius: 20px; padding: 36px 32px 32px; margin-bottom: 24px;
|
||||
border: 1px solid var(--border); position: relative; overflow: hidden;
|
||||
box-shadow: 0 2px 8px var(--shadow-soft), 0 8px 32px var(--shadow-card);
|
||||
}
|
||||
.course-hero::before { content: ''; position: absolute; top: -60px; right: -40px; width: 180px; height: 180px; border-radius: 50%; background: radial-gradient(circle, rgba(232, 93, 76, 0.08) 0%, transparent 70%); }
|
||||
.course-hero::after { content: ''; position: absolute; bottom: -40px; left: -30px; width: 140px; height: 140px; border-radius: 50%; background: radial-gradient(circle, rgba(240, 168, 74, 0.06) 0%, transparent 70%); }
|
||||
|
||||
.hero-badge { display: inline-flex; align-items: center; gap: 6px; background: linear-gradient(135deg, var(--coral) 0%, var(--amber) 100%); color: white; font-size: 0.75em; font-weight: 600; padding: 6px 16px; border-radius: 20px; margin-bottom: 16px; position: relative; z-index: 1; letter-spacing: 0.5px; }
|
||||
.hero-title { font-family: 'Noto Serif SC', serif; font-size: 2.2em; font-weight: 700; color: var(--ink); line-height: 1.3; margin-bottom: 8px; position: relative; z-index: 1; letter-spacing: 2px; }
|
||||
.hero-subtitle { font-size: 0.95em; color: var(--ink-soft); margin-bottom: 20px; position: relative; z-index: 1; }
|
||||
.hero-divider { width: 60px; height: 3px; background: linear-gradient(90deg, var(--coral), var(--amber)); border-radius: 2px; margin-bottom: 20px; position: relative; z-index: 1; }
|
||||
.hero-info { display: flex; flex-wrap: wrap; gap: 16px; position: relative; z-index: 1; }
|
||||
.hero-info-item { display: flex; align-items: center; gap: 6px; font-size: 0.85em; color: var(--ink-soft); }
|
||||
.hero-info-item .icon { font-size: 1.1em; }
|
||||
|
||||
.goals-section { background: var(--cream); border-radius: 16px; padding: 24px; margin-bottom: 28px; border: 1px solid var(--border); box-shadow: 0 2px 12px var(--shadow-soft); }
|
||||
.goals-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; }
|
||||
.goals-title { font-family: 'Noto Serif SC', serif; font-size: 1em; font-weight: 600; color: var(--ink); display: flex; align-items: center; gap: 8px; }
|
||||
.goals-title .title-icon { font-size: 1.2em; }
|
||||
.goals-toggle { font-size: 0.78em; color: var(--ink-soft); cursor: pointer; background: var(--paper-warm); border: 1px solid var(--border); font-family: inherit; padding: 5px 12px; border-radius: 8px; transition: all 0.2s ease; }
|
||||
.goals-toggle:hover { background: var(--coral); color: white; border-color: var(--coral); }
|
||||
.goals-list { list-style: none; display: block; }
|
||||
.goals-list.collapsed { display: none; }
|
||||
.goals-list li { padding: 12px 16px; background: var(--paper); border-radius: 10px; margin-bottom: 10px; font-size: 0.9em; color: var(--ink-soft); display: flex; align-items: flex-start; gap: 12px; border-left: 3px solid transparent; transition: all 0.2s ease; }
|
||||
.goals-list li:hover { border-left-color: var(--coral); background: var(--cream); transform: translateX(4px); }
|
||||
.goals-list li:last-child { margin-bottom: 0; }
|
||||
.goal-num { background: linear-gradient(135deg, var(--coral) 0%, var(--amber) 100%); color: white; width: 26px; height: 26px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 0.78em; font-weight: 600; flex-shrink: 0; margin-top: 1px; }
|
||||
.goal-text { flex: 1; line-height: 1.6; }
|
||||
|
||||
.cards-slider-wrapper { position: relative; border-radius: 16px; margin-bottom: 20px; overflow: hidden; }
|
||||
.cards-slider { position: relative; min-height: 300px; }
|
||||
|
||||
.student-card {
|
||||
background: var(--cream); border-radius: 16px; border: 1px solid var(--border);
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
position: absolute; width: 100%; top: 0; left: 0;
|
||||
opacity: 0; transform: translateX(60px) scale(0.96); pointer-events: none;
|
||||
box-shadow: 0 4px 20px var(--shadow-card);
|
||||
}
|
||||
.student-card.active { opacity: 1; transform: translateX(0) scale(1); pointer-events: auto; position: relative; }
|
||||
.student-card.prev { transform: translateX(-60px) scale(0.96); opacity: 0; }
|
||||
.student-card:hover { box-shadow: 0 8px 32px var(--shadow-medium); }
|
||||
|
||||
.card-header { padding: 18px 24px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); background: linear-gradient(135deg, rgba(250, 246, 241, 0.5) 0%, rgba(245, 239, 232, 0.5) 100%); border-radius: 16px 16px 0 0; }
|
||||
.student-name { font-family: 'Noto Serif SC', serif; font-size: 1.15em; font-weight: 600; color: var(--ink); letter-spacing: 1px; }
|
||||
.card-badge { font-size: 0.75em; padding: 5px 12px; border-radius: 20px; font-weight: 500; }
|
||||
.badge-normal { background: #e8f5e9; color: #2e7d32; }
|
||||
.badge-makeup { background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%); color: #e65100; }
|
||||
.badge-absent { background: #fce4ec; color: #c2185b; }
|
||||
|
||||
.card-body { padding: 24px; }
|
||||
.feedback-content { font-size: 0.92em; line-height: 2; color: var(--ink-soft); margin-bottom: 20px; }
|
||||
.metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
|
||||
.metric-item { padding: 14px; background: var(--paper); border-radius: 10px; border: 1px solid transparent; transition: all 0.2s ease; }
|
||||
.metric-item:hover { border-color: var(--border); background: var(--cream); }
|
||||
.metric-label { font-size: 0.72em; color: #999; margin-bottom: 5px; text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
.metric-value { font-size: 0.88em; font-weight: 500; color: var(--ink); }
|
||||
.metric-stars { color: var(--amber); letter-spacing: 1px; }
|
||||
|
||||
.star-rating { display: flex; align-items: center; gap: 2px; margin-top: 6px; }
|
||||
.star-rating .star { font-size: 1.3em; color: #ddd5cc; cursor: default; transition: all 0.15s ease; user-select: none; line-height: 1; }
|
||||
.star-rating .star.filled { color: var(--amber); }
|
||||
.star-score { font-size: 0.78em; color: var(--ink-soft); margin-left: 6px; font-weight: 500; min-width: 28px; }
|
||||
.metric-comment { margin-top: 8px; padding: 8px 10px; background: var(--paper); border-radius: 8px; font-size: 0.82em; color: var(--ink-soft); line-height: 1.5; border: 1px solid transparent; min-height: 32px; }
|
||||
|
||||
.side-nav-btn {
|
||||
position: fixed; top: 50%; transform: translateY(-50%); z-index: 90;
|
||||
width: 52px; height: 80px; border: none;
|
||||
background: rgba(250, 246, 241, 0.85); backdrop-filter: blur(12px);
|
||||
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||||
font-size: 1.4em; color: var(--ink-soft); transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 16px var(--shadow-medium);
|
||||
}
|
||||
.side-nav-btn:hover:not(:disabled) { background: var(--cream); color: var(--coral); width: 60px; box-shadow: 0 6px 24px rgba(232, 93, 76, 0.15); }
|
||||
.side-nav-btn:disabled { opacity: 0.25; cursor: not-allowed; }
|
||||
.side-nav-btn.prev-btn { left: 0; border-radius: 0 12px 12px 0; border-right: 1px solid var(--border); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding-right: 4px; }
|
||||
.side-nav-btn.next-btn { right: 0; border-radius: 12px 0 0 12px; border-left: 1px solid var(--border); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding-left: 4px; }
|
||||
.side-nav-btn .arrow { transition: transform 0.3s ease; }
|
||||
.side-nav-btn:hover .arrow.prev-arrow { transform: translateX(-3px); }
|
||||
.side-nav-btn:hover .arrow.next-arrow { transform: translateX(3px); }
|
||||
|
||||
.nav-controls { display: flex; justify-content: center; align-items: center; gap: 20px; margin-bottom: 16px; }
|
||||
.page-indicator { font-family: 'Noto Serif SC', serif; font-size: 0.95em; color: var(--ink-soft); font-weight: 500; min-width: 70px; text-align: center; letter-spacing: 1px; }
|
||||
|
||||
.progress-dots { display: flex; justify-content: center; gap: 10px; margin-top: 4px; }
|
||||
.progress-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); cursor: pointer; transition: all 0.3s ease; position: relative; }
|
||||
.progress-dot.active { background: var(--coral); width: 28px; border-radius: 4px; }
|
||||
.progress-dot:hover:not(.active) { background: var(--coral-light); transform: scale(1.3); }
|
||||
|
||||
.toast { position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--ink); color: white; padding: 12px 28px; border-radius: 10px; font-size: 0.85em; opacity: 0; transition: all 0.3s ease; pointer-events: none; z-index: 200; box-shadow: 0 4px 16px rgba(0,0,0,0.15); }
|
||||
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||||
|
||||
.footer { text-align: center; padding: 36px 20px; color: #bbb; font-size: 0.78em; font-family: 'Noto Serif SC', serif; letter-spacing: 1px; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hero-title { font-size: 1.7em; }
|
||||
.side-nav-btn { width: 40px; height: 60px; font-size: 1.1em; }
|
||||
.main { padding: 20px 16px 160px; }
|
||||
.course-hero { padding: 28px 20px 24px; }
|
||||
}
|
||||
</style>
|
||||
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- ========== 顶栏 ========== -->
|
||||
<div class="topbar">
|
||||
<div>
|
||||
<div class="topbar-title">{{第N周}} · {{班级简称}}班课评</div>
|
||||
<div class="topbar-meta">{{日期中文}} · 《{{课程名称}}》 · {{老师}}老师</div>
|
||||
</div>
|
||||
<div class="topbar-actions">
|
||||
<button class="btn btn-outline" onclick="exportText()">📋 导出</button>
|
||||
<button class="btn btn-success" id="screenshotBtn" onclick="downloadAllScreenshots()">📸 全部下载</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ========== 左右切换按钮 ========== -->
|
||||
<button class="side-nav-btn prev-btn" id="sidePrevBtn" onclick="prevCard()" title="上一张"><span class="arrow prev-arrow">‹</span></button>
|
||||
<button class="side-nav-btn next-btn" id="sideNextBtn" onclick="nextCard()" title="下一张"><span class="arrow next-arrow">›</span></button>
|
||||
|
||||
<!-- ========== 主内容区 ========== -->
|
||||
<div class="main">
|
||||
<!-- 课程头部 -->
|
||||
<div class="course-hero">
|
||||
<div class="hero-badge">📚 本周课程</div>
|
||||
<h1 class="hero-title">《{{课程名称}}》</h1>
|
||||
<p class="hero-subtitle">{{课程副标题}} · 第{{课次}}课</p>
|
||||
<div class="hero-divider"></div>
|
||||
<div class="hero-info">
|
||||
<div class="hero-info-item"><span class="icon">📅</span><span>{{日期中文}}</span></div>
|
||||
<div class="hero-info-item"><span class="icon">⏰</span><span>{{上课时间}}</span></div>
|
||||
<div class="hero-info-item"><span class="icon">👩🏫</span><span>{{老师}}老师</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 知识点 -->
|
||||
<div class="goals-section">
|
||||
<div class="goals-header">
|
||||
<span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span>
|
||||
<button class="goals-toggle" onclick="toggleGoals()">收起</button>
|
||||
</div>
|
||||
<ul class="goals-list" id="goalsList">
|
||||
{{知识点列表}}
|
||||
<!-- 示例格式:
|
||||
<li><span class="goal-num">1</span><span class="goal-text">知识点内容</span></li>
|
||||
-->
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 学生卡片区(由 JS 动态生成) -->
|
||||
<div class="cards-slider-wrapper">
|
||||
<div class="cards-slider" id="cardsSlider"></div>
|
||||
</div>
|
||||
|
||||
<!-- 页码指示器 -->
|
||||
<div class="nav-controls"><span class="page-indicator" id="pageIndicator"></span></div>
|
||||
<div class="progress-dots" id="progressDots"></div>
|
||||
|
||||
<div class="footer">{{底部文案}}</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
// ============================================================
|
||||
// 📝 配置区:填写以下数据即可生成课评网页
|
||||
// ============================================================
|
||||
|
||||
// 页面元信息
|
||||
var PAGE = {
|
||||
weekLabel: '{{第N周}}', // 如 "第17周"
|
||||
classShort: '{{班级简称}}', // 如 "K4"
|
||||
courseName: '{{课程名称}}', // 如 "成语接龙"
|
||||
courseSubtitle: '{{课程副标题}}', // 如 "列表 · 插入与查找元素"
|
||||
lessonNum: '{{课次}}', // 如 "17"
|
||||
dateCN: '{{日期中文}}', // 如 "2026年6月26日"
|
||||
dateISO: '{{日期ISO}}', // 如 "2026-06-26"
|
||||
timeSlot: '{{上课时间}}', // 如 "周五 19:00-20:30"
|
||||
teacher: '{{老师}}', // 如 "橙子"
|
||||
footerText: '{{底部文案}}' // 如 "穹狼科创 · K4班 · 橙子老师"
|
||||
};
|
||||
|
||||
// 知识点列表(数组,每项一条)
|
||||
var GOALS = [
|
||||
// 示例:
|
||||
// '理解词语接龙的游戏规则:下一个词的首字必须等于上一个词的末字',
|
||||
// '学习使用变量"旧词语"和列表"词语表"存储和管理接龙数据',
|
||||
];
|
||||
|
||||
// 学生数据(数组,每项一个学生)
|
||||
// badge: 'normal' | 'makeup' | 'absent'
|
||||
// metrics: [{ label, score(1-5), comment }, ...]
|
||||
var STUDENTS = [
|
||||
// 示例:
|
||||
// {
|
||||
// name: '陈圆振',
|
||||
// badge: 'normal',
|
||||
// badgeText: '正常上课',
|
||||
// feedback: '圆振这节课表现很积极~...',
|
||||
// metrics: [
|
||||
// { label: '课堂互动', score: 5, comment: '积极回答问题' },
|
||||
// { label: '知识理解', score: 5, comment: '理解透彻' },
|
||||
// ]
|
||||
// },
|
||||
];
|
||||
|
||||
// 截图下载的文件名格式:{姓名}-第{课次}课{课程名称}.png
|
||||
function getScreenshotFilename(studentName) {
|
||||
return studentName + '-第' + PAGE.lessonNum + '课' + PAGE.courseName + '.png';
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 🔧 以下为渲染引擎,一般无需修改
|
||||
// ============================================================
|
||||
|
||||
var totalCards = STUDENTS.length;
|
||||
var currentCard = 0;
|
||||
|
||||
// 渲染知识点
|
||||
(function renderGoals() {
|
||||
var html = '';
|
||||
GOALS.forEach(function(g, i) {
|
||||
html += '<li><span class="goal-num">' + (i + 1) + '</span><span class="goal-text">' + g + '</span></li>';
|
||||
});
|
||||
document.getElementById('goalsList').innerHTML = html;
|
||||
})();
|
||||
|
||||
// 渲染学生卡片
|
||||
(function renderCards() {
|
||||
var badgeClassMap = { normal: 'badge-normal', makeup: 'badge-makeup', absent: 'badge-absent' };
|
||||
var scoreLabels = ['未评', '需加强', '合格', '良好', '优秀', '超棒'];
|
||||
var cardsHtml = '';
|
||||
STUDENTS.forEach(function(s, idx) {
|
||||
var isActive = idx === 0 ? ' active' : '';
|
||||
cardsHtml += '<div class="student-card' + isActive + '" data-index="' + idx + '">';
|
||||
cardsHtml += '<div class="card-header"><span class="student-name">' + s.name + '</span><span class="card-badge ' + (badgeClassMap[s.badge] || 'badge-normal') + '">' + s.badgeText + '</span></div>';
|
||||
cardsHtml += '<div class="card-body">';
|
||||
cardsHtml += '<div class="feedback-content" data-student="' + s.name + '">' + s.feedback + '</div>';
|
||||
cardsHtml += '<div class="metrics">';
|
||||
s.metrics.forEach(function(m) {
|
||||
var starsHtml = '';
|
||||
for (var si = 1; si <= 5; si++) {
|
||||
starsHtml += '<span class="star' + (si <= m.score ? ' filled' : '') + '" data-val="' + si + '">★</span>';
|
||||
}
|
||||
cardsHtml += '<div class="metric-item" data-metric="' + m.label + '">';
|
||||
cardsHtml += '<div class="metric-label">' + m.label + '</div>';
|
||||
cardsHtml += '<div class="star-rating" data-score="' + m.score + '">' + starsHtml + '<span class="star-score">' + (scoreLabels[m.score] || '未评') + '</span></div>';
|
||||
cardsHtml += '<div class="metric-comment" data-metric-comment="' + m.label + '">' + m.comment + '</div>';
|
||||
cardsHtml += '</div>';
|
||||
});
|
||||
cardsHtml += '</div></div></div>';
|
||||
});
|
||||
document.getElementById('cardsSlider').innerHTML = cardsHtml;
|
||||
})();
|
||||
|
||||
// 渲染进度点
|
||||
(function renderDots() {
|
||||
var dotsHtml = '';
|
||||
for (var i = 0; i < totalCards; i++) {
|
||||
dotsHtml += '<div class="progress-dot' + (i === 0 ? ' active' : '') + '" onclick="goToCard(' + i + ')"></div>';
|
||||
}
|
||||
document.getElementById('progressDots').innerHTML = dotsHtml;
|
||||
document.getElementById('pageIndicator').textContent = '1 / ' + totalCards;
|
||||
})();
|
||||
|
||||
// 卡片切换
|
||||
var allCards, sidePrevBtn, sideNextBtn, pageIndicatorEl, progressDots;
|
||||
|
||||
function initSliderRefs() {
|
||||
allCards = document.querySelectorAll('.student-card');
|
||||
sidePrevBtn = document.getElementById('sidePrevBtn');
|
||||
sideNextBtn = document.getElementById('sideNextBtn');
|
||||
pageIndicatorEl = document.getElementById('pageIndicator');
|
||||
progressDots = document.querySelectorAll('.progress-dot');
|
||||
updateSlider();
|
||||
}
|
||||
|
||||
function updateSlider() {
|
||||
if (!allCards) return;
|
||||
allCards.forEach(function(card, i) {
|
||||
card.classList.remove('active', 'prev');
|
||||
if (i === currentCard) card.classList.add('active');
|
||||
else if (i < currentCard) card.classList.add('prev');
|
||||
});
|
||||
if (pageIndicatorEl) pageIndicatorEl.textContent = (currentCard + 1) + ' / ' + totalCards;
|
||||
if (sidePrevBtn) sidePrevBtn.disabled = currentCard === 0;
|
||||
if (sideNextBtn) sideNextBtn.disabled = currentCard === totalCards - 1;
|
||||
if (progressDots) progressDots.forEach(function(dot, i) { dot.classList.toggle('active', i === currentCard); });
|
||||
}
|
||||
|
||||
function nextCard() { if (currentCard < totalCards - 1) { currentCard++; updateSlider(); } }
|
||||
function prevCard() { if (currentCard > 0) { currentCard--; updateSlider(); } }
|
||||
function goToCard(i) { currentCard = i; updateSlider(); }
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'ArrowLeft') prevCard();
|
||||
if (e.key === 'ArrowRight') nextCard();
|
||||
});
|
||||
|
||||
var touchStartX = 0;
|
||||
document.getElementById('cardsSlider').addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; });
|
||||
document.getElementById('cardsSlider').addEventListener('touchend', function(e) {
|
||||
var dx = e.changedTouches[0].screenX;
|
||||
if (touchStartX - dx > 50) nextCard();
|
||||
if (dx - touchStartX > 50) prevCard();
|
||||
});
|
||||
|
||||
initSliderRefs();
|
||||
|
||||
// 知识点展开/收起
|
||||
function toggleGoals() {
|
||||
var list = document.getElementById('goalsList');
|
||||
var btn = document.querySelector('.goals-toggle');
|
||||
list.classList.toggle('collapsed');
|
||||
btn.textContent = list.classList.contains('collapsed') ? '展开' : '收起';
|
||||
}
|
||||
|
||||
// Toast 提示
|
||||
function showToast(msg) {
|
||||
var toast = document.getElementById('toast');
|
||||
toast.textContent = msg;
|
||||
toast.classList.add('show');
|
||||
setTimeout(function() { toast.classList.remove('show'); }, 2000);
|
||||
}
|
||||
|
||||
// 导出文本
|
||||
function exportText() {
|
||||
var sep = '═══════════════════════════════════════';
|
||||
var text = PAGE.weekLabel + PAGE.classShort + '班课评\n';
|
||||
text += PAGE.dateCN + ' · 《' + PAGE.courseName + '》 · ' + PAGE.teacher + '老师\n';
|
||||
text += sep + '\n\n';
|
||||
text += '🎯 本周知识点\n';
|
||||
text += '─────────────────────────────────────\n';
|
||||
GOALS.forEach(function(g, i) { text += (i + 1) + '. ' + g + '\n'; });
|
||||
text += '\n' + sep + '\n\n';
|
||||
|
||||
STUDENTS.forEach(function(s) {
|
||||
text += '【' + s.name + '】' + s.badgeText + '\n';
|
||||
text += '─────────────────────────────────\n';
|
||||
text += s.feedback + '\n\n';
|
||||
});
|
||||
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
showToast('✓ 已复制到剪贴板,可直接粘贴发送');
|
||||
}).catch(function() {
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = text; document.body.appendChild(ta); ta.select();
|
||||
document.execCommand('copy'); document.body.removeChild(ta);
|
||||
showToast('✓ 已复制到剪贴板');
|
||||
});
|
||||
}
|
||||
|
||||
// 📸 批量截图下载
|
||||
function downloadAllScreenshots() {
|
||||
var btn = document.getElementById('screenshotBtn');
|
||||
var originalText = btn.textContent;
|
||||
btn.disabled = true;
|
||||
btn.textContent = '⏳ 截图准备中...';
|
||||
|
||||
var savedCard = currentCard;
|
||||
var goalsEl = document.getElementById('goalsList');
|
||||
var goalsCollapsed = goalsEl.classList.contains('collapsed');
|
||||
var sidePrev = document.getElementById('sidePrevBtn');
|
||||
var sideNext = document.getElementById('sideNextBtn');
|
||||
var mainEl = document.querySelector('.main');
|
||||
|
||||
if (goalsCollapsed) goalsEl.classList.remove('collapsed');
|
||||
|
||||
function captureOne(i) {
|
||||
if (i >= totalCards) {
|
||||
goToCard(savedCard);
|
||||
if (goalsCollapsed) goalsEl.classList.add('collapsed');
|
||||
btn.disabled = false;
|
||||
btn.textContent = originalText;
|
||||
sidePrev.style.display = '';
|
||||
sideNext.style.display = '';
|
||||
mainEl.style.paddingBottom = '';
|
||||
showToast('✓ ' + totalCards + '张截图已下载');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.textContent = '⏳ 截图 ' + (i + 1) + '/' + totalCards;
|
||||
goToCard(i);
|
||||
sidePrev.style.display = 'none';
|
||||
sideNext.style.display = 'none';
|
||||
mainEl.style.paddingBottom = '40px';
|
||||
|
||||
setTimeout(function() {
|
||||
html2canvas(mainEl, {
|
||||
backgroundColor: '#faf6f1',
|
||||
scale: 2,
|
||||
useCORS: true
|
||||
}).then(function(canvas) {
|
||||
var link = document.createElement('a');
|
||||
link.download = getScreenshotFilename(STUDENTS[i].name);
|
||||
link.href = canvas.toDataURL('image/png');
|
||||
link.click();
|
||||
captureOne(i + 1);
|
||||
}).catch(function() {
|
||||
captureOne(i + 1);
|
||||
});
|
||||
}, 450);
|
||||
}
|
||||
|
||||
captureOne(0);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user