Enable editing for draft exams
This commit is contained in:
@@ -77,7 +77,7 @@ function toast(title, message = '') {
|
||||
}
|
||||
|
||||
function setModal(content) {
|
||||
modalRoot.innerHTML = `<div class="modal-layer" data-action="close-modal"><div class="modal-card" role="dialog" aria-modal="true" onclick="event.stopPropagation()">${content}</div></div>`;
|
||||
modalRoot.innerHTML = `<div class="modal-layer" data-modal-backdrop><div class="modal-card" role="dialog" aria-modal="true">${content}</div></div>`;
|
||||
setTimeout(() => modalRoot.querySelector('input,textarea,button')?.focus(), 30);
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ function adminRegistrations(registrations) {
|
||||
}
|
||||
|
||||
function adminExams(exams) {
|
||||
return `<div class="admin-exam-grid">${exams.map(exam => `<article class="admin-exam-card ${exam.status}"><header><span class="exam-code">${h(exam.code)}</span>${badge(exam.status)}</header><h2>${h(exam.name)}</h2><p>${h(exam.description)}</p><dl><div><dt>报名时间</dt><dd>${dateRange(exam.registrationStart, exam.registrationEnd)}</dd></div><div><dt>考试时间</dt><dd>${dateRange(exam.examStart, exam.examEnd)}</dd></div><div><dt>考点</dt><dd>${h(exam.location)}</dd></div></dl><div class="admin-subjects">${exam.subjects.map(subject => `<span><b>${h(subject.name)}</b><small>${h(subject.date)} ${h(subject.start)}</small></span>`).join('') || '<span>科目待配置</span>'}</div><footer><span>${exam.registrationCount} 人报名 · ${exam.subjects.length} 科</span><button class="row-action" data-action="toggle-exam" data-id="${h(exam.id)}" data-status="${exam.status === 'published' ? 'draft' : 'published'}">${exam.status === 'published' ? '撤回为草稿' : '发布考试'}</button></footer></article>`).join('')}</div>`;
|
||||
return `<div class="admin-exam-grid">${exams.map(exam => `<article class="admin-exam-card ${exam.status}${exam.status === 'draft' ? ' editable' : ''}" ${exam.status === 'draft' ? `data-action="edit-exam" data-id="${h(exam.id)}" title="点击编辑草稿"` : ''}><header><span class="exam-code">${h(exam.code)}</span>${badge(exam.status)}</header><h2>${h(exam.name)}</h2><p>${h(exam.description)}</p><dl><div><dt>报名时间</dt><dd>${dateRange(exam.registrationStart, exam.registrationEnd)}</dd></div><div><dt>考试时间</dt><dd>${dateRange(exam.examStart, exam.examEnd)}</dd></div><div><dt>考点</dt><dd>${h(exam.location)}</dd></div></dl><div class="admin-subjects">${exam.subjects.map(subject => `<span><b>${h(subject.name)}</b><small>${h(subject.date)} ${h(subject.start)}</small></span>`).join('') || '<span>科目待配置</span>'}</div><footer><span>${exam.registrationCount} 人报名 · ${exam.subjects.length} 科</span><div class="exam-card-actions">${exam.status === 'draft' ? `<button class="row-action" data-action="edit-exam" data-id="${h(exam.id)}">编辑草稿</button>` : ''}<button class="row-action" data-action="toggle-exam" data-id="${h(exam.id)}" data-status="${exam.status === 'published' ? 'draft' : 'published'}">${exam.status === 'published' ? '撤回为草稿' : '发布考试'}</button></div></footer></article>`).join('')}</div>`;
|
||||
}
|
||||
|
||||
function adminNotices(notices) {
|
||||
@@ -325,6 +325,7 @@ document.addEventListener('click', async event => {
|
||||
event.preventDefault();
|
||||
return navigate(routeTarget.dataset.route);
|
||||
}
|
||||
if (event.target.matches('[data-modal-backdrop]')) return closeModal();
|
||||
const target = event.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
const action = target.dataset.action;
|
||||
@@ -358,6 +359,7 @@ document.addEventListener('click', async event => {
|
||||
if (action === 'download-admit') { window.location.href = `/api/candidate/registrations/${target.dataset.id}/admit-card`; return; }
|
||||
if (action === 'new-notice') return openNoticeForm();
|
||||
if (action === 'new-exam') return openExamForm();
|
||||
if (action === 'edit-exam') return openExamForm(state.pageData.exams.find(exam => exam.id === target.dataset.id));
|
||||
if (action === 'review-candidate') return openCandidateReview(target.dataset.id);
|
||||
if (action === 'review-registration') return openRegistrationReview(target.dataset.id);
|
||||
if (action === 'generate-admit') {
|
||||
@@ -446,8 +448,9 @@ document.addEventListener('submit', async event => {
|
||||
} else if (kind === 'exam-form') {
|
||||
const body = formObject(form); body.subjects = body.subjects.split(/[,,]/).map(item => item.trim()).filter(Boolean);
|
||||
['registrationStart','registrationEnd','examStart','examEnd','admitDownloadStart','admitDownloadEnd'].forEach(field => body[field] = new Date(body[field]).toISOString());
|
||||
await api('/api/admin/exams', { method: 'POST', body });
|
||||
closeModal(); await refreshPublic(); toast('考试计划已创建', `${body.subjects.length} 个科目已加入`); renderRoute();
|
||||
const editing = Boolean(body.id);
|
||||
await api(editing ? `/api/admin/exams/${body.id}` : '/api/admin/exams', { method: editing ? 'PATCH' : 'POST', body });
|
||||
closeModal(); await refreshPublic(); toast(editing ? '考试草稿已更新' : '考试计划已创建', `${body.subjects.length} 个科目已配置`); renderRoute();
|
||||
} else if (kind === 'result-entry') {
|
||||
const body = formObject(form); body.published = form.published.checked;
|
||||
await api('/api/admin/results', { method: 'POST', body });
|
||||
@@ -471,8 +474,18 @@ function openNoticeForm() {
|
||||
setModal(`<div class="modal-head"><div><span>NEW NOTICE</span><h2>发布通知公告</h2><p>发布后将立即显示在公开首页和考生中心。</p></div><button data-action="close-modal">×</button></div><form class="modal-form" data-form="notice-form"><div class="field-row"><label><span>通知分类</span><select name="category"><option>报名通知</option><option>考试须知</option><option>考点公告</option><option>成绩通知</option><option>系统公告</option></select></label><label><span>发布方式</span><select name="status"><option value="published">立即发布</option><option value="draft">保存草稿</option></select></label></div><label><span>通知标题 *</span><input name="title" required placeholder="清楚说明通知事项"></label><label><span>首页摘要</span><input name="summary" placeholder="用于首页列表展示,建议 60 字以内"></label><label><span>通知正文 *</span><textarea name="content" rows="7" required placeholder="请输入完整通知内容"></textarea></label><label class="agreement"><input type="checkbox" name="pinned"><span>在公开首页置顶展示</span></label><div class="modal-foot"><button type="button" class="ghost-button" data-action="close-modal">取消</button><button type="submit" class="solid-button">保存通知</button></div></form>`);
|
||||
}
|
||||
|
||||
function openExamForm() {
|
||||
setModal(`<div class="modal-head"><div><span>NEW EXAM</span><h2>创建考试与科目</h2><p>创建后可选择直接发布或先保存为草稿。</p></div><button data-action="close-modal">×</button></div><form class="modal-form wide-form" data-form="exam-form"><div class="field-row"><label><span>考试名称 *</span><input name="name" required placeholder="例如:2027 年春季学业考试"></label><label><span>考试代码</span><input name="code" placeholder="自动生成或手动填写"></label></div><label><span>考试说明</span><textarea name="description" rows="2" placeholder="报名对象、考试范围等"></textarea></label><div class="field-row"><label><span>报名开始 *</span><input name="registrationStart" type="datetime-local" required></label><label><span>报名结束 *</span><input name="registrationEnd" type="datetime-local" required></label></div><div class="field-row"><label><span>考试开始 *</span><input name="examStart" type="datetime-local" required></label><label><span>考试结束 *</span><input name="examEnd" type="datetime-local" required></label></div><div class="field-row"><label><span>准考证下载开始 *</span><input name="admitDownloadStart" type="datetime-local" required></label><label><span>准考证下载结束 *</span><input name="admitDownloadEnd" type="datetime-local" required></label></div><label><span>考试科目 *</span><input name="subjects" required placeholder="用逗号分隔,例如:语文,数学,英语"></label><div class="field-row"><label><span>考点说明</span><input name="location" placeholder="例如:全市指定考点"></label><label><span>创建状态</span><select name="status"><option value="draft">保存为草稿</option><option value="published">立即发布</option></select></label></div><div class="modal-foot"><button type="button" class="ghost-button" data-action="close-modal">取消</button><button type="submit" class="solid-button">创建考试</button></div></form>`);
|
||||
function dateTimeLocal(value) {
|
||||
if (!value) return '';
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) return '';
|
||||
const pad = number => String(number).padStart(2, '0');
|
||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
||||
}
|
||||
|
||||
function openExamForm(exam = null) {
|
||||
const editing = Boolean(exam);
|
||||
if (editing && exam.status !== 'draft') return toast('无法编辑', '请先将已发布考试撤回为草稿');
|
||||
setModal(`<div class="modal-head"><div><span>${editing ? 'EDIT EXAM DRAFT' : 'NEW EXAM'}</span><h2>${editing ? '编辑考试草稿' : '创建考试与科目'}</h2><p>${editing ? '补全考试信息和科目后,可保存草稿或直接发布。' : '创建后可选择直接发布或先保存为草稿。'}</p></div><button type="button" data-action="close-modal" aria-label="关闭弹窗">×</button></div><form class="modal-form wide-form" data-form="exam-form">${editing ? `<input type="hidden" name="id" value="${h(exam.id)}">` : ''}<div class="field-row"><label><span>考试名称 *</span><input name="name" required value="${h(exam?.name)}" placeholder="例如:2027 年春季学业考试"></label><label><span>考试代码</span><input name="code" value="${h(exam?.code)}" placeholder="自动生成或手动填写"></label></div><label><span>考试说明</span><textarea name="description" rows="2" placeholder="报名对象、考试范围等">${h(exam?.description)}</textarea></label><div class="field-row"><label><span>报名开始 *</span><input name="registrationStart" type="datetime-local" value="${dateTimeLocal(exam?.registrationStart)}" required></label><label><span>报名结束 *</span><input name="registrationEnd" type="datetime-local" value="${dateTimeLocal(exam?.registrationEnd)}" required></label></div><div class="field-row"><label><span>考试开始 *</span><input name="examStart" type="datetime-local" value="${dateTimeLocal(exam?.examStart)}" required></label><label><span>考试结束 *</span><input name="examEnd" type="datetime-local" value="${dateTimeLocal(exam?.examEnd)}" required></label></div><div class="field-row"><label><span>准考证下载开始 *</span><input name="admitDownloadStart" type="datetime-local" value="${dateTimeLocal(exam?.admitDownloadStart)}" required></label><label><span>准考证下载结束 *</span><input name="admitDownloadEnd" type="datetime-local" value="${dateTimeLocal(exam?.admitDownloadEnd)}" required></label></div><label><span>考试科目 *</span><input name="subjects" required value="${h(exam?.subjects?.map(subject => subject.name).join(','))}" placeholder="用逗号分隔,例如:语文,数学,英语"></label><div class="field-row"><label><span>考点说明</span><input name="location" value="${h(exam?.location)}" placeholder="例如:全市指定考点"></label><label><span>${editing ? '保存状态' : '创建状态'}</span><select name="status"><option value="draft">保存为草稿</option><option value="published">立即发布</option></select></label></div><div class="modal-foot"><button type="button" class="ghost-button" data-action="close-modal">取消</button><button type="submit" class="solid-button">${editing ? '保存考试' : '创建考试'}</button></div></form>`);
|
||||
}
|
||||
|
||||
function openAdmitPreview(reg) {
|
||||
|
||||
Reference in New Issue
Block a user