fix: show full student summaries

This commit is contained in:
Codex
2026-07-06 13:35:55 +08:00
parent bd5fd7815e
commit 9884e91612
5 changed files with 39 additions and 58 deletions
+2 -2
View File
@@ -12,7 +12,7 @@ from ..api_utils import (
payload_to_teacher,
read_register_payload,
)
from ..auth import verify_admin_auth, verify_student_profiles_auth
from ..auth import verify_admin_auth, verify_any_auth, verify_student_profiles_auth
from ..config import (
ACCOUNTS_PATH,
ADMIN_TASKS_PATH,
@@ -176,7 +176,7 @@ def students(
@router.get("/api/students/{student}")
def student_detail(student: str, _user: str = Depends(verify_student_profiles_auth)):
def student_detail(student: str, _user: str = Depends(verify_any_auth)):
for student_profile in load_student_profiles():
if student_profile.student == student or student_profile.student_id == student:
return student_profile_to_dict(student_profile)
+3 -33
View File
@@ -50,7 +50,6 @@ let currentRecordOrder = [];
let correctedRecords = new Map();
let correctedRecordOrder = [];
let expandedSummaryRecords = new Set();
let expandedSummaryBodies = new Set();
let collapsedTeacherGroups = new Set();
let currentRecordPage = { query: "", offset: 0, limit: 0, total: 0, shown: 0, hasMore: false };
let activeCorrectionKey = "";
@@ -244,16 +243,7 @@ function renderRecordRow(row, rowNumber) {
</tr>`;
}
function summaryBodyKey(recordKey, index) {
return `${recordKey}:${index}`;
}
function summaryPreviewText(value) {
const text = String(value || "暂无正文");
return text.length > 120 ? `${text.slice(0, 120)}...` : text;
}
function renderSummaryEntry(summary, recordKey, index) {
function renderSummaryEntry(summary) {
const title = summary.title || "课程小结";
const time = summary.time_range ? ` · ${summary.time_range}` : "";
const meta = [
@@ -261,15 +251,11 @@ function renderSummaryEntry(summary, recordKey, index) {
summary.teacher || "",
summary.subject || "",
].filter(Boolean).join(" · ");
const bodyKey = summaryBodyKey(recordKey, index);
const body = summary.body || "暂无正文";
const expanded = expandedSummaryBodies.has(bodyKey);
const canToggle = body.length > 120;
return `<div class="record-summary-item">
<div class="record-summary-title">${escapeHtml(title)}${escapeHtml(time)}</div>
${meta ? `<div class="record-summary-meta">${escapeHtml(meta)}</div>` : ""}
<div class="summary-body${expanded ? " summary-full" : " summary-preview"}">${escapeHtml(expanded ? body : summaryPreviewText(body))}</div>
${canToggle ? `<button class="summary-toggle" type="button" data-summary-body-key="${escapeHtml(bodyKey)}">${expanded ? "收起全文" : "展开全文"}</button>` : ""}
<div class="summary-body summary-full">${escapeHtml(body)}</div>
</div>`;
}
@@ -300,7 +286,7 @@ function renderGroupedRecords(records) {
const summaryCount = Number(row.summary_count || 0);
const summaryRow = summaryCount
? `<tr class="summary-collapse-row" data-summary-row="${escapeHtml(row._recordKey)}" ${expandedSummaryRecords.has(row._recordKey) ? "" : "hidden"}>
<td colspan="${RECORD_TABLE_COLUMN_COUNT}">${(row.summaries || []).map((summary, index) => renderSummaryEntry(summary, row._recordKey, index)).join("")}</td>
<td colspan="${RECORD_TABLE_COLUMN_COUNT}">${(row.summaries || []).map((summary) => renderSummaryEntry(summary)).join("")}</td>
</tr>`
: renderSummaryMissingRow(row._recordKey, expandedSummaryRecords.has(row._recordKey));
return `${renderRecordRow(row, displayIndex)}${summaryRow}`;
@@ -341,15 +327,6 @@ function toggleTeacherGroup(teacher) {
renderCurrentRecords();
}
function toggleSummaryBody(key) {
if (expandedSummaryBodies.has(key)) {
expandedSummaryBodies.delete(key);
} else {
expandedSummaryBodies.add(key);
}
renderCurrentRecords();
}
function statusClass(status) {
if (status === "欠费") return "debt";
if (status === "预警") return "warning";
@@ -414,7 +391,6 @@ function resetCorrections() {
correctedRecordOrder = [];
currentRecordOrder = [];
expandedSummaryRecords = new Set();
expandedSummaryBodies = new Set();
collapsedTeacherGroups = new Set();
activeCorrectionKey = "";
updateCorrectionToolbar();
@@ -782,7 +758,6 @@ async function queryRecords(query, options = {}) {
} else {
currentRecordOrder = [];
expandedSummaryRecords = new Set();
expandedSummaryBodies = new Set();
collapsedTeacherGroups = new Set();
}
try {
@@ -853,7 +828,6 @@ recordRows.addEventListener("click", (event) => {
const editButton = event.target.closest(".correction-edit");
const deleteButton = event.target.closest(".record-delete");
const teacherToggle = event.target.closest(".teacher-group-toggle");
const summaryToggle = event.target.closest(".summary-toggle");
if (summarySupplementButton) {
openSummarySupplementDialog(summarySupplementButton.dataset.recordKey);
return;
@@ -870,10 +844,6 @@ recordRows.addEventListener("click", (event) => {
toggleTeacherGroup(teacherToggle.dataset.teacher);
return;
}
if (summaryToggle) {
toggleSummaryBody(summaryToggle.dataset.summaryBodyKey);
return;
}
const row = event.target.closest(".record-row");
if (row && !event.target.closest(".record-action-cell")) toggleRecordSummary(row.dataset.recordKey);
});
+2 -2
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>新时空教务管理系统</title>
<link rel="stylesheet" href="/static/styles.css?v=20260626-record-index" />
<link rel="stylesheet" href="/static/styles.css?v=20260704-summary-full" />
</head>
<body>
<header class="topbar">
@@ -167,6 +167,6 @@
</section>
</div>
<script src="/static/app.js?v=20260626-record-index"></script>
<script src="/static/app.js?v=20260704-summary-full"></script>
</body>
</html>
-21
View File
@@ -933,27 +933,6 @@ textarea:focus {
border-top: 1px solid var(--line);
}
.summary-body + .summary-toggle,
.summary-full + .summary-toggle {
margin-top: 8px;
}
.summary-toggle {
min-height: 30px;
padding: 0 10px;
border: 1px solid var(--line);
border-radius: 6px;
background: #fff;
color: var(--accent-strong);
cursor: pointer;
font-size: 13px;
font-weight: 700;
}
.summary-toggle:hover {
border-color: var(--accent);
}
.summary-conflict-list {
display: grid;
gap: 10px;
+32
View File
@@ -119,6 +119,38 @@ assertEqual("纠错后排序仍使用显示记录", value("currentRecordOrder.jo
vm.runInContext("updateCorrectionToolbar('测试提交按钮')", context);
assertEqual("提交审核按钮文案", value("submitCorrectionsBtn.textContent"), "提交审核 1 条");
vm.runInContext(
`
const longSummaryBody = "完整课程小结内容".repeat(20);
currentRecords = [
{
date: "2026.06.14",
weekday: "星期日",
time: "10:00-11:00",
student: "甲",
duration: "1小时0分",
duration_hours: 1,
teacher: "王老师",
subject: "英语",
_recordIndex: 0,
_recordKey: "summary-test",
summary_count: 1,
summaries: [{ title: "课程小结", body: longSummaryBody, teacher: "王老师", subject: "英语" }],
},
];
expandedSummaryRecords = new Set(["summary-test"]);
collapsedTeacherGroups = new Set();
const summaryHtml = renderGroupedRecords(currentRecords);
if (!summaryHtml.includes(longSummaryBody)) {
throw new Error("课程小结展开后应直接显示完整正文");
}
if (summaryHtml.includes("展开全文") || summaryHtml.includes("summary-toggle") || summaryHtml.includes("summary-preview")) {
throw new Error("课程小结展开后不应再渲染展开全文按钮或预览裁切");
}
`,
context,
);
const adminElements = new Map();
function adminElement(id) {
if (!adminElements.has(id)) {