Add series count sorting

This commit is contained in:
Codex
2026-05-27 10:28:51 +08:00
parent ac75c37e3f
commit 45017fbdfd
4 changed files with 24 additions and 12 deletions

View File

@@ -42,7 +42,7 @@ uvicorn app:app --host 127.0.0.1 --port 8107
- 影像操作:支持鼠标滚轮缩放、拖拽平移、按钮缩放和复位。 - 影像操作:支持鼠标滚轮缩放、拖拽平移、按钮缩放和复位。
- 图像叠层:可显示/隐藏患者、检查、方向、张数、窗宽窗位和缩放信息。 - 图像叠层:可显示/隐藏患者、检查、方向、张数、窗宽窗位和缩放信息。
- DICOM 信息:查看患者、检查、序列、像素间距、切片间距等元数据。 - DICOM 信息:查看患者、检查、序列、像素间距、切片间距等元数据。
- 序列列表:默认按拍摄时间升序排序,可切换降序;少于 80 张且未标注部位的序列默认略过 - 序列列表:默认按拍摄时间升序排序,可切换时间升降序或张数升降序;略过序列固定在最下方,并在略过分组内继续按当前排序规则排列
- 序列标注:选择略过、平扫 CT、头颈部、胸部、上腹部、下腹部、盆腔点击后自动保存上腹部需继续选择动脉期、门静脉期或无法判别。 - 序列标注:选择略过、平扫 CT、头颈部、胸部、上腹部、下腹部、盆腔点击后自动保存上腹部需继续选择动脉期、门静脉期或无法判别。
- AI 识别:配置 Kimi 后,可把序列张数及轴位原始、矢状位重建、冠状位重建代表图像传入 AI自动给出部位、期相和备注建议。 - AI 识别:配置 Kimi 后,可把序列张数及轴位原始、矢状位重建、冠状位重建代表图像传入 AI自动给出部位、期相和备注建议。
- 设置:支持用户创建、角色权限展示、数据库状态和 AI 配置查看。 - 设置:支持用户创建、角色权限展示、数据库状态和 AI 配置查看。

View File

@@ -18,7 +18,7 @@ const app = {
saveTimer: null, saveTimer: null,
pendingImage: null, pendingImage: null,
drag: null, drag: null,
seriesSort: "asc", seriesSort: "timeAsc",
showOverlay: true, showOverlay: true,
}; };
@@ -173,8 +173,12 @@ function sortSeries(list) {
const skipA = a.annotation?.skipped ? 1 : 0; const skipA = a.annotation?.skipped ? 1 : 0;
const skipB = b.annotation?.skipped ? 1 : 0; const skipB = b.annotation?.skipped ? 1 : 0;
if (skipA !== skipB) return skipA - skipB; if (skipA !== skipB) return skipA - skipB;
const result = timeKey(a).localeCompare(timeKey(b)) || String(a.series_number || "").localeCompare(String(b.series_number || ""), undefined, { numeric: true }); const timeResult = timeKey(a).localeCompare(timeKey(b)) || String(a.series_number || "").localeCompare(String(b.series_number || ""), undefined, { numeric: true });
return app.seriesSort === "asc" ? result : -result; const countResult = Number(a.count || 0) - Number(b.count || 0) || timeResult;
if (app.seriesSort === "timeDesc") return -timeResult;
if (app.seriesSort === "countAsc") return countResult;
if (app.seriesSort === "countDesc") return -countResult;
return timeResult;
}); });
} }
@@ -762,8 +766,9 @@ function wireImageGestures() {
function setSort(direction) { function setSort(direction) {
app.seriesSort = direction; app.seriesSort = direction;
$("sortAsc").classList.toggle("active", direction === "asc"); document.querySelectorAll("[data-sort]").forEach((button) => {
$("sortDesc").classList.toggle("active", direction === "desc"); button.classList.toggle("active", button.dataset.sort === direction);
});
app.series = sortSeries(app.series); app.series = sortSeries(app.series);
renderSeries(); renderSeries();
if (app.activeSeries) { if (app.activeSeries) {
@@ -783,8 +788,9 @@ function wire() {
app.showOverlay = !app.showOverlay; app.showOverlay = !app.showOverlay;
updateOverlay(); updateOverlay();
}); });
$("sortAsc").addEventListener("click", () => setSort("asc")); document.querySelectorAll("[data-sort]").forEach((button) => {
$("sortDesc").addEventListener("click", () => setSort("desc")); button.addEventListener("click", () => setSort(button.dataset.sort));
});
$("studySearch").addEventListener("input", () => { $("studySearch").addEventListener("input", () => {
clearTimeout(app.searchTimer); clearTimeout(app.searchTimer);
app.searchTimer = setTimeout(loadStudies, 250); app.searchTimer = setTimeout(loadStudies, 250);

View File

@@ -54,8 +54,10 @@
<div class="pane-head"> <div class="pane-head">
<h2>序列</h2> <h2>序列</h2>
<div class="series-head-tools"> <div class="series-head-tools">
<button id="sortAsc" class="sort-btn active">时间 ↑</button> <button id="sortTimeAsc" class="sort-btn active" data-sort="timeAsc">时间 ↑</button>
<button id="sortDesc" class="sort-btn">时间 ↓</button> <button id="sortTimeDesc" class="sort-btn" data-sort="timeDesc">时间 ↓</button>
<button id="sortCountAsc" class="sort-btn" data-sort="countAsc">张数 ↑</button>
<button id="sortCountDesc" class="sort-btn" data-sort="countDesc">张数 ↓</button>
<span id="seriesCount">0</span> <span id="seriesCount">0</span>
</div> </div>
</div> </div>

View File

@@ -287,17 +287,21 @@ button:disabled {
.series-head-tools { .series-head-tools {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 6px; gap: 6px;
max-width: 330px;
} }
.sort-btn { .sort-btn {
height: 26px; height: 26px;
padding: 0 8px; min-width: 56px;
padding: 0 7px;
border: 1px solid var(--stroke); border: 1px solid var(--stroke);
border-radius: 7px; border-radius: 7px;
background: #0b0f16; background: #0b0f16;
color: var(--muted); color: var(--muted);
font-size: 12px; font-size: 11px;
} }
.sort-btn.active { .sort-btn.active {