Refactor Assistant navigation and update HomePage button

Updated the AppShell and Sidebar components to streamline navigation for the Assistant section, consolidating assistant-related pages under a single "assistants" key. Removed deprecated assistant sub-items and adjusted the HomePage button to link to the new assistant navigation. Enhanced the AssistantPage with a list view for managing assistants, including mock data for demonstration.
This commit is contained in:
Xin Wang
2026-06-05 16:58:13 +08:00
parent 66e75fa856
commit 1794957bb1
4 changed files with 189 additions and 61 deletions

View File

@@ -6,7 +6,6 @@ import { Topbar } from "./Topbar";
import { HomePage } from "@/components/pages/HomePage"; import { HomePage } from "@/components/pages/HomePage";
import { AssistantPage } from "@/components/pages/AssistantPage"; import { AssistantPage } from "@/components/pages/AssistantPage";
import { AssistantWorkflowPage } from "@/components/pages/AssistantWorkflowPage";
import { ComponentsModelsPage } from "@/components/pages/ComponentsModelsPage"; import { ComponentsModelsPage } from "@/components/pages/ComponentsModelsPage";
import { ComponentsKnowledgePage } from "@/components/pages/ComponentsKnowledgePage"; import { ComponentsKnowledgePage } from "@/components/pages/ComponentsKnowledgePage";
import { ComponentsToolsPage } from "@/components/pages/ComponentsToolsPage"; import { ComponentsToolsPage } from "@/components/pages/ComponentsToolsPage";
@@ -17,8 +16,7 @@ import { ProfilePage } from "@/components/pages/ProfilePage";
export type NavKey = export type NavKey =
| "home" | "home"
| "assistant-prompt" | "assistants"
| "assistant-workflow"
| "components-models" | "components-models"
| "components-knowledge" | "components-knowledge"
| "components-tools" | "components-tools"
@@ -46,10 +44,7 @@ export function AppShell() {
<div className="flex-1 overflow-y-auto px-8 py-10"> <div className="flex-1 overflow-y-auto px-8 py-10">
{active === "home" && <HomePage onNavigate={setActive} />} {active === "home" && <HomePage onNavigate={setActive} />}
{active === "assistants" && <AssistantPage />}
{active === "assistant-prompt" && <AssistantPage />}
{active === "assistant-workflow" && <AssistantWorkflowPage />}
{active === "components-models" && <ComponentsModelsPage />} {active === "components-models" && <ComponentsModelsPage />}
{active === "components-knowledge" && <ComponentsKnowledgePage />} {active === "components-knowledge" && <ComponentsKnowledgePage />}
{active === "components-tools" && <ComponentsToolsPage />} {active === "components-tools" && <ComponentsToolsPage />}

View File

@@ -9,7 +9,6 @@ import {
Clock3, Clock3,
Database, Database,
Wrench, Wrench,
FileText,
Home, Home,
PlayCircle, PlayCircle,
Video, Video,
@@ -34,15 +33,6 @@ const mainItems: Array<{
{ key: "test", label: "测试助手", icon: PlayCircle }, { key: "test", label: "测试助手", icon: PlayCircle },
]; ];
const assistantSubItems: Array<{
key: NavKey;
label: string;
icon: React.ComponentType<{ size?: number }>;
}> = [
{ key: "assistant-prompt", label: "提示词模式", icon: FileText },
{ key: "assistant-workflow", label: "工作流模式", icon: Workflow },
];
const componentSubItems: Array<{ const componentSubItems: Array<{
key: NavKey; key: NavKey;
label: string; label: string;
@@ -59,8 +49,7 @@ export function Sidebar({
onNavigate, onNavigate,
onToggle, onToggle,
}: SidebarProps) { }: SidebarProps) {
const assistantActive = const assistantActive = active === "assistants";
active === "assistant-prompt" || active === "assistant-workflow";
const componentActive = const componentActive =
active === "components-models" || active === "components-knowledge" || active === "components-tools"; active === "components-models" || active === "components-knowledge" || active === "components-tools";
@@ -106,46 +95,14 @@ export function Sidebar({
label="控制台" label="控制台"
onClick={() => onNavigate("home")} onClick={() => onNavigate("home")}
/> />
<div className="pt-2"> <div className="pt-2">
{collapsed ? ( <NavButton
<div active={assistantActive}
className="flex h-8 items-center justify-center" collapsed={collapsed}
aria-hidden="true" icon={Bot}
title="创建助手" label="创建助手"
> onClick={() => onNavigate("assistants")}
<span className="h-px w-6 rounded-full bg-hairline-strong" /> />
</div>
) : (
<div
className={[
"flex h-11 w-full items-center gap-3 rounded-full px-3 text-sm",
assistantActive ? "text-foreground" : "text-muted-foreground",
].join(" ")}
>
<Bot size={18} />
<span className="font-medium"></span>
</div>
)}
<div
className={[
"mt-1 space-y-1 transition-[padding] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]",
collapsed ? "pl-0" : "pl-5",
].join(" ")}
>
{assistantSubItems.map((item) => (
<NavButton
key={item.key}
active={active === item.key}
collapsed={collapsed}
icon={item.icon}
label={item.label}
onClick={() => onNavigate(item.key)}
small
/>
))}
</div>
</div> </div>
<div className="pt-2"> <div className="pt-2">

View File

@@ -1,13 +1,19 @@
"use client"; "use client";
import { useState } from "react";
import { import {
Bot, Bot,
Brain, Brain,
Database,
Mic, Mic,
MoreHorizontal,
Pencil,
Plus,
Rocket, Rocket,
Save, Save,
Search,
Sparkles, Sparkles,
Trash2,
Volume2,
} from "lucide-react"; } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -28,6 +34,7 @@ import {
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import { useState } from "react";
type AssistantForm = { type AssistantForm = {
name: string; name: string;
@@ -40,6 +47,47 @@ type AssistantForm = {
enableInterrupt: boolean; enableInterrupt: boolean;
}; };
type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT";
type AssistantListItem = {
id: string;
name: string;
type: AssistantType;
status: "运行中" | "草稿" | "已停用";
updatedAt: string;
};
const mockAssistants: AssistantListItem[] = [
{
id: "asst_001",
name: "政务视频咨询助手",
type: "提示词",
status: "运行中",
updatedAt: "2026-06-05 18:20",
},
{
id: "asst_002",
name: "热线工单辅助助手",
type: "工作流",
status: "草稿",
updatedAt: "2026-06-04 15:12",
},
{
id: "asst_003",
name: "Dify 知识库问答助手",
type: "Dify",
status: "运行中",
updatedAt: "2026-06-02 09:48",
},
{
id: "asst_004",
name: "FastGPT 售后咨询助手",
type: "FastGPT",
status: "已停用",
updatedAt: "2026-05-29 11:06",
},
];
export function AssistantPage() { export function AssistantPage() {
const [form, setForm] = useState<AssistantForm>({ const [form, setForm] = useState<AssistantForm>({
@@ -53,6 +101,8 @@ export function AssistantPage() {
knowledgeBase: "政务政策知识库", knowledgeBase: "政务政策知识库",
enableInterrupt: true, enableInterrupt: true,
}); });
const [view, setView] = useState<"list" | "create">("list");
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
function updateForm<K extends keyof AssistantForm>( function updateForm<K extends keyof AssistantForm>(
key: K, key: K,
@@ -63,7 +113,125 @@ export function AssistantPage() {
[key]: value, [key]: value,
})); }));
} }
if (view === "list") {
return (
<div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6">
<div className="flex items-start justify-between">
<div>
<div className="flex items-center gap-3">
<span className="h-3 w-3 rounded-full bg-blue-400 shadow-[0_0_0_4px_rgba(46,161,255,.16),0_0_14px_rgba(46,161,255,.35)]" />
<h1 className="text-3xl font-bold"></h1>
</div>
<p className="mt-2 text-sm text-muted-soft">
Dify FastGPT
</p>
</div>
<button
onClick={() => setView("create")}
className="flex h-10 items-center gap-2 rounded-xl bg-blue-500 px-4 text-sm font-semibold text-white shadow-[0_8px_24px_rgba(29,123,255,.35)]"
>
<Plus size={16} />
</button>
</div>
<section className="rounded-2xl border border-sidebar-border bg-sidebar p-5">
<div className="mb-5 flex items-center justify-between gap-4">
<div>
<div className="text-lg font-semibold"></div>
<div className="mt-1 text-sm text-muted-soft">
{mockAssistants.length}
</div>
</div>
<div className="flex h-10 w-[280px] items-center gap-3 rounded-xl border border-hairline-strong bg-surface-strong/60 px-3 text-sm text-muted-soft">
<Search size={16} />
<span>...</span>
</div>
</div>
<div className="overflow-hidden rounded-2xl border border-hairline-strong">
<div className="grid grid-cols-[1fr_120px_120px_160px_120px] bg-surface-strong/70 px-5 py-3 text-xs font-medium text-muted-soft">
<div></div>
<div></div>
<div></div>
<div></div>
<div className="text-right"></div>
</div>
<div className="divide-y divide-hairline-strong">
{mockAssistants.map((assistant) => (
<div
key={assistant.id}
className="grid grid-cols-[1fr_120px_120px_160px_120px] items-center px-5 py-4 text-sm transition-colors hover:bg-sidebar-accent/30"
>
<div>
<div className="font-medium text-foreground">
{assistant.name}
</div>
<div className="mt-1 text-xs text-muted-soft">
{assistant.id}
</div>
</div>
<div>
<span className="rounded-full border border-hairline-strong bg-surface-strong px-2.5 py-1 text-xs text-muted-foreground">
{assistant.type}
</span>
</div>
<div>
<span
className={[
"rounded-full px-2.5 py-1 text-xs",
assistant.status === "运行中"
? "bg-green-500/10 text-green-400"
: assistant.status === "草稿"
? "bg-yellow-500/10 text-yellow-400"
: "bg-muted/30 text-muted-foreground",
].join(" ")}
>
{assistant.status}
</span>
</div>
<div className="text-muted-soft">{assistant.updatedAt}</div>
<div className="relative flex justify-end gap-2">
<button className="flex h-8 items-center gap-1 rounded-lg border border-hairline-strong px-3 text-xs text-muted-foreground transition-colors hover:bg-sidebar-accent hover:text-foreground">
<Pencil size={14} />
</button>
<button
onClick={() =>
setOpenMenuId(
openMenuId === assistant.id ? null : assistant.id,
)
}
className="flex h-8 w-8 items-center justify-center rounded-lg border border-hairline-strong text-muted-foreground transition-colors hover:bg-sidebar-accent hover:text-foreground"
>
<MoreHorizontal size={15} />
</button>
{openMenuId === assistant.id && (
<div className="absolute right-0 top-9 z-10 w-28 rounded-xl border border-hairline-strong bg-sidebar p-1 shadow-xl">
<button className="flex h-9 w-full items-center gap-2 rounded-lg px-3 text-sm text-red-400 transition-colors hover:bg-red-500/10">
<Trash2 size={14} />
</button>
</div>
)}
</div>
</div>
))}
</div>
</div>
</section>
</div>
);
}
return ( return (
<div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6"> <div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6">
<div className="flex items-start justify-between gap-6"> <div className="flex items-start justify-between gap-6">
@@ -78,6 +246,14 @@ export function AssistantPage() {
</div> </div>
<div className="flex shrink-0 gap-3"> <div className="flex shrink-0 gap-3">
<Button
variant="outline"
size="lg"
className="gap-2 border-hairline-strong text-muted-foreground hover:text-foreground"
onClick={() => setView("list")}
>
</Button>
<Button <Button
variant="outline" variant="outline"
size="lg" size="lg"

View File

@@ -44,7 +44,7 @@ export function HomePage({ onNavigate }: HomePageProps) {
<Button <Button
size="lg" size="lg"
className="gap-2 px-5" className="gap-2 px-5"
onClick={() => onNavigate("assistant-prompt")} onClick={() => onNavigate("assistants")}
> >
<Plus size={17} /> <Plus size={17} />