Add manual study completion toggle
This commit is contained in:
@@ -241,10 +241,7 @@ function sortStudies(list) {
|
||||
}
|
||||
|
||||
function studyStatus(study) {
|
||||
const total = Number(study.series_count || 0);
|
||||
const unannotated = Number(study.unannotated_series || 0);
|
||||
if (total > 0 && unannotated === 0) return "complete";
|
||||
return "incomplete";
|
||||
return study?.completed ? "complete" : "incomplete";
|
||||
}
|
||||
|
||||
function studyStatusLabel(status) {
|
||||
@@ -321,22 +318,60 @@ function renderStudies() {
|
||||
for (const study of studies) {
|
||||
const button = document.createElement("button");
|
||||
const status = studyStatus(study);
|
||||
const nextStatusLabel = status === "complete" ? "待处理" : "已完成";
|
||||
button.className = "study-card";
|
||||
button.classList.toggle("active", app.study?.ct_number === study.ct_number);
|
||||
button.classList.toggle("complete", status === "complete");
|
||||
const name = study.source_patient_name || study.patient_name_dicom || "无姓名";
|
||||
button.innerHTML = `
|
||||
<i class="study-status-badge status-${status}" title="${status === "complete" ? "已处理完毕" : "仍有序列未标注"}">${studyStatusLabel(status)}</i>
|
||||
<i class="study-status-badge status-${status}" title="点击切换为${nextStatusLabel}">${studyStatusLabel(status)}</i>
|
||||
<strong>${escapeHtml(study.ct_number)}</strong>
|
||||
<span>${escapeHtml(name)} · ${escapeHtml(study.patient_id || "无ID")}</span>
|
||||
<span>${escapeHtml(fmtDate(study.study_date))} ${escapeHtml(fmtTime(study.study_time))} · ${Number(study.dicom_file_count || 0)} 张</span>
|
||||
<span>${Number(study.annotated_series || 0)} 个序列已标注,${Number(study.unannotated_series || 0)} 个序列未标注</span>
|
||||
`;
|
||||
button.onclick = () => selectStudy(study.ct_number);
|
||||
button.querySelector(".study-status-badge").onclick = (event) => toggleStudyCompletion(study.ct_number, event);
|
||||
list.appendChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
function applyStudyCompletion(data) {
|
||||
const completed = Boolean(data.completed);
|
||||
const study = app.studies.find((item) => item.ct_number === data.ct_number);
|
||||
if (study) {
|
||||
study.completed = completed;
|
||||
study.completed_by = data.completed_by || "";
|
||||
study.completed_at = data.completed_at || "";
|
||||
}
|
||||
if (app.study?.ct_number === data.ct_number) {
|
||||
app.study.completed = completed;
|
||||
app.study.completed_by = data.completed_by || "";
|
||||
app.study.completed_at = data.completed_at || "";
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleStudyCompletion(ctNumber, event) {
|
||||
event.stopPropagation();
|
||||
const study = app.studies.find((item) => item.ct_number === ctNumber);
|
||||
if (!study) return;
|
||||
const previous = Boolean(study.completed);
|
||||
applyStudyCompletion({ ct_number: ctNumber, completed: !previous });
|
||||
renderStudies();
|
||||
try {
|
||||
const data = await json(`/api/studies/${encodeURIComponent(ctNumber)}/completion`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ completed: !previous }),
|
||||
});
|
||||
applyStudyCompletion(data);
|
||||
renderStudies();
|
||||
} catch (err) {
|
||||
applyStudyCompletion({ ct_number: ctNumber, completed: previous });
|
||||
renderStudies();
|
||||
$("saveState").textContent = `状态更新失败:${err.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function selectStudy(ctNumber) {
|
||||
if (app.study?.ct_number && app.study.ct_number !== ctNumber) await confirmSaveIfDirty();
|
||||
app.study = app.studies.find((item) => item.ct_number === ctNumber) || { ct_number: ctNumber };
|
||||
@@ -351,6 +386,7 @@ async function selectStudy(ctNumber) {
|
||||
try {
|
||||
const data = await json(`/api/studies/${encodeURIComponent(ctNumber)}/series`);
|
||||
app.study = data.study;
|
||||
applyStudyCompletion(data.study);
|
||||
setSeries(data.series || []);
|
||||
refreshStudyAnnotationSummary();
|
||||
renderStudies();
|
||||
|
||||
Reference in New Issue
Block a user