feat: 导出按班级/组别筛选 + 随机抽取页 + 零依赖 XLSX 导出
导出跟随分类筛选 - api.php export / export_absent 新增 cls、grp 参数,按当前筛选过滤 rows - 缺考口径与页面完全一致:筛选后名单 − 筛选后已提交(按学号匹配) - 导出文件名附带班级 / 组别(如 成绩明细_高一数学月考_高一(1)班_A组_时间戳.csv) - app.js 两个导出按钮追加 cls/grp 参数并提示导出范围 随机抽取页 draw.php - 来源:学号名单 / 某试卷已提交人员;支持班级、组别筛选与抽取人数设置 - 「排除已抽中」累计去重,抽取结果存入 localStorage,刷新后仍可下载 - 抽取动画(滚动定格),结果表格含序号 / 学号 / 姓名 / 班级 / 组别 - 下载「白名单导入模板.xlsx」「白名单列表.xlsx」:两列 姓名 / 登陆账号 XLSX 导出能力 - 新增 lib/XlsxWriter.php:零依赖生成 xlsx,有 zip 扩展走 ZipArchive, 无则回退手写 ZIP(stored);单元格按共享字符串 + 文本格式(numFmtId=49) 写入,长学号不会变科学计数法 - 新增 api.php action=draw_export,输出与「白名单列表.xlsx」模板一致的结构 其他 - index.php 顶栏新增「随机抽取」入口;支持 index.php#roster 直接打开名单管理 - tools/test-xlsxwriter.php 自测:18 项全通过(含无 ZipArchive 的手写打包路径)
This commit is contained in:
+23
-2
@@ -92,6 +92,14 @@
|
||||
el.className = 'alert' + (type === 'info' ? ' info' : '');
|
||||
}
|
||||
|
||||
// 导出提示:说明本次导出的筛选范围
|
||||
function exportTip(what, cls, grp) {
|
||||
const parts = [];
|
||||
if (cls) parts.push(cls + (cls.indexOf('班') >= 0 ? '' : '班'));
|
||||
if (grp) parts.push(grp + (grp.indexOf('组') >= 0 ? '' : '组'));
|
||||
return '已导出' + what + (parts.length ? '(' + parts.join(' / ') + ')' : '(全部班级 / 组别)');
|
||||
}
|
||||
|
||||
/* ---------------- 问卷列表 ---------------- */
|
||||
// 把数组渲染到 #projectSel(抽出便于缓存复用)
|
||||
function renderProjects() {
|
||||
@@ -661,17 +669,24 @@
|
||||
});
|
||||
});
|
||||
|
||||
// 导出跟随当前班级 / 组别筛选(统计卡片与表格显示什么,就导出什么)
|
||||
$('#btnExport').addEventListener('click', () => {
|
||||
const pid = $('#projectSel').value;
|
||||
if (!pid) return showAlert('请先选择问卷 / 考试');
|
||||
const cls = $('#clsSel').value, grp = $('#grpSel').value;
|
||||
location.href = 'api.php?action=export&projectId=' + encodeURIComponent(pid) +
|
||||
'&nameQid=' + encodeURIComponent($('#nameFieldSel').value);
|
||||
'&nameQid=' + encodeURIComponent($('#nameFieldSel').value) +
|
||||
'&cls=' + encodeURIComponent(cls) + '&grp=' + encodeURIComponent(grp);
|
||||
showAlert(exportTip('成绩明细', cls, grp), 'info');
|
||||
});
|
||||
$('#btnExportAbsent').addEventListener('click', () => {
|
||||
const pid = $('#projectSel').value;
|
||||
if (!pid) return showAlert('请先选择问卷 / 考试');
|
||||
const cls = $('#clsSel').value, grp = $('#grpSel').value;
|
||||
location.href = 'api.php?action=export_absent&projectId=' + encodeURIComponent(pid) +
|
||||
'&nameQid=' + encodeURIComponent($('#nameFieldSel').value);
|
||||
'&nameQid=' + encodeURIComponent($('#nameFieldSel').value) +
|
||||
'&cls=' + encodeURIComponent(cls) + '&grp=' + encodeURIComponent(grp);
|
||||
showAlert(exportTip('缺考名单', cls, grp), 'info');
|
||||
});
|
||||
|
||||
/* 弹窗关闭 */
|
||||
@@ -803,6 +818,12 @@
|
||||
// 退出登录:跳转到独立 logout.php(清服务端会话)
|
||||
$('#btnLogout').addEventListener('click', () => { location.href = 'logout.php'; });
|
||||
|
||||
// 3) 支持 index.php#roster 直接打开名单管理(随机抽取页的「名单管理」入口用)
|
||||
if (location.hash === '#roster') {
|
||||
openRoster();
|
||||
if (history.replaceState) history.replaceState(null, '', location.pathname + location.search);
|
||||
}
|
||||
|
||||
// 启动:主界面在 PHP 端已做会话校验(未登录会跳到 login.php),此处直接加载数据
|
||||
schedule();
|
||||
loadProjects();
|
||||
|
||||
Reference in New Issue
Block a user