优化2 patch2
This commit is contained in:
@@ -177,6 +177,39 @@ function applyTableFilters(tableId) {
|
||||
if (table.closest('.qualification-ledger')) updateQualificationSelection(table.closest('.qualification-ledger'));
|
||||
}
|
||||
|
||||
function updateResultScoreInput(input) {
|
||||
const row = input.closest('tr');
|
||||
const error = row?.querySelector('[data-score-error]');
|
||||
const value = input.value.trim();
|
||||
const score = Number(value);
|
||||
const max = Number(input.max);
|
||||
const invalid = value !== '' && (!Number.isFinite(score) || score < 0 || score > max);
|
||||
input.dataset.dirty = String(value !== input.defaultValue);
|
||||
input.setAttribute('aria-invalid', String(invalid));
|
||||
row?.classList.toggle('score-row-invalid', invalid);
|
||||
if (error) error.textContent = invalid ? `须在 0—${max} 之间` : '';
|
||||
const form = input.closest('form');
|
||||
const dirty = form?.querySelectorAll('[data-result-score][data-dirty="true"]').length || 0;
|
||||
const count = form?.querySelector('[data-result-dirty-count]');
|
||||
if (count) count.textContent = dirty ? `${dirty} 条成绩尚未暂存` : '尚无未保存修改';
|
||||
}
|
||||
|
||||
function updateFeatureScoreInput(input) {
|
||||
const row = input.closest('tr');
|
||||
const error = row?.querySelector('[data-feature-score-error]');
|
||||
const value = input.value.trim();
|
||||
const score = Number(value);
|
||||
const invalid = value === '' || !Number.isFinite(score) || score < 0 || score > 1000;
|
||||
input.dataset.dirty = String(value !== input.defaultValue);
|
||||
input.setAttribute('aria-invalid', String(invalid));
|
||||
row?.classList.toggle('score-row-invalid', invalid);
|
||||
if (error) error.textContent = invalid ? '须在 0—1000 之间' : '';
|
||||
const form = input.closest('form');
|
||||
const dirty = form?.querySelectorAll('[data-feature-score][data-dirty="true"]').length || 0;
|
||||
const count = form?.querySelector('[data-feature-dirty-count]');
|
||||
if (count) count.textContent = dirty ? `${dirty} 条特征分尚未保存` : '尚无未保存修改';
|
||||
}
|
||||
|
||||
async function refreshPublic() {
|
||||
state.publicData = await api('/api/public/home');
|
||||
}
|
||||
@@ -266,7 +299,7 @@ document.addEventListener('click', async event => {
|
||||
const reviewNote = window.prompt(target.dataset.status === 'approved' ? '填写审核意见(可留空)' : '请填写退回原因', '') ?? null;
|
||||
if (reviewNote == null) return;
|
||||
await api(`/api/admin/admission-plans/${target.dataset.id}`, { method: 'PATCH', body: { status: target.dataset.status, reviewNote } });
|
||||
toast(target.dataset.status === 'approved' ? '招生计划已通过' : '招生计划已退回'); return renderRoute();
|
||||
toast(target.dataset.status === 'approved' ? '招生计划已通过并自动公示' : '招生计划已退回', target.dataset.status === 'approved' ? '公开通知公告已同步生成招生计划公示' : '招生学校可以修改后重新提交'); return renderRoute();
|
||||
}
|
||||
if (action === 'admission-match') {
|
||||
if (!window.confirm('确认按“分数优先、遵循志愿”执行本轮投档?填报顺序将锁定。')) return;
|
||||
@@ -517,6 +550,7 @@ document.addEventListener('click', async event => {
|
||||
if (target.dataset.template === '1') query.set('template', '1');
|
||||
if (target.dataset.batchId) query.set('batchId', target.dataset.batchId);
|
||||
if (target.dataset.examId) query.set('examId', target.dataset.examId);
|
||||
else if (target.dataset.resource === 'results' && state.resultExamFilter) query.set('examId', state.resultExamFilter);
|
||||
window.location.href = `/api/admin/excel/${target.dataset.resource}?${query}`;
|
||||
return;
|
||||
}
|
||||
@@ -526,6 +560,7 @@ document.addEventListener('click', async event => {
|
||||
}
|
||||
if (action === 'result-exam-filter') {
|
||||
state.resultExamFilter = target.dataset.id;
|
||||
state.resultSubjectFilter = '';
|
||||
return renderRoute();
|
||||
}
|
||||
if (action === 'cancel-result-import') {
|
||||
@@ -585,6 +620,8 @@ document.addEventListener('input', event => {
|
||||
if (event.target.matches('[data-action="table-search"]')) {
|
||||
applyTableFilters(event.target.dataset.target);
|
||||
}
|
||||
if (event.target.matches('[data-result-score]')) updateResultScoreInput(event.target);
|
||||
if (event.target.matches('[data-feature-score]')) updateFeatureScoreInput(event.target);
|
||||
if (event.target.matches('.subject-options input')) {
|
||||
const form = event.target.closest('form');
|
||||
const checked = [...form.querySelectorAll('.subject-options input:checked')];
|
||||
@@ -598,6 +635,15 @@ document.addEventListener('input', event => {
|
||||
});
|
||||
|
||||
document.addEventListener('change', event => {
|
||||
if (event.target.matches('[data-action="result-bulk-exam"]')) {
|
||||
state.resultExamFilter = event.target.value;
|
||||
state.resultSubjectFilter = '';
|
||||
renderRoute();
|
||||
}
|
||||
if (event.target.matches('[data-action="result-bulk-subject"]')) {
|
||||
state.resultSubjectFilter = event.target.value;
|
||||
renderRoute();
|
||||
}
|
||||
if (event.target.matches('[data-qualification-select]')) updateQualificationSelection(event.target.closest('.qualification-ledger'));
|
||||
if (event.target.matches('[data-table-filter]')) applyTableFilters(event.target.dataset.target);
|
||||
if (event.target.matches('[data-registration-select]')) updateRegistrationSelection();
|
||||
@@ -742,7 +788,7 @@ document.addEventListener('submit', async event => {
|
||||
const form = event.target.closest('form[data-form]');
|
||||
if (!form) return;
|
||||
event.preventDefault();
|
||||
const submit = form.querySelector('button[type="submit"]');
|
||||
const submit = event.submitter || form.querySelector('button[type="submit"]');
|
||||
const original = submit?.innerHTML;
|
||||
if (submit) { submit.disabled = true; submit.textContent = '正在处理…'; }
|
||||
try {
|
||||
@@ -943,10 +989,42 @@ document.addEventListener('submit', async event => {
|
||||
const body = formObject(form); body.published = form.published.checked;
|
||||
await api('/api/admin/results', { method: 'POST', body });
|
||||
toast(body.published ? '成绩已发布' : '成绩已保存', '考生端可见状态已更新'); renderRoute();
|
||||
} else if (kind === 'result-bulk-entry') {
|
||||
const mode = event.submitter?.dataset.resultMode || 'draft';
|
||||
const inputs = [...form.querySelectorAll('[data-result-score]')];
|
||||
const invalid = inputs.find(input => input.value.trim() !== '' && (!Number.isFinite(Number(input.value)) || Number(input.value) < 0 || Number(input.value) > Number(input.max)));
|
||||
if (invalid) { invalid.focus(); throw new Error(`成绩须在 0—${invalid.max} 之间`); }
|
||||
const targets = mode === 'publish'
|
||||
? inputs.filter(input => input.value.trim() !== '')
|
||||
: inputs.filter(input => input.dataset.dirty === 'true' && input.value.trim() !== '');
|
||||
if (mode === 'publish') {
|
||||
const missing = inputs.filter(input => input.value.trim() === '');
|
||||
if (missing.length) { missing[0].focus(); throw new Error(`还有 ${missing.length} 名考生未录入成绩,补齐后才能整科发布`); }
|
||||
if (!window.confirm(`确认发布本科学目 ${targets.length} 名考生的成绩吗?发布后考生可立即查询。`)) return;
|
||||
}
|
||||
if (!targets.length) throw new Error(mode === 'publish' ? '当前科目没有可发布的成绩' : '请先修改至少一条成绩');
|
||||
const body = {
|
||||
examId: form.examId.value,
|
||||
subjectId: form.subjectId.value,
|
||||
published: mode === 'publish',
|
||||
rows: targets.map(input => ({ registrationId: input.dataset.registrationId, score: Number(input.value) }))
|
||||
};
|
||||
const result = await api('/api/admin/results/bulk', { method: 'POST', body });
|
||||
toast(mode === 'publish' ? '本科学目成绩已发布' : '成绩已暂存', `${result.count} 条成绩已在同一事务中保存`);
|
||||
renderRoute();
|
||||
} else if (kind === 'feature-score-entry') {
|
||||
const body = formObject(form); body.featureScore = Number(body.featureScore || 0);
|
||||
await api(`/api/admin/registrations/${body.registrationId}/feature-score`, { method: 'PATCH', body });
|
||||
toast('特征分已登记', '该分数独立于考试科目,默认值为 0'); renderRoute();
|
||||
} else if (kind === 'feature-score-bulk') {
|
||||
const inputs = [...form.querySelectorAll('[data-feature-score]')];
|
||||
const invalid = inputs.find(input => input.value.trim() === '' || !Number.isFinite(Number(input.value)) || Number(input.value) < 0 || Number(input.value) > 1000);
|
||||
if (invalid) { invalid.focus(); throw new Error('特征分必须在 0—1000 之间;未参加时填写 0'); }
|
||||
const targets = inputs.filter(input => input.dataset.dirty === 'true');
|
||||
if (!targets.length) throw new Error('请先修改至少一名考生的特征分');
|
||||
const result = await api('/api/admin/feature-scores/bulk', { method: 'POST', body: { examId: form.examId.value, rows: targets.map(input => ({ registrationId: input.dataset.registrationId, featureScore: Number(input.value) })) } });
|
||||
toast('特征分已保存', `${result.count} 名考生已更新;其余考生继续保持 0 分`);
|
||||
renderRoute();
|
||||
} else if (kind === 'result-import-commit') {
|
||||
const rows = state.resultImportPreview?.rows || [];
|
||||
if (!rows.length) throw new Error('没有可提交的成绩预览');
|
||||
@@ -1184,7 +1262,16 @@ function openAdmitPreview(reg) {
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', renderRoute);
|
||||
window.addEventListener('keydown', event => { if (event.key === 'Escape') closeModal(); });
|
||||
window.addEventListener('keydown', event => {
|
||||
if (event.key === 'Escape') closeModal();
|
||||
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {
|
||||
const form = document.querySelector('form[data-form="result-bulk-entry"]');
|
||||
if (form) {
|
||||
event.preventDefault();
|
||||
form.requestSubmit(form.querySelector('[data-result-mode="draft"]'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await Promise.all([refreshPublic(), refreshSession()]);
|
||||
|
||||
Reference in New Issue
Block a user