Implement assistant type selection and creation flow in AssistantPage
Added a new selection step for assistant types, allowing users to choose between different construction methods (提示词, 工作流, Dify, FastGPT) before creating an assistant. Enhanced the UI to display options with descriptions and icons, and updated the state management to handle the new view for selecting assistant types. This improves the user experience by guiding users through the assistant creation process.
This commit is contained in:
@@ -2,7 +2,11 @@
|
||||
|
||||
import {
|
||||
Bot,
|
||||
Boxes,
|
||||
Brain,
|
||||
Check,
|
||||
Database,
|
||||
MessageSquareText,
|
||||
Mic,
|
||||
MoreHorizontal,
|
||||
Pencil,
|
||||
@@ -11,6 +15,7 @@ import {
|
||||
Search,
|
||||
Sparkles,
|
||||
Trash2,
|
||||
Workflow,
|
||||
} from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -53,6 +58,46 @@ type AssistantForm = {
|
||||
|
||||
type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT";
|
||||
|
||||
type AssistantTypeOption = {
|
||||
type: AssistantType;
|
||||
label: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
/** 提示词类型已落地,其余三种暂时显示占位页 */
|
||||
available: boolean;
|
||||
};
|
||||
|
||||
const assistantTypeOptions: AssistantTypeOption[] = [
|
||||
{
|
||||
type: "提示词",
|
||||
label: "使用提示词构建",
|
||||
description: "通过提示词、模型与语音快速搭建对话助手,适合大多数场景。",
|
||||
icon: <MessageSquareText size={20} />,
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
type: "工作流",
|
||||
label: "使用工作流构建",
|
||||
description: "用可视化编排串联多个节点,适合多步骤、带分支的复杂流程。",
|
||||
icon: <Workflow size={20} />,
|
||||
available: false,
|
||||
},
|
||||
{
|
||||
type: "Dify",
|
||||
label: "使用 Dify 构建",
|
||||
description: "对接 Dify 应用,复用其编排能力与知识库配置。",
|
||||
icon: <Boxes size={20} />,
|
||||
available: false,
|
||||
},
|
||||
{
|
||||
type: "FastGPT",
|
||||
label: "使用 FastGPT 构建",
|
||||
description: "对接 FastGPT 应用,复用其知识库问答与工作流能力。",
|
||||
icon: <Database size={20} />,
|
||||
available: false,
|
||||
},
|
||||
];
|
||||
|
||||
type AssistantListItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -100,8 +145,34 @@ export function AssistantPage() {
|
||||
knowledgeBase: "政务政策知识库",
|
||||
enableInterrupt: true,
|
||||
});
|
||||
const [view, setView] = useState<"list" | "create">("list");
|
||||
const [view, setView] = useState<"list" | "choose" | "create" | "placeholder">(
|
||||
"list",
|
||||
);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
// choose 步骤的草稿:名称与已选类型,确认后才决定进入哪个构建页
|
||||
const [draftName, setDraftName] = useState("");
|
||||
const [draftType, setDraftType] = useState<AssistantType | null>(null);
|
||||
|
||||
function startCreate() {
|
||||
setDraftName("");
|
||||
setDraftType(null);
|
||||
setView("choose");
|
||||
}
|
||||
|
||||
function confirmType() {
|
||||
if (!draftName.trim() || !draftType) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (draftType === "提示词") {
|
||||
// 提示词类型:复用现有创建表单,并把已填的名称带过去
|
||||
updateForm("name", draftName.trim());
|
||||
setView("create");
|
||||
} else {
|
||||
// 工作流 / Dify / FastGPT:暂时显示占位页
|
||||
setView("placeholder");
|
||||
}
|
||||
}
|
||||
|
||||
const filteredAssistants = mockAssistants.filter((assistant) => {
|
||||
const keyword = searchQuery.trim().toLowerCase();
|
||||
@@ -140,7 +211,7 @@ export function AssistantPage() {
|
||||
<Button
|
||||
size="lg"
|
||||
className="w-full shrink-0 gap-2 sm:w-auto"
|
||||
onClick={() => setView("create")}
|
||||
onClick={startCreate}
|
||||
>
|
||||
<Plus size={16} />
|
||||
创建助手
|
||||
@@ -272,6 +343,189 @@ export function AssistantPage() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (view === "choose") {
|
||||
const selectedOption = assistantTypeOptions.find(
|
||||
(option) => option.type === draftType,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex w-full max-w-[920px] flex-col gap-8">
|
||||
<div className="flex items-start justify-between gap-6">
|
||||
<div>
|
||||
<div className="caption-label text-muted-soft">新建助手</div>
|
||||
<h1 className="font-display display-lg mt-3 text-ink">创建助手</h1>
|
||||
<p className="mt-3 max-w-2xl text-[15px] leading-7 text-muted-foreground">
|
||||
先为助手取个名字,再选择构建方式。不同方式将进入不同的构建流程。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="shrink-0 border-hairline-strong text-muted-foreground hover:text-foreground"
|
||||
onClick={() => setView("list")}
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<section className="rounded-2xl border border-hairline bg-card p-6 shadow-sm">
|
||||
<label className="block">
|
||||
<div className="mb-2 text-sm font-medium text-foreground">
|
||||
助手名称
|
||||
</div>
|
||||
<Input
|
||||
value={draftName}
|
||||
autoFocus
|
||||
onChange={(event) => setDraftName(event.target.value)}
|
||||
placeholder="请输入助手名称"
|
||||
className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
|
||||
/>
|
||||
</label>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-4">
|
||||
<div className="text-sm font-medium text-foreground">构建方式</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
{assistantTypeOptions.map((option) => {
|
||||
const selected = draftType === option.type;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={option.type}
|
||||
type="button"
|
||||
onClick={() => setDraftType(option.type)}
|
||||
className={`group relative flex flex-col gap-4 rounded-2xl border bg-card p-5 text-left transition-colors ${
|
||||
selected
|
||||
? "border-primary ring-1 ring-primary"
|
||||
: "border-hairline hover:border-hairline-strong"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex h-11 w-11 items-center justify-center rounded-full bg-surface-strong text-foreground">
|
||||
{option.icon}
|
||||
</div>
|
||||
|
||||
{selected ? (
|
||||
<span className="flex h-6 w-6 items-center justify-center rounded-full bg-primary text-primary-foreground">
|
||||
<Check size={14} />
|
||||
</span>
|
||||
) : (
|
||||
!option.available && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-6 bg-surface-strong px-3 text-xs text-muted-foreground"
|
||||
>
|
||||
即将上线
|
||||
</Badge>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-base font-medium text-foreground">
|
||||
{option.label}
|
||||
</div>
|
||||
<p className="mt-1.5 text-sm leading-6 text-muted-foreground">
|
||||
{option.description}
|
||||
</p>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="border-hairline-strong text-muted-foreground hover:text-foreground"
|
||||
onClick={() => setView("list")}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
size="lg"
|
||||
className="gap-2"
|
||||
disabled={!draftName.trim() || !draftType}
|
||||
onClick={confirmType}
|
||||
>
|
||||
<Rocket size={16} />
|
||||
{selectedOption && !selectedOption.available
|
||||
? "下一步"
|
||||
: "开始构建"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (view === "placeholder") {
|
||||
const option = assistantTypeOptions.find(
|
||||
(item) => item.type === draftType,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex w-full max-w-[1180px] flex-col gap-6">
|
||||
<div className="flex items-start justify-between gap-6">
|
||||
<div>
|
||||
<div className="caption-label text-muted-soft">
|
||||
{option?.label ?? "新建助手"}
|
||||
</div>
|
||||
<h1 className="font-display display-lg mt-3 text-ink">
|
||||
{draftName.trim() || "创建助手"}
|
||||
</h1>
|
||||
<p className="mt-3 max-w-2xl text-[15px] leading-7 text-muted-foreground">
|
||||
{draftType} 构建方式正在开发中,敬请期待。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="shrink-0 border-hairline-strong text-muted-foreground hover:text-foreground"
|
||||
onClick={() => setView("list")}
|
||||
>
|
||||
返回列表
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<section className="relative overflow-hidden rounded-3xl border border-hairline bg-canvas-soft px-10 py-20 text-center">
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute -right-24 top-0 h-72 w-72 rounded-full opacity-50 blur-3xl"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, color-mix(in srgb, var(--gradient-sky) 50%, transparent), transparent 70%)",
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute -left-20 bottom-0 h-64 w-64 rounded-full opacity-45 blur-3xl"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle, color-mix(in srgb, var(--gradient-lavender) 50%, transparent), transparent 70%)",
|
||||
}}
|
||||
/>
|
||||
<div className="relative">
|
||||
<div className="caption-label inline-flex rounded-full bg-surface-strong px-3 py-1 text-muted-foreground">
|
||||
建设中
|
||||
</div>
|
||||
<p className="font-display display-sm mx-auto mt-5 max-w-md text-ink">
|
||||
{draftType} 构建页面正在编写中
|
||||
</p>
|
||||
<p className="mx-auto mt-3 max-w-md text-sm leading-7 text-body">
|
||||
页面骨架与设计语言已就绪,后续将填充具体构建流程与数据。
|
||||
</p>
|
||||
</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">
|
||||
|
||||
Reference in New Issue
Block a user