diff --git a/PACS_DICOM处理/数据处理网页端/app.py b/PACS_DICOM处理/数据处理网页端/app.py index 45abf8f..51fde37 100644 --- a/PACS_DICOM处理/数据处理网页端/app.py +++ b/PACS_DICOM处理/数据处理网页端/app.py @@ -350,7 +350,7 @@ def studies(_: str = Depends(require_auth), q: str = "", limit: int = 200) -> li SELECT ct_number, batch_name, target_folder_name, source_patient_name, patient_name_dicom, patient_id, study_date, study_time, modality, dicom_file_count, - processed_path, needs_ct_number_fix, status + series_count, processed_path, needs_ct_number_fix, status FROM public.{PGTABLE} {where} ORDER BY study_date DESC NULLS LAST, study_time DESC NULLS LAST, ct_number @@ -361,14 +361,20 @@ def studies(_: str = Depends(require_auth), q: str = "", limit: int = 200) -> li """ SELECT ct_number, count(*)::int AS annotated_series FROM public.pacs_dicom_series_annotations - WHERE skipped IS NOT TRUE AND jsonb_array_length(body_parts) > 0 + WHERE skipped IS TRUE + OR jsonb_array_length(body_parts) > 0 + OR plain_ct IS TRUE + OR NULLIF(notes, '') IS NOT NULL + OR ai_result IS NOT NULL GROUP BY ct_number """, timeout=8, ) annotation_map = {row["ct_number"]: row["annotated_series"] for row in annotations} for row in rows: - row["annotated_series"] = annotation_map.get(row["ct_number"], 0) + total_series = int(row.get("series_count") or 0) + row["annotated_series"] = min(total_series, int(annotation_map.get(row["ct_number"], 0))) + row["unannotated_series"] = max(0, total_series - int(row["annotated_series"])) return rows diff --git a/PACS_DICOM处理/数据处理网页端/static/app.js b/PACS_DICOM处理/数据处理网页端/static/app.js index 0c079fc..d3f340f 100644 --- a/PACS_DICOM处理/数据处理网页端/static/app.js +++ b/PACS_DICOM处理/数据处理网页端/static/app.js @@ -191,6 +191,25 @@ function setSeries(list) { renderSeries(); } +function isSeriesAnnotated(series) { + const annotation = series.annotation || {}; + return Boolean(annotation.skipped || annotation.plain_ct || asList(annotation.body_parts).length || annotation.notes || annotation.ai_model); +} + +function refreshStudyAnnotationSummary() { + if (!app.study || !app.series.length) return; + const annotated = app.series.filter(isSeriesAnnotated).length; + const total = app.series.length; + const summary = { + annotated_series: annotated, + unannotated_series: Math.max(0, total - annotated), + series_count: total, + }; + Object.assign(app.study, summary); + const study = app.studies.find((item) => item.ct_number === app.study.ct_number); + if (study) Object.assign(study, summary); +} + async function loadStudies() { const q = encodeURIComponent($("studySearch").value.trim()); app.studies = await json(`/api/studies?q=${q}&limit=500`); @@ -211,7 +230,7 @@ function renderStudies() { ${escapeHtml(study.ct_number)} ${escapeHtml(name)} · ${escapeHtml(study.patient_id || "无ID")} ${escapeHtml(fmtDate(study.study_date))} ${escapeHtml(fmtTime(study.study_time))} · ${Number(study.dicom_file_count || 0)} 张 - ${Number(study.annotated_series || 0)} 个序列已标注 + ${Number(study.annotated_series || 0)} 个序列已标注,${Number(study.unannotated_series || 0)} 个序列未标注 `; button.onclick = () => selectStudy(study.ct_number); list.appendChild(button); @@ -233,6 +252,8 @@ async function selectStudy(ctNumber) { const data = await json(`/api/studies/${encodeURIComponent(ctNumber)}/series`); app.study = data.study; setSeries(data.series || []); + refreshStudyAnnotationSummary(); + renderStudies(); if (app.series.length) selectSeries(app.series[0].series_uid); } catch (err) { $("seriesGrid").innerHTML = `
${escapeHtml(err.message)}
`; @@ -509,7 +530,9 @@ function updateLocalAnnotation(annotation) { const index = app.series.findIndex((item) => item.series_uid === app.activeSeries.series_uid); if (index >= 0) app.series[index].annotation = normalized; app.series = sortSeries(app.series); + refreshStudyAnnotationSummary(); renderSeries(); + renderStudies(); applyAnnotationControls(); }