189 lines
4.8 KiB
TypeScript
189 lines
4.8 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* 测试用例顶部紧凑模式选择器:固定脚本 / 用户模拟。
|
|
*/
|
|
|
|
import {
|
|
AudioLines,
|
|
Check,
|
|
ChevronDown,
|
|
MessageSquareText,
|
|
Mic,
|
|
Type,
|
|
Volume2,
|
|
} from "lucide-react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import {
|
|
TEST_CASE_INPUT_MODE_LABEL,
|
|
type TestCaseInputMode,
|
|
} from "@/data/test-suites";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const FIXED_SCRIPT_OPTIONS: {
|
|
value: TestCaseInputMode;
|
|
title: string;
|
|
description: string;
|
|
icon: typeof Type;
|
|
available: boolean;
|
|
}[] = [
|
|
{
|
|
value: "fixed_script_text",
|
|
title: "文字",
|
|
description: "使用固定文字逐轮测试",
|
|
icon: Type,
|
|
available: true,
|
|
},
|
|
{
|
|
value: "fixed_script_turn_voice",
|
|
title: "逐轮语音",
|
|
description: "固定文字自动合成为语音",
|
|
icon: Volume2,
|
|
available: false,
|
|
},
|
|
{
|
|
value: "fixed_script_continuous_voice",
|
|
title: "连续语音",
|
|
description: "按指定时序连续发送语音",
|
|
icon: AudioLines,
|
|
available: false,
|
|
},
|
|
];
|
|
|
|
const USER_SIM_OPTIONS: {
|
|
value: TestCaseInputMode;
|
|
title: string;
|
|
description: string;
|
|
icon: typeof MessageSquareText;
|
|
available: boolean;
|
|
}[] = [
|
|
{
|
|
value: "user_sim_text",
|
|
title: "文字",
|
|
description: "使用模型模拟文字用户",
|
|
icon: MessageSquareText,
|
|
available: false,
|
|
},
|
|
{
|
|
value: "user_sim_voice",
|
|
title: "语音",
|
|
description: "使用模型模拟语音用户",
|
|
icon: Mic,
|
|
available: false,
|
|
},
|
|
];
|
|
|
|
export function InputModePicker({
|
|
value,
|
|
onChange,
|
|
}: {
|
|
value: TestCaseInputMode;
|
|
onChange: (mode: TestCaseInputMode) => void;
|
|
}) {
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
size="sm"
|
|
className="h-9 max-w-[220px] shrink-0 gap-1.5 rounded-full border-hairline-strong bg-background px-3 text-xs font-normal text-foreground"
|
|
>
|
|
<span className="truncate">{TEST_CASE_INPUT_MODE_LABEL[value]}</span>
|
|
<ChevronDown size={14} className="shrink-0 text-muted-soft" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="start" className="w-72 p-1.5">
|
|
<DropdownMenuLabel className="px-2.5 py-1.5 text-[11px] font-medium tracking-wide text-muted-soft uppercase">
|
|
固定脚本
|
|
</DropdownMenuLabel>
|
|
{FIXED_SCRIPT_OPTIONS.map((option) => (
|
|
<ModeMenuItem
|
|
key={option.value}
|
|
selected={value === option.value}
|
|
title={option.title}
|
|
description={option.description}
|
|
icon={option.icon}
|
|
available={option.available}
|
|
onSelect={() => onChange(option.value)}
|
|
/>
|
|
))}
|
|
|
|
<DropdownMenuSeparator className="my-1.5" />
|
|
|
|
<DropdownMenuLabel className="px-2.5 py-1.5 text-[11px] font-medium tracking-wide text-muted-soft uppercase">
|
|
用户模拟
|
|
</DropdownMenuLabel>
|
|
{USER_SIM_OPTIONS.map((option) => (
|
|
<ModeMenuItem
|
|
key={option.value}
|
|
selected={value === option.value}
|
|
title={option.title}
|
|
description={option.description}
|
|
icon={option.icon}
|
|
available={option.available}
|
|
onSelect={() => onChange(option.value)}
|
|
/>
|
|
))}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|
|
|
|
function ModeMenuItem({
|
|
selected,
|
|
title,
|
|
description,
|
|
icon: Icon,
|
|
available,
|
|
onSelect,
|
|
}: {
|
|
selected: boolean;
|
|
title: string;
|
|
description: string;
|
|
icon: typeof Type;
|
|
available: boolean;
|
|
onSelect: () => void;
|
|
}) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
disabled={!available}
|
|
aria-disabled={!available}
|
|
title={available ? undefined : `${title}模式即将支持`}
|
|
onClick={available ? onSelect : undefined}
|
|
className={cn(
|
|
"flex w-full items-start gap-2.5 rounded-lg px-2.5 py-2 text-left transition-colors",
|
|
available
|
|
? "hover:bg-surface-strong"
|
|
: "cursor-not-allowed opacity-55",
|
|
selected && "bg-surface-strong/80",
|
|
)}
|
|
>
|
|
<Icon size={15} className="mt-0.5 shrink-0 text-muted-foreground" />
|
|
<span className="min-w-0 flex-1">
|
|
<span className="flex items-center gap-1.5 text-sm font-medium text-foreground">
|
|
{title}
|
|
{selected && <Check size={13} className="text-muted-foreground" />}
|
|
{!available && (
|
|
<span className="ml-auto text-[11px] font-normal text-muted-soft">
|
|
即将支持
|
|
</span>
|
|
)}
|
|
</span>
|
|
<span className="mt-0.5 block text-xs leading-4 text-muted-soft">
|
|
{description}
|
|
</span>
|
|
</span>
|
|
</button>
|
|
);
|
|
}
|