From 03f5ecdcaf4070e328821d8a5a33d036169e5644 Mon Sep 17 00:00:00 2001 From: Aisland Date: Wed, 2 Sep 2026 01:00:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(console):=20=E5=AA=92=E4=BD=93=E6=8B=96?= =?UTF-8?q?=E6=8B=BD=E6=94=B9=E6=A7=BD=E4=BD=8D=E5=88=B6=E2=80=94=E2=80=94?= =?UTF-8?q?=E9=A2=84=E8=AE=BE=E8=90=BD=E4=BD=8D+=E8=BE=B9=E7=95=8C?= =?UTF-8?q?=E6=AD=BB=E5=8C=BA(=C2=B112%=E8=A1=8C=E9=AB=98)=E9=98=B2?= =?UTF-8?q?=E4=B9=B1=E8=B7=B3=EF=BC=8C=E4=BB=85=E5=86=B3=E5=AE=9A=E6=80=A7?= =?UTF-8?q?=E8=B6=8A=E8=BF=87=E6=89=8D=E6=8F=90=E4=BA=A4=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E3=80=81=E5=85=B6=E4=BB=96=E8=A1=8CFLIP=E8=AE=A9=E4=BD=8D(260m?= =?UTF-8?q?s=E7=BC=93=E5=87=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_content/lib/client.js | 24 +++++++++++++++--------- 01_content/src/client/split.tsx | 28 +++++++++++++++++----------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/01_content/lib/client.js b/01_content/lib/client.js index ac1cdc4..52a7f07 100644 --- a/01_content/lib/client.js +++ b/01_content/lib/client.js @@ -18087,6 +18087,7 @@ function ConsolePane() { }; const dragRowRef = (0, import_react.useRef)(null); const dragFlipRef = (0, import_react.useRef)(null); + const lastTargetRef = (0, import_react.useRef)(-1); const [dragRowId, setDragRowId] = (0, import_react.useState)(null); (0, import_react.useLayoutEffect)(() => { const first = dragFlipRef.current; @@ -18099,7 +18100,7 @@ function ConsolePane() { const r = el.getBoundingClientRect(); const dx = f.x - r.left; const dy = f.y - r.top; - if (dx || dy) el.animate([{ transform: "translate(" + dx + "px," + dy + "px)" }, { transform: "none" }], { duration: 160, easing: "cubic-bezier(.22,.61,.36,1)" }); + if (dx || dy) el.animate([{ transform: "translate(" + dx + "px," + dy + "px)" }, { transform: "none" }], { duration: 260, easing: "cubic-bezier(.25,.6,.3,1)" }); }); }, [photoList]); const onHandleDown = (id, e) => { @@ -18107,29 +18108,34 @@ function ConsolePane() { e.preventDefault(); e.stopPropagation(); dragRowRef.current = id; + lastTargetRef.current = photoList.findIndex((x) => x.id === id); setDragRowId(id); const onMove = (ev) => { if (dragRowRef.current !== id) return; const rows = Array.from(document.querySelectorAll(".dsh-wt_photoRow")); + if (rows.length === 0) return; + const first = rows[0].getBoundingClientRect(); + const h = first.height; + const rel = (ev.clientY - first.top) / h; + let t = Math.max(0, Math.min(rows.length - 1, Math.floor(rel + 0.5))); + const frac = rel - Math.floor(rel); + if (Math.abs(frac - 0.5) < 0.12) t = lastTargetRef.current; + if (t === lastTargetRef.current) return; + const from = photoList.findIndex((x) => x.id === id); + if (from < 0) return; const rects = /* @__PURE__ */ new Map(); rows.forEach((el) => { const k = el.dataset.rid ?? ""; const r = el.getBoundingClientRect(); rects.set(k, { x: r.left, y: r.top }); }); - let target = 0; - for (let i = 0; i < rows.length; i++) { - const r = rows[i].getBoundingClientRect(); - if (ev.clientY > r.top + r.height / 2) target = i + 1; - } - const from = photoList.findIndex((x) => x.id === id); - if (from < 0) return; const next = [...photoList]; const moved = next.splice(from, 1)[0]; - const to = Math.max(0, Math.min(target > from ? target - 1 : target, next.length)); + const to = Math.max(0, Math.min(t, next.length)); next.splice(to, 0, moved); dragFlipRef.current = rects; setPhotoList(next); + lastTargetRef.current = t; }; const onUp = () => { dragRowRef.current = null; diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index f72321d..5ee04a0 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -1575,8 +1575,9 @@ function ConsolePane() { /** 抓手拖拽排序:按住抓手上下移动 → 行实时重排,松手持久化 */ const dragRowRef = useRef(null) const dragFlipRef = useRef | null>(null) + const lastTargetRef = useRef(-1) const [dragRowId, setDragRowId] = useState(null) - // FLIP:重排后旧位置 → 新位置的平滑滑动(160ms 缓动) + // FLIP:落位提交后,其他行从旧位置平滑让位(260ms 缓出) useLayoutEffect(() => { const first = dragFlipRef.current if (!first) return @@ -1588,7 +1589,7 @@ function ConsolePane() { const r = el.getBoundingClientRect() const dx = f.x - r.left const dy = f.y - r.top - if (dx || dy) el.animate([{ transform: 'translate(' + dx + 'px,' + dy + 'px)' }, { transform: 'none' }], { duration: 160, easing: 'cubic-bezier(.22,.61,.36,1)' }) + if (dx || dy) el.animate([{ transform: 'translate(' + dx + 'px,' + dy + 'px)' }, { transform: 'none' }], { duration: 260, easing: 'cubic-bezier(.25,.6,.3,1)' }) }) }, [photoList]) const onHandleDown = (id: string, e: { button: number; preventDefault: () => void; stopPropagation: () => void }) => { @@ -1596,26 +1597,31 @@ function ConsolePane() { e.preventDefault() e.stopPropagation() dragRowRef.current = id + lastTargetRef.current = photoList.findIndex((x) => x.id === id) setDragRowId(id) const onMove = (ev: PointerEvent) => { if (dragRowRef.current !== id) return const rows = Array.from(document.querySelectorAll('.dsh-wt_photoRow')) - // 收集当前(重排前)位置用于 FLIP - const rects = new Map() - rows.forEach((el) => { const k = el.dataset.rid ?? ''; const r = el.getBoundingClientRect(); rects.set(k, { x: r.left, y: r.top }) }) - let target = 0 - for (let i = 0; i < rows.length; i++) { - const r = rows[i].getBoundingClientRect() - if (ev.clientY > r.top + r.height / 2) target = i + 1 - } + if (rows.length === 0) return + // 槽位制:按固定行高算最近槽位;边界 ±0.12 行高为死区,未决定性越过前不切换 + const first = rows[0].getBoundingClientRect() + const h = first.height + const rel = (ev.clientY - first.top) / h + let t = Math.max(0, Math.min(rows.length - 1, Math.floor(rel + 0.5))) + const frac = rel - Math.floor(rel) + if (Math.abs(frac - 0.5) < 0.12) t = lastTargetRef.current + if (t === lastTargetRef.current) return const from = photoList.findIndex((x) => x.id === id) if (from < 0) return + const rects = new Map() + rows.forEach((el) => { const k = el.dataset.rid ?? ''; const r = el.getBoundingClientRect(); rects.set(k, { x: r.left, y: r.top }) }) const next = [...photoList] const moved = next.splice(from, 1)[0] - const to = Math.max(0, Math.min(target > from ? target - 1 : target, next.length)) + const to = Math.max(0, Math.min(t, next.length)) next.splice(to, 0, moved) dragFlipRef.current = rects setPhotoList(next) + lastTargetRef.current = t } const onUp = () => { dragRowRef.current = null