feat:前端修改(最后一次)

This commit is contained in:
2026-09-14 20:58:47 +08:00
parent d9c2c5e207
commit 0835335978
6 changed files with 395 additions and 90 deletions
@@ -58,7 +58,8 @@ export function AssistantLauncher() {
const [open, setOpen] = useState(false);
const [tab, setTab] = useState<"chat" | "drafts">("chat");
const [sessionId, setSessionId] = useState(() => newSessionId());
/* 会话在「打开抽屉」时才建立(见 openAssistant),关闭时丢弃,不在挂载时就占用上下文 */
const [sessionId, setSessionId] = useState<string | null>(null);
const [customers, setCustomers] = useState<Customer[]>([]);
const [customerId, setCustomerId] = useState<number | null>(null);
const [messages, setMessages] = useState<ChatMessage[]>([]);
@@ -87,7 +88,7 @@ export function AssistantLauncher() {
return () => clearInterval(timer);
}, [streaming]);
const sessionTag = useMemo(() => sessionId.slice(-6), [sessionId]);
const sessionTag = useMemo(() => (sessionId ? sessionId.slice(-6) : "--------"), [sessionId]);
/* 客户列表只用于会话上下文选择,失败不阻断助手 */
useEffect(() => {
@@ -101,8 +102,18 @@ export function AssistantLauncher() {
})();
}, []);
/* 会话 ID 变化时恢复该会话的历史;新会话为空属正常,不报错。 */
/*
* 会话握手:打开抽屉(sessionId 就绪)后拉一次该会话的记录。
* 投顾 Agent 没有独立的 session/create,后端按 (advisor_id, session_id) 惰性建立上下文,
* 所以这个请求就是「打开助手时发出的会话请求」;关闭抽屉会把 sessionId 置空、丢弃上下文。
*/
useEffect(() => {
if (!sessionId) {
setMessages([]);
setHistoryError(null);
setHistoryLoading(false);
return;
}
let alive = true;
void (async () => {
setHistoryLoading(true);
@@ -182,7 +193,7 @@ export function AssistantLauncher() {
const result = await assistantApi.chatOnce(
{
query,
session_id: sessionId,
session_id: sessionId ?? undefined,
scope: customerId ? "customer" : "advisor",
customer_id: customerId,
},
@@ -241,7 +252,7 @@ export function AssistantLauncher() {
setStreaming(true);
try {
if (tool === "data-query") {
const result = await assistantApi.dataQuery({ query, session_id: sessionId });
const result = await assistantApi.dataQuery({ query, session_id: sessionId ?? undefined });
pushPair(query, result.answer ?? result.summary ?? "查询完成,无文本摘要。", "data_query");
} else if (tool === "fund-analysis") {
const result = await assistantApi.fundAnalysis(query);
@@ -272,7 +283,30 @@ export function AssistantLauncher() {
[customerId, input, loadDrafts, pushPair, sessionId, toast]
);
/** 结束会话:中止生成、清空上下文并启用新的 session_id。 */
/**
* 打开抽屉 = 建立会话。
* 投顾 Agent 后端只有 chat/stream 与 session/{id}/history,没有独立的 session/create,
* 所以这里生成会话键,由上面的 useEffect 调 history 完成握手(后端按需建立上下文)。
*/
const openAssistant = useCallback(() => {
setOpen(true);
setSessionId((current) => current ?? newSessionId());
}, []);
/**
* 关闭抽屉 = 结束会话:中止生成、清空消息并丢弃上下文。
* 投顾侧后端未提供 session/end,因此结束只能在前端完成(下次打开是新的 session_id)。
*/
const closeAssistant = useCallback(() => {
abortRef.current?.abort();
setOpen(false);
setMessages([]);
setInput("");
setStreaming(false);
setSessionId(null);
}, []);
/** 抽屉内「结束会话」:不等关闭,立即换一个全新会话并重新握手。 */
const endSession = useCallback(() => {
abortRef.current?.abort();
setMessages([]);
@@ -328,7 +362,7 @@ export function AssistantLauncher() {
<>
{!open && (
<button
onClick={() => setOpen(true)}
onClick={openAssistant}
aria-label="打开投顾助手"
className="fixed bottom-6 right-6 z-40 flex h-14 w-14 items-center justify-center rounded-full bg-indigo-600 text-white shadow-lg shadow-indigo-600/30 transition-transform hover:scale-105 hover:bg-indigo-700"
>
@@ -345,7 +379,7 @@ export function AssistantLauncher() {
<>
<div
className="fixed inset-0 z-40 bg-slate-900/10"
onClick={() => setOpen(false)}
onClick={closeAssistant}
aria-hidden
/>
<aside className="fixed inset-y-0 right-0 z-50 flex w-full max-w-[560px] flex-col bg-white shadow-2xl">
@@ -370,7 +404,7 @@ export function AssistantLauncher() {
结束会话
</Button>
<button
onClick={() => setOpen(false)}
onClick={closeAssistant}
aria-label="收起助手"
className="rounded-lg p-2 text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-600"
>
@@ -414,7 +448,7 @@ export function AssistantLauncher() {
<>
<div ref={scrollRef} className="flex-1 space-y-4 overflow-y-auto px-5 py-4">
{historyLoading && messages.length === 0 && (
<p className="py-8 text-center text-sm text-slate-400">正在恢复会话...</p>
<p className="py-8 text-center text-sm text-slate-400">正在建立会话...</p>
)}
{historyError && (
<p className="rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600">{historyError}</p>