feat: 简化字段卡片交互 - 点击直接打开编辑弹窗
- 移除字段卡片选中样式 - 点击字段直接打开编辑弹窗 - 简化 FieldItem 组件,移除 isSelected 属性 - 简化 FieldList 接口,onSelect 改为 onEdit fix: 优化字段编辑弹窗 - 去除弹窗描述文字 - 字段名称增加字符计数 (x/20) - 字段描述增加字符计数 (x/50) - 保持 placeholder 提示 fix: 修复弹窗顶部间距问题 - DialogContent 添加 pt-6 避开关闭按钮 - 内容区域移除顶部 padding,改为 pb-6 fix: 增加弹窗顶部间距 (pt-6 → pt-8) fix: 优化弹窗尺寸和按钮间距 - 弹窗最大宽度 360→420px 适配标签页 - 增加按钮 padding (px-2→px-3, py-1→py-1.5) - 添加按钮增加 padding (h-8→h-9, px-3)
This commit is contained in:
@@ -73,9 +73,12 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
||||
{/* 基础配置 */}
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-foreground">
|
||||
{t('testDataGenerator_fieldName')}
|
||||
</label>
|
||||
<span className="text-xs text-muted-foreground">{field.name.length}/20</span>
|
||||
</div>
|
||||
<Input
|
||||
value={field.name}
|
||||
onChange={(e) => handleNameChange(e.target.value)}
|
||||
@@ -86,9 +89,14 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-foreground">
|
||||
{t('testDataGenerator_fieldDescription')}
|
||||
</label>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{(field.description || '').length}/50
|
||||
</span>
|
||||
</div>
|
||||
<Input
|
||||
value={field.description || ''}
|
||||
onChange={(e) => handleDescriptionChange(e.target.value)}
|
||||
@@ -132,7 +140,7 @@ export default function FieldEditor({ field, onChange }: FieldEditorProps) {
|
||||
<button
|
||||
key={preset.value}
|
||||
onClick={() => handleNullRateChange(preset.value)}
|
||||
className={`px-2 py-1 text-xs rounded-md transition-colors ${
|
||||
className={`px-3 py-1.5 text-xs rounded-md transition-colors ${
|
||||
field.nullRate === preset.value
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'bg-muted text-muted-foreground hover:bg-muted/80'
|
||||
|
||||
@@ -11,20 +11,15 @@ import type { FieldConfig } from '@/types/testDataGenerator';
|
||||
interface FieldItemProps {
|
||||
field: FieldConfig;
|
||||
onClick: () => void;
|
||||
isSelected: boolean;
|
||||
}
|
||||
|
||||
export default function FieldItem({ field, onClick, isSelected }: FieldItemProps) {
|
||||
export default function FieldItem({ field, onClick }: FieldItemProps) {
|
||||
const { t } = useI18n('testDataGenerator');
|
||||
const generator = getGeneratorById(field.generatorId);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex-1 min-w-0 cursor-pointer rounded-md transition-all ${
|
||||
isSelected
|
||||
? 'bg-primary/10 pl-2 border-l-2 border-l-primary'
|
||||
: 'hover:bg-muted/50 border-l-2 border-l-transparent'
|
||||
}`}
|
||||
className="flex-1 min-w-0 cursor-pointer rounded-md transition-all hover:bg-muted/50"
|
||||
onClick={onClick}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -44,21 +44,18 @@ interface FieldListProps {
|
||||
onUpdate: (index: number, field: FieldConfig) => void;
|
||||
onRemove: (index: number) => void;
|
||||
onAdd: () => void;
|
||||
onSelect: (index: number) => void;
|
||||
selectedIndex: number | null;
|
||||
onEdit: (index: number) => void;
|
||||
onReorder: (oldIndex: number, newIndex: number) => void;
|
||||
}
|
||||
|
||||
/** 可排序的字段项 */
|
||||
function SortableFieldItem({
|
||||
field,
|
||||
isSelected,
|
||||
onSelect,
|
||||
onEdit,
|
||||
onRemove,
|
||||
}: {
|
||||
field: FieldConfig;
|
||||
isSelected: boolean;
|
||||
onSelect: () => void;
|
||||
onEdit: () => void;
|
||||
onRemove: () => void;
|
||||
}) {
|
||||
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
||||
@@ -78,10 +75,8 @@ function SortableFieldItem({
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={`group relative rounded-lg border transition-all ${
|
||||
isDragging ? 'border-primary shadow-lg' : ''
|
||||
} ${
|
||||
isSelected
|
||||
? 'border-primary bg-primary/8 shadow-sm ring-1 ring-primary/20'
|
||||
isDragging
|
||||
? 'border-primary shadow-lg'
|
||||
: 'border-border hover:border-muted-foreground/30 hover:shadow-sm'
|
||||
}`}
|
||||
>
|
||||
@@ -96,7 +91,7 @@ function SortableFieldItem({
|
||||
</button>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<FieldItem field={field} onClick={onSelect} isSelected={isSelected} />
|
||||
<FieldItem field={field} onClick={onEdit} />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
@@ -117,8 +112,7 @@ export default function FieldList({
|
||||
onUpdate: _onUpdate,
|
||||
onRemove,
|
||||
onAdd,
|
||||
onSelect,
|
||||
selectedIndex,
|
||||
onEdit,
|
||||
onReorder,
|
||||
}: FieldListProps) {
|
||||
const { t } = useI18n('testDataGenerator');
|
||||
@@ -135,14 +129,6 @@ export default function FieldList({
|
||||
}),
|
||||
);
|
||||
|
||||
// 点击已选中的字段时取消选中
|
||||
const handleToggleSelect = useCallback(
|
||||
(index: number) => {
|
||||
onSelect(selectedIndex === index ? -1 : index);
|
||||
},
|
||||
[selectedIndex, onSelect],
|
||||
);
|
||||
|
||||
const handleDragStart = (event: DragStartEvent) => {
|
||||
setActiveId(String(event.active.id));
|
||||
};
|
||||
@@ -230,7 +216,7 @@ export default function FieldList({
|
||||
size="sm"
|
||||
onClick={onAdd}
|
||||
disabled={isMaxReached}
|
||||
className="h-8 gap-1.5"
|
||||
className="h-9 gap-1.5 px-3"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
{t('testDataGenerator_addField')}
|
||||
@@ -284,8 +270,7 @@ export default function FieldList({
|
||||
>
|
||||
<SortableFieldItem
|
||||
field={field}
|
||||
isSelected={selectedIndex === realIndex}
|
||||
onSelect={() => handleToggleSelect(realIndex)}
|
||||
onEdit={() => onEdit(realIndex)}
|
||||
onRemove={() => onRemove(realIndex)}
|
||||
/>
|
||||
</div>
|
||||
@@ -300,8 +285,7 @@ export default function FieldList({
|
||||
<SortableFieldItem
|
||||
key={field.id}
|
||||
field={field}
|
||||
isSelected={selectedIndex === index}
|
||||
onSelect={() => handleToggleSelect(index)}
|
||||
onEdit={() => onEdit(index)}
|
||||
onRemove={() => onRemove(index)}
|
||||
/>
|
||||
))}
|
||||
@@ -317,7 +301,7 @@ export default function FieldList({
|
||||
<GripVertical className="h-4 w-4 text-muted-foreground" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<FieldItem field={activeField} isSelected={false} onClick={() => {}} />
|
||||
<FieldItem field={activeField} onClick={() => {}} />
|
||||
</div>
|
||||
<div className="h-8 w-8 shrink-0" />
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { cn } from '@/lib/utils';
|
||||
import { useGenerator } from './hooks/useGenerator';
|
||||
import { getGeneratorById } from '@/lib/generators';
|
||||
import type { FieldConfig, GenerateResult } from '@/types/testDataGenerator';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogDescription } from '@/components/ui/dialog';
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
||||
|
||||
// 生成唯一 ID 的辅助函数
|
||||
function generateId(): string {
|
||||
@@ -227,8 +227,7 @@ export default function TestDataGeneratorPage() {
|
||||
onUpdate={handleUpdateField}
|
||||
onRemove={handleRemoveField}
|
||||
onAdd={handleAddField}
|
||||
onSelect={handleOpenEditor}
|
||||
selectedIndex={selectedIndex}
|
||||
onEdit={handleOpenEditor}
|
||||
onReorder={handleReorder}
|
||||
/>
|
||||
</div>
|
||||
@@ -303,11 +302,8 @@ export default function TestDataGeneratorPage() {
|
||||
|
||||
{/* 字段编辑弹窗 */}
|
||||
<Dialog open={isEditorOpen} onOpenChange={setIsEditorOpen}>
|
||||
<DialogContent className="w-[calc(100vw-2rem)] max-w-[360px] max-h-[calc(100vh-4rem)] overflow-hidden p-0">
|
||||
<DialogHeader className="px-6 pt-6 pb-0">
|
||||
<DialogDescription>{t('testDataGenerator_selectFieldToEdit')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="overflow-y-auto max-h-[calc(100vh-8rem)] px-6 pb-6">
|
||||
<DialogContent className="w-[calc(100vw-4rem)] max-w-[420px] max-h-[calc(100vh-4rem)] overflow-hidden p-0 pt-8">
|
||||
<div className="overflow-y-auto max-h-[calc(100vh-6rem)] px-6 pb-6">
|
||||
{selectedField && selectedIndex !== null && (
|
||||
<FieldEditor
|
||||
field={selectedField}
|
||||
|
||||
Reference in New Issue
Block a user