feat(asset-ai): simplify count answers and refine mobile conversation layout
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-23 18:35:31 +08:00
parent fd514177c6
commit 5be6240bbf
13 changed files with 251 additions and 58 deletions
+23 -30
View File
@@ -30,7 +30,6 @@ import {
} from "../../../shared/assets/assistant";
import { askAssetAssistant, AssistantRequestError } from "./client";
import { fetchAuthenticated } from "../../../auth/api-client";
import { DemandGaps } from "./DemandGaps";
import { ThinkingState } from "./ThinkingState";
import { CompoundResultView } from "./CompoundResultView";
import { BUSINESS_QUESTIONS, conversationTitle, findConversationResult, replaceAnalysisResult } from "./conversation-presentation";
@@ -90,6 +89,23 @@ export default function AssetAssistant({
close: () => void;
appearance: "light" | "dark";
}) {
const page = useRef<HTMLElement>(null);
useLayoutEffect(() => {
const viewport = window.visualViewport;
const updateViewport = () => {
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);
return () => {
viewport?.removeEventListener('resize', updateViewport);
viewport?.removeEventListener('scroll', updateViewport);
window.removeEventListener('resize', updateViewport);
};
}, []);
const [theme, setTheme] = useState(appearance);
const [turns, setTurns] = useState<Turn[]>([]);
const turnsRef = useRef(turns);
@@ -110,7 +126,6 @@ export default function AssetAssistant({
const [activeResult, setActiveResult] = useState<AssistantResult>();
const sessionRef = useRef<string | undefined>(undefined);
const sessions = useRef(new Map<string, string | null>());
const [showGaps, setShowGaps] = useState(false);
const nextId = useRef(0);
const composer = useRef<HTMLTextAreaElement>(null);
const scroller = useRef<HTMLDivElement>(null);
@@ -189,7 +204,6 @@ export default function AssetAssistant({
return () => controller.abort();
}, []);
const revealTurn = (id: number) => {
setShowGaps(false);
setExpandedTurns((old) => new Set(old).add(id));
autoFollow.current = null;
setViewedTurn(id);
@@ -232,7 +246,6 @@ export default function AssetAssistant({
action?: AssistantAction,
) => {
if (!message.trim() || abortRef.current) return;
setShowGaps(false);
setIndependent(false);
const inlineTurn = action && base?.resultId
? turnsRef.current.find(turn => !!findConversationResult([turn], base.resultId!))
@@ -344,7 +357,6 @@ export default function AssetAssistant({
).catch(() => {});
sessionRef.current = undefined;
setActiveResult(undefined);
setShowGaps(false);
setTurns([]);
setExpandedTurns(new Set());
setDraft("");
@@ -355,6 +367,7 @@ export default function AssetAssistant({
}, [subject]);
return (
<section
ref={page}
className={`aq-shell aq-page aq-${theme}`}
aria-label="资产 AI 问数"
>
@@ -388,10 +401,6 @@ export default function AssetAssistant({
返回资产总览
<ArrowUpRight size={14} />
</button>
<button className="aq-nav" onClick={() => setShowGaps(true)}>
<CircleHelp size={16} />
待完善需求
</button>
<div className="aq-side-label aq-history-label">
本次对话<span>{turns.length.toString().padStart(2, "0")}</span>
</div>
@@ -438,13 +447,6 @@ export default function AssetAssistant({
<span className="aq-header-subtitle">你的资产分析助手</span>
</div>
<div>
<button
className="aq-icon-button"
onClick={() => setShowGaps(!showGaps)}
aria-label="查看待完善需求"
>
<History size={17} />
</button>
<button
className="aq-icon-button aq-mobile-new"
onClick={reset}
@@ -509,9 +511,7 @@ export default function AssetAssistant({
onTouchMove={() => { autoFollow.current = null; readerRevision.current++; }}
onPointerDown={() => { autoFollow.current = null; readerRevision.current++; }}
onKeyDown={(event) => { if (["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(event.key)) { autoFollow.current = null; readerRevision.current++; } }}>
{showGaps ? (
<DemandGaps close={() => setShowGaps(false)} />
) : !turns.length ? (
{!turns.length ? (
<div className="aq-welcome">
<div className="aq-welcome-mark">
<Sparkles size={30} strokeWidth={1.3} />
@@ -519,15 +519,14 @@ export default function AssetAssistant({
<h2>关于资产,你想了解什么?</h2>
<p>
用一句话,发现数据里的答案。
<br className="aq-mobile-break" />{" "}
从全局统计,一路看到每一台车。
<span className="aq-welcome-detail"> 从全局统计,一路看到每一台车。</span>
</p>
<div className="aq-prompt-grid">
{PROMPTS.map((p) => (
<button key={p.title} onClick={() => void ask(p.text)}>
<div>
<p.icon size={18} />
<ArrowUpRight size={14} />
<p.icon size={18} aria-hidden="true" />
<ArrowUpRight size={14} aria-hidden="true" />
</div>
<strong>{p.title}</strong>
<span>{p.detail}</span>
@@ -711,13 +710,7 @@ export default function AssetAssistant({
}
}}
/>
) : (
<div className="aq-waiting">
<span />
<span />
<span />
</div>
)}
) : null}
</>
)}
</section>