feat(embed): iframe 嵌入模式(去 chrome + 主题隔离 / hideJump / 登录用户隔离)

外部系统用 iframe 套用深链单智能体问答/多智能体会商时,三个按标签页(sessionStorage)
开关,由深链 URL 参数开启、跨登录跳转/刷新/页内导航存活,绝不跨标签污染正常系统页:

- embed=1(可带 theme=):去全局导航栏 + 侧边栏;按外部主题色强制明/暗,走
  next-themes forcedTheme(不写 localStorage),嵌入侧不调 setTheme/persistSidebarEnabled
- hideJump=1:隐藏深链底部「快捷跳转」栏 TaskJumpBar(底部「下一步」按钮 + 右侧悬浮菜单)
- 登录隔离:嵌入态鉴权/身份键(deerflow.auth/userInfo/login.*/tools_token 等)改走
  sessionStorage(core/auth/scoped-storage.ts 的 authStorage),iframe 登录用户与正常
  登录用户完全隔离、互不覆盖;token 读取统一过 getStoredAuth,改中心函数即全体生效;
  跨标签账号变更监听 AuthSyncWatcher 嵌入态禁用

嵌入会话在 main.tsx 渲染前同步启用(早于任何鉴权写入)。正常标签页 isXxx() 恒 false,
行为零变化。新增 core/embed/embed-session.ts、core/auth/scoped-storage.ts。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
fengxiangdebaoziandClaude Opus 4.8 committed 2026-06-19 12:02:36 +08:00
1 parent 2b58fe6c8b
commit 31f9838095
16 files changed
+337 -58

No files matched your search

@@ -4,6 +4,7 @@ import {
getKnowledgeIframeApiUrl,
getKnowledgeIframeSkin,
} from "@/core/strategy/external-links";
import { authStorageGet } from "@/core/auth/scoped-storage";
import { requestCrudService } from "@/service/request-axios-service";
import ExternalIframePage from "../common/ExternalIframePage";
@@ -18,7 +19,7 @@ const KnowledgeBaseResourceManagement: React.FC = () => {
const apiUrl = getKnowledgeIframeApiUrl();
if (!apiUrl) return;
const jsonStr = localStorage.getItem("userInfo");
const jsonStr = authStorageGet("userInfo");
if (!jsonStr) return;
try {
@@ -36,6 +36,7 @@ import {
type TaskBusiness,
} from "@/core/auth/task-buttons";
import { useTaskButtons } from "@/strategy-components/api/task-buttons";
import { isJumpBarHidden } from "@/core/embed/embed-session";
import { desensitize } from "@/lib/desensitize";
import { TaskPurposeDialog } from "@/strategy-components/components/task-components/TaskPurposePanel";
@@ -77,6 +78,9 @@ export function TaskJumpBar({
business === "xdfx" && ctxActionId && ctxActionId !== taskId ? ctxActionId : undefined;
if (jumpButtons.length === 0) return null;
// 深链 `hideJump=1`(外部 iframe 套用时):整条跳转栏隐藏——底部「下一步」等按钮 +
// 右侧悬浮菜单都不渲染。按标签页生效,不影响正常系统页(见 embed-session.ts)。
if (isJumpBarHidden()) return null;
const handleRun = (btn: (typeof jumpButtons)[number]) => {
if (btn.linkType === "purpose") {
@@ -1,10 +1,12 @@
/**
* 轻应用共享常量 + 运行时 URL 构造(管理页预览 / 列表页跳转 / iframe 宿主共用)。
*
* 登录参数运行时从 `localStorage.getItem("userInfo")`(JSON) 解析;主题参数用配置值。
* 登录参数运行时从 `userInfo`(JSON) 解析(经 authStorage:嵌入态 sessionStorage / 正常态
* localStorage,见 scoped-storage.ts);主题参数用配置值。
*/
import type { LightApp, LightAppRouteParam } from "@/strategy-components/api/light-apps";
import { authStorageGet } from "@/core/auth/scoped-storage";
/** iframe 可挂载的父菜单(取自 core/page-layout/sidebar-menu.ts 的现有菜单 id)。 */
export const MOUNT_OPTIONS: { label: string; value: string }[] = [
@@ -114,7 +116,7 @@ export function resolveThemeParamValue(
/** 读取并解析 localStorage 中的 userInfo。 */
export function readUserInfo(): Record<string, unknown> {
try {
const raw = localStorage.getItem("userInfo");
const raw = authStorageGet("userInfo");
if (!raw) return {};
const parsed = JSON.parse(raw);
return parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : {};