From c268348e29ab1925e9b994953bd2f0153c2f0af8 Mon Sep 17 00:00:00 2001 From: xuhd Date: Fri, 12 Jun 2026 10:14:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(studio):=20=E4=B8=8A=E4=BC=A0=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E7=94=A8=E6=88=91=E7=9A=84=E7=AC=94=E8=AE=B0=20token?= =?UTF-8?q?=20+=20=E5=85=B3=E9=97=AD=E4=B8=8A=E4=BC=A0=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E6=9D=A5=E6=BA=90=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - document-upload-popup: 新增 getNotebookToken(),上传/导入到笔记后端 (source/import、documents/fileupload)改用「我的笔记」token; 其余请求由调用方在 init.headers 自带 Authorization,不再注入本系统 token - query-client-provider: 导出 queryClient 单例,便于非 hook 处读取缓存的 token - network-actor: consumerUrl 改为读 VITE_AIPI_CONSUMER_URL;修复 source/import headers 语法并去掉重复 token - StudioNotebookDetailPage: DocumentUploadDialogProvider 增加 onClose, 关闭上传弹窗时刷新来源列表与 source_count Co-Authored-By: Claude Opus 4.8 (1M context) --- .../assistant-ui/document-upload-popup.tsx | 19 +++++++++++++++---- .../components/assistant-ui/network-actor.tsx | 15 +++------------ .../src/components/query-client-provider.tsx | 2 +- .../src/pages/StudioNotebookDetailPage.tsx | 5 +++++ 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/frontend-web/src/components/assistant-ui/document-upload-popup.tsx b/frontend-web/src/components/assistant-ui/document-upload-popup.tsx index 363866e6..240b93f5 100644 --- a/frontend-web/src/components/assistant-ui/document-upload-popup.tsx +++ b/frontend-web/src/components/assistant-ui/document-upload-popup.tsx @@ -26,13 +26,24 @@ import { import { Button } from "@/components/ui/button"; import { toast } from "sonner"; import { getStoredAuth } from "@/core/auth"; +import { queryClient } from "@/components/query-client-provider"; import Empty from "./empty"; import { NetworkActor } from "./network-actor"; // ── 适配层 ───────────────────────────────────────────────── -function authenticatedFetch(url: string, init?: RequestInit) { - const token = getStoredAuth()?.access_token; +// 本组件只对接「我的笔记/空间」后端,用不到本系统(DeerFlow)token。 +// notebook token 由 fetchStudioToken(getTokenByEmail) 获取,缓存在 react-query +// 的 ["studio","token",email] 下(见 core/studio/hooks)。 +function getNotebookToken(): string | undefined { + const email = getStoredAuth()?.email ?? ""; + return queryClient.getQueryData(["studio", "token", email]); +} + +// 上传到笔记后端时传 useNotebookToken=true 注入我的笔记 token; +// 其余请求不注入本系统 token,调用方自行在 init.headers 里带 Authorization。 +export function authenticatedFetch(url: string, init?: RequestInit, useNotebookToken = false): Promise { + const token = useNotebookToken ? getNotebookToken() : undefined; return fetch(url, { ...init, headers: { @@ -334,7 +345,7 @@ const DocumentUploadPopupContent: FC<{ if (!files.length) return; setUploading(true); try { - const token = getStoredAuth()?.access_token ?? ""; + const token = getNotebookToken() ?? ""; const formData = new FormData(); formData.append("search_space_id", searchSpaceId); for (const file of files) { @@ -389,7 +400,7 @@ const DocumentUploadPopupContent: FC<{ search_space_id: Number(searchSpaceId), source_list: dataList, }), - }); + }, true); if (response.ok) { const data = await response.json() as { imported_count?: number }; toast.success(`成功导入 ${data.imported_count || dataList.length} 个来源`); diff --git a/frontend-web/src/components/assistant-ui/network-actor.tsx b/frontend-web/src/components/assistant-ui/network-actor.tsx index a4848248..9be9cfcd 100644 --- a/frontend-web/src/components/assistant-ui/network-actor.tsx +++ b/frontend-web/src/components/assistant-ui/network-actor.tsx @@ -10,17 +10,8 @@ import { Loader2, Plus, Search, Trash2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { toast } from "sonner"; import { getStoredAuth } from "@/core/auth"; +import { authenticatedFetch } from "@/components/assistant-ui/document-upload-popup"; -function authenticatedFetch(url: string, init?: RequestInit) { - const token = getStoredAuth()?.access_token; - return fetch(url, { - ...init, - headers: { - ...(init?.headers ?? {}), - ...(token ? { Authorization: `Bearer ${token}` } : {}), - }, - }); -} interface NetworkActorProps { inputValue: string; @@ -195,7 +186,7 @@ export function NetworkActor({ inputValue, searchSpaceId, onSuccess }: NetworkAc const [actorCount, setActorCount] = useState(0); const [directionType, setDirectionType] = useState('TW'); const directionValue = useRef('TW'); - const consumerUrl = 'http://ch1.b.uat.4.cn/consumer'; + const consumerUrl = import.meta.env.VITE_AIPI_CONSUMER_URL || 'https://ch1.b.uat.4.cn/consumer'; const backendUrl = typeof window !== 'undefined' ? (import.meta.env.VITE_BACKEND_BASE_URL || 'http://localhost:8001') : 'http://localhost:8001'; @@ -395,7 +386,7 @@ export function NetworkActor({ inputValue, searchSpaceId, onSuccess }: NetworkAc search_space_id: Number(searchSpaceId), source_list: dataList, }), - }); + }, true); if (response.ok) { const data = await response.json(); toast.success(`成功导入 ${data.imported_count || dataList.length} 个来源`); diff --git a/frontend-web/src/components/query-client-provider.tsx b/frontend-web/src/components/query-client-provider.tsx index 99745f9f..cf130f0d 100644 --- a/frontend-web/src/components/query-client-provider.tsx +++ b/frontend-web/src/components/query-client-provider.tsx @@ -5,7 +5,7 @@ import { QueryClientProvider as TanStackQueryClientProvider, } from "@tanstack/react-query"; -const queryClient = new QueryClient(); +export const queryClient = new QueryClient(); export function QueryClientProvider({ children, diff --git a/frontend-web/src/pages/StudioNotebookDetailPage.tsx b/frontend-web/src/pages/StudioNotebookDetailPage.tsx index d2fad8a5..ed841f52 100644 --- a/frontend-web/src/pages/StudioNotebookDetailPage.tsx +++ b/frontend-web/src/pages/StudioNotebookDetailPage.tsx @@ -455,6 +455,11 @@ export default function StudioNotebookDetailPage() { return ( { + // 关闭上传弹窗时刷新来源列表与 source_count(覆盖文件上传 / A·B·Y 导入等所有路径) + void queryClient.invalidateQueries({ queryKey: ["studio", "sources"] }); + void queryClient.invalidateQueries({ queryKey: ["studio", "notebooks", studioToken] }); + }} onUploadSuccess={() => { void queryClient.invalidateQueries({ queryKey: ["studio", "sources"] }); void queryClient.invalidateQueries({ queryKey: ["studio", "notebooks", studioToken] });