diff --git a/frontend-web/src/contexts/ThemeContext.tsx b/frontend-web/src/contexts/ThemeContext.tsx index 0c7fc748..004900f9 100644 --- a/frontend-web/src/contexts/ThemeContext.tsx +++ b/frontend-web/src/contexts/ThemeContext.tsx @@ -227,11 +227,18 @@ export const ThemeProvider: React.FC = ({ children }) => { if (theme === 'dark') { root.setAttribute('theme-mode', 'dark'); root.classList.add('dark'); + root.removeAttribute('data-theme'); return; } root.removeAttribute('theme-mode'); root.classList.remove('dark'); + + if (theme === 'lightblue') { + root.setAttribute('data-theme', 'lightblue'); + } else { + root.removeAttribute('data-theme'); + } }, [theme]); const toggleTheme = () => { diff --git a/frontend-web/src/pages/LightAppListPage.tsx b/frontend-web/src/pages/LightAppListPage.tsx index 43328404..86d2cb05 100644 --- a/frontend-web/src/pages/LightAppListPage.tsx +++ b/frontend-web/src/pages/LightAppListPage.tsx @@ -34,6 +34,7 @@ import { toast } from "sonner"; import { Pagination } from "@/components/ui/pagination"; import { cn } from "@/lib/utils"; +import { useTheme } from "@/contexts/ThemeContext"; import { useLightApps, type LightApp } from "@/strategy-components/api/light-apps"; import { buildLightAppUrl } from "@/strategy-components/lib/light-app"; @@ -67,6 +68,8 @@ export default function LightAppListPage() { const [search, setSearch] = useState(""); const [page, setPage] = useState(1); const [copiedId, setCopiedId] = useState(null); + const { theme } = useTheme(); + const isLightBlue = theme === 'lightblue'; const { data: apps = [], isLoading } = useLightApps({ appType: "window_open", @@ -115,13 +118,13 @@ export default function LightAppListPage() {
- - + +

应用列表

- + 导航工作台
@@ -139,7 +142,7 @@ export default function LightAppListPage() { value={search} onChange={(e) => setSearch(e.target.value)} placeholder="键入应用名称、目标地址、或描述,实时过滤检索…" - className="w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:border-[#CF1322]/60 focus:bg-white focus:outline-none focus:ring-2 focus:ring-[#CF1322]/20 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25" + className={cn("w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:bg-white focus:outline-none focus:ring-2 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25", isLightBlue ? "focus:border-[#0062D9]/60 focus:ring-[#0062D9]/20" : "focus:border-[#CF1322]/60 focus:ring-[#CF1322]/20")} /> {search && ( @@ -235,8 +238,10 @@ function AppCard({ onCopy: () => void; onOpen: () => void; }) { + const { theme } = useTheme(); + const isLightBlue = theme === 'lightblue'; const Icon = ICON_POOL[hashIndex(app.appId, ICON_POOL.length)]; - const theme = THEME_POOL[hashIndex(app.appId, THEME_POOL.length)]; + const cardTheme = THEME_POOL[hashIndex(app.appId, THEME_POOL.length)]; const parsedUrl = buildLightAppUrl(app); const hasParams = (app.routeParams ?? []).some((p) => p.key) && parsedUrl !== app.url; @@ -246,12 +251,12 @@ function AppCard({ {/* 上:图标 + 标题 + 描述 */}
-
+
-

+

{app.name}

@@ -265,7 +270,7 @@ function AppCard({
拼接后目标路由终端: - + 自动拼接已激活参
@@ -307,7 +312,7 @@ function AppCard({ {isOpen && ( -
-
+
+
历史草稿 {drafts.length} 条
@@ -1788,7 +1831,11 @@ function HistoryDropdown(props: HistoryDropdownProps) { const openOrLoad = () => isActiveJob && d.jobId ? onOpenJob(d.jobId) : onLoad(d.id); return ( -
  • +
  • {isRenaming ? ( diff --git a/frontend-web/src/roundtable-planning/styles/roundtable-planning.css b/frontend-web/src/roundtable-planning/styles/roundtable-planning.css index 30e65c52..7d80b460 100644 --- a/frontend-web/src/roundtable-planning/styles/roundtable-planning.css +++ b/frontend-web/src/roundtable-planning/styles/roundtable-planning.css @@ -110,10 +110,13 @@ --rt-primary-hover: var(--primary); --rt-primary-soft: var(--accent); color: var(--foreground); - /* 整页背景换深蓝主题底图(仅深色;浅色保持红白主题不受影响)。 - * background-image 叠在 background-color 上 —— 底色作为图加载前/未覆盖区域的回落; - * cover 铺满、fixed 固定不随内容滚动(大屏背板观感,与应用渲染大屏一致)。 - * url() 里的 SVG 由 Vite 当独立资源输出(非内联),浏览器缓存。 */ +} + +/* 整页背景换深蓝主题底图(仅页面根 .roundtable-planning;浅色不受影响)。 + * background-image 叠在 background-color 上 —— 底色作为图加载前/未覆盖区域的回落; + * cover 铺满、fixed 固定不随内容滚动(大屏背板观感,与应用渲染大屏一致)。 + * url() 里的 SVG 由 Vite 当独立资源输出(非内联),浏览器缓存。 */ +.dark .roundtable-planning { background-color: var(--background); background-image: url("../../assets/img/layout-bg-theme-dark-blue.svg"); background-size: cover; @@ -122,6 +125,19 @@ background-attachment: fixed; } +/* Portal 弹窗(RecommendAgentsDialog 等挂 .roundtable-planning--dark 但不在页面根内): + * 不透明实底、无底图 —— 对齐 §21 Modal 容器色 ZS-004-08。 */ +.roundtable-planning--dark:not(.roundtable-planning) { + --background: #122347; + --card: #0c1836; + --popover: #122347; + --muted: #0f1c3d; + --secondary: #1a2f5a; + --accent: #1a2f5a; + background-color: var(--background); + background-image: none; +} + .dark .roundtable-planning ::-webkit-scrollbar-thumb, .roundtable-planning--dark ::-webkit-scrollbar-thumb { background: color-mix(in oklch, var(--primary) 45%, var(--border)); @@ -388,7 +404,7 @@ /* 顶栏 */ .dark .roundtable-planning > header, .roundtable-planning--dark > header { - background-color: var(--card) !important; + background-color: #122347 !important; border-color: var(--border) !important; box-shadow: none !important; } @@ -407,6 +423,16 @@ color: var(--foreground) !important; } +/* 历史记录下拉面板:深色下改为不透明实底(避免 token 半透明透出底图)。 */ +:is(.dark .roundtable-planning, .roundtable-planning--dark) .rt-history-dropdown-panel { + background-color: #122347 !important; + background-image: none !important; +} + +:is(.dark .roundtable-planning, .roundtable-planning--dark) .rt-history-dropdown-header { + background-color: #122347 !important; +} + /* ============================================================================= * 派活链路流程图连接线(DispatchChainModal)。 * diff --git a/frontend-web/src/strategy-components/Header.tsx b/frontend-web/src/strategy-components/Header.tsx index b27f18a5..0b2e12f7 100644 --- a/frontend-web/src/strategy-components/Header.tsx +++ b/frontend-web/src/strategy-components/Header.tsx @@ -294,7 +294,7 @@ const Header = ({ collapsed }: HeaderProps) => { open={notificationOpen} onOpenChange={setNotificationOpen} /> -
    +
    {showTopNav ? ( <> {/* 左分区(flex-1):菜单靠右贴近中间基座 */} diff --git a/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx index 25d61dad..910f3238 100644 --- a/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/ActionAnalyzes.tsx @@ -23,7 +23,8 @@ export const ActionAnalyzes: React.FC = ({ title, category, const isDark = theme === 'dark'; // 主题颜色变量 const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white'; - const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-100'; + const isLightBlue = theme === 'lightblue'; + const cardBorder = isDark ? 'border-blue-800/30' : isLightBlue ? 'border-[#D4E9FF]' : 'border-red-100'; const textPrimary = isDark ? 'text-white' : 'text-gray-900'; const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600'; const textMuted = isDark ? 'text-slate-500' : 'text-gray-400'; @@ -137,7 +138,7 @@ export const ActionAnalyzes: React.FC = ({ title, category, value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} onKeyDown={(e) => handleKeyDown(e)} - className={`w-full pl-10 pr-4 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 transition-colors ${inputBg} ${cardBorder} ${textPrimary} placeholder:${textMuted}`} + className={`w-full pl-10 pr-4 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 ${isLightBlue ? 'focus:ring-[#0062D9]/20' : 'focus:ring-red-500/20'} transition-colors ${inputBg} ${cardBorder} ${textPrimary} placeholder:${textMuted}`} />
    {/* 任务列表 */} diff --git a/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx b/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx index 9bcfc62f..e48462bb 100644 --- a/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx +++ b/frontend-web/src/strategy-components/components/task-components/ActionColumn.tsx @@ -27,7 +27,8 @@ export const ActionColumn: React.FC = ({ title, category, sub const isDark = theme === 'dark'; // 主题颜色变量 const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white'; - const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-100'; + const isLightBlue = theme === 'lightblue'; + const cardBorder = isDark ? 'border-blue-800/30' : isLightBlue ? 'border-[#D4E9FF]' : 'border-red-100'; const textPrimary = isDark ? 'text-white' : 'text-gray-900'; const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600'; const textMuted = isDark ? 'text-slate-500' : 'text-gray-400'; diff --git a/frontend-web/src/strategy-components/components/task-components/KanbanColumn.tsx b/frontend-web/src/strategy-components/components/task-components/KanbanColumn.tsx index d59ede02..eacf4464 100644 --- a/frontend-web/src/strategy-components/components/task-components/KanbanColumn.tsx +++ b/frontend-web/src/strategy-components/components/task-components/KanbanColumn.tsx @@ -28,6 +28,7 @@ export const KanbanColumn: React.FC = ({ }) => { const { theme } = useTheme(); const isDark = theme === 'dark'; + const isLightBlue = theme === 'lightblue'; const [pageNum, setPageNum] = useState(1); const handlePageChange = async (value: number) => { @@ -37,7 +38,9 @@ export const KanbanColumn: React.FC = ({ const columnClass = isDark ? 'border border-[rgba(67,89,124,0.46)] bg-[linear-gradient(180deg,rgba(18,36,67,0.96),rgba(12,28,54,0.96))] shadow-[0_18px_40px_rgba(3,10,22,0.18)]' - : 'border border-[#E8E8E8] bg-[linear-gradient(180deg,#FFFFFF_0%,#FFF9F9_100%)] shadow-[0_2px_8px_rgba(34,34,34,0.08)]'; + : isLightBlue + ? 'border border-[#E8E8E8] bg-[linear-gradient(180deg,#FFFFFF_0%,#F4F9FF_100%)] shadow-[0_2px_8px_rgba(34,34,34,0.08)]' + : 'border border-[#E8E8E8] bg-[linear-gradient(180deg,#FFFFFF_0%,#FFF9F9_100%)] shadow-[0_2px_8px_rgba(34,34,34,0.08)]'; return (
    @@ -54,7 +57,7 @@ export const KanbanColumn: React.FC = ({ {count} @@ -86,7 +89,7 @@ export const KanbanColumn: React.FC = ({ className={`flex h-full min-h-[220px] flex-col items-center justify-center rounded border border-dashed ${ isDark ? 'border-[rgba(87,111,149,0.42)] bg-[rgba(12,24,44,0.46)] text-slate-400' - : 'border-[#F3C4C8] bg-[#FFF7F7] text-[#A6A6A6]' + : isLightBlue ? 'border-[#AAD2FF] bg-[#F4F9FF] text-[#A6A6A6]' : 'border-[#F3C4C8] bg-[#FFF7F7] text-[#A6A6A6]' }`} > diff --git a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx index f722dac2..d4f60fd2 100644 --- a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx +++ b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx @@ -33,6 +33,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa const { theme } = useTheme(); const navigate = useNavigate(); const isDark = theme === 'dark'; + const isLightBlue = theme === 'lightblue'; const [searchQuery, setSearchQuery] = useState(''); const [showAnalysisModal, setShowAnalysisModal] = useState(false); @@ -222,7 +223,9 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa const shellClass = isDark ? 'strategy-data h-full overflow-y-auto' - : 'strategy-data h-full overflow-y-auto bg-[linear-gradient(180deg,#FFFDFD_0%,#FFF7F7_46%,#FAFAFA_100%)]'; + : isLightBlue + ? 'strategy-data h-full overflow-y-auto bg-[linear-gradient(180deg,#F9FCFF_0%,#F4F9FF_46%,#FAFAFA_100%)]' + : 'strategy-data h-full overflow-y-auto bg-[linear-gradient(180deg,#FFFDFD_0%,#FFF7F7_46%,#FAFAFA_100%)]'; const toolbarClass = isDark ? 'border border-[rgba(43,143,254,0.55)] bg-[rgba(3,38,80,0.82)] text-white shadow-[0_16px_36px_rgba(3,10,22,0.2)]' @@ -238,8 +241,8 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa const metrics = [ { label: '全部任务', value: unanalyzedTotal + runningTotal + completedTotal, icon: Layers, fg: '#222222', chipBg: '#F5F5F5', chipFg: '#7F7F7F' }, - { label: '未分析', value: unanalyzedTotal, icon: Inbox, fg: '#F5222D', chipBg: '#FEEDED', chipFg: '#F5222D' }, - { label: '分析中', value: runningTotal, icon: Loader, fg: '#1677FF', chipBg: '#EAF4FF', chipFg: '#1677FF' }, + { label: '未分析', value: unanalyzedTotal, icon: Inbox, fg: isLightBlue ? '#0062D9' : '#F5222D', chipBg: isLightBlue ? '#EAF4FF' : '#FEEDED', chipFg: isLightBlue ? '#0062D9' : '#F5222D' }, + { label: '分析中', value: runningTotal, icon: Loader, fg: isLightBlue ? '#0079FE' : '#1677FF', chipBg: isLightBlue ? '#F4F9FF' : '#EAF4FF', chipFg: isLightBlue ? '#0079FE' : '#1677FF' }, { label: '已完成', value: completedTotal, icon: CircleCheck, fg: '#52C41A', chipBg: '#EEFCF7', chipFg: '#189D72' }, ]; @@ -250,11 +253,11 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa
    - + {category} - + {subCategory}
    @@ -293,7 +296,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa @@ -406,7 +409,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa @@ -399,7 +402,7 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor