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

View File

@@ -9,7 +9,6 @@ import {
Clock3,
Database,
Wrench,
FileText,
Home,
PlayCircle,
Video,
@@ -34,15 +33,6 @@ const mainItems: Array<{
{ 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<{
key: NavKey;
label: string;
@@ -59,8 +49,7 @@ export function Sidebar({
onNavigate,
onToggle,
}: SidebarProps) {
const assistantActive =
active === "assistant-prompt" || active === "assistant-workflow";
const assistantActive = active === "assistants";
const componentActive =
active === "components-models" || active === "components-knowledge" || active === "components-tools";
@@ -106,46 +95,14 @@ export function Sidebar({
label="控制台"
onClick={() => onNavigate("home")}
/>
<div className="pt-2">
{collapsed ? (
<div
className="flex h-8 items-center justify-center"
aria-hidden="true"
title="创建助手"
>
<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>
<NavButton
active={assistantActive}
collapsed={collapsed}
icon={Bot}
label="创建助手"
onClick={() => onNavigate("assistants")}
/>
</div>
<div className="pt-2">

View File

@@ -1,13 +1,19 @@
"use client";
import { useState } from "react";
import {
Bot,
Brain,
Database,
Mic,
MoreHorizontal,
Pencil,
Plus,
Rocket,
Save,
Search,
Sparkles,
Trash2,
Volume2,
} from "lucide-react";
import { Button } from "@/components/ui/button";
@@ -28,6 +34,7 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { useState } from "react";
type AssistantForm = {
name: string;
@@ -40,6 +47,47 @@ type AssistantForm = {
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() {
const [form, setForm] = useState<AssistantForm>({
@@ -53,6 +101,8 @@ export function AssistantPage() {
knowledgeBase: "政务政策知识库",
enableInterrupt: true,
});
const [view, setView] = useState<"list" | "create">("list");
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
function updateForm<K extends keyof AssistantForm>(
key: K,
@@ -63,7 +113,125 @@ export function AssistantPage() {
[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 (
<div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6">
<div className="flex items-start justify-between gap-6">
@@ -78,6 +246,14 @@ export function AssistantPage() {
</div>
<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
variant="outline"
size="lg"

View File

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