feat: 数据格式改为按钮组选择

- 移除 Select 下拉框
- 改为 JSON/CSV 按钮组
- 选中状态与生成数量按钮样式统一

feat: 优化空值率设置

- 增加 75% 预设选项
- 设置 100% 时自动设为必填
- 限制输入范围 0-100

fix: 空值率预设改为纯数字显示

- 5%/20%/50%/75% 统一样式

fix: 移除空值率低/中/高 i18n 翻译键

fix: 精简生成数量预设选项

- 移除 10、500
- 保留 50、100、1000、5000、10000
This commit is contained in:
雨霖铃
2026-06-06 10:47:01 +08:00
parent ea10b27c14
commit a374bf456d
3 changed files with 39 additions and 34 deletions
@@ -38,7 +38,14 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
};
const handleNullRateChange = (nullRate: number) => {
onChange({ ...field, nullRate });
// 限制范围 0-100
const clampedRate = Math.max(0, Math.min(100, nullRate));
// 设置为 100% 时自动设为必填
if (clampedRate === 100) {
onChange({ ...field, nullRate: clampedRate, required: true });
} else {
onChange({ ...field, nullRate: clampedRate });
}
};
const handleUniqueChange = (unique: boolean) => {
@@ -63,9 +70,10 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
};
const nullRatePresets = [
{ label: t('testDataGenerator_nullRateLow'), value: 5 },
{ label: t('testDataGenerator_nullRateMedium'), value: 20 },
{ label: t('testDataGenerator_nullRateHigh'), value: 50 },
{ label: '5%', value: 5 },
{ label: '20%', value: 20 },
{ label: '50%', value: 50 },
{ label: '75%', value: 75 },
];
return (
@@ -129,7 +137,12 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
<Input
type="number"
value={field.nullRate}
onChange={(e) => handleNullRateChange(Number(e.target.value))}
onChange={(e) => {
const value = Number(e.target.value);
if (value >= 0 && value <= 100) {
handleNullRateChange(value);
}
}}
min={0}
max={100}
step={5}
@@ -5,13 +5,6 @@
import { useI18n } from '@/utils/chromeI18n';
import { Input } from '@/components/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
interface GenerateOptionsProps {
count: number;
@@ -22,7 +15,12 @@ interface GenerateOptionsProps {
onDefaultNullRateChange: (rate: number) => void;
}
const COUNT_PRESETS = [10, 50, 100, 500, 1000, 5000, 10000];
const COUNT_PRESETS = [50, 100, 1000, 5000, 10000];
const FORMAT_OPTIONS = [
{ value: 'json' as const, label: 'JSON' },
{ value: 'csv' as const, label: 'CSV' },
];
export default function GenerateOptions({
count,
@@ -76,15 +74,21 @@ export default function GenerateOptions({
<label className="text-sm font-medium text-foreground">
{t('testDataGenerator_format')}
</label>
<Select value={format} onValueChange={(v) => onFormatChange(v as 'json' | 'csv')}>
<SelectTrigger className="h-9">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="json">JSON</SelectItem>
<SelectItem value="csv">CSV</SelectItem>
</SelectContent>
</Select>
<div className="flex gap-2">
{FORMAT_OPTIONS.map((option) => (
<button
key={option.value}
onClick={() => onFormatChange(option.value)}
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
format === option.value
? 'bg-primary text-primary-foreground'
: 'bg-muted text-muted-foreground hover:bg-muted/80'
}`}
>
{option.label}
</button>
))}
</div>
</div>
{/* 默认空值率 */}