129 lines
4.8 KiB
TypeScript
129 lines
4.8 KiB
TypeScript
"use client";
|
|||
|
|
|
||
|
|
import { MessageSquareText } from "lucide-react";
|
||
|
|
|
||
|
|
import { SectionCard } from "@/components/editor/section-card";
|
||
|
|
import { Input } from "@/components/ui/input";
|
||
|
|
import { Switch } from "@/components/ui/switch";
|
||
|
|
import { Textarea } from "@/components/ui/textarea";
|
||
|
|
|
||
|
|
import type { WorkflowNodeData } from "../specs";
|
||
|
|
|
||
|
|
export function MessageNodePanel({
|
||
|
|
draft,
|
||
|
|
set,
|
||
|
|
setPatch,
|
||
|
|
}: {
|
||
|
|
draft: WorkflowNodeData;
|
||
|
|
set: (key: string, value: unknown) => void;
|
||
|
|
setPatch: (patch: Partial<WorkflowNodeData>) => void;
|
||
|
|
}) {
|
||
|
|
const showMessage = Boolean(draft.showMessage);
|
||
|
|
const requireConfirmation = Boolean(draft.requireConfirmation);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<SectionCard
|
||
|
|
icon={<MessageSquareText size={15} />}
|
||
|
|
title="播报与确认"
|
||
|
|
description="播放固定话术,并可同时显示平台内置的客户端消息"
|
||
|
|
>
|
||
|
|
<label className="block">
|
||
|
|
<div className="mb-1.5 text-sm font-medium text-foreground">
|
||
|
|
固定播报(可选)
|
||
|
|
</div>
|
||
|
|
<Textarea
|
||
|
|
rows={4}
|
||
|
|
value={draft.speech ?? ""}
|
||
|
|
onChange={(event) => set("speech", event.target.value)}
|
||
|
|
placeholder="例如:您好,在开始服务前请确认以下重要信息。"
|
||
|
|
className="field-sizing-fixed min-h-28 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
|
||
|
|
/>
|
||
|
|
<span className="mt-1.5 block text-xs leading-5 text-muted-foreground">
|
||
|
|
支持 {"{{variable}}"} 动态变量。仅播报时,播放完成后进入下一节点。
|
||
|
|
</span>
|
||
|
|
</label>
|
||
|
|
|
||
|
|
<label className="flex items-start justify-between gap-4 rounded-xl border border-hairline bg-canvas-soft px-4 py-3">
|
||
|
|
<span>
|
||
|
|
<span className="block text-sm font-medium text-foreground">
|
||
|
|
显示客户端消息
|
||
|
|
</span>
|
||
|
|
<span className="mt-1 block text-xs leading-5 text-muted-foreground">
|
||
|
|
使用平台内置弹窗,不需要创建或绑定 Client Tool。
|
||
|
|
</span>
|
||
|
|
</span>
|
||
|
|
<Switch
|
||
|
|
checked={showMessage}
|
||
|
|
onCheckedChange={(checked) =>
|
||
|
|
setPatch({
|
||
|
|
showMessage: checked,
|
||
|
|
...(!checked ? { requireConfirmation: false } : {}),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
|
||
|
|
{showMessage && (
|
||
|
|
<div className="space-y-3 rounded-xl border border-hairline bg-canvas-soft p-4">
|
||
|
|
<label className="block">
|
||
|
|
<span className="mb-1.5 block text-sm font-medium text-foreground">
|
||
|
|
弹窗标题
|
||
|
|
</span>
|
||
|
|
<Input
|
||
|
|
value={draft.title ?? ""}
|
||
|
|
onChange={(event) => set("title", event.target.value)}
|
||
|
|
placeholder="重要提示"
|
||
|
|
className="border-hairline-strong bg-background"
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
<label className="block">
|
||
|
|
<span className="mb-1.5 block text-sm font-medium text-foreground">
|
||
|
|
重要信息 <span className="text-destructive">*</span>
|
||
|
|
</span>
|
||
|
|
<Textarea
|
||
|
|
rows={4}
|
||
|
|
value={draft.message ?? ""}
|
||
|
|
onChange={(event) => set("message", event.target.value)}
|
||
|
|
placeholder="请输入需要向用户展示的重要信息"
|
||
|
|
className="field-sizing-fixed min-h-28 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
<label className="block">
|
||
|
|
<span className="mb-1.5 block text-sm font-medium text-foreground">
|
||
|
|
按钮文字
|
||
|
|
</span>
|
||
|
|
<Input
|
||
|
|
value={draft.confirmLabel ?? ""}
|
||
|
|
onChange={(event) => set("confirmLabel", event.target.value)}
|
||
|
|
placeholder="确认"
|
||
|
|
className="border-hairline-strong bg-background"
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
<label className="flex items-start justify-between gap-4 border-t border-hairline pt-3">
|
||
|
|
<span>
|
||
|
|
<span className="block text-sm font-medium text-foreground">
|
||
|
|
等待用户确认
|
||
|
|
</span>
|
||
|
|
<span className="mt-1 block text-xs leading-5 text-muted-foreground">
|
||
|
|
确认前禁止语音、文字和图片输入;确认后立即进入下一节点,不等待播报结束。
|
||
|
|
</span>
|
||
|
|
</span>
|
||
|
|
<Switch
|
||
|
|
checked={requireConfirmation}
|
||
|
|
onCheckedChange={(checked) =>
|
||
|
|
set("requireConfirmation", checked)
|
||
|
|
}
|
||
|
|
/>
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{!draft.speech?.trim() && !showMessage && (
|
||
|
|
<p role="alert" className="text-xs leading-5 text-destructive">
|
||
|
|
Message 至少需要固定播报或客户端消息。
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</SectionCard>
|
||
|
|
);
|
||
|
|
}
|