Merge branch 'dhk-1' into 'master'
Dhk 1 See merge request knowledge-base-bj/deerflow-code!3
This commit is contained in:
commit
871d98e6f2
7 files changed
+43
-55
No files matched your search
@@ -8,10 +8,10 @@
|
|||||||
// 5. 布尔开关也用字符串形式填写:"true" / "false"。
|
// 5. 布尔开关也用字符串形式填写:"true" / "false"。
|
||||||
window.__CM_RUNTIME_CONFIG__ = {
|
window.__CM_RUNTIME_CONFIG__ = {
|
||||||
// DeerFlow Gateway 地址:前端自有后端接口,例如 /api/agents、/api/auth、/api/threads 等。
|
// DeerFlow Gateway 地址:前端自有后端接口,例如 /api/agents、/api/auth、/api/threads 等。
|
||||||
// VITE_BACKEND_BASE_URL: "http://10.19.200.5:2026",
|
VITE_BACKEND_BASE_URL: "http://10.19.200.5:2026",
|
||||||
|
|
||||||
// LangGraph 流式对话接口地址:普通问答、智能体对话等流式能力使用。
|
// LangGraph 流式对话接口地址:普通问答、智能体对话等流式能力使用。
|
||||||
// VITE_LANGGRAPH_BASE_URL: "http://10.19.200.5:2026/api",
|
VITE_LANGGRAPH_BASE_URL: "http://10.19.200.5:2026/api",
|
||||||
|
|
||||||
// Canvas/AI 写作独立 LangGraph 地址:为空时前端会回退使用 VITE_LANGGRAPH_BASE_URL。
|
// Canvas/AI 写作独立 LangGraph 地址:为空时前端会回退使用 VITE_LANGGRAPH_BASE_URL。
|
||||||
VITE_CANVAS_LANGGRAPH_BASE_URL: "",
|
VITE_CANVAS_LANGGRAPH_BASE_URL: "",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
import { PanelLeftOpen, PanelLeftClose } from "lucide-react";
|
|
||||||
|
|
||||||
import { getStoredAuth } from "@/core/auth";
|
import { getStoredAuth } from "@/core/auth";
|
||||||
import { isWujieEnv } from "@/core/embed/wujie";
|
import { isWujieEnv } from "@/core/embed/wujie";
|
||||||
@@ -13,13 +12,7 @@ import {
|
|||||||
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
|
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
|
||||||
import './page-sdebar.css'
|
import './page-sdebar.css'
|
||||||
|
|
||||||
type PageSidebarDarkProps = {
|
export function PageSidebarDark() {
|
||||||
/** 是否收起(true 时只渲染左下角浮动入口,sidebar 主体隐藏) */
|
|
||||||
collapsed: boolean;
|
|
||||||
onToggleCollapsed: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDarkProps) {
|
|
||||||
const isAdmin = getStoredAuth()?.system_role === "admin";
|
const isAdmin = getStoredAuth()?.system_role === "admin";
|
||||||
const visibleMenuItems = useSidebarMenuItems(!!isAdmin);
|
const visibleMenuItems = useSidebarMenuItems(!!isAdmin);
|
||||||
const inWujieEnv = isWujieEnv();
|
const inWujieEnv = isWujieEnv();
|
||||||
@@ -196,22 +189,6 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
// collapsed 状态:sidebar 主体完全消失(包括占据的宽度),只渲染左下角浮动入口
|
|
||||||
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 (
|
return (
|
||||||
<aside className={`sidebar-contnet ${inWujieEnv ? "" : "sidebar-contnet--top-submenu"}`}>
|
<aside className={`sidebar-contnet ${inWujieEnv ? "" : "sidebar-contnet--top-submenu"}`}>
|
||||||
<div className="sidebar-contents">
|
<div className="sidebar-contents">
|
||||||
@@ -243,18 +220,6 @@ export function PageSidebarDark({ collapsed, onToggleCollapsed }: PageSidebarDar
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* 底部"收起面板"按钮:独立样式,mt-auto 推到底 */}
|
|
||||||
<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>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { useDisplayDesensitizer } from "@/core/sensitive-words/use-display-desensitizer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 紧凑模式(正常 App)新对话落地页的品牌欢迎块 —— 按 CM-assistant 参考图重画。
|
* 紧凑模式(正常 App)新对话落地页的品牌欢迎块 —— 按 CM-assistant 参考图重画。
|
||||||
@@ -8,6 +9,8 @@ import { cn } from "@/lib/utils";
|
|||||||
* 非紧凑模式仍用 <Welcome/>,本组件不参与。
|
* 非紧凑模式仍用 <Welcome/>,本组件不参与。
|
||||||
*/
|
*/
|
||||||
export function CompactWelcome({ className }: { className?: string }) {
|
export function CompactWelcome({ className }: { className?: string }) {
|
||||||
|
const desensitizeText = useDisplayDesensitizer();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -33,13 +36,13 @@ export function CompactWelcome({ className }: { className?: string }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="text-2xl font-black tracking-wide text-white italic">
|
<span className="text-2xl font-black tracking-wide text-white italic">
|
||||||
CM
|
{desensitizeText("CM")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 className="flex items-center justify-center text-2xl font-bold tracking-tight text-foreground/90">
|
<h1 className="flex items-center justify-center text-2xl font-bold tracking-tight text-foreground/90">
|
||||||
欢迎使用CM助手
|
{desensitizeText("欢迎使用CM助手")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-muted-foreground mx-auto mt-2 max-w-sm text-xs leading-relaxed">
|
<p className="text-muted-foreground mx-auto mt-2 max-w-sm text-xs leading-relaxed">
|
||||||
基于先进深度推理模型,为您提供高效的市场分析、专业报告撰写、调研设计与协同脑暴支持。
|
基于先进深度推理模型,为您提供高效的市场分析、专业报告撰写、调研设计与协同脑暴支持。
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useSearchParams } from "next/navigation";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
|
import { useDisplayDesensitizer } from "@/core/sensitive-words/use-display-desensitizer";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
import { AuroraText } from "../ui/aurora-text";
|
import { AuroraText } from "../ui/aurora-text";
|
||||||
@@ -16,6 +17,7 @@ export function Welcome({
|
|||||||
mode?: "ultra" | "pro" | "thinking" | "flash";
|
mode?: "ultra" | "pro" | "thinking" | "flash";
|
||||||
}) {
|
}) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const desensitizeText = useDisplayDesensitizer();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const isUltra = useMemo(() => mode === "ultra", [mode]);
|
const isUltra = useMemo(() => mode === "ultra", [mode]);
|
||||||
const colors = useMemo(() => {
|
const colors = useMemo(() => {
|
||||||
@@ -36,7 +38,7 @@ export function Welcome({
|
|||||||
t.welcome.createYourOwnSkill
|
t.welcome.createYourOwnSkill
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<AuroraText colors={colors}>{t.welcome.greeting}</AuroraText>
|
<AuroraText colors={colors}>{desensitizeText(t.welcome.greeting)}</AuroraText>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
import { desensitize, makeDesensitizer } from "@/lib/desensitize";
|
||||||
|
import { useSensitiveWords, wordsToMap } from "@/strategy-components/api/sensitive-words";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回用于界面静态文本的脱敏函数。
|
||||||
|
*
|
||||||
|
* 与导航菜单使用同一份敏感词查询:后台存在配置时以后台为准,未配置时回退到内置种子。
|
||||||
|
* Hook 订阅 React Query 缓存,管理员保存敏感词后,使用它的导航/欢迎区会自动重新渲染。
|
||||||
|
*/
|
||||||
|
export function useDisplayDesensitizer(): (text: string) => string {
|
||||||
|
const { data: words = [] } = useSensitiveWords();
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => (words.length > 0 ? makeDesensitizer(wordsToMap(words)) : desensitize),
|
||||||
|
[words],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ function PageLayout() {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
const isDark = theme === "dark";
|
const isDark = theme === "dark";
|
||||||
|
// 深色导航侧栏不提供收起入口,始终保持展开,避免切换主题后沿用浅色模式的收起状态。
|
||||||
|
const sidebarCollapsed = isDark ? false : collapsed;
|
||||||
// 浅色非嵌入:侧边栏为新版「二级导航图标卡片」窄栏(96px);wujie 嵌入仍走旧版手风琴(64/256px)。
|
// 浅色非嵌入:侧边栏为新版「二级导航图标卡片」窄栏(96px);wujie 嵌入仍走旧版手风琴(64/256px)。
|
||||||
const inWujie = useMemo(() => isWujieEnv(), []);
|
const inWujie = useMemo(() => isWujieEnv(), []);
|
||||||
const lightNarrowSidebar = !isDark && !inWujie;
|
const lightNarrowSidebar = !isDark && !inWujie;
|
||||||
@@ -74,17 +76,14 @@ function PageLayout() {
|
|||||||
return (
|
return (
|
||||||
<RoundtableJobNotifier>
|
<RoundtableJobNotifier>
|
||||||
<div className="h-full flex flex-col bg-muted/20">
|
<div className="h-full flex flex-col bg-muted/20">
|
||||||
{pageSidebarAllowed && <Header collapsed={collapsed} />}
|
{pageSidebarAllowed && <Header collapsed={sidebarCollapsed} />}
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-1 overflow-hidden">
|
||||||
{pageSidebarAllowed && (
|
{pageSidebarAllowed && (
|
||||||
isDark ? (
|
isDark ? (
|
||||||
<PageSidebarDark
|
<PageSidebarDark />
|
||||||
collapsed={collapsed}
|
|
||||||
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<PageSidebar
|
<PageSidebar
|
||||||
collapsed={collapsed}
|
collapsed={sidebarCollapsed}
|
||||||
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
|
onToggleCollapsed={() => setCollapsed((prev) => !prev)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -94,10 +93,8 @@ function PageLayout() {
|
|||||||
!pageSidebarAllowed
|
!pageSidebarAllowed
|
||||||
? ""
|
? ""
|
||||||
: isDark
|
: isDark
|
||||||
// 深色 sidebar:展开 118px(10 + 98 + 10 gap),收起 = 0 sidebar 完全消失,
|
// 深色 sidebar 固定展开 118px(10 + 98 + 10 gap)。
|
||||||
// 只剩左下角浮动按钮(fixed,叠在 main 上不影响布局)。
|
? "pl-[118px]"
|
||||||
// 不加 transition:transition + sidebar 立刻 unmount 不同步会抽搐
|
|
||||||
? (collapsed ? "pl-0" : "pl-[118px]")
|
|
||||||
: lightNarrowSidebar
|
: lightNarrowSidebar
|
||||||
// 浅色新版窄栏:展开三级列时 96→236px,主内容左内边距随之过渡
|
// 浅色新版窄栏:展开三级列时 96→236px,主内容左内边距随之过渡
|
||||||
? `transition-[padding] duration-300 ${lightExpanded ? "pl-[236px]" : "pl-[96px]"}`
|
? `transition-[padding] duration-300 ${lightExpanded ? "pl-[236px]" : "pl-[96px]"}`
|
||||||
@@ -111,7 +108,7 @@ function PageLayout() {
|
|||||||
path="workspace/*"
|
path="workspace/*"
|
||||||
element={
|
element={
|
||||||
<WorkspaceRoutes
|
<WorkspaceRoutes
|
||||||
pageSidebarCollapsed={collapsed}
|
pageSidebarCollapsed={sidebarCollapsed}
|
||||||
pageSidebarHidden={!pageSidebarAllowed}
|
pageSidebarHidden={!pageSidebarAllowed}
|
||||||
headerHidden={!pageSidebarAllowed}
|
headerHidden={!pageSidebarAllowed}
|
||||||
compactWorkspaceSidebar={pageSidebarAllowed}
|
compactWorkspaceSidebar={pageSidebarAllowed}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
type MenuItem,
|
type MenuItem,
|
||||||
} from "@/core/page-layout/sidebar-menu";
|
} from "@/core/page-layout/sidebar-menu";
|
||||||
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
|
import { useSidebarMenuItems } from "@/core/page-layout/use-sidebar-menu";
|
||||||
|
import { useDisplayDesensitizer } from "@/core/sensitive-words/use-display-desensitizer";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
import { useTheme } from "../contexts/ThemeContext";
|
import { useTheme } from "../contexts/ThemeContext";
|
||||||
@@ -53,6 +54,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
|||||||
const auth = getStoredAuth();
|
const auth = getStoredAuth();
|
||||||
const isAdmin = auth?.system_role === "admin";
|
const isAdmin = auth?.system_role === "admin";
|
||||||
const visibleMenuItems = useSidebarMenuItems(!!isAdmin);
|
const visibleMenuItems = useSidebarMenuItems(!!isAdmin);
|
||||||
|
const desensitizeText = useDisplayDesensitizer();
|
||||||
const { data: myPosition } = useMyPosition();
|
const { data: myPosition } = useMyPosition();
|
||||||
const positionName = myPosition?.name?.trim() || "";
|
const positionName = myPosition?.name?.trim() || "";
|
||||||
|
|
||||||
@@ -236,7 +238,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 中:CM助手(落在背景图发光基座上,纯文字无图标) */}
|
{/* 中:CM助手(落在背景图发光基座上,纯文字无图标) */}
|
||||||
<div className="header-center-title">CM业务中心</div>
|
<div className="header-center-title">{desensitizeText("CM业务中心")}</div>
|
||||||
|
|
||||||
{/* 右分区(flex-1):菜单靠左贴近中间基座,操作区靠最右 */}
|
{/* 右分区(flex-1):菜单靠左贴近中间基座,操作区靠最右 */}
|
||||||
<div className="flex h-full min-w-0 flex-1 items-center justify-between">
|
<div className="flex h-full min-w-0 flex-1 items-center justify-between">
|
||||||
@@ -262,7 +264,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
|||||||
<FileText className="h-4 w-4 text-white" />
|
<FileText className="h-4 w-4 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<span className="whitespace-nowrap text-base font-semibold text-white">
|
<span className="whitespace-nowrap text-base font-semibold text-white">
|
||||||
CM业务中心
|
{desensitizeText("CM业务中心")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<nav className="light-topnav" aria-label="一级菜单">
|
<nav className="light-topnav" aria-label="一级菜单">
|
||||||
@@ -289,7 +291,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
<span className="text-sm font-semibold text-white">
|
<span className="text-sm font-semibold text-white">
|
||||||
CM业务中心
|
{desensitizeText("CM业务中心")}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user