好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 zhubaihui 于 2026-7-19 06:44 编辑
准考证生成系统,附模板,请填写好模板,设置考试日程安排,解析数据后就可以直接生成准考证。
没有试场数据的科目过滤不显示,只显示有试场、座位号、试场位置科目的数据。
如选择物化生的不会显示政治和地理两科。选科物化政的不会出现生物地理科目,考试日常是统一全部显示的,
无论选哪个组合科目时间都有。代码和模板都在附件里,下载就能用。
更新了一下:中间版本就不放上来了,主要增加了:下载模板,补打丢失准考证,可同时查询多人,
凑够一页打印,也可凑够几页一起打印,查询记录累计缓存到一起。调整了四个准考证之间的距离
防止学生分准考证是撕坏相邻准考证。更新代码就不发了,放附件里了。
代码如下:
[HTML] 纯文本查看 复制代码 <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>准考证生成系统(V1.0)</title>
<script src="https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js"></script>
<style>
:root {
--ticket-w: 138mm;
--ticket-h: 95mm;
--gap: 3mm;
--border: 1px solid #000;
--primary: #1677ff;
--success: #52c41a;
--danger: #ff4d4f;
--gray-bg: #f0f2f5;
--card-bg: #ffffff;
--text-main: #1f2937;
--text-secondary: #6b7280;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: "SimSun", "Songti SC", "Microsoft YaHei", serif;
background: var(--gray-bg);
color: var(--text-main);
font-size: 12px;
line-height: 1.35;
padding: 20px;
}
/* ========== 控制面板 ========== */
.panel {
max-width: 1020px;
margin: 0 auto 24px;
padding: 24px;
background: var(--card-bg);
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
.panel h1 {
text-align: center;
font-size: 22px;
margin-bottom: 20px;
color: #111827;
letter-spacing: 1px;
}
.config-section {
margin-bottom: 22px;
padding-bottom: 16px;
border-bottom: 1px solid #e5e7eb;
}
.config-section:last-of-type { border-bottom: none; }
.config-section h2 {
font-size: 15px;
font-weight: 600;
margin-bottom: 12px;
color: #374151;
display: flex;
align-items: center;
gap: 6px;
}
.config-section h2::before {
content: "";
width: 4px;
height: 14px;
background: var(--primary);
display: inline-block;
border-radius: 2px;
}
#schedule-list {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
font-size: 12px;
border-radius: 6px;
overflow: hidden;
}
#schedule-list th, #schedule-list td {
border: 1px solid #d1d5db;
padding: 6px 8px;
line-height: 1.3;
text-align: left;
}
#schedule-list th {
font-weight: 500;
/* 移除灰色背景 */
}
.btn-add-schedule {
background: linear-gradient(135deg, #1677ff, #4096ff);
color: white;
border: none;
padding: 6px 14px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
margin-top: 10px;
transition: all 0.2s ease;
}
.btn-add-schedule:hover { opacity: 0.9; transform: translateY(-1px); }
.btn-remove {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 3px;
background: linear-gradient(135deg, #ff4d4f, #ff7875);
color: white;
border: none;
min-width: 52px;
height: 28px;
padding: 0 12px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
transition: all 0.25s ease;
box-shadow: 0 2px 4px rgba(255, 77, 79, 0.2);
}
.btn-remove::before { content: "🗑️"; font-size: 13px; line-height: 1; }
.btn-remove:hover {
background: linear-gradient(135deg, #cf1322, #ff4d4f);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(255, 77, 79, 0.35);
}
.btn-remove:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(255, 77, 79, 0.2); }
.form-row { display: flex; gap: 16px; margin-bottom: 12px; }
.form-col { flex: 1; min-width: 200px; }
.form-col label {
display: block;
font-weight: 500;
margin-bottom: 6px;
font-size: 12px;
color: #374151;
}
.form-col input {
width: 100%;
padding: 7px 10px;
border: 1px solid #d1d5db;
border-radius: 6px;
font-size: 12px;
transition: border 0.2s;
}
.form-col input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.1);
}
.btn-group {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
margin-top: 20px;
}
button, .file-label {
padding: 10px 24px;
font-size: 13px;
cursor: pointer;
border: none;
border-radius: 6px;
color: white;
transition: all 0.2s ease;
font-weight: 500;
}
.file-label {
background: linear-gradient(135deg, #1677ff, #4096ff);
display: inline-block;
}
.btn-print { background: linear-gradient(135deg, #52c41a, #73d13d); }
.btn-clear { background: linear-gradient(135deg, #ff4d4f, #ff7875); }
button:hover, .file-label:hover { opacity: 0.92; transform: translateY(-1px); }
#status {
text-align: center;
margin-top: 14px;
font-size: 13px;
color: var(--text-secondary);
font-weight: 500;
}
/* ========== 准考证页面 ========== */
.page {
width: 297mm;
height: 210mm;
margin: 16px auto;
padding: 2mm;
background: white;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: var(--gap);
page-break-after: always;
page-break-inside: avoid;
}
.ticket {
border: var(--border);
padding: 1.5mm;
display: flex;
flex-direction: column;
overflow: visible;
page-break-inside: avoid !important;
}
.ticket-title {
text-align: center;
font-size: 14px;
font-weight: bold;
letter-spacing: 1px;
padding-bottom: 1mm;
margin-bottom: 1mm;
}
.header-row {
display: table;
width: 100%;
margin-bottom: 1mm;
line-height: 1.3;
}
.header-cell {
display: table-cell;
padding: 0.6mm 1mm;
vertical-align: middle;
font-size: 12px;
}
.label { font-weight: bold; }
.value { font-weight: bold; margin-left: 3px; }
/* ========== ★ 试场表格(列顺序已互换,宽度已调整) ★ ========== */
.venue-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1mm;
font-size: 11.5px;
line-height: 1.3;
table-layout: fixed;
}
.venue-table th,
.venue-table td {
border: var(--border);
padding: 0.8mm 0.6mm;
text-align: center;
vertical-align: middle;
overflow: hidden;
}
.venue-table th {
font-weight: normal;
/* 移除灰色表头背景 */
}
/* ★ 新列序:考点 | 科类 | 试场 | 座位号 | 试场位置 ★ */
/* 第1列:考点 12mm */
.venue-table th:nth-child(1),
.venue-table td:nth-child(1) {
width: 12mm !important;
min-width: 12mm;
max-width: 12mm;
}
/* 第2列:科类 18mm —— 移除加粗 */
.venue-table th:nth-child(2),
.venue-table td:nth-child(2) {
width: 18mm !important;
min-width: 18mm;
max-width: 18mm;
}
/* 第3列:试场 8mm */
.venue-table th:nth-child(3),
.venue-table td:nth-child(3) {
width: 5mm !important;
min-width: 5mm;
max-width: 5mm;
}
/* ★ 第4列:座位号 8mm(原5mm→12mm,保证"座位号"+编号不换行) ★ */
.venue-table th:nth-child(4),
.venue-table td:nth-child(4) {
width: 12mm !important;
min-width: 12mm;
max-width: 12mm;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ★ 第5列:试场位置 43mm(原50mm→43mm,为座位号腾出7mm) ★ */
.venue-table th:nth-child(5),
.venue-table td:nth-child(5) {
width: 43mm !important;
min-width: 43mm;
max-width: 43mm;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
/* ========== 日程表格 ========== */
.schedule-table {
width: 100%;
border-collapse: collapse;
font-size: 11.5px;
line-height: 1.25;
table-layout: fixed;
margin-bottom: 1mm;
}
.schedule-table th, .schedule-table td {
border: var(--border);
padding: 0.7mm 0.6mm;
text-align: center;
vertical-align: middle;
white-space: normal;
word-break: break-all;
overflow: visible;
}
.schedule-table th {
font-weight: normal;
/* 移除灰色表头背景 */
}
/* 日期列取消加粗 */
.date-col { width: 24mm; }
.time-col { width: 34mm; }
.subject-col { width: auto; }
.ticket-footer {
margin-top: auto;
font-size: 8px;
text-align: center;
border-top: 1px dashed #999;
padding-top: 0.6mm;
color: #444;
line-height: 1.2;
}
/* ========== 打印样式 ========== */
@media print {
@page { size: A4 landscape; margin: 0mm; }
body { background: white; padding: 0; margin: 0; }
.panel { display: none !important; }
.page {
margin: 0;
width: 297mm;
height: 210mm;
page-break-after: always;
page-break-inside: avoid;
padding: 1mm;
}
.ticket {
padding: 1.2mm;
page-break-inside: avoid !important;
}
}
</style>
</head>
<body>
<div class="panel">
<h1>🎓 准考证生成系统(V1.0)</h1>
<div class="config-section">
<h2>自定义考试日程(增删科目时间)</h2>
<table id="schedule-list">
<thead>
<tr><th>考试日期</th><th>考试时间</th><th>考试科目</th><th>操作</th></tr>
</thead>
<tbody>
<tr>
<td><input type="text" value="2026年9月17日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="07:30—10:00" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="语 文" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月17日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="10:20—11:35" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="物理/历史" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月17日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="13:30—15:30" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="数 学" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月18日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="07:30—08:45" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="化 学" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月18日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="09:00—10:15" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="生 物" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月18日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="10:30—11:45" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="政 治" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月18日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="13:30—14:15" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="地 理" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
<tr>
<td><input type="text" value="2026年9月18日" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="15:00—17:00" style="width:100%;padding:4px;font-size:12px;"></td>
<td><input type="text" value="英 语" style="width:100%;padding:4px;font-size:12px;"></td>
<td><button class="btn-remove">删除</button></td>
</tr>
</tbody>
</table>
<button class="btn-add-schedule">+ 新增考试日程行</button>
</div>
<div class="config-section">
<h2>基础打印配置</h2>
<div class="form-row">
<div class="form-col">
<label>考试名称</label>
<input type="text" id="cfgTitle" value="实验中学考试准考证">
</div>
<div class="form-col">
<label>考点名称</label>
<input type="text" id="cfgVenue" value="博学楼">
</div>
</div>
</div>
<div class="btn-group">
<label for="excelFile" class="file-label">📂 上传考生Excel数据</label>
<input type="file" id="excelFile" accept=".xlsx,.xls" hidden>
<button class="btn-print">🖨️ 直接打印准考证</button>
<button class="btn-clear">🗑️ 清空全部生成内容</button>
</div>
<div id="status">请上传考生数据生成准考证...</div>
</div>
<div id="pages-container"></div>
<script>
// ========== 自适应字体计算(仅用于试场位置列) ==========
function calcRoomFontSize(text) {
var str = String(text || "").trim();
if (!str) return "11.5px";
var cjkCount = (str.match(/[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/g) || []).length;
var otherCount = str.length - cjkCount;
var equivChars = cjkCount + otherCount * 0.55;
// 43mm ≈ 163px,减去左右padding各≈2.3px,可用≈158px
var availableWidth = 158;
var fontSize = Math.floor(availableWidth / equivChars);
fontSize = Math.max(7, Math.min(fontSize, 11.5));
return fontSize + "px";
}
// ========== 日程管理 ==========
function addScheduleRow() {
var tbody = document.querySelector('#schedule-list tbody');
var newRow = document.createElement('tr');
newRow.innerHTML =
'<td><input type="text" placeholder="2026年9月17日" style="width:100%;padding:4px;font-size:12px;"></td>' +
'<td><input type="text" placeholder="07:30—10:00" style="width:100%;padding:4px;font-size:12px;"></td>' +
'<td><input type="text" placeholder="语文" style="width:100%;padding:4px;font-size:12px;"></td>' +
'<td><button class="btn-remove">删除</button></td>';
tbody.appendChild(newRow);
newRow.querySelector('.btn-remove').onclick = function() {
if (tbody.children.length <= 1) return alert("至少保留一条考试日程!");
this.closest('tr').remove();
};
}
document.querySelectorAll('.btn-remove').forEach(function(btn) {
btn.onclick = function() {
var tbody = document.querySelector('#schedule-list tbody');
if (tbody.children.length <= 1) return alert("至少保留一条考试日程!");
this.closest('tr').remove();
};
});
function getScheduleData() {
return Array.from(document.querySelectorAll('#schedule-list tbody tr')).map(function(row) {
var inputs = row.querySelectorAll('input');
return { date: inputs[0].value.trim(), time: inputs[1].value.trim(), subject: inputs[2].value.trim() };
}).filter(function(i) { return i.date && i.time && i.subject; });
}
// ========== Excel解析 ==========
document.getElementById('excelFile').addEventListener('change', function(e) {
var file = e.target.files[0];
if (!file) return;
var statusDom = document.getElementById('status');
statusDom.textContent = "文件解析中,请稍候...";
statusDom.style.color = "#1677ff";
var reader = new FileReader();
reader.onload = function(ev) {
try {
var data = new Uint8Array(ev.target.result);
var wb = XLSX.read(data, { type: 'array' });
var ws = wb.Sheets[wb.SheetNames[0]];
var rows = XLSX.utils.sheet_to_json(ws, { header: 1 });
buildTickets(rows);
var ticketCount = document.querySelectorAll('.ticket').length;
statusDom.textContent = "✅ 生成完成,共 " + ticketCount + " 张准考证";
statusDom.style.color = "#52c41a";
} catch (err) {
console.error(err);
statusDom.textContent = "❌ 文件解析失败,请检查Excel格式";
statusDom.style.color = "#ff4d4f";
}
};
reader.readAsArrayBuffer(file);
});
function findColIndex(headers, keyword) {
return headers.findIndex(function(h) { return String(h || '').includes(keyword); });
}
function filterValidVenueList(venueArr) {
return venueArr.filter(function(item) {
if (item.subj === "语数外物历") return true;
var hall = String(item.hall || "").trim();
return hall !== "" && hall !== "无";
});
}
function buildTickets(rows) {
var cfg = getConfig();
var container = document.getElementById('pages-container');
container.innerHTML = '';
var hdrIdx = -1, headers = [];
for (var i = 0; i < Math.min(15, rows.length); i++) {
var rowStr = JSON.stringify(rows[i] || []);
if (rowStr.includes("姓名") && rowStr.includes("考号")) {
hdrIdx = i;
headers = rows[i].map(function(h) { return String(h || '').trim(); });
break;
}
}
if (hdrIdx === -1) {
return alert("Excel未识别到【姓名、考号】表头,请检查表格!");
}
var ci = function(kw) { return findColIndex(headers, kw); };
var colMap = {
name: ci("姓名"), examNo: ci("考号"), className: ci("班级"),
reqRoom: ci("必选科目考场"), reqHall: ci("必选试场"), reqSeat: ci("必选座位号"),
chemRoom: ci("化学考场"), chemHall: ci("化学试场"), chemSeat: ci("化学座位号"),
bioRoom: ci("生物考场"), bioHall: ci("生物试场"), bioSeat: ci("生物座位号"),
polRoom: ci("政治考场"), polHall: ci("政治试场"), polSeat: ci("政治座位号"),
geoRoom: ci("地理考场"), geoHall: ci("地理试场"), geoSeat: ci("地理座位号")
};
var students = [];
for (var j = hdrIdx + 1; j < rows.length; j++) {
var r = rows[j];
if (!r || !r[colMap.name]) continue;
students.push({
name: r[colMap.name] || "",
examNo: r[colMap.examNo] || "",
className: r[colMap.className] || "",
venues: [
{ subj: "语数外物历", room: r[colMap.reqRoom] || "无", hall: r[colMap.reqHall] || "无", seat: r[colMap.reqSeat] || "无" },
{ subj: "化 学", room: r[colMap.chemRoom] || "无", hall: r[colMap.chemHall] || "无", seat: r[colMap.chemSeat] || "无" },
{ subj: "地 理", room: r[colMap.geoRoom] || "无", hall: r[colMap.geoHall] || "无", seat: r[colMap.geoSeat] || "无" },
{ subj: "政 治", room: r[colMap.polRoom] || "无", hall: r[colMap.polHall] || "无", seat: r[colMap.polSeat] || "无" },
{ subj: "生 物", room: r[colMap.bioRoom] || "无", hall: r[colMap.bioHall] || "无", seat: r[colMap.bioSeat] || "无" }
]
});
}
var pages = [];
var currentPage = [];
var currentClass = null;
for (var k = 0; k < students.length; k++) {
var stu = students[k];
if (stu.className !== currentClass && currentPage.length > 0) {
pages.push(currentPage.slice());
currentPage = [];
currentClass = stu.className;
}
if (currentPage.length >= 4) {
pages.push(currentPage.slice());
currentPage = [];
}
currentPage.push(stu);
currentClass = stu.className;
}
if (currentPage.length > 0) pages.push(currentPage.slice());
for (var p = 0; p < pages.length; p++) {
var pageDiv = document.createElement('div');
pageDiv.className = 'page';
for (var s = 0; s < pages[p].length; s++) {
pageDiv.insertAdjacentHTML('beforeend', renderTicket(pages[p][s], cfg));
}
container.appendChild(pageDiv);
}
}
function getConfig() {
return {
title: document.getElementById('cfgTitle').value.trim() || "准考证",
venue: document.getElementById('cfgVenue').value.trim() || "考点",
schedule: getScheduleData(),
footer: "1. 凭准考证入场;2. 严禁携带手机、智能手表等通讯工具;3. 开考15分钟后禁止入场。"
};
}
// ========== 单张准考证渲染(★列顺序已互换★) ==========
function renderTicket(s, cfg) {
var headerRow =
'<div class="header-row">' +
'<div class="header-cell"><span class="label">姓名:</span><span class="value">' + s.name + '</span></div>' +
'<div class="header-cell"><span class="label">班级:</span><span class="value">' + s.className + '</span></div>' +
'<div class="header-cell"><span class="label">考号:</span><span class="value">' + s.examNo + '</span></div>' +
'</div>';
var validVenues = filterValidVenueList(s.venues);
// ★ 新列序:考点 | 科类 | 试场 | 座位号 | 试场位置 ★
var venueRows = validVenues.map(function(v) {
var adaptiveSize = calcRoomFontSize(v.room);
return '<tr>' +
'<td>' + cfg.venue + '</td>' +
'<td>' + v.subj + '</td>' +
'<td>' + v.hall + '</td>' +
'<td>' + v.seat + '</td>' +
'<td style="font-size:' + adaptiveSize + '" title="' + v.room + '">' + v.room + '</td>' +
'</tr>';
}).join('');
var schedRows = cfg.schedule.map(function(item) {
return '<tr>' +
'<td class="date-col">' + item.date + '</td>' +
'<td class="time-col">' + item.time + '</td>' +
'<td colspan="2" class="subject-col">' + item.subject + '</td>' +
'</tr>';
}).join('');
return '<div class="ticket">' +
'<div class="ticket-title">' + cfg.title + '</div>' +
headerRow +
'<table class="venue-table">' +
'<thead><tr><th>考 点</th><th>科类</th><th>试场</th><th>座位号</th><th>试场位置</th></tr></thead>' +
'<tbody>' + venueRows + '</tbody>' +
'</table>' +
'<table class="schedule-table">' +
'<thead><tr><th class="date-col">考试日期</th><th class="time-col">考试时间</th><th colspan="2" class="subject-col">考试科目</th></tr></thead>' +
'<tbody>' + schedRows + '</tbody>' +
'</table>' +
'<div class="ticket-footer">' + cfg.footer.replace(/\n/g, '<br>') + '</div>' +
'</div>';
}
function doPrint() {
if (!document.querySelector('.ticket')) {
return alert("请先上传Excel考生数据,生成准考证后再打印!");
}
window.print();
}
function clearAll() {
document.getElementById('pages-container').innerHTML = '';
document.getElementById('excelFile').value = '';
var statusDom = document.getElementById('status');
statusDom.textContent = "请上传考生数据生成准考证...";
statusDom.style.color = "#6b7280";
}
</script>
</body>
</html> |
免费评分
-
查看全部评分
本帖被以下淘专辑推荐:
- · 软件合辑|主题: 4594, 订阅: 2789
|