代码提交

This commit is contained in:
董宏凯 committed 2026-07-24 11:24:11 +08:00
1 parent 28bf1ac7b2
commit 91ba47bf47
4 files changed
+55 -21

No files matched your search

+6 -1
View File
@@ -101,6 +101,11 @@ export default function ChatPage() {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();
// `chatMode=full` is used by an embedded standard chat. It intentionally
// overrides the user's compact-layout preference for this route only, so
// the page keeps the full landing composition and its agent/history sidebar.
const fullChatMode =
searchParams.get("chatMode")?.trim().toLowerCase() === "full";
const { open: historySidebarOpen, toggleSidebar: toggleHistorySidebar } =
useSidebar();
const { t } = useI18n();
@@ -452,7 +457,7 @@ export default function ChatPage() {
// 主题底图(workspace-chat-bg)不生效。非紧凑(嵌入/standalone)保持原样。
const layoutMode = effectiveLayoutMode;
const chromeByPreference =
layoutMode === "full"
fullChatMode || layoutMode === "full"
? true
: layoutMode === "compact"
? false
+21 -5
View File
@@ -69,6 +69,7 @@ const DEFAULT_USERNAME = 'guest';
const IFRAME_LOGIN_SOURCE = 'iframe';
const DEFAULT_REDIRECT_PATH = '/page/workspace/chats/new';
const IFRAME_REDIRECT_PATH = '/page/workspace/chats_iframe/new';
const FULL_CHAT_MODE = 'full';
type LoginStatus = 'loading' | 'success' | 'error';
@@ -89,13 +90,28 @@ export default function LoginPage() {
() => readEmbedParam(searchParams.toString()) === 'on',
[searchParams],
);
const redirectPath = useMemo(
() =>
searchParams.get('from') === IFRAME_LOGIN_SOURCE
? IFRAME_REDIRECT_PATH
: DEFAULT_REDIRECT_PATH,
// External consumers may still send `from=iframe` for the legacy protocol
// chat. `chatMode=full` is an explicit escape hatch: always use the regular
// full ChatPage instead, which is the route expected by ordinary iframe
// nesting and browser deep links.
const fullChatRequested = useMemo(
() => searchParams.get('chatMode')?.trim().toLowerCase() === FULL_CHAT_MODE,
[searchParams],
);
const redirectPath = useMemo(
() => {
// Keep the mode on the destination URL so PageRoutes can retain the
// full chat workspace sidebar while hideChrome hides only the global
// application chrome.
if (fullChatRequested) {
return `${DEFAULT_REDIRECT_PATH}?chatMode=${FULL_CHAT_MODE}`;
}
return searchParams.get('from') === IFRAME_LOGIN_SOURCE
? IFRAME_REDIRECT_PATH
: DEFAULT_REDIRECT_PATH;
},
[fullChatRequested, searchParams],
);
const resolvedUsername = useMemo(() => {
const raw = username?.trim();
return raw && raw.length > 0 ? raw : DEFAULT_USERNAME;
+21 -3
View File
@@ -69,6 +69,19 @@ function PageLayout() {
() => isHideChromeActive() || readHideChromeParam(location.search) === "on",
[location.pathname, location.search],
);
// `chatMode=full` is the embed-friendly standard chat view: hide the global
// Header/PageSidebar when `hideChrome=1`, but keep WorkspaceSidebar so users
// can still pick an agent and access their common agents/history.
const fullChatMode = useMemo(() => {
const mode = new URLSearchParams(location.search)
.get("chatMode")
?.trim()
.toLowerCase();
return (
mode === "full" &&
location.pathname.startsWith("/page/workspace/chats/")
);
}, [location.pathname, location.search]);
// 「大屏绘制」独立页(/page/strategy/dashboard-agent)本就是「带导航栏 + 侧边栏」的独立页,
// 但它常被深链「上一步」从去 chrome 的工作区/新标签打开——那里 chromeByPreference 可能为 false
// (界面模式非全量、或会话级 sidebar 未置位),导致整页没有顶栏/侧栏。故对该路由**强制全局 chrome**
@@ -125,12 +138,17 @@ function PageLayout() {
<WorkspaceRoutes
pageSidebarCollapsed={collapsed}
pageSidebarHidden={!pageSidebarAllowed}
workspaceSidebarHidden={hideChromeActive}
workspaceSidebarHidden={hideChromeActive && !fullChatMode}
headerHidden={!pageSidebarAllowed}
compactWorkspaceSidebar={pageSidebarAllowed}
// Full-chat embedding has no global PageSidebar, but it
// still needs the full GeneralQaSidebar (common agents and
// conversation history) inside the workspace.
compactWorkspaceSidebar={pageSidebarAllowed || fullChatMode}
compactActionsHidden={hideChromeActive}
pageSidebarDark={isDark}
forceWorkspaceSidebarCollapsed={forceCollapsedSidebar}
forceWorkspaceSidebarCollapsed={
forceCollapsedSidebar && !fullChatMode
}
/>
}
/>
+7 -12
View File
@@ -72,14 +72,6 @@ function NewAgentPageWithKey() {
return <NewAgentPage key={thread_id} />;
}
function isInIframe(): boolean {
try {
return window.self !== window.top;
} catch {
return true;
}
}
function shouldShowCompactTopActions(pathname: string): boolean {
return (
pathname === '/page/workspace/agents' ||
@@ -246,10 +238,13 @@ function NewChatEntryRoute({
forceWorkspaceSidebarCollapsed: boolean;
};
}) {
if (isInIframe()) {
return <Navigate to="/page/workspace/chats_iframe/new" replace />;
}
// Do not infer the chat experience from window.self !== window.top here.
// A generic `/chats/new` deep link must render the same standard chat both
// top-level and inside an iframe. The dedicated iframe protocol page remains
// available only through its explicit `/chats_iframe/...` route (LoginPage
// selects it for `from=iframe`). Otherwise a normal deep link was silently
// redirected to IframeChatPage, whose new-thread state intentionally has no
// manually selected agent and therefore stopped at "选择 Agent".
return (
<WorkspaceLayout {...layoutProps} defaultHistorySidebarOpen>
<ChatRuntime>