From 00d6bd85955d3b13b9c26341bc59c697fdf707b4 Mon Sep 17 00:00:00 2001 From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com> Date: Fri, 12 Jun 2026 21:38:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BB=E9=A2=98=E8=89=B2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend-web/src/pages/LightAppIframeView.tsx | 3 +- .../src/pages/LightAppManagementPage.tsx | 143 +++++++++++------- .../src/strategy-components/api/light-apps.ts | 4 +- .../src/strategy-components/lib/light-app.ts | 68 ++++++++- 4 files changed, 157 insertions(+), 61 deletions(-) diff --git a/frontend-web/src/pages/LightAppIframeView.tsx b/frontend-web/src/pages/LightAppIframeView.tsx index 02bd5cbb..c4ce4237 100644 --- a/frontend-web/src/pages/LightAppIframeView.tsx +++ b/frontend-web/src/pages/LightAppIframeView.tsx @@ -17,7 +17,8 @@ export default function LightAppIframeView() { const isDark = theme === "dark"; const { data: app, isLoading, error } = useLightApp(appId); - const src = useMemo(() => (app ? buildLightAppUrl(app) : ""), [app]); + // 依赖 theme:切换主题色时重建 src,把对应主题色重新传给被嵌套应用。 + const src = useMemo(() => (app ? buildLightAppUrl(app) : ""), [app, theme]); const centerClass = `flex h-full w-full items-center justify-center text-sm ${ isDark ? "text-slate-400" : "text-slate-500" diff --git a/frontend-web/src/pages/LightAppManagementPage.tsx b/frontend-web/src/pages/LightAppManagementPage.tsx index 1b54131a..bab529e4 100644 --- a/frontend-web/src/pages/LightAppManagementPage.tsx +++ b/frontend-web/src/pages/LightAppManagementPage.tsx @@ -23,9 +23,12 @@ import { type LightAppType, } from "@/strategy-components/api/light-apps"; import { + APP_THEME_COLORS, LOGIN_SOURCE_OPTIONS, MOUNT_OPTIONS, mountLabel, + parseThemeMap, + stringifyThemeMap, } from "@/strategy-components/lib/light-app"; interface FormState { @@ -53,7 +56,7 @@ const newParam = (): LightAppRouteParam => ({ paramType: "login", source: "accessToken", customValue: "", - themeValue: "dark-blue", + themeValue: "red=red;blue=blue;dark-blue=dark-blue", }); function formFromApp(app: LightApp): FormState { @@ -69,7 +72,7 @@ function formFromApp(app: LightApp): FormState { paramType: p.paramType, source: p.source ?? "accessToken", customValue: p.customValue ?? "", - themeValue: p.themeValue ?? "dark-blue", + themeValue: p.themeValue ?? "", })), }; } @@ -512,10 +515,12 @@ export default function LightAppManagementPage() {
路由参数 - + > + +
- + {/* 主题参数:逐主题色配置传给目标应用的值(左=系统主题色,右=目标应用值,可改) */} + {p.paramType === "theme" && ( +
+

+ 各系统主题色跳转/嵌套时传给该应用的值(默认同名,可按对方命名修改) +

+ {APP_THEME_COLORS.map((c) => ( +
+ + + {c.label} + + + {c.key} = + + + patchParam(idx, { + themeValue: stringifyThemeMap({ + ...themeMap, + [c.key]: e.target.value, + }), + }) + } + placeholder={c.key} + className="h-7 flex-1 rounded-[2px] border border-[#DBDBDB] bg-white px-2 font-mono text-[12px] focus:border-[#F5222D] focus:outline-none focus:ring-px focus:ring-[#F5222D]" + /> +
+ ))} +
+ )} - ))} + ); + })} ) : (
@@ -669,6 +707,7 @@ function cleanParams(params: LightAppRouteParam[]): LightAppRouteParam[] { base.customValue = (p.customValue ?? "").trim(); } } else { + // theme:存映射串(或纯值),运行时按当前主题解析取值 base.themeValue = (p.themeValue ?? "").trim(); } return base; diff --git a/frontend-web/src/strategy-components/api/light-apps.ts b/frontend-web/src/strategy-components/api/light-apps.ts index 4fa88ec9..9f476e7a 100644 --- a/frontend-web/src/strategy-components/api/light-apps.ts +++ b/frontend-web/src/strategy-components/api/light-apps.ts @@ -20,7 +20,7 @@ import { getBackendBaseURL } from "@/core/config"; export type LightAppType = "window_open" | "iframe"; export type RouteParamType = "login" | "theme"; -/** 路由参数项。登录参数运行时从 localStorage.userInfo 解析;主题参数用 themeValue。 */ +/** 路由参数项。登录参数运行时从 localStorage.userInfo 解析;主题参数随当前系统主题自动注入。 */ export interface LightAppRouteParam { key: string; paramType: RouteParamType; @@ -28,7 +28,7 @@ export interface LightAppRouteParam { source?: string | null; /** 登录参数且 source==="other" 时的字面值。 */ customValue?: string | null; - /** 主题参数的值(dark-blue / red / blue,可改)。 */ + /** 主题参数配置:映射串 `light=red;dark=darkBlue`(或纯值);运行时按当前系统主题取对应值(见 resolveThemeParamValue)。 */ themeValue?: string | null; } diff --git a/frontend-web/src/strategy-components/lib/light-app.ts b/frontend-web/src/strategy-components/lib/light-app.ts index b2066f47..5b8e66ac 100644 --- a/frontend-web/src/strategy-components/lib/light-app.ts +++ b/frontend-web/src/strategy-components/lib/light-app.ts @@ -27,13 +27,68 @@ export const LOGIN_SOURCE_OPTIONS: { label: string; value: string }[] = [ { label: "其他(自定义值)", value: "other" }, ]; -/** 主题参数示例值(深蓝 / 红 / 蓝),可改。 */ -export const THEME_EXAMPLE_OPTIONS: { label: string; value: string }[] = [ - { label: "深蓝色 dark-blue", value: "dark-blue" }, - { label: "红色 red", value: "red" }, - { label: "蓝色 blue", value: "blue" }, +/** + * 我方主题色键。当前启用 red(浅色) / dark-blue(深色);blue 为后续将新增的主题。 + * 主题参数的映射以这些键为左侧 key(如 `dark-blue=darkBlue`)。 + */ +export type AppThemeColor = "red" | "blue" | "dark-blue"; + +/** 我方全部主题色(「应用管理」主题参数逐项配置目标值时遍历;dot 为配色小圆点)。 */ +export const APP_THEME_COLORS: { key: AppThemeColor; label: string; dot: string }[] = [ + { key: "red", label: "红色", dot: "#F5222D" }, + { key: "blue", label: "蓝色", dot: "#1677FF" }, + { key: "dark-blue", label: "深蓝色", dot: "#002B5C" }, ]; +/** + * 读取我方当前主题色,以 ThemeContext 写在 上的 `dark` class 为准 + * (含嵌入场景的强制主题)。当前:深色=dark-blue,浅色=red。 + * TODO: 后续新增 blue 主题后,在此区分 blue 与 dark-blue。 + */ +export function getCurrentTheme(): AppThemeColor { + if (typeof document !== "undefined" && document.documentElement.classList.contains("dark")) { + return "dark-blue"; + } + return "red"; +} + +/** 解析主题映射串(`red=red;dark-blue=darkBlue`)为 { 主题色键: 目标值 }。值不做 trim,便于表单回显。 */ +export function parseThemeMap(raw: string | null | undefined): Record { + const map: Record = {}; + for (const pair of (raw ?? "").split(/[;,]/)) { + const idx = pair.search(/[=:]/); + if (idx <= 0) continue; + const k = pair.slice(0, idx).trim().toLowerCase(); + map[k] = pair.slice(idx + 1); + } + return map; +} + +/** 把主题映射对象序列化为映射串,按 APP_THEME_COLORS 顺序输出,缺省走同名(identity)。 */ +export function stringifyThemeMap(map: Record): string { + return APP_THEME_COLORS.map((c) => `${c.key}=${map[c.key] ?? c.key}`).join(";"); +} + +/** + * 按我方当前主题,从配置中取目标轻应用对应的值(跳转 / iframe 嵌套时注入)。 + * + * 配置支持两种写法(管理员在「应用管理」主题参数里配置): + * 1) 映射串:`red=red;blue=blue;dark-blue=darkBlue` —— 按当前主题取对应值; + * 缺当前主题映射时回退到 red,再回退到首个值,最后回退到主题色名本身。 + * 2) 纯值:`red` —— 不区分主题,原样返回。 + */ +export function resolveThemeParamValue( + raw: string | null | undefined, + theme: AppThemeColor = getCurrentTheme(), +): string { + const value = (raw ?? "").trim(); + if (!value) return theme; + // 不含键值分隔符 → 纯值,不区分主题原样返回 + if (!/[=:]/.test(value)) return value; + const map = parseThemeMap(value); + return (map[theme] ?? map.red ?? Object.values(map)[0] ?? theme).trim(); +} + /** 读取并解析 localStorage 中的 userInfo。 */ export function readUserInfo(): Record { try { @@ -52,7 +107,8 @@ export function resolveRouteParamValue( userInfo: Record = readUserInfo(), ): string { if (param.paramType === "theme") { - return param.themeValue ?? ""; + // 主题参数:按我方当前系统主题,从管理员配置的映射中取目标应用对应的值。 + return resolveThemeParamValue(param.themeValue); } // login if (param.source === "other") {