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:
@@ -971,18 +971,6 @@
|
|||||||
"message": "空值率",
|
"message": "空值率",
|
||||||
"description": "Translation key: testDataGenerator_nullRate"
|
"description": "Translation key: testDataGenerator_nullRate"
|
||||||
},
|
},
|
||||||
"testDataGenerator_nullRateLow": {
|
|
||||||
"message": "低 (5%)",
|
|
||||||
"description": "Translation key: testDataGenerator_nullRateLow"
|
|
||||||
},
|
|
||||||
"testDataGenerator_nullRateMedium": {
|
|
||||||
"message": "中 (20%)",
|
|
||||||
"description": "Translation key: testDataGenerator_nullRateMedium"
|
|
||||||
},
|
|
||||||
"testDataGenerator_nullRateHigh": {
|
|
||||||
"message": "高 (50%)",
|
|
||||||
"description": "Translation key: testDataGenerator_nullRateHigh"
|
|
||||||
},
|
|
||||||
"testDataGenerator_uniqueConstraint": {
|
"testDataGenerator_uniqueConstraint": {
|
||||||
"message": "唯一性约束",
|
"message": "唯一性约束",
|
||||||
"description": "Translation key: testDataGenerator_uniqueConstraint"
|
"description": "Translation key: testDataGenerator_uniqueConstraint"
|
||||||
|
|||||||
@@ -38,7 +38,14 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleNullRateChange = (nullRate: number) => {
|
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) => {
|
const handleUniqueChange = (unique: boolean) => {
|
||||||
@@ -63,9 +70,10 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const nullRatePresets = [
|
const nullRatePresets = [
|
||||||
{ label: t('testDataGenerator_nullRateLow'), value: 5 },
|
{ label: '5%', value: 5 },
|
||||||
{ label: t('testDataGenerator_nullRateMedium'), value: 20 },
|
{ label: '20%', value: 20 },
|
||||||
{ label: t('testDataGenerator_nullRateHigh'), value: 50 },
|
{ label: '50%', value: 50 },
|
||||||
|
{ label: '75%', value: 75 },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -129,7 +137,12 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
|||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
value={field.nullRate}
|
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}
|
min={0}
|
||||||
max={100}
|
max={100}
|
||||||
step={5}
|
step={5}
|
||||||
|
|||||||
@@ -5,13 +5,6 @@
|
|||||||
|
|
||||||
import { useI18n } from '@/utils/chromeI18n';
|
import { useI18n } from '@/utils/chromeI18n';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from '@/components/ui/select';
|
|
||||||
|
|
||||||
interface GenerateOptionsProps {
|
interface GenerateOptionsProps {
|
||||||
count: number;
|
count: number;
|
||||||
@@ -22,7 +15,12 @@ interface GenerateOptionsProps {
|
|||||||
onDefaultNullRateChange: (rate: number) => void;
|
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({
|
export default function GenerateOptions({
|
||||||
count,
|
count,
|
||||||
@@ -76,15 +74,21 @@ export default function GenerateOptions({
|
|||||||
<label className="text-sm font-medium text-foreground">
|
<label className="text-sm font-medium text-foreground">
|
||||||
{t('testDataGenerator_format')}
|
{t('testDataGenerator_format')}
|
||||||
</label>
|
</label>
|
||||||
<Select value={format} onValueChange={(v) => onFormatChange(v as 'json' | 'csv')}>
|
<div className="flex gap-2">
|
||||||
<SelectTrigger className="h-9">
|
{FORMAT_OPTIONS.map((option) => (
|
||||||
<SelectValue />
|
<button
|
||||||
</SelectTrigger>
|
key={option.value}
|
||||||
<SelectContent>
|
onClick={() => onFormatChange(option.value)}
|
||||||
<SelectItem value="json">JSON</SelectItem>
|
className={`flex-1 px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
|
||||||
<SelectItem value="csv">CSV</SelectItem>
|
format === option.value
|
||||||
</SelectContent>
|
? 'bg-primary text-primary-foreground'
|
||||||
</Select>
|
: 'bg-muted text-muted-foreground hover:bg-muted/80'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 默认空值率 */}
|
{/* 默认空值率 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user