From 6de77adb47003b9e5ad3e3421cab2e4851c3d64f Mon Sep 17 00:00:00 2001 From: shishengliang Date: Wed, 23 Sep 2026 18:49:26 +0800 Subject: [PATCH] fix(asset-ai): refine mobile viewport and operating query scope --- .../assets/assistant/AssetAssistant.tsx | 49 +++++++++++++++---- src/modules/assets/assistant/ResultView.tsx | 12 ++--- src/modules/assets/assistant/assistant.css | 20 ++++++++ .../routes/asset-assistant/experience.test.ts | 25 ++++++++++ .../routes/asset-assistant/generative.test.ts | 12 +++++ .../routes/asset-assistant/generative.ts | 9 +++- .../routes/asset-assistant/model.test.ts | 14 ++++++ src/server/routes/asset-assistant/model.ts | 2 +- src/server/routes/asset-assistant/planner.ts | 8 +-- src/server/routes/vehicles/model.test.ts | 11 +++++ src/server/routes/vehicles/model.ts | 6 ++- 11 files changed, 145 insertions(+), 23 deletions(-) diff --git a/src/modules/assets/assistant/AssetAssistant.tsx b/src/modules/assets/assistant/AssetAssistant.tsx index c13450a..f6546b9 100644 --- a/src/modules/assets/assistant/AssetAssistant.tsx +++ b/src/modules/assets/assistant/AssetAssistant.tsx @@ -92,18 +92,47 @@ export default function AssetAssistant({ const page = useRef(null); useLayoutEffect(() => { const viewport = window.visualViewport; + const mobile = window.matchMedia('(max-width: 767px)'); + let frame = 0; + let unlock: (() => void) | undefined; const updateViewport = () => { + frame = 0; + if (!mobile.matches || (viewport && viewport.scale !== 1)) return; page.current?.style.setProperty('--aq-viewport-height', `${viewport?.height ?? window.innerHeight}px`); page.current?.style.setProperty('--aq-viewport-top', `${viewport?.offsetTop ?? 0}px`); }; - updateViewport(); - viewport?.addEventListener('resize', updateViewport); - viewport?.addEventListener('scroll', updateViewport); - window.addEventListener('resize', updateViewport); + const scheduleViewport = () => { + if (!frame) frame = requestAnimationFrame(updateViewport); + }; + const syncMobile = () => { + unlock?.(); + unlock = undefined; + if (mobile.matches) { + const scrollY = window.scrollY; + const body = document.body; + const previous = body.style.top; + body.style.top = `${-scrollY}px`; + body.classList.add('aq-mobile-open'); + unlock = () => { + body.classList.remove('aq-mobile-open'); + body.style.top = previous; + window.scrollTo({ top: scrollY, behavior: 'instant' }); + }; + } + updateViewport(); + }; + syncMobile(); + mobile.addEventListener('change', syncMobile); + viewport?.addEventListener('resize', scheduleViewport); + viewport?.addEventListener('scroll', scheduleViewport); + window.addEventListener('resize', scheduleViewport); return () => { - viewport?.removeEventListener('resize', updateViewport); - viewport?.removeEventListener('scroll', updateViewport); - window.removeEventListener('resize', updateViewport); + cancelAnimationFrame(frame); + mobile.removeEventListener('change', syncMobile); + viewport?.removeEventListener('resize', scheduleViewport); + viewport?.removeEventListener('scroll', scheduleViewport); + window.removeEventListener('resize', scheduleViewport); + unlock?.(); }; }, []); const [theme, setTheme] = useState(appearance); @@ -214,7 +243,7 @@ export default function AssetAssistant({ setActiveResult(undefined); sessionRef.current = undefined; setIndependent(true); - composer.current?.focus(); + composer.current?.focus({ preventScroll: true }); }; useEffect( () => () => { @@ -360,7 +389,7 @@ export default function AssetAssistant({ setTurns([]); setExpandedTurns(new Set()); setDraft(""); - composer.current?.focus(); + composer.current?.focus({ preventScroll: true }); }; useEffect(() => { reset(); @@ -390,7 +419,7 @@ export default function AssetAssistant({ className="aq-nav-active" onClick={() => { scroller.current?.scrollTo({ top: 0 }); - composer.current?.focus(); + composer.current?.focus({ preventScroll: true }); }} > diff --git a/src/modules/assets/assistant/ResultView.tsx b/src/modules/assets/assistant/ResultView.tsx index 3bc78bb..dc266f0 100644 --- a/src/modules/assets/assistant/ResultView.tsx +++ b/src/modules/assets/assistant/ResultView.tsx @@ -799,9 +799,7 @@ function ResultViewContent({ "分组", "车辆数", "占比", - "运营率", - "异动", - "待交车", + ...(result.plan.category === "operating" ? [] : ["运营率", "异动", "待交车"]), "下钻", ].map((h) => ( {h} @@ -814,9 +812,11 @@ function ResultViewContent({ {g.name} {g.count} {g.share}% - {g.rate}% - {g.abnormal} - {g.pending} + {result.plan.category !== "operating" && <> + {g.rate}% + {g.abnormal} + {g.pending} + }