diff --git a/.gitignore b/.gitignore index ba42257b..663c0f2e 100644 --- a/.gitignore +++ b/.gitignore @@ -84,5 +84,12 @@ offline-backend-20260512/backend/tests/* deploy .history +# Repo-root offline dependency pack (local only) +/dist/ + +# Frontend offline pack working directories +frontend-web/.offline-pack-build/ +frontend-web/.offline-extract-test/ + # Frontend skills components must be tracked (excluded from the broad skills/ ignore above) !frontend-web/src/components/workspace/skills/ diff --git a/frontend-web/.env.example b/frontend-web/.env.example index ae6121cf..80a2b0f7 100644 --- a/frontend-web/.env.example +++ b/frontend-web/.env.example @@ -5,15 +5,14 @@ # ├─────────────────┼──────────────────────────────────────────────────┤ # │ pnpm dev │ .env.development + .env.development.local │ # │ pnpm build │ .env.production + .env.production.local │ -# │ pnpm build:sit │ .env.sit + .env.sit.local │ +# │ pnpm build:network │ .env.network + .env.network.local(内网地址) │ # │ scripts/start-* │ 脚本注入的环境变量会覆盖上述文件(见下方说明) │ # └─────────────────┴──────────────────────────────────────────────────┘ # # 推荐: # - 日常本地开发:改 .env.development(已提交,团队默认 UAT 地址) # - 本机连 127.0.0.1:8001:复制 .env.development.local.example → .env.development.local -# - 内网 UAT 打包部署:改 .env.production 后再执行 pnpm build -# - SIT 环境打包:改 .env.sit 后再执行 pnpm build:sit(地址为 UAT 的 sit 版本) +# - 内网打包部署:改 .env.network 后执行 pnpm build:network(或改 .env.production 后 pnpm build) # # 若浏览器直连后端报 CORS,请在 Gateway 配置 CORS_ORIGINS,包含前端源站,例如: # CORS_ORIGINS=http://127.0.0.1:5173,http://localhost:5173,http://127.0.0.1:5174 diff --git a/frontend-web/.env.network b/frontend-web/.env.network new file mode 100644 index 00000000..f8962ea6 --- /dev/null +++ b/frontend-web/.env.network @@ -0,0 +1,30 @@ +# 内网 / 局域网生产打包(npm run build:network 或 pnpm build:network) +# 打包前请将 192.168.1.100 改为实际服务器 IP;变量会写入 dist,运行时不可再改 + +# Gateway / DeerFlow API(与 offline-backend DEPLOY 文档一致) +VITE_BACKEND_BASE_URL=http://47.88.25.99 +VITE_LANGGRAPH_BASE_URL=http://47.88.25.99/api + +# 轻应用「新建笔记」系列接口 +VITE_NOTE_API_BASE_URL=http://192.168.1.100:8000 +# CMZS 后端接口 +VITE_API_BASE_URL=http://192.168.1.100/zncm +# 佳来模型对话接口 +VITE_AIPI_CHAT_URL=http://192.168.1.100/gpt +# 多轮检索接口 +VITE_AIPI_GENERATE_CHAT_URL=http://192.168.1.100/jialai_b1_chat +VITE_AIPI_TASK_CHAT_URL=http://192.168.1.100/qq_b1_chat +VITE_AIPI_KNOWLEDGE_URL=http://192.168.1.100/knowlibrary +VITE_AIPI_B1COH_URL=http://192.168.1.100/web +VITE_AIPI_B2ACTOR_URL=http://192.168.1.100 +VITE_AIPI_B2ACTOR_XWT_PATH=/fromB/toXWT?isFrame=1 +VITE_AIPI_KNOWLEDGE_IFRAME_API_URL=http://192.168.1.100/knowes/api/iframeKnowledgeUrl +VITE_AIPI_KNOWLEDGE_IFRAME_SKIN=red +VITE_AIPI_MOPECHAT_URL=http://192.168.1.100/likun_b1_mope +VITE_AIPI_BACKENP_URL=http://192.168.1.100 +VITE_AIPI_CONSUMER_URL=http://192.168.1.100/consumer +VITE_AIPI_PGLINKTO_URL=http://192.168.1.100 +VITE_AIPI_XKLINKTO_URL=http://192.168.1.100 + +# 可选:Canvas 独立 LangGraph 地址 +# VITE_CANVAS_LANGGRAPH_BASE_URL= diff --git a/frontend-web/package.json b/frontend-web/package.json index 3ecf6627..368e9fa6 100644 --- a/frontend-web/package.json +++ b/frontend-web/package.json @@ -7,6 +7,7 @@ "dev": "vite", "build": "node --max-old-space-size=8192 ./node_modules/vite/bin/vite.js build", "build:sit": "node --max-old-space-size=8192 ./node_modules/vite/bin/vite.js build --mode sit", + "build:network": "node --max-old-space-size=8192 ./node_modules/vite/bin/vite.js build --mode network", "preview": "vite preview", "typecheck": "tsc --noEmit" }, diff --git a/frontend-web/src/App.tsx b/frontend-web/src/App.tsx index ea03c986..5649c323 100644 --- a/frontend-web/src/App.tsx +++ b/frontend-web/src/App.tsx @@ -2,6 +2,7 @@ import { useMemo } from "react"; import { Navigate, Route, Routes } from "react-router-dom"; import { ThemeProvider as NextThemesProvider } from "next-themes"; +import { FontScaleApplier } from "@/components/font-scale"; import { QueryClientProvider } from "@/components/query-client-provider"; import { AuthSyncWatcher } from "@/core/auth/sync"; import { I18nProvider } from "@/core/i18n/context"; @@ -39,6 +40,7 @@ function AppProviders({ children }: { children: React.ReactNode }) { + {children} diff --git a/frontend-web/src/components/font-scale.tsx b/frontend-web/src/components/font-scale.tsx new file mode 100644 index 00000000..14c97c8e --- /dev/null +++ b/frontend-web/src/components/font-scale.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useEffect } from "react"; + +import { useLocalSettings } from "@/core/settings"; + +/** + * 基准字号 = 16px,对应《深蓝色 UI 规范》§2.1.2 后台系统正文字号(16px Regular)。 + * 用户在「外观 → 字号」里选择的倍数通过 CSS 变量 `--ui-font-scale` 生效:globals.css + * 只把 Tailwind 的 `--text-*` 字号 token 乘以该倍数,**不动间距 token**,所以放大 / 缩小 + * 的只有文字本身,padding / margin / 宽高等布局尺寸保持不变,不会把页面挤错位。 + * `fontScale === 1` 即默认 16px。 + */ +export const BASE_FONT_PX = 16; + +export const FONT_SCALE_OPTIONS: { value: number; label: string; px: number }[] = + [ + { value: 0.875, label: "小", px: 14 }, + { value: 1, label: "标准", px: 16 }, + { value: 1.125, label: "大", px: 18 }, + { value: 1.25, label: "特大", px: 20 }, + ]; + +/** + * 把用户选择的字号倍数写到 的 `--ui-font-scale` CSS 变量。挂在应用根部, + * 保证刷新后即时生效、全局统一。只设变量、不直接改 font-size,因此布局不受影响。 + * 不渲染任何 DOM。 + */ +export function FontScaleApplier() { + const [settings] = useLocalSettings(); + const { fontScale } = settings.display; + + useEffect(() => { + const scale = + typeof fontScale === "number" && Number.isFinite(fontScale) && fontScale > 0 + ? fontScale + : 1; + const root = document.documentElement; + root.style.setProperty("--ui-font-scale", String(scale)); + // 清掉旧实现可能残留的根级 font-size 内联样式(旧版用它做整页缩放)。 + root.style.removeProperty("font-size"); + }, [fontScale]); + + return null; +} diff --git a/frontend-web/src/components/workspace/messages/markdown-content.tsx b/frontend-web/src/components/workspace/messages/markdown-content.tsx index dc0888c5..739bcd77 100644 --- a/frontend-web/src/components/workspace/messages/markdown-content.tsx +++ b/frontend-web/src/components/workspace/messages/markdown-content.tsx @@ -8,7 +8,6 @@ import { type MessageResponseProps, } from "@/components/ai-elements/message"; import { streamdownPlugins } from "@/core/streamdown"; -import { desensitize } from "@/lib/desensitize"; import { cn } from "@/lib/utils"; import { CitationLink } from "../citations/citation-link"; @@ -36,13 +35,13 @@ export function MarkdownContent({ }: MarkdownContentProps) { const components = useMemo(() => { return { - a: (props: AnchorHTMLAttributes) => { - if (props.href?.startsWith("#reference-")) { - return ; - } - if (typeof props.children === "string") { - const match = /^citation:(.+)$/.exec(props.children); - if (match) { + a: (props: AnchorHTMLAttributes) => { + if (props.href?.startsWith("#reference-")) { + return ; + } + if (typeof props.children === "string") { + const match = /^citation:(.+)$/.exec(props.children); + if (match) { const [, text] = match; return {text}; } @@ -67,8 +66,6 @@ export function MarkdownContent({ if (!content) return null; - const displayContent = desensitize(content); - return ( - {displayContent} + {content} ); } diff --git a/frontend-web/src/components/workspace/messages/message-list-item.tsx b/frontend-web/src/components/workspace/messages/message-list-item.tsx index 4daa04ce..3c35df6f 100644 --- a/frontend-web/src/components/workspace/messages/message-list-item.tsx +++ b/frontend-web/src/components/workspace/messages/message-list-item.tsx @@ -42,7 +42,6 @@ import { type RuntimeDisplaySource, } from "@/core/skill-display/runtime"; import { humanMessagePlugins } from "@/core/streamdown"; -import { desensitize } from "@/lib/desensitize"; import { cn } from "@/lib/utils"; import { CitationLink } from "../citations/citation-link"; @@ -259,7 +258,7 @@ function MessageContent_({
- {desensitize(contentToDisplay)} + {contentToDisplay}
@@ -273,7 +272,7 @@ function MessageContent_({ - {desensitize(reasoningContent)} + {reasoningContent} - {desensitize(contentToDisplay)} + {contentToDisplay} ) : null; return ( diff --git a/frontend-web/src/components/workspace/settings/appearance-settings-page.tsx b/frontend-web/src/components/workspace/settings/appearance-settings-page.tsx index 5970d17e..5720df7c 100644 --- a/frontend-web/src/components/workspace/settings/appearance-settings-page.tsx +++ b/frontend-web/src/components/workspace/settings/appearance-settings-page.tsx @@ -6,6 +6,7 @@ import { toast } from "sonner"; import { useTheme } from "@/contexts/ThemeContext"; +import { FONT_SCALE_OPTIONS } from "@/components/font-scale"; import { Button } from "@/components/ui/button"; import { Select, @@ -21,12 +22,12 @@ import { getStoredAuth } from "@/core/auth"; import { enUS, isLocale, zhCN, type Locale } from "@/core/i18n"; import { useI18n } from "@/core/i18n/hooks"; import { useLocalSettings } from "@/core/settings"; -import { - useAppearanceSettings, - useCitationDisplaySettings, - useUpdateAppearanceSettings, - useUpdateCitationDisplaySettings, -} from "@/core/system-settings/hooks"; +import { + useAppearanceSettings, + useCitationDisplaySettings, + useUpdateAppearanceSettings, + useUpdateCitationDisplaySettings, +} from "@/core/system-settings/hooks"; import { cn } from "@/lib/utils"; import { SettingsSection } from "./settings-section"; @@ -42,13 +43,13 @@ export function AppearanceSettingsPage() { const currentTheme = theme; const [settings, setSettings] = useLocalSettings(); const isAdmin = getStoredAuth()?.system_role === "admin"; - const { data: appearance } = useAppearanceSettings(); - const updateAppearance = useUpdateAppearanceSettings(); - const { data: citationDisplay } = useCitationDisplaySettings(); - const updateCitationDisplay = useUpdateCitationDisplaySettings(); - const globalDefault = appearance?.default_theme ?? "light"; - const cleanupWords = - citationDisplay?.cleanup_words ?? settings.display.citationCleanupWords ?? []; + const { data: appearance } = useAppearanceSettings(); + const updateAppearance = useUpdateAppearanceSettings(); + const { data: citationDisplay } = useCitationDisplaySettings(); + const updateCitationDisplay = useUpdateCitationDisplaySettings(); + const globalDefault = appearance?.default_theme ?? "light"; + const cleanupWords = + citationDisplay?.cleanup_words ?? settings.display.citationCleanupWords ?? []; const handleSetGlobalDefault = async (value: "light" | "dark") => { if (value === globalDefault) return; @@ -147,6 +148,39 @@ export function AppearanceSettingsPage() { + +
+ +
+ 预览:多智能体圆桌研讨 · The quick brown fox · 0123456789 +
+
+
+ + + -