Merge branch 'dhk-1' into 'master'
Dhk 1 See merge request knowledge-base-bj/deerflow-code!4
This commit is contained in:
commit
2c331aa744
16 files changed
+242
-38
No files matched your search
@@ -16,7 +16,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<title>CM 助手</title>
|
||||
<script src="/runtime-config.js"></script>
|
||||
<script src="/runtime-config.js" data-runtime-config></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@@ -7,6 +7,25 @@
|
||||
// 4. 这里的默认值来自 .env.network;如某个环境不用某项,可以留空字符串。
|
||||
// 5. 布尔开关也用字符串形式填写:"true" / "false"。
|
||||
window.__CM_RUNTIME_CONFIG__ = {
|
||||
// 品牌图片相对路径会以 runtime-config.js 所在目录为基准解析。
|
||||
// Nginx 以子路径部署时不需要修改前端图片路径。
|
||||
// 打包后可直接替换 dist/brand-assets/ 内的同名 PNG。
|
||||
// 也可以把下方图片地址改为其他 PNG 地址,无需重新打包。
|
||||
// 是否显示整块欢迎页图标区域:"true" 显示,"false" 隐藏,默认隐藏。
|
||||
VITE_WELCOME_LOGO_VISIBLE: "false",
|
||||
// 红白主题的顶栏系统 Logo 图片地址。
|
||||
VITE_BRAND_LOGO_LIGHT_URL: "brand-assets/brand-logo-light.png",
|
||||
// 浅蓝主题的顶栏系统 Logo 图片地址。
|
||||
VITE_BRAND_LOGO_LIGHTBLUE_URL: "brand-assets/brand-logo-lightblue.png",
|
||||
// 深色主题的顶栏系统 Logo 图片地址。
|
||||
VITE_BRAND_LOGO_DARK_URL: "brand-assets/brand-logo-dark.png",
|
||||
// 红白主题的欢迎页 Logo 图片地址:为空时显示原有 CM 文字和渐变背景。
|
||||
VITE_BRAND_WELCOME_LIGHT_URL: "",
|
||||
// 浅蓝主题的欢迎页 Logo 图片地址:为空时显示原有 CM 文字和渐变背景。
|
||||
VITE_BRAND_WELCOME_LIGHTBLUE_URL: "",
|
||||
// 深色主题的欢迎页 Logo 图片地址:为空时显示原有 CM 文字和渐变背景。
|
||||
VITE_BRAND_WELCOME_DARK_URL: "",
|
||||
|
||||
// DeerFlow Gateway 地址:前端自有后端接口,例如 /api/agents、/api/auth、/api/threads 等。
|
||||
VITE_BACKEND_BASE_URL: "http://10.19.200.5:2026",
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { PanelLeftOpen, PanelLeftClose } from "lucide-react";
|
||||
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { isWujieEnv } from "@/core/embed/wujie";
|
||||
@@ -12,7 +13,13 @@ import {
|
||||
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
|
||||
import './page-sdebar.css'
|
||||
|
||||
export function PageSidebarDark() {
|
||||
type PageSidebarDarkProps = {
|
||||
/** 是否收起(true 时只渲染左下角浮动入口,sidebar 主体隐藏) */
|
||||
collapsed: boolean;
|
||||
onToggleCollapsed: () => void;
|
||||
};
|
||||
|
||||
export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDarkProps) {
|
||||
const isAdmin = getStoredAuth()?.system_role === "admin";
|
||||
const visibleMenuItems = useSidebarMenuItems(!!isAdmin);
|
||||
const inWujieEnv = isWujieEnv();
|
||||
@@ -189,6 +196,22 @@ export function PageSidebarDark() {
|
||||
</div>
|
||||
);
|
||||
|
||||
// 收起时主侧栏不占宽度,保留左下角入口以便随时恢复。
|
||||
if (collapsed) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
title="展开侧边栏"
|
||||
aria-label="展开侧边栏"
|
||||
className="sidebar-collapse-btn sidebar-collapse-btn--floating"
|
||||
onClick={onToggleCollapsed}
|
||||
>
|
||||
<PanelLeftOpen className="sidebar-collapse-btn__icon" aria-hidden="true" />
|
||||
<span className="sidebar-collapse-btn__label">展开面板</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className={`sidebar-contnet ${inWujieEnv ? "" : "sidebar-contnet--top-submenu"}`}>
|
||||
<div className="sidebar-contents">
|
||||
@@ -220,6 +243,17 @@ export function PageSidebarDark() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
title="收起侧边栏"
|
||||
aria-label="收起侧边栏"
|
||||
className="sidebar-collapse-btn sidebar-collapse-btn--inline"
|
||||
onClick={onToggleCollapsed}
|
||||
>
|
||||
<PanelLeftClose className="sidebar-collapse-btn__icon" aria-hidden="true" />
|
||||
<span className="sidebar-collapse-btn__label">收起面板</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { getWelcomeBrandAsset } from "@/core/branding/brand-assets";
|
||||
import { readRuntimeFlag } from "@/env";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useDisplayDesensitizer } from "@/core/sensitive-words/use-display-desensitizer";
|
||||
|
||||
@@ -10,6 +15,13 @@ import { useDisplayDesensitizer } from "@/core/sensitive-words/use-display-desen
|
||||
*/
|
||||
export function CompactWelcome({ className }: { className?: string }) {
|
||||
const desensitizeText = useDisplayDesensitizer();
|
||||
const { theme } = useTheme();
|
||||
const brandTheme = theme;
|
||||
const welcomeLogo = getWelcomeBrandAsset(brandTheme);
|
||||
const [failedWelcomeLogo, setFailedWelcomeLogo] = useState<string | null>(null);
|
||||
const shouldShowWelcomeLogo =
|
||||
Boolean(welcomeLogo) && failedWelcomeLogo !== welcomeLogo;
|
||||
const isWelcomeLogoVisible = readRuntimeFlag("VITE_WELCOME_LOGO_VISIBLE");
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -19,6 +31,8 @@ export function CompactWelcome({ className }: { className?: string }) {
|
||||
)}
|
||||
>
|
||||
{/* CM logo:浅底圆环 + 主色渐变圆角方块 */}
|
||||
{/* Controlled by VITE_WELCOME_LOGO_VISIBLE in runtime-config.js. */}
|
||||
{isWelcomeLogoVisible && (
|
||||
<div
|
||||
className="mb-3.5 inline-flex items-center justify-center rounded-full p-3"
|
||||
style={{
|
||||
@@ -28,18 +42,29 @@ export function CompactWelcome({ className }: { className?: string }) {
|
||||
"1px solid rgb(var(--legacy-workspace-brand-rgb) / 12%)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex size-14 items-center justify-center rounded-2xl shadow-md"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(to top right, var(--workspace-brand), var(--brand-200))",
|
||||
}}
|
||||
>
|
||||
<span className="text-2xl font-black tracking-wide text-white italic">
|
||||
{desensitizeText("CM")}
|
||||
</span>
|
||||
</div>
|
||||
{shouldShowWelcomeLogo && welcomeLogo ? (
|
||||
<img
|
||||
src={welcomeLogo}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="size-16 object-contain"
|
||||
onError={() => setFailedWelcomeLogo(welcomeLogo)}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="flex size-14 items-center justify-center rounded-2xl shadow-md"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"linear-gradient(to top right, var(--workspace-brand), var(--brand-200))",
|
||||
}}
|
||||
>
|
||||
<span className="text-2xl font-black tracking-wide text-white italic">
|
||||
{desensitizeText("CM")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h1 className="flex items-center justify-center text-2xl font-bold tracking-tight text-foreground/90">
|
||||
{desensitizeText("欢迎使用CM助手")}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import fallbackLogoDark from "@/assets/img/brand-logo-dark.png";
|
||||
import fallbackLogoLight from "@/assets/img/brand-logo-light.png";
|
||||
import fallbackLogoLightblue from "@/assets/img/brand-logo-lightblue.png";
|
||||
import { readRuntimeEnv } from "@/env";
|
||||
|
||||
export type BrandTheme = "light" | "lightblue" | "dark";
|
||||
|
||||
const headerFallbackAssets: Record<BrandTheme, string> = {
|
||||
light: fallbackLogoLight,
|
||||
lightblue: fallbackLogoLightblue,
|
||||
dark: fallbackLogoDark,
|
||||
};
|
||||
|
||||
const headerRuntimeKeys: Record<BrandTheme, string> = {
|
||||
light: "VITE_BRAND_LOGO_LIGHT_URL",
|
||||
lightblue: "VITE_BRAND_LOGO_LIGHTBLUE_URL",
|
||||
dark: "VITE_BRAND_LOGO_DARK_URL",
|
||||
};
|
||||
|
||||
const welcomeRuntimeKeys: Record<BrandTheme, string> = {
|
||||
light: "VITE_BRAND_WELCOME_LIGHT_URL",
|
||||
lightblue: "VITE_BRAND_WELCOME_LIGHTBLUE_URL",
|
||||
dark: "VITE_BRAND_WELCOME_DARK_URL",
|
||||
};
|
||||
|
||||
function runtimeConfigBaseUrl(): string | undefined {
|
||||
if (typeof document === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return document.querySelector<HTMLScriptElement>("script[data-runtime-config]")?.src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an optional post-build brand override from runtime-config.js.
|
||||
* Relative paths are anchored to runtime-config.js, which keeps the URL valid
|
||||
* when the whole SPA is mounted below an Nginx location prefix.
|
||||
*/
|
||||
function readRuntimeBrandAsset(key: string): string | undefined {
|
||||
const configuredUrl = readRuntimeEnv(key);
|
||||
if (!configuredUrl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const baseUrl =
|
||||
runtimeConfigBaseUrl() ??
|
||||
(typeof window !== "undefined" ? window.location.href : undefined);
|
||||
return baseUrl ? new URL(configuredUrl, baseUrl).href : configuredUrl;
|
||||
} catch {
|
||||
return configuredUrl;
|
||||
}
|
||||
}
|
||||
|
||||
export function getHeaderBrandAsset(theme: BrandTheme): string {
|
||||
return readRuntimeBrandAsset(headerRuntimeKeys[theme]) ?? headerFallbackAssets[theme];
|
||||
}
|
||||
|
||||
export function getHeaderBrandFallback(theme: BrandTheme): string {
|
||||
return headerFallbackAssets[theme];
|
||||
}
|
||||
|
||||
/**
|
||||
* Welcome content deliberately has no bundled image fallback. An empty
|
||||
* runtime URL keeps the original CM text + gradient treatment.
|
||||
*/
|
||||
export function getWelcomeBrandAsset(theme: BrandTheme): string | undefined {
|
||||
return readRuntimeBrandAsset(welcomeRuntimeKeys[theme]);
|
||||
}
|
||||
@@ -31,8 +31,6 @@ function PageLayout() {
|
||||
const location = useLocation();
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === "dark";
|
||||
// 深色导航侧栏不提供收起入口,始终保持展开,避免切换主题后沿用浅色模式的收起状态。
|
||||
const sidebarCollapsed = isDark ? false : collapsed;
|
||||
// 浅色非嵌入:侧边栏为新版「二级导航图标卡片」窄栏(96px);wujie 嵌入仍走旧版手风琴(64/256px)。
|
||||
const inWujie = useMemo(() => isWujieEnv(), []);
|
||||
const lightNarrowSidebar = !isDark && !inWujie;
|
||||
@@ -76,14 +74,17 @@ function PageLayout() {
|
||||
return (
|
||||
<RoundtableJobNotifier>
|
||||
<div className="h-full flex flex-col bg-muted/20">
|
||||
{pageSidebarAllowed && <Header collapsed={sidebarCollapsed} />}
|
||||
{pageSidebarAllowed && <Header collapsed={collapsed} />}
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
{pageSidebarAllowed && (
|
||||
isDark ? (
|
||||
<PageSidebarDark />
|
||||
<PageSidebarDark
|
||||
collapsed={collapsed}
|
||||
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
|
||||
/>
|
||||
) : (
|
||||
<PageSidebar
|
||||
collapsed={sidebarCollapsed}
|
||||
collapsed={collapsed}
|
||||
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
|
||||
/>
|
||||
)
|
||||
@@ -93,8 +94,8 @@ function PageLayout() {
|
||||
!pageSidebarAllowed
|
||||
? ""
|
||||
: isDark
|
||||
// 深色 sidebar 固定展开 118px(10 + 98 + 10 gap)。
|
||||
? "pl-[118px]"
|
||||
// 深色 sidebar:展开 118px(10 + 98 + 10 gap),收起时主内容不留左内边距。
|
||||
? (collapsed ? "pl-0" : "pl-[118px]")
|
||||
: lightNarrowSidebar
|
||||
// 浅色新版窄栏:展开三级列时 96→236px,主内容左内边距随之过渡
|
||||
? `transition-[padding] duration-300 ${lightExpanded ? "pl-[236px]" : "pl-[96px]"}`
|
||||
@@ -108,7 +109,7 @@ function PageLayout() {
|
||||
path="workspace/*"
|
||||
element={
|
||||
<WorkspaceRoutes
|
||||
pageSidebarCollapsed={sidebarCollapsed}
|
||||
pageSidebarCollapsed={collapsed}
|
||||
pageSidebarHidden={!pageSidebarAllowed}
|
||||
headerHidden={!pageSidebarAllowed}
|
||||
compactWorkspaceSidebar={pageSidebarAllowed}
|
||||
|
||||
@@ -4240,7 +4240,7 @@ function RightSidebar({
|
||||
{timelineEntries.map((entry) => (
|
||||
<div
|
||||
key={entry.id}
|
||||
className="relative rounded-lg px-1.5 py-1 transition-colors hover:bg-slate-50/80"
|
||||
className="roundtable-clarification-entry relative rounded-lg px-1.5 py-1 transition-colors hover:bg-slate-50/80"
|
||||
>
|
||||
<div className="absolute -left-[20.5px] top-2 h-3 w-3 rounded-full bg-primary border-2 border-white ring-2 ring-[var(--brand-200)]" />
|
||||
<div className="grid grid-cols-[68px_minmax(0,1fr)] gap-x-2">
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
--rt-primary-active: var(--brand-950, #a8071a);
|
||||
--rt-primary-soft: var(--brand-200, #feeded);
|
||||
--rt-page-bg: #fef6f6;
|
||||
/* 圆桌全页最小可读字号(含 Step 3 方案展示 / 结果绘制) */
|
||||
--roundtable-chat-font-size: 16px;
|
||||
--roundtable-chat-meta-font-size: 16px;
|
||||
font-size: 16px;
|
||||
/* 圆桌全页最小可读字号(含 Step 3 方案展示 / 结果绘制),跟随「设置 → 字号」。 */
|
||||
--roundtable-chat-font-size: calc(16px * var(--ui-font-scale, 1));
|
||||
--roundtable-chat-meta-font-size: calc(16px * var(--ui-font-scale, 1));
|
||||
font-size: calc(16px * var(--ui-font-scale, 1));
|
||||
}
|
||||
|
||||
/* 会商对话区:气泡正文、步骤卡、Markdown 块 */
|
||||
@@ -29,10 +29,11 @@
|
||||
|
||||
/*
|
||||
* 抬升页内显式写死的小字号类(text-xs / text-sm / text-[10–14px] / calc),
|
||||
* 避免 Step 3、侧栏、按钮条等遗漏逐文件改 class。text-base 及以上标题保持不变。
|
||||
* 并让它们跟随设置页字号倍率,避免 Step 3、左右记录区和对话列表遗漏。
|
||||
* text-base 及以上标题由全局 --text-* token 处理。
|
||||
*/
|
||||
.roundtable-planning :where(.text-xs, .text-sm) {
|
||||
font-size: 16px;
|
||||
font-size: calc(16px * var(--ui-font-scale, 1));
|
||||
}
|
||||
|
||||
.roundtable-planning :where(
|
||||
@@ -46,7 +47,7 @@
|
||||
[class*="text-[14px"],
|
||||
[class*="text-[calc"]
|
||||
):not(.w-5) {
|
||||
font-size: 16px;
|
||||
font-size: calc(16px * var(--ui-font-scale, 1));
|
||||
}
|
||||
|
||||
.roundtable-planning ::-webkit-scrollbar-thumb {
|
||||
@@ -343,6 +344,17 @@
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* ---- Step1 右侧「澄清记录」:覆盖 hover:bg-slate-50/80,避免深色下泛灰白 ---- */
|
||||
:is(.dark .roundtable-planning, .roundtable-planning--dark)
|
||||
.roundtable-clarification-entry:hover {
|
||||
background-color: rgb(22 119 255 / 18%) !important;
|
||||
}
|
||||
|
||||
:is(.dark .roundtable-planning, .roundtable-planning--dark)
|
||||
.roundtable-clarification-entry:hover h4 {
|
||||
color: #e8edf5 !important;
|
||||
}
|
||||
|
||||
/* ---- focus ring:brand-200 → 主色淡环 ---- */
|
||||
:is(.dark .roundtable-planning, .roundtable-planning--dark)
|
||||
:is(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Bell, ChevronDown, FileText, User } from "lucide-react";
|
||||
import { Bell, ChevronDown, User } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import { NotificationDialog } from "@/components/workspace/notification-dialog";
|
||||
import { getStoredAuth } from "@/core/auth";
|
||||
import { useLiveAccount } from "@/core/auth/use-live-account";
|
||||
import { getHeaderBrandAsset, getHeaderBrandFallback } from "@/core/branding/brand-assets";
|
||||
import { isWujieEnv } from "@/core/embed/wujie";
|
||||
import { useUnreadCount } from "@/core/notifications";
|
||||
import { useMyPosition } from "@/core/positions";
|
||||
@@ -46,6 +47,17 @@ type HeaderProps = {
|
||||
const Header = ({ collapsed }: HeaderProps) => {
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === "dark";
|
||||
const brandTheme = theme;
|
||||
const configuredBrandLogo = getHeaderBrandAsset(brandTheme);
|
||||
const fallbackBrandLogo = getHeaderBrandFallback(brandTheme);
|
||||
const [failedBrandLogo, setFailedBrandLogo] = useState<string | null>(null);
|
||||
const brandLogo =
|
||||
failedBrandLogo === configuredBrandLogo ? fallbackBrandLogo : configuredBrandLogo;
|
||||
const handleBrandLogoError = () => {
|
||||
if (brandLogo !== fallbackBrandLogo) {
|
||||
setFailedBrandLogo(brandLogo);
|
||||
}
|
||||
};
|
||||
const [notificationOpen, setNotificationOpen] = useState(false);
|
||||
const { data: unreadCount = 0 } = useUnreadCount();
|
||||
const navigate = useNavigate();
|
||||
@@ -59,7 +71,8 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
const positionName = myPosition?.name?.trim() || "";
|
||||
|
||||
const displayName = liveAccount.displayName;
|
||||
const showTopNav = isDark && !collapsed && !isWujieEnv();
|
||||
// 深色侧栏收起只影响左侧导航,不应让顶栏回退到浅色的图标布局。
|
||||
const showTopNav = isDark && !isWujieEnv();
|
||||
// 浅色(红/蓝)顶栏:一级导航正常横排进顶栏,不做深色那种围绕基座的特殊处理。
|
||||
// 与 collapsed 解耦(折叠只影响侧边栏,一级导航始终可见);wujie 嵌入下隐藏,
|
||||
// 此时一级导航回落到侧边栏(见 page-sidebar.tsx)。
|
||||
@@ -226,7 +239,19 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
{showTopNav ? (
|
||||
<>
|
||||
{/* 左分区(flex-1):菜单靠右贴近中间基座 */}
|
||||
<div className="flex h-full min-w-0 flex-1 items-center justify-end">
|
||||
<div className="flex h-full min-w-0 flex-1 items-center justify-between">
|
||||
<div
|
||||
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border border-cyan-300/25 bg-blue-950/55"
|
||||
title="系统 Logo"
|
||||
>
|
||||
<img
|
||||
src={brandLogo}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="h-[35px] w-[35px] object-contain"
|
||||
onError={handleBrandLogoError}
|
||||
/>
|
||||
</div>
|
||||
<nav
|
||||
className="top-submenu-bar top-submenu-bar--group"
|
||||
aria-label="左侧菜单"
|
||||
@@ -237,8 +262,12 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* 中:CM助手(落在背景图发光基座上,纯文字无图标) */}
|
||||
<div className="header-center-title">{desensitizeText("CM业务中心")}</div>
|
||||
{/* 中:系统 logo + 名称,落在背景图发光基座上。 */}
|
||||
<div className="header-center-title">
|
||||
<span className="header-center-title__label">
|
||||
{desensitizeText("CM业务中心")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 右分区(flex-1):菜单靠左贴近中间基座,操作区靠最右 */}
|
||||
<div className="flex h-full min-w-0 flex-1 items-center justify-between">
|
||||
@@ -260,10 +289,16 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
{/* 浅色顶栏:logo + 一级导航横排(白字落在 banner 上) */}
|
||||
<div className="flex h-full min-w-0 flex-1 items-center">
|
||||
<div className="flex flex-shrink-0 items-center gap-2 pr-1">
|
||||
<div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-white/20">
|
||||
<FileText className="h-4 w-4 text-white" />
|
||||
<div className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-white/20">
|
||||
<img
|
||||
src={brandLogo}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="h-[35px] w-[35px] object-contain"
|
||||
onError={handleBrandLogoError}
|
||||
/>
|
||||
</div>
|
||||
<span className="whitespace-nowrap text-base font-semibold text-white">
|
||||
<span className="whitespace-nowrap text-lg font-semibold text-white">
|
||||
{desensitizeText("CM业务中心")}
|
||||
</span>
|
||||
</div>
|
||||
@@ -287,7 +322,13 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
: "bg-white/20",
|
||||
)}
|
||||
>
|
||||
<FileText className="h-4 w-4 text-white" />
|
||||
<img
|
||||
src={brandLogo}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
className="h-7 w-7 object-contain"
|
||||
onError={handleBrandLogoError}
|
||||
/>
|
||||
</div>
|
||||
{!collapsed && (
|
||||
<span className="text-sm font-semibold text-white">
|
||||
|
||||
@@ -1179,6 +1179,9 @@ html.dark .strategy-app-header {
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.header-center-title__label {
|
||||
/* 白→浅蓝→白 金属质感渐变文字 */
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
|
||||
Reference in new issue
Block a user