/** * filekorolheader: 添加/编辑参数对话框 - 参数模板配置组件 * 功能:新增参数、编辑参数信息、表单验证、不同类型参数配置 * 路径:/ai-crop-model/data-sense-center/device-parameter/components * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn语义化样式 */ import { useState, useEffect } from 'react'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { ParameterDefinition, DeviceType, DeviceParameterAction } from './deviceParameterReducer'; import { Save, X, Plus } from 'lucide-react'; import { toast } from 'sonner'; interface AddParameterDialogProps { open: boolean; onOpenChange: (open: boolean) => void; editingParam: ParameterDefinition | null; selectedType: DeviceType | null; dispatch: React.Dispatch; } interface ParamForm { key: string; label: string; type: 'string' | 'number' | 'boolean' | 'select'; required: boolean; defaultValue: string; unit: string; min: string; max: string; description: string; options: { label: string; value: string }[]; } export function AddParameterDialog({ open, onOpenChange, editingParam, selectedType, dispatch }: AddParameterDialogProps) { const [paramForm, setParamForm] = useState({ key: '', label: '', type: 'string', required: false, defaultValue: '', unit: '', min: '', max: '', description: '', options: [] }); const [optionLabel, setOptionLabel] = useState(''); const [optionValue, setOptionValue] = useState(''); const [errors, setErrors] = useState>>({}); useEffect(() => { if (editingParam) { setParamForm({ key: editingParam.key, label: editingParam.label, type: editingParam.type, required: editingParam.required || false, defaultValue: editingParam.defaultValue?.toString() || '', unit: editingParam.unit || '', min: editingParam.min?.toString() || '', max: editingParam.max?.toString() || '', description: editingParam.description || '', options: editingParam.options || [] }); } else { setParamForm({ key: '', label: '', type: 'string', required: false, defaultValue: '', unit: '', min: '', max: '', description: '', options: [] }); } setErrors({}); setOptionLabel(''); setOptionValue(''); }, [editingParam, open]); const validateForm = (): boolean => { const newErrors: Partial> = {}; if (!paramForm.key.trim()) { newErrors.key = '请输入参数标识'; } if (!paramForm.label.trim()) { newErrors.label = '请输入参数名称'; } // 检查参数标识是否重复(编辑时除外) if (!editingParam || editingParam.key !== paramForm.key) { const exists = selectedType?.parameterDefinitions?.some(p => p.key === paramForm.key.trim()); if (exists) { newErrors.key = '参数标识已存在'; } } // 验证数字类型的范围 if (paramForm.type === 'number') { if (paramForm.min && paramForm.max) { const min = parseFloat(paramForm.min); const max = parseFloat(paramForm.max); if (min >= max) { newErrors.max = '最大值必须大于最小值'; } } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSaveParam = () => { if (!selectedType) return; if (!validateForm()) { return; } try { // 构建新参数 const newParam: ParameterDefinition = { key: paramForm.key.trim(), label: paramForm.label.trim(), type: paramForm.type, required: paramForm.required, description: paramForm.description.trim() }; // 根据类型设置默认值和属性 if (paramForm.type === 'number') { newParam.defaultValue = paramForm.defaultValue ? parseFloat(paramForm.defaultValue) : 0; if (paramForm.unit) newParam.unit = paramForm.unit; if (paramForm.min) newParam.min = parseFloat(paramForm.min); if (paramForm.max) newParam.max = parseFloat(paramForm.max); } else if (paramForm.type === 'boolean') { newParam.defaultValue = String(paramForm.defaultValue).toLowerCase() === 'true'; } else if (paramForm.type === 'select') { newParam.options = paramForm.options; newParam.defaultValue = paramForm.defaultValue || (paramForm.options[0]?.value || ''); } else { newParam.defaultValue = paramForm.defaultValue; } if (editingParam) { dispatch({ type: 'UPDATE_PARAMETER', payload: newParam }); } else { dispatch({ type: 'ADD_PARAMETER', payload: newParam }); } onOpenChange(false); } catch (error) { console.error('保存失败:', error); toast.error('保存失败,请重试'); } }; const handleAddOption = () => { if (!optionLabel.trim() || !optionValue.trim()) { toast.error('请填写选项标签和值'); return; } const newOption = { label: optionLabel.trim(), value: optionValue.trim() }; setParamForm({ ...paramForm, options: [...paramForm.options, newOption] }); setOptionLabel(''); setOptionValue(''); }; const handleRemoveOption = (index: number) => { setParamForm({ ...paramForm, options: paramForm.options.filter((_, i) => i !== index) }); }; const handleInputChange = (field: keyof ParamForm, value: any) => { setParamForm(prev => ({ ...prev, [field]: value })); // 清除该字段的错误 if (errors[field]) { setErrors(prev => ({ ...prev, [field]: undefined })); } }; return ( {editingParam ? '编辑参数' : '新增参数'} 为 {selectedType?.name} 配置参数定义
{/* 基本信息 */}
handleInputChange('key', e.target.value)} placeholder="例如:temperature" disabled={!!editingParam} className={errors.key ? 'border-red-500' : ''} /> {errors.key && (

{errors.key}

)}

英文标识,用于数据传输

handleInputChange('label', e.target.value)} placeholder="例如:温度" className={errors.label ? 'border-red-500' : ''} /> {errors.label && (

{errors.label}

)}
handleInputChange('required', checked)} />
{/* 根据类型显示不同字段 */} {paramForm.type === 'number' && (
handleInputChange('unit', e.target.value)} placeholder="例如:°C" />
handleInputChange('min', e.target.value)} placeholder="最小值" />
handleInputChange('max', e.target.value)} placeholder="最大值" className={errors.max ? 'border-red-500' : ''} /> {errors.max && (

{errors.max}

)}
)} {/* 选择类型的选项配置 */} {paramForm.type === 'select' && (
setOptionLabel(e.target.value)} placeholder="选项标签(显示文本)" className="flex-1" /> setOptionValue(e.target.value)} placeholder="选项值" className="flex-1" />
{paramForm.options.length > 0 && (

已添加的选项:

{paramForm.options.map((option, index) => (
{option.label} ({option.value})
))}
)}
)} {/* 默认值 */}
{paramForm.type === 'boolean' ? ( ) : paramForm.type === 'select' && paramForm.options.length > 0 ? ( ) : ( handleInputChange('defaultValue', e.target.value)} placeholder="参数默认值" /> )}
{/* 描述 */}