Main.py:WHITE_HOSTS 增 rollcall/viper/venom 主机,STATIC_SITES 增 rollcall/venom 静态根,静态站点路由下 /API/ 前缀请求转交 Django 处理。 gvsds:settings.py 注册 gvsds.apps.rollcall,urls.py 挂载 API/RollCall/;新增 rollcall 应用(模型/视图/路由/迁移 + RollCallManager 数据访问层)与 TempLate/rollcall 前端站点。 .gitignore:排除 Viper/Venom 前端工程与部署产物、TempLate/FTP 二进制分发目录。
254 lines
11 KiB
HTML
254 lines
11 KiB
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="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700;900&family=Noto+Serif+SC:wght@600;700;900&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="style.css" />
|
||
</head>
|
||
<body>
|
||
<!-- 顶部导航 -->
|
||
<header class="topbar">
|
||
<div class="brand">
|
||
<span class="brand-mark" aria-hidden="true">
|
||
<svg viewBox="0 0 32 32" width="28" height="28">
|
||
<rect x="3" y="6" width="26" height="20" rx="3" fill="#e8a838"/>
|
||
<rect x="3" y="6" width="26" height="6" rx="3" fill="#1a2238"/>
|
||
<circle cx="11" cy="19" r="3" fill="#f5f0e6"/>
|
||
<rect x="16" y="17" width="9" height="2" rx="1" fill="#1a2238"/>
|
||
<rect x="16" y="21" width="7" height="2" rx="1" fill="#1a2238"/>
|
||
</svg>
|
||
</span>
|
||
<h1 class="brand-title">同学点名</h1>
|
||
<span class="brand-sub">课堂随机抽取系统</span>
|
||
</div>
|
||
<nav class="tabs" role="tablist">
|
||
<button class="tab active" data-view="roll" role="tab">点名</button>
|
||
<button class="tab" data-view="settings" role="tab">设置</button>
|
||
</nav>
|
||
<div class="topbar-right">
|
||
<button class="btn btn-ghost btn-sm" id="refreshBtn" title="从服务器刷新学生名单与题库">
|
||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-3px;margin-right:4px;"><path d="M3 12a9 9 0 1 0 2.6-6.4"/><polyline points="3 4 3 10 9 10"/></svg>
|
||
刷新
|
||
</button>
|
||
<span class="count-badge" id="countBadge">0 人</span>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="app">
|
||
<!-- ============ 点名视图 ============ -->
|
||
<section class="view view-roll active" id="view-roll">
|
||
<div class="roll-stage">
|
||
<!-- 抽取动画区 -->
|
||
<div class="roller" id="roller">
|
||
<div class="roller-card" id="rollerCard">
|
||
<div class="roller-avatar" id="rollerAvatar"></div>
|
||
<div class="roller-name" id="rollerName">准备就绪</div>
|
||
<div class="roller-tag" id="rollerTag">点击下方按钮开始点名</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 粒子层 -->
|
||
<canvas class="confetti" id="confetti" aria-hidden="true"></canvas>
|
||
|
||
<!-- 结果浮层 -->
|
||
<div class="result-toast" id="resultToast" hidden>
|
||
<div class="result-toast-inner">
|
||
<span class="result-label">本次抽中</span>
|
||
<span class="result-name" id="resultName"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 多人抽取结果展示区(持久化) -->
|
||
<div class="multi-results" id="multiResults" hidden>
|
||
<div class="multi-results-head">
|
||
<span class="multi-results-title">本次抽取结果</span>
|
||
<span class="multi-results-count" id="multiResultsCount"></span>
|
||
</div>
|
||
<div class="multi-results-grid" id="multiResultsGrid"></div>
|
||
</div>
|
||
|
||
<!-- 题目结果展示区 -->
|
||
<div class="question-result" id="questionResult" hidden>
|
||
<div class="question-result-head">
|
||
<span class="qr-title">本次抽题</span>
|
||
</div>
|
||
<div class="question-display" id="questionDisplay">
|
||
<span class="question-placeholder">点击下方按钮开始抽题</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 模式开关 -->
|
||
<div class="mode-toggles">
|
||
<button class="mode-toggle active" data-toggle="person">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
||
抽人
|
||
</button>
|
||
<button class="mode-toggle" data-toggle="question">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
||
抽题
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 控制栏 -->
|
||
<div class="controls">
|
||
<div class="person-controls" id="personControls">
|
||
<div class="mode-switch" id="modeSwitch">
|
||
<button class="mode-btn active" data-mode="single">单人抽取</button>
|
||
<button class="mode-btn" data-mode="multi">多人抽取</button>
|
||
<button class="mode-btn" data-mode="norepeat">不重复抽取</button>
|
||
</div>
|
||
<div class="group-filter">
|
||
<label class="group-label">分组</label>
|
||
<select class="group-select" id="groupSelect">
|
||
<option value="">全部学生</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="question-controls" id="questionControls" hidden>
|
||
<select class="subject-select" id="subjectSelect">
|
||
<option value="">全部学科</option>
|
||
</select>
|
||
<label class="check-inline">
|
||
<input type="checkbox" id="questionNoRepeat" />
|
||
<span>不重复</span>
|
||
</label>
|
||
</div>
|
||
<button class="btn btn-primary btn-lg" id="rollBtn">
|
||
<span class="btn-icon">
|
||
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polygon points="6 4 20 12 6 20 6 4"/></svg>
|
||
</span>
|
||
<span class="btn-text">开始</span>
|
||
</button>
|
||
<button class="btn btn-ghost" id="resetBtn" title="重置已抽中记录">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><polyline points="3 4 3 10 9 10"/></svg>
|
||
重置
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 多人抽取数量 -->
|
||
<div class="multi-config" id="multiConfig" hidden>
|
||
<label>抽取人数</label>
|
||
<div class="stepper">
|
||
<button class="step-btn" id="stepDown">−</button>
|
||
<span class="step-val" id="stepVal">3</span>
|
||
<button class="step-btn" id="stepUp">+</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 学生卡片墙 -->
|
||
<div class="wall-section">
|
||
<div class="section-head">
|
||
<h2 class="section-title">学生名单</h2>
|
||
<div class="wall-filter">
|
||
<button class="filter-btn active" data-filter="all">全部 <span id="cntAll">0</span></button>
|
||
<button class="filter-btn" data-filter="pending">待抽 <span id="cntPending">0</span></button>
|
||
<button class="filter-btn" data-filter="picked">已抽 <span id="cntPicked">0</span></button>
|
||
</div>
|
||
</div>
|
||
<div class="wall" id="wall"></div>
|
||
<div class="empty-state" id="wallEmpty" hidden>
|
||
<p>暂无学生数据</p>
|
||
<button class="btn btn-ghost" id="loadDemoBtn">加载示例数据</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 历史记录 -->
|
||
<div class="history-section" id="historySection">
|
||
<div class="section-head">
|
||
<h2 class="section-title">本次课堂记录</h2>
|
||
<button class="btn btn-ghost btn-sm" id="clearHistoryBtn">清空</button>
|
||
</div>
|
||
<div class="history-list" id="historyList"></div>
|
||
<div class="history-empty" id="historyEmpty">尚未抽取</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ 设置视图 ============ -->
|
||
<section class="view view-settings" id="view-settings">
|
||
<h2 class="section-title">设置</h2>
|
||
|
||
<div class="settings-card">
|
||
<h3 class="settings-group-title">抽取行为</h3>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">动画速度</span>
|
||
<span class="setting-desc">控制抽取动画的快慢</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<input type="range" id="speedRange" min="1" max="5" value="3" class="slider" />
|
||
<span class="setting-val" id="speedVal">标准</span>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">音效</span>
|
||
<span class="setting-desc">抽取时播放提示音</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<label class="switch">
|
||
<input type="checkbox" id="soundToggle" />
|
||
<span class="switch-track"><span class="switch-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">自动记录历史</span>
|
||
<span class="setting-desc">将每次抽取结果记入课堂记录</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<label class="switch">
|
||
<input type="checkbox" id="historyToggle" checked />
|
||
<span class="switch-track"><span class="switch-thumb"></span></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-card">
|
||
<h3 class="settings-group-title">数据管理</h3>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">管理控制台</span>
|
||
<span class="setting-desc">学生与题目管理已迁移至管理员端</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<a class="btn btn-ghost btn-sm" href="./admin/" target="_blank" rel="noopener">前往管理端</a>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">示例数据</span>
|
||
<span class="setting-desc">加载一组示例学生用于体验</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<button class="btn btn-ghost btn-sm" id="loadDemoBtn2">加载示例</button>
|
||
</div>
|
||
</div>
|
||
<div class="setting-row">
|
||
<div class="setting-label">
|
||
<span class="setting-name">清空所有数据</span>
|
||
<span class="setting-desc">删除全部学生与课堂记录(不可恢复)</span>
|
||
</div>
|
||
<div class="setting-control">
|
||
<button class="btn btn-danger btn-sm" id="clearAllBtn">清空</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p class="settings-foot">数据保存在浏览器本地 (localStorage),不会上传服务器。</p>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Toast 提示 -->
|
||
<div class="toast" id="toast" hidden></div>
|
||
|
||
<script src="script.js"></script>
|
||
</body>
|
||
</html>
|