329 lines
13 KiB
TypeScript
329 lines
13 KiB
TypeScript
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Card } from "@/components/ui/card";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Label } from "@/components/ui/label";
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||
import { Textarea } from "@/components/ui/textarea";
|
||
import { Droplets, Power, PowerOff, Settings, Thermometer, Zap } from "lucide-react";
|
||
|
||
import type { DecisionFormState, DecisionLevel, ExecutionMode } from "./types";
|
||
|
||
interface DecisionFormDialogProps {
|
||
mode: 'create' | 'edit';
|
||
open: boolean;
|
||
onOpenChange: (open: boolean) => void;
|
||
formState: DecisionFormState;
|
||
onFormChange: <K extends keyof DecisionFormState>(key: K, value: DecisionFormState[K]) => void;
|
||
onSubmit: () => void;
|
||
}
|
||
|
||
const triggerDeviceOptions = [
|
||
{ value: '土壤传感器-01', label: '土壤传感器-01', icon: Droplets },
|
||
{ value: '土壤传感器-02', label: '土壤传感器-02', icon: Droplets },
|
||
{ value: '土壤传感器-03', label: '土壤传感器-03', icon: Droplets },
|
||
{ value: '温度传感器-01', label: '温度传感器-01', icon: Thermometer },
|
||
{ value: '温度传感器-02', label: '温度传感器-02', icon: Thermometer },
|
||
{ value: '湿度传感器-01', label: '湿度传感器-01' },
|
||
{ value: '光照传感器-01', label: '光照传感器-01' },
|
||
{ value: 'CO2传感器-01', label: 'CO2传感器-01' },
|
||
];
|
||
|
||
const triggerParameterOptions = [
|
||
{ value: '土壤湿度', label: '土壤湿度 (%)' },
|
||
{ value: '土壤温度', label: '土壤温度 (℃)' },
|
||
{ value: '空气温度', label: '空气温度 (℃)' },
|
||
{ value: '空气湿度', label: '空气湿度 (%)' },
|
||
{ value: '光照强度', label: '光照强度 (lux)' },
|
||
{ value: 'CO2浓度', label: 'CO₂ 浓度 (ppm)' },
|
||
{ value: 'EC值', label: 'EC 值 (mS/cm)' },
|
||
{ value: 'PH值', label: 'PH 值' },
|
||
];
|
||
|
||
const compareOperatorOptions = [
|
||
{ value: '>', label: '大于' },
|
||
{ value: '<', label: '小于' },
|
||
{ value: '>=', label: '大于等于' },
|
||
{ value: '<=', label: '小于等于' },
|
||
{ value: '==', label: '等于' },
|
||
];
|
||
|
||
const targetDeviceOptions = [
|
||
'水肥机-01',
|
||
'水肥机-02',
|
||
'灌溉阀门-A1',
|
||
'灌溉阀门-B2',
|
||
'排风扇-01',
|
||
'排风扇-02',
|
||
'喷雾器-01',
|
||
'喷雾器-02',
|
||
'补光灯-01',
|
||
'加热器-01',
|
||
];
|
||
|
||
export function DecisionFormDialog({ mode, open, onOpenChange, formState, onFormChange, onSubmit }: DecisionFormDialogProps) {
|
||
const dialogTitle = mode === 'create' ? '新建决策' : '编辑决策';
|
||
const dialogDescription =
|
||
mode === 'create'
|
||
? '创建基于设备参数的业务融合决策。'
|
||
: '更新当前决策的触发条件、执行动作与详细内容。';
|
||
const submitLabel = mode === 'create' ? '保存决策' : '保存修改';
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
|
||
<DialogHeader>
|
||
<DialogTitle>{dialogTitle}</DialogTitle>
|
||
<DialogDescription>{dialogDescription}</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<div className="space-y-6">
|
||
<Card className="p-4">
|
||
<h4 className="mb-4 text-sm font-medium">基础信息</h4>
|
||
<div className="space-y-4">
|
||
<div>
|
||
<Label>决策名称 *</Label>
|
||
<Input
|
||
placeholder="例如:3号大棚灌溉决策"
|
||
value={formState.name}
|
||
onChange={(event) => onFormChange('name', event.target.value)}
|
||
/>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||
<div>
|
||
<Label>决策级别</Label>
|
||
<Select
|
||
value={formState.level}
|
||
onValueChange={(value) => onFormChange('level', value as DecisionLevel)}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="选择决策级别" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="critical">紧急</SelectItem>
|
||
<SelectItem value="important">重要</SelectItem>
|
||
<SelectItem value="normal">一般</SelectItem>
|
||
<SelectItem value="suggestion">建议</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div>
|
||
<Label>置信度 (%)</Label>
|
||
<Input
|
||
type="number"
|
||
min={0}
|
||
max={100}
|
||
value={formState.confidence}
|
||
onChange={(event) => onFormChange('confidence', Number(event.target.value))}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<Label>执行模式 *</Label>
|
||
<Select
|
||
value={formState.executionMode}
|
||
onValueChange={(value) => onFormChange('executionMode', value as ExecutionMode)}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="选择执行模式" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="manual">手动执行(点击执行按钮时执行)</SelectItem>
|
||
<SelectItem value="auto">自动执行(条件满足时自动执行)</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
<p className="text-xs text-muted-foreground mt-1">
|
||
{formState.executionMode === 'auto'
|
||
? '当触发条件满足时,系统将自动执行设备控制操作。'
|
||
: '需要人工点击执行按钮,验证触发条件后再执行。'}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="p-4 bg-warning/10 border-warning/30">
|
||
<div className="flex items-center gap-2 mb-4">
|
||
<Settings className="w-5 h-5 text-warning" />
|
||
<h4 className="text-sm font-medium">触发条件设置</h4>
|
||
</div>
|
||
<p className="text-sm text-muted-foreground mb-4">
|
||
设置触发条件:当设备参数满足指定阈值时自动触发决策。
|
||
</p>
|
||
<div className="space-y-4">
|
||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||
<div>
|
||
<Label>选择设备 *</Label>
|
||
<Select value={formState.triggerDevice} onValueChange={(value) => onFormChange('triggerDevice', value)}>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="请选择设备" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{triggerDeviceOptions.map((option) => (
|
||
<SelectItem key={option.value} value={option.value}>
|
||
<span className="flex items-center gap-2">
|
||
{option.icon ? <option.icon className="w-4 h-4" /> : null}
|
||
{option.label}
|
||
</span>
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div>
|
||
<Label>选择参数 *</Label>
|
||
<Select
|
||
value={formState.triggerParameter}
|
||
onValueChange={(value) => onFormChange('triggerParameter', value)}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="请选择参数" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{triggerParameterOptions.map((option) => (
|
||
<SelectItem key={option.value} value={option.value}>
|
||
{option.label}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
||
<div>
|
||
<Label>比较符号 *</Label>
|
||
<Select
|
||
value={formState.triggerOperator}
|
||
onValueChange={(value) => onFormChange('triggerOperator', value)}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="请选择比较符号" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{compareOperatorOptions.map((option) => (
|
||
<SelectItem key={option.value} value={option.value}>
|
||
{option.value} {option.label}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div className="md:col-span-2">
|
||
<Label>阈值 *</Label>
|
||
<Input
|
||
placeholder="请输入阈值"
|
||
value={formState.triggerValue}
|
||
onChange={(event) => onFormChange('triggerValue', event.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="p-4 bg-success/10 border-success/30">
|
||
<div className="flex items-center gap-2 mb-4">
|
||
<Zap className="w-5 h-5 text-success" />
|
||
<h4 className="text-sm font-medium">执行设置</h4>
|
||
</div>
|
||
<p className="text-sm text-muted-foreground mb-4">配置决策触发后要执行的设备和动作。</p>
|
||
<div className="space-y-4">
|
||
<div>
|
||
<Label>目标设备 *</Label>
|
||
<Select value={formState.targetDevice} onValueChange={(value) => onFormChange('targetDevice', value)}>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="请选择目标设备" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{targetDeviceOptions.map((device) => (
|
||
<SelectItem key={device} value={device}>
|
||
{device}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||
<div>
|
||
<Label>开关状态 *</Label>
|
||
<Select
|
||
value={formState.targetAction}
|
||
onValueChange={(value) => onFormChange('targetAction', value === 'open' ? 'open' : 'close')}
|
||
>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="请选择动作" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="open">
|
||
<span className="flex items-center gap-2">
|
||
<Power className="w-4 h-4 text-success" /> 打开
|
||
</span>
|
||
</SelectItem>
|
||
<SelectItem value="close">
|
||
<span className="flex items-center gap-2">
|
||
<PowerOff className="w-4 h-4 text-destructive" /> 关闭
|
||
</span>
|
||
</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div>
|
||
<Label>持续时间(分钟)*</Label>
|
||
<Input
|
||
type="number"
|
||
min={1}
|
||
value={formState.duration}
|
||
onChange={(event) => onFormChange('duration', Number(event.target.value))}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="p-4">
|
||
<h4 className="mb-4 text-sm font-medium">决策内容</h4>
|
||
<div className="space-y-4">
|
||
<div>
|
||
<Label>推荐建议 *</Label>
|
||
<Textarea
|
||
rows={3}
|
||
value={formState.recommendation}
|
||
onChange={(event) => onFormChange('recommendation', event.target.value)}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<Label>详细说明</Label>
|
||
<Textarea
|
||
rows={5}
|
||
value={formState.explanation}
|
||
onChange={(event) => onFormChange('explanation', event.target.value)}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<Label>执行步骤 *(每行一个步骤)</Label>
|
||
<Textarea
|
||
rows={6}
|
||
value={formState.actionItems}
|
||
onChange={(event) => onFormChange('actionItems', event.target.value)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||
取消
|
||
</Button>
|
||
<Button className="bg-success hover:bg-success/90" onClick={onSubmit}>
|
||
{submitLabel}
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
}
|
||
|