完成批次 L-R:限流移除/白名单驱动/打印增强/全屏/表格对齐/主题变量/滚动闪烁修复
- 移除登录失败限流;fix-config.php 修正 e2e 串味的 127.0.0.1 连接 - 白名单驱动缺/待考名单(DataService + SurveyKingClient::getWhitelist,复用已取 survey) - 打印成绩明细增强(范围/合格列默认关/去页脚);看板全屏占满;表格 vertical-align:middle;隐藏登陆账号;导入默认追加 - 主题变量收口(:root 新增 brand/primary-2/ok-2 等,替换硬编码渐变);删死规则 - 表头/数据列对齐修复(index 未匹配表、dashboard 成员榜、draw 结果/历史/排除表);看板占位卡片配色一致 - 修复滚动闪烁:row-drop-in 动画经 _dropAnim 门控,仅强制重绘时播放 - 测试:新增 test-whitelist.js;run-all.sh 全绿 132
This commit is contained in:
+38
-54
@@ -6,14 +6,22 @@
|
||||
--text: #1d2433;
|
||||
--text-2: #5b6577;
|
||||
--text-3: #8b95a7;
|
||||
/* 主色阶:--primary 基准、--primary-2 悬停/激活深一档、--primary-3 浅色渐变端 */
|
||||
--primary: #2f6bff;
|
||||
--primary-2: #2559db;
|
||||
--primary-3: #5b8bff;
|
||||
--primary-weak: #eaf0ff;
|
||||
--brand-2: #6a4bff; /* 品牌渐变收尾(紫)—— logo/面板条/登录条 */
|
||||
--ok: #12a86a;
|
||||
--ok-2: #3ec99a; /* 成功渐变亮端(toast) */
|
||||
--ok-weak: #e7f7ef;
|
||||
--warn: #e08c1a;
|
||||
--warn-2: #f0a54a; /* 警告渐变亮端(toast) */
|
||||
--warn-weak: #fdf3e2;
|
||||
--danger: #e0483d;
|
||||
--danger-2: #ef6c64; /* 危险渐变亮端(toast) */
|
||||
--danger-weak: #fdecea;
|
||||
--ink: #1b2440; /* 登录页深底 */
|
||||
--shadow: 0 1px 2px rgba(20, 30, 60, .05), 0 8px 24px rgba(20, 30, 60, .06);
|
||||
--shadow-lg: 0 12px 32px rgba(20, 30, 60, .12);
|
||||
--radius: 12px;
|
||||
@@ -120,7 +128,7 @@ body {
|
||||
color: #fff;
|
||||
}
|
||||
.btn-primary { background: var(--primary); border-color: var(--primary); color: #fff; }
|
||||
.btn-primary:hover { background: #2559db; border-color: #2559db; }
|
||||
.btn-primary:hover { background: var(--primary-2); border-color: var(--primary-2); }
|
||||
.btn.sm { padding: 5px 10px; font-size: 12px; }
|
||||
.btn.xs { padding: 3px 8px; font-size: 11px; }
|
||||
.btn.danger { color: var(--danger); border-color: #f3cfcb; }
|
||||
@@ -260,8 +268,6 @@ select:focus, input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px
|
||||
.dot.stale { background: var(--danger); animation: blink 1s infinite; }
|
||||
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
|
||||
|
||||
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
@media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }
|
||||
|
||||
/* ---------- 三 panel 布局容器(默认 / 成绩明细与缺考名单同行) ---------- */
|
||||
.layout {
|
||||
@@ -296,25 +302,31 @@ select:focus, input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px
|
||||
}
|
||||
|
||||
/* ---------- 表格 ---------- */
|
||||
.table-scroll { overflow: auto; max-height: 62vh; }
|
||||
.table-scroll { overflow: auto; max-height: 62vh; scrollbar-gutter: stable; }
|
||||
.table-scroll.short { max-height: 320px; }
|
||||
.table-scroll.mid { max-height: 380px; }
|
||||
|
||||
table.grid { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
table.grid { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13px; table-layout: fixed; }
|
||||
table.grid th {
|
||||
position: sticky; top: 0; z-index: 2;
|
||||
background: linear-gradient(180deg, #fbfcfe, #f4f7fc); color: var(--text-2);
|
||||
text-align: left; font-weight: 600; font-size: 12px;
|
||||
padding: 11px 14px; border-bottom: 1px solid var(--border);
|
||||
white-space: nowrap;
|
||||
padding: 11px 14px;
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
/* 用 box-shadow 画分隔线而非 border:border 在 border-collapse:separate + sticky 下
|
||||
不会与下方 td 边框产生折叠重绘缝隙(消除吸顶表头在滚动边界的 1px 双线/错位观感) */
|
||||
background-clip: padding-box;
|
||||
box-shadow: inset 0 -1px 0 var(--border);
|
||||
}
|
||||
table.grid th.sortable { cursor: pointer; user-select: none; }
|
||||
table.grid th.sortable:hover { color: var(--primary); }
|
||||
table.grid th .arrow { color: var(--primary); margin-left: 3px; }
|
||||
table.grid td { padding: 10px 14px; border-bottom: 1px solid var(--border-2); }
|
||||
table.grid td { padding: 10px 14px; border-bottom: 1px solid var(--border-2); vertical-align: middle; background-clip: padding-box; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
/* 含按钮的操作列:不能被 ellipsis 的 overflow:hidden 裁掉按钮 */
|
||||
table.grid td.act { overflow: visible; text-overflow: clip; }
|
||||
/* 虚拟滚动占位行:不占视觉空间、不响应 hover/条纹、不显示边框 */
|
||||
table.grid tbody tr.vspacer td { padding: 0; border: 0; background: transparent !important; }
|
||||
table.grid tbody tr.vspacer:nth-child(even) td { background: transparent !important; }
|
||||
table.grid tbody tr.vspacer:hover td { background: transparent !important; }
|
||||
table.grid tbody tr:nth-child(even) td { background: #fbfcff; }
|
||||
table.grid tbody tr:hover td { background: var(--primary-weak); }
|
||||
@@ -324,6 +336,7 @@ td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||||
td.sid { font-weight: 600; color: var(--text-2); font-variant-numeric: tabular-nums; }
|
||||
/* 数值列右对齐:成绩 / 次数 / 时长纵向扫读时更容易对齐比对 */
|
||||
table.grid td.num, table.grid td.score { text-align: right; }
|
||||
/* 表头对齐 = data-k 派生,与单元格的正则保持一致;避免"表头左对齐、数据右对齐"造成的视觉错列 */
|
||||
table.grid thead th[data-k="score"],
|
||||
table.grid thead th[data-k="attempts"],
|
||||
table.grid thead th[data-k="submit_ts"],
|
||||
@@ -335,17 +348,22 @@ td.score { font-weight: 700; font-variant-numeric: tabular-nums; }
|
||||
.score-high { color: var(--ok); }
|
||||
.score-mid { color: var(--warn); }
|
||||
.score-low { color: var(--danger); }
|
||||
.diff { animation: flash 1.6s ease-out; }
|
||||
@keyframes flash { from { background: #fff6d9; } to { background: transparent; } }
|
||||
|
||||
/* 新数据行动画:FLIP 滑动(行移动) + 全新行落入;尊重 prefers-reduced-motion */
|
||||
@keyframes rowDrop { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
|
||||
table.grid tbody tr.row-drop-in { animation: rowDrop .42s ease; }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
table.grid tbody tr.row-drop-in { animation: none; }
|
||||
}
|
||||
|
||||
/* ---------- Toast 顶部飘窗通知 ---------- */
|
||||
.toast {
|
||||
background: linear-gradient(135deg, #2f6bff, #5b8bff);
|
||||
background: linear-gradient(135deg, var(--primary), var(--primary-3));
|
||||
color: #fff;
|
||||
}
|
||||
.toast-ok { background: linear-gradient(135deg, #12a86a, #3ec99a); color: #fff; }
|
||||
.toast-error{ background: linear-gradient(135deg, #e0483d, #ef6c64); color: #fff; }
|
||||
.toast-warn { background: linear-gradient(135deg, #e08c1a, #f0a54a); color: #fff; }
|
||||
.toast-ok { background: linear-gradient(135deg, var(--ok), var(--ok-2)); color: #fff; }
|
||||
.toast-error{ background: linear-gradient(135deg, var(--danger), var(--danger-2)); color: #fff; }
|
||||
.toast-warn { background: linear-gradient(135deg, var(--warn), var(--warn-2)); color: #fff; }
|
||||
@keyframes toastIn {
|
||||
from { opacity: 0; transform: translateY(-12px) scale(.96); }
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||
@@ -405,6 +423,9 @@ table.grid tbody tr.new.clickable:hover td { background: #d6f2e2; }
|
||||
.x { border: 0; background: none; font-size: 22px; line-height: 1; cursor: pointer; color: var(--text-3); }
|
||||
.x:hover { color: var(--text); }
|
||||
.modal-body { padding: 18px; overflow: auto; }
|
||||
/* 弹窗内的表格不做吸顶:弹窗自身是滚动容器,吸顶表头会与内容错层(且贴边观感差) */
|
||||
.modal-body table.grid th { position: static; }
|
||||
.modal-body table.grid { box-shadow: inset 0 0 0 1px var(--border-2); border-radius: 8px; }
|
||||
.modal-foot {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 12px 18px; border-top: 1px solid var(--border); background: #fbfcfe;
|
||||
@@ -419,11 +440,6 @@ table.grid tbody tr.new.clickable:hover td { background: #d6f2e2; }
|
||||
.fi label .req { color: var(--danger, #e5484d); margin-left: 2px; }
|
||||
.fi-inline { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
|
||||
.fi-inline .chk { font-weight: 500; font-size: 13px; color: var(--text); }
|
||||
.fullscores { display: flex; flex-direction: column; gap: 6px; }
|
||||
.fullscores .row { display: flex; align-items: center; gap: 8px; }
|
||||
.fullscores label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.fullscores input { width: 90px; flex: none; }
|
||||
.fullscores .empty { padding: 6px 0; color: var(--text-3); font-size: 12px; text-align: left; }
|
||||
.hint { margin: 0; font-size: 11px; color: var(--text-3); }
|
||||
.fi.checks { flex-direction: row; flex-wrap: wrap; gap: 18px; }
|
||||
.fi.checks label { display: flex; align-items: center; gap: 6px; font-weight: 500; font-size: 13px; color: var(--text); }
|
||||
@@ -487,9 +503,6 @@ table.grid tbody tr.new.clickable:hover td { background: #d6f2e2; }
|
||||
.login-box .fi { margin-bottom: 14px; }
|
||||
.login-actions { display: flex; gap: 10px; margin-top: 6px; }
|
||||
.login-actions .btn { flex: 1; }
|
||||
.login-msg { margin-top: 12px; font-size: 12px; min-height: 18px; white-space: pre-wrap; }
|
||||
.login-msg.ok { color: var(--ok); }
|
||||
.login-msg.err { color: var(--danger); }
|
||||
|
||||
/* ---------- 全屏适配 ---------- */
|
||||
body.fs-on .wrap { max-width: none; padding-top: 8px; }
|
||||
@@ -509,7 +522,6 @@ body.fs-on .topbar { padding-top: 8px; padding-bottom: 8px; }
|
||||
|
||||
/* 平板横屏(769~1024):卡片改 4 列、工具栏字段占满整行 */
|
||||
@media (max-width: 1024px) {
|
||||
.grid-2 { grid-template-columns: 1fr; }
|
||||
.field.grow, .field.grow-2 { flex: 1 1 100%; min-width: 0; }
|
||||
.cards { grid-template-columns: repeat(4, 1fr); }
|
||||
.toolbar { gap: 14px; }
|
||||
@@ -529,8 +541,6 @@ body.fs-on .topbar { padding-top: 8px; padding-bottom: 8px; }
|
||||
.field { flex: 1 1 100%; min-width: 0; }
|
||||
.field.btns { flex: 1 1 100%; flex-wrap: wrap; row-gap: 8px; }
|
||||
.field.btns select { width: 100%; }
|
||||
/* 导出区的复选标签在小屏独占一行,避免和按钮挤成一团 */
|
||||
.field.btns > label[style*="cursor:pointer"] { flex: 1 1 auto; }
|
||||
.cards { grid-template-columns: repeat(3, 1fr); gap: 8px; }
|
||||
.card { padding: 10px 12px; }
|
||||
.card b { font-size: 20px; }
|
||||
@@ -612,15 +622,6 @@ body.fs-on .topbar { padding-top: 8px; padding-bottom: 8px; }
|
||||
.sec-title { margin: 22px 0 4px; font-size: 15px; font-weight: 700; display: flex; align-items: center; gap: 8px; }
|
||||
.sec-title .tag-gray { background: var(--border-2); color: var(--text-3); padding: 1px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; }
|
||||
|
||||
.class-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; margin-top: 14px; }
|
||||
.class-card {
|
||||
background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
|
||||
padding: 16px 18px; box-shadow: var(--shadow); transition: transform .18s, box-shadow .18s;
|
||||
}
|
||||
.class-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
|
||||
.class-card h3 { margin: 0 0 2px; font-size: 16px; display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
|
||||
.class-card .rate-num { font-size: 15px; font-weight: 800; white-space: nowrap; }
|
||||
.class-card .sub { font-size: 12px; color: var(--text-3); margin-bottom: 12px; }
|
||||
.bar { height: 9px; border-radius: 999px; background: var(--border-2); overflow: hidden; }
|
||||
.bar > i { display: block; height: 100%; border-radius: 999px; transition: width .5s ease; }
|
||||
.class-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; margin-top: 14px; }
|
||||
@@ -628,23 +629,10 @@ body.fs-on .topbar { padding-top: 8px; padding-bottom: 8px; }
|
||||
.class-metrics .m span { color: var(--text-3); font-size: 11px; }
|
||||
.class-metrics .m b { font-size: 17px; font-weight: 700; }
|
||||
.metric-ok b { color: var(--ok); }
|
||||
.metric-warn b { color: var(--warn); }
|
||||
.metric-danger b { color: var(--danger); }
|
||||
|
||||
.empty { text-align: center; color: var(--text-3); padding: 40px 0; }
|
||||
|
||||
/* 班级卡片:可点击进入该班详情 */
|
||||
.class-card.clickable { cursor: pointer; }
|
||||
.class-card.clickable:hover { border-color: var(--primary); }
|
||||
.grp-tag {
|
||||
display: inline-block; margin-top: 12px; padding: 2px 10px; border-radius: 999px;
|
||||
font-size: 11px; font-weight: 600; color: var(--primary); background: var(--primary-weak);
|
||||
}
|
||||
|
||||
/* 班级详情头部 */
|
||||
.detail-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 18px; }
|
||||
.detail-head h2 { margin: 0; font-size: 18px; font-weight: 700; }
|
||||
|
||||
/* 分组对比:A 在左、B 在右 */
|
||||
.group-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 14px; }
|
||||
@media (max-width: 860px) { .group-compare { grid-template-columns: 1fr; } }
|
||||
@@ -679,8 +667,8 @@ body.fs-on .topbar { padding-top: 8px; padding-bottom: 8px; }
|
||||
.rk-3 { background: #fbe9dd; color: #b45309; }
|
||||
|
||||
/* 防溢出:网格子项允许收缩,长内容不撑破页面 */
|
||||
.class-grid, .group-compare, .cards, .gpanel, .class-card { min-width: 0; }
|
||||
.gpanel, .class-card { overflow: hidden; }
|
||||
.group-compare, .cards, .gpanel { min-width: 0; }
|
||||
.gpanel { overflow: hidden; }
|
||||
.member-list td.name { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
|
||||
/* 看板全屏:整页不溢出屏幕(外层锁 100vh + overflow:hidden,内部区域自行滚动) */
|
||||
@@ -693,13 +681,9 @@ body.dash.fs-on .sec-title { margin: 12px 0 4px; font-size: 14px; }
|
||||
body.dash.fs-on .cards { gap: 10px; margin-top: 10px; }
|
||||
body.dash.fs-on .card { padding: 10px 12px; }
|
||||
body.dash.fs-on .card b { font-size: 20px; }
|
||||
body.dash.fs-on #overview, body.dash.fs-on #detail {
|
||||
flex: 1 1 auto; min-height: 0; overflow: auto;
|
||||
}
|
||||
body.dash.fs-on .class-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
|
||||
body.dash.fs-on .group-compare { gap: 12px; }
|
||||
body.dash.fs-on .gpanel { padding: 12px 14px; }
|
||||
body.dash.fs-on .member-list { max-height: 30vh; }
|
||||
body.dash.fs-on .member-list { max-height: none; }
|
||||
|
||||
|
||||
/* ================= 随机抽取页 ================= */
|
||||
|
||||
Reference in New Issue
Block a user