diff --git a/frontend/web/src/admin/AdminApp.tsx b/frontend/web/src/admin/AdminApp.tsx index 91eff12..7f486e9 100644 --- a/frontend/web/src/admin/AdminApp.tsx +++ b/frontend/web/src/admin/AdminApp.tsx @@ -4,6 +4,7 @@ import { getAuthToken, getStoredRole } from "../lib/api"; import { ADMIN_GROUPS, ADMIN_SECTIONS } from "./sections"; import { navigateAdmin, type AdminSectionId } from "./router"; import { Button, Tag } from "../components/primitives"; +import { Icon } from "../components/Icon"; import { DashboardModule } from "./modules/Dashboard"; import { PersonasModule } from "./modules/Personas"; import { SessionsModule } from "./modules/Sessions"; @@ -57,7 +58,7 @@ function AdminSidebar({ active }: { active: AdminSectionId }): React.ReactNode { : "text-[var(--mu-text-mid)] hover:bg-[var(--mu-surface-4)]" }`} > - {s.icon} + {s.label} ))} @@ -93,7 +94,7 @@ function AdminTopBar({ section }: { section: AdminSectionId }): React.ReactNode aria-label="切换主题" className="inline-flex h-8 w-8 items-center justify-center rounded-[var(--mu-radius)] bg-[var(--mu-surface-4)] text-sm transition-all duration-200 ease-[var(--mu-spring)] hover:bg-[var(--mu-surface-5)] active:scale-95" > - {theme === "dark" ? "☀" : "☾"} + ))} diff --git a/frontend/web/src/admin/modules/Observability.tsx b/frontend/web/src/admin/modules/Observability.tsx index 549019f..f136a2e 100644 --- a/frontend/web/src/admin/modules/Observability.tsx +++ b/frontend/web/src/admin/modules/Observability.tsx @@ -3,6 +3,7 @@ import { useAppStore } from "../../store/useAppStore"; import { useAuditStore } from "../audit"; import { CardGrid, Notice, PageHeader, StatCard } from "../components"; import { Button, Surface, Tag } from "../../components/primitives"; +import { Icon } from "../../components/Icon"; type Tab = "logs" | "trace" | "metrics" | "audit"; @@ -84,10 +85,10 @@ function MetricsView(): React.ReactNode { return (
- - - - + } label="请求 QPS" value="—" sub="网关指标占位" tone="accent" /> + } label="LLM 调用次数" value="—" sub="用量/费用占位" tone="neutral" /> + } label="子代理事件" value="—" sub="编排指标占位" tone="ok" /> + } label="工时/Token" value="—" sub="成本占位" tone="warn" /> 指标时序图 / 导出需后端 M10+ 提供。
diff --git a/frontend/web/src/admin/modules/System.tsx b/frontend/web/src/admin/modules/System.tsx index 1a5e9b5..08b6d5e 100644 --- a/frontend/web/src/admin/modules/System.tsx +++ b/frontend/web/src/admin/modules/System.tsx @@ -3,6 +3,7 @@ import { getStoredRole } from "../../lib/api"; import { useAuditStore } from "../audit"; import { KeyValueRow, Notice, PageHeader } from "../components"; import { Button, Surface, Tag } from "../../components/primitives"; +import { Icon } from "../../components/Icon"; export function SystemModule(): React.ReactNode { const isOwner = getStoredRole() === "owner"; @@ -24,7 +25,7 @@ export function SystemModule(): React.ReactNode {
- + } title="安全 & 密钥" ownerOnly /> @@ -35,7 +36,7 @@ export function SystemModule(): React.ReactNode { - + } title="存储" /> @@ -46,7 +47,7 @@ export function SystemModule(): React.ReactNode { - + } title="环境变量" /> @@ -56,7 +57,7 @@ export function SystemModule(): React.ReactNode { - + } title="运行时" />
日志级别 @@ -85,10 +86,10 @@ export function SystemModule(): React.ReactNode { ); } -function SectionTitle({ icon, title, ownerOnly = false }: { icon: string; title: string; ownerOnly?: boolean }): React.ReactNode { +function SectionTitle({ icon, title, ownerOnly = false }: { icon: React.ReactNode; title: string; ownerOnly?: boolean }): React.ReactNode { return (

- {icon} + {icon} {title} {ownerOnly ? owner : null}

diff --git a/frontend/web/src/components/ChatInput.tsx b/frontend/web/src/components/ChatInput.tsx index 63683b6..b395af9 100644 --- a/frontend/web/src/components/ChatInput.tsx +++ b/frontend/web/src/components/ChatInput.tsx @@ -1,13 +1,25 @@ import { useEffect, useRef, useState } from "react"; import { Button } from "./primitives"; +import { Icon, type IconName } from "./Icon"; +import { useModeStore } from "../store/useModeStore"; +import type { Mode } from "../lib/types"; export interface ChatInputProps { - onSend: (text: string) => void; + onSend: (text: string, mode: Mode) => void; sending: boolean; onVoice: () => void; placeholder?: string; } +const INPUT_MODES: ReadonlyArray<{ mode: Mode; label: string; icon: IconName }> = [ + { mode: "chat", label: "对话", icon: "chat" }, + { mode: "code", label: "代码", icon: "terminal" }, + { mode: "home", label: "家居", icon: "home" }, + { mode: "work", label: "工作", icon: "folder" }, + { mode: "docs", label: "知识库", icon: "docs" }, + { mode: "vision", label: "视觉", icon: "vision" }, +]; + export function ChatInput({ onSend, sending, @@ -16,6 +28,8 @@ export function ChatInput({ }: ChatInputProps): React.ReactNode { const [value, setValue] = useState(""); const taRef = useRef(null); + const mode = useModeStore((s) => s.mode); + const setMode = useModeStore((s) => s.setMode); // auto-grow the textarea up to a max height useEffect(() => { @@ -28,12 +42,31 @@ export function ChatInput({ const submit = () => { const t = value.trim(); if (!t || sending) return; - onSend(t); + onSend(t, mode); setValue(""); }; return (
+ {/* input-mode switcher: sets the mode for the NEXT message (design/07 §1). */} +
+ 行为模式 + {INPUT_MODES.map(({ mode: m, label, icon }) => ( + + ))} +
+