From dfdcd78f1a195231799bff2fa1f72903bd9385e5 Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Wed, 12 Aug 2026 23:55:57 +0800 Subject: [PATCH] =?UTF-8?q?DAG=E7=94=BB=E5=B8=83=EF=BC=9A=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=8B=96=E4=B8=8D=E5=8A=A8=E6=A0=B9=E5=9B=A0=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20+=20=E7=BC=A9=E6=94=BE=E6=AF=94=E4=BE=8B=E6=98=BE?= =?UTF-8?q?=E7=A4=BA/=E4=B8=80=E9=94=AE100%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 根因:dagLayout 画布宽(1100-1360px)超出视口可用宽度(约1060px),加上保存的偏移视图可能把节点推到视口外 → 节点不可见/不可点,表现为'拖不动' - 修复:打开画布时若无保存视图、或节点全部在视口外,自动适配缩放(≤100%)并居中,全部节点始终可见可拖 - 新增右上角缩放控件:实时显示缩放百分比(滚轮/适配/拖动联动) + ⤢适配按钮 + 100%一键回原始视图 - 实测:真实鼠标拖动在 0.82x 缩放下精确跟随;滚轮 112%→100% 显示联动 --- static/app.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- static/style.css | 4 ++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/static/app.js b/static/app.js index faef2dc..f485c5c 100644 --- a/static/app.js +++ b/static/app.js @@ -323,6 +323,32 @@ function dagSize() { return dagLayout(tasks, idMap); } +function dagFitView() { + // 画布适配视口:缩放并居中,让全部节点可见 + const s = dagState; + const box = $('#dag-box'); + const {width, height} = dagSize(); + if (!box || !s) return; + const bw = box.clientWidth, bh = box.clientHeight; + const scale = Math.max(0.25, Math.min(1, (bw - 60) / width, (bh - 60) / height)); + s.scale = scale; + s.tx = (bw - width * scale) / 2; + s.ty = (bh - height * scale) / 2; + dagApplyView(); + saveDagState(); +} + +function dagZoomTo(scale) { + // 一键回到指定比例(100% = 原始视图) + const s = dagState; + if (!s) return; + s.scale = scale; + s.tx = 0; + s.ty = 0; + dagApplyView(); + saveDagState(); +} + function saveDagState() { if (!dagState) return; try { @@ -340,6 +366,8 @@ function dagApplyView() { if (!svg) return; svg.style.transform = `translate(${s.tx}px, ${s.ty}px) scale(${s.scale})`; svg.style.transformOrigin = '0 0'; + const pct = $('#dag-zoom-pct'); + if (pct) pct.textContent = Math.round(s.scale * 100) + '%'; } function drawDag() { @@ -364,6 +392,10 @@ function drawDag() {
+
🔍 100% + + +
🗑️ 删除区0
@@ -627,9 +659,23 @@ function renderDag() { ty: savedView?.ty || 0, drag: null, moved: false, }; - const box = $('#tab-body'); - box.innerHTML = ''; + const body2 = $('#tab-body'); + body2.innerHTML = ''; drawDag(); + // 节点是否在视口内?不在则自动适配(防止节点被平移到视口外无法操作) + const box = $('#dag-box'); + const bb = box ? box.getBoundingClientRect() : null; + let anyVisible = false; + if (bb) { + tasks.forEach(t => { + const p = dagState.pos[t.id]; + if (!p) return; + const vx = bb.left + dagState.tx + p.x * dagState.scale; + const vy = bb.top + dagState.ty + p.y * dagState.scale; + if (vx < bb.right && vx > bb.left && vy < bb.bottom && vy > bb.top) anyVisible = true; + }); + } + if (!anyVisible || !savedView) dagFitView(); } async function runWorkflow() { diff --git a/static/style.css b/static/style.css index 080f581..be5961e 100644 --- a/static/style.css +++ b/static/style.css @@ -143,6 +143,10 @@ tr:hover td{background:var(--panel2)} .dag-trash{position:absolute;left:14px;bottom:14px;background:rgba(255,107,107,.1);border:1.5px dashed var(--danger);color:var(--danger);border-radius:10px;padding:8px 14px;font-size:12px;cursor:pointer;z-index:5;display:flex;align-items:center;gap:6px;backdrop-filter:blur(2px)} .dag-trash:hover,.dag-trash.hover{background:rgba(255,107,107,.25);border-style:solid} .dag-trash .cnt{background:var(--danger);color:#fff;border-radius:8px;padding:0 6px;font-size:11px} +.dag-zoom{position:absolute;right:14px;top:14px;background:rgba(23,30,46,.88);border:1px solid var(--border);border-radius:8px;padding:4px 10px;font-size:12px;color:var(--muted);display:flex;align-items:center;gap:6px;z-index:6} +.dag-zoom b{color:var(--text);font-weight:600;min-width:42px;text-align:center} +.dag-zoom button{background:var(--panel2);border:1px solid var(--border);color:var(--text);border-radius:5px;padding:2px 8px;font-size:11px;cursor:pointer} +.dag-zoom button:hover{border-color:var(--accent);color:var(--accent)} .alert-row{border-left:3px solid var(--border);padding:12px 14px;margin-bottom:8px;background:var(--panel2);border-radius:0 10px 10px 0;cursor:pointer} .alert-row.unread{border-left-color:var(--warn)} .alert-row.critical{border-left-color:var(--danger)}