xieyonghong 3 лет назад
Родитель
Сommit
7ca8ed364a

+ 1 - 6
src/components/ProTableCard/CardItems/scene.tsx

@@ -38,21 +38,16 @@ export default (props: DeviceCardProps) => {
         </div>
         <div className={'card-item-body'}>
           <div className={'card-item-header'}>
-            {/*<span className={'card-item-header-name ellipsis'}>*/}
-            {/*  <Tooltip title={props.name}>{props.name}</Tooltip>*/}
-            {/*</span>*/}
             <Ellipsis title={props.name} titleClassName={'card-item-header-name'} />
           </div>
-          <div className={'card-item-content'}>
+          <div>
             <div>
               <label>触发方式</label>
               <Ellipsis title={TriggerWayType[props.triggerType]} />
-              {/*<div className={'ellipsis'}>{TriggerWayType[props.triggerType]}</div>*/}
             </div>
             <div>
               <label>说明</label>
               <Ellipsis title={props.description} />
-              {/*<div className={'ellipsis'}>{props.description || ''}</div>*/}
             </div>
           </div>
         </div>

+ 6 - 4
src/pages/rule-engine/Scene/Save/components/TriggerWay/index.less

@@ -1,4 +1,4 @@
-@import '~antd/es/style/themes/default.less';
+@import '../../../../../../../node_modules/antd/es/style/themes/default.less';
 
 .trigger-way-warp {
   display: flex;
@@ -7,7 +7,9 @@
 
   .trigger-way-item {
     display: flex;
-    padding: 22px 16px;
+    justify-content: space-between;
+    width: 100%;
+    padding: 16px;
     border: 1px solid #e0e4e8;
     border-radius: 2px;
     cursor: pointer;
@@ -22,13 +24,13 @@
       }
 
       span {
-        color: rgba(#000, 0.24);
+        color: rgba(#000, 0.35);
         font-size: 12px;
       }
     }
 
     .way-item-image {
-      margin-left: 26px;
+      margin: 0 !important;
     }
 
     &:hover {

+ 12 - 6
src/pages/rule-engine/Scene/Save/components/TriggerWay/index.tsx

@@ -48,9 +48,11 @@ export default (props: TriggerWayProps) => {
       >
         <div className={'way-item-title'}>
           <p>设备触发</p>
-          <span>DEVICE TRIGGER</span>
+          <span>适用于设备数据或行为满足触发条件时,执行指定的动作</span>
+        </div>
+        <div className={'way-item-image'}>
+          <img width={48} src={'/images/device-trigger.png'} />
         </div>
-        <img className={'way-item-image'} src={'/images/device-trigger.png'} />
       </div>
       <div
         className={classNames('trigger-way-item', {
@@ -62,9 +64,11 @@ export default (props: TriggerWayProps) => {
       >
         <div className={'way-item-title'}>
           <p>手动触发</p>
-          <span>MANUAL TRIGGER</span>
+          <span>适用于第三方平台向物联网平台下发指令控制设备.</span>
+        </div>
+        <div className={'way-item-image'}>
+          <img width={48} src={'/images/manual-trigger.png'} />
         </div>
-        <img className={'way-item-image'} src={'/images/manual-trigger.png'} />
       </div>
       <div
         className={classNames('trigger-way-item', {
@@ -76,9 +80,11 @@ export default (props: TriggerWayProps) => {
       >
         <div className={'way-item-title'}>
           <p>定时触发</p>
-          <span>TIMING TRIGGER</span>
+          <span>适用于定期执行固定任务.</span>
+        </div>
+        <div className={'way-item-image'}>
+          <img width={48} src={'/images/timing-trigger.png'} />
         </div>
-        <img className={'way-item-image'} src={'/images/timing-trigger.png'} />
       </div>
     </div>
   );

+ 58 - 439
src/pages/rule-engine/Scene/Save/index.tsx

@@ -1,446 +1,65 @@
-import { PageContainer } from '@ant-design/pro-layout';
-import { Button, Card, Form, Input, InputNumber, Radio, Space, Switch, Tooltip } from 'antd';
-import { useIntl, useHistory } from 'umi';
-import { useCallback, useEffect, useRef, useState } from 'react';
-import { PermissionButton, TitleComponent } from '@/components';
-import ActionItems from './action/action';
-import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons';
-import { TimingTrigger, TriggerWay } from './components';
-import { TriggerWayType } from './components/TriggerWay';
-import TriggerTerm from '@/pages/rule-engine/Scene/TriggerTerm';
-import TriggerDevice from './trigger';
-import { service } from '../index';
-import './index.less';
-import { model } from '@formily/reactive';
-import type { FormModelType } from '@/pages/rule-engine/Scene/typings';
-import { onlyMessage } from '@/utils/util';
-import Explanation from './Explanation';
-import { getMenuPathByCode } from '@/utils/menu';
-import { useLocation } from '@/hooks';
-
-type ShakeLimitType = {
-  enabled: boolean;
-  groupType?: string;
-  time?: number;
-  threshold?: number;
-  alarmFirst?: boolean;
-};
-
-const DefaultShakeLimit = {
-  enabled: false,
-  alarmFirst: false,
-};
-
-export let FormModel = model<FormModelType>({});
-
-export default () => {
-  const location = useLocation();
+import { Modal } from '@/components';
+import { Form, Input } from 'antd';
+import TriggerWay from '@/pages/rule-engine/Scene/Save/components/TriggerWay';
+import type { SceneItem } from '@/pages/rule-engine/Scene/typings';
+import { useEffect } from 'react';
+
+interface Props {
+  close: () => void;
+  data: Partial<SceneItem>;
+}
+
+export default (props: Props) => {
   const [form] = Form.useForm();
-  const intl = useIntl();
-  const triggerRef = useRef<any>();
-  const history = useHistory();
-
-  const { getOtherPermission } = PermissionButton.usePermission('rule-engine/Scene');
-  const [triggerType, setTriggerType] = useState('device');
-
-  const [loading, setLoading] = useState(false);
-  const [parallel, setParallel] = useState(true); // 是否并行
-  const [shakeLimit, setShakeLimit] = useState<ShakeLimitType>(DefaultShakeLimit);
-  const [targetTypeDisabled, setTargetTypeDisabled] = useState(false);
-
-  const [requestParams, setRequestParams] = useState<any>(undefined);
-  const [triggerValue, setTriggerValue] = useState<any>([]);
-  const [triggerDatas, setTriggerDatas] = useState<any>({});
-  const [actionParams, setActionParams] = useState<any>(undefined);
-  const [actionDataCount, setActionDataCount] = useState(0);
-
-  const [actionsData, setActionsData] = useState<any[]>([]);
-  const [isEdit, setIsEdit] = useState(false);
-  const [view, setView] = useState<boolean>(false);
 
   useEffect(() => {
-    FormModel = {};
-  }, []);
-
-  const getDetail = useCallback(
-    async (id: string) => {
-      const resp = await service.detail(id);
-      if (resp.status === 200 && resp.result) {
-        setIsEdit(true);
-        const _data: any = resp.result;
-        FormModel = _data;
-        console.log(_data);
-
-        form.setFieldsValue(_data);
-        // debugger;
-        setParallel(_data.parallel);
-
-        setTriggerValue({ trigger: _data.terms || [] });
-        setTriggerDatas(_data.trigger);
-        setActionParams({ trigger: _data.trigger });
-        if (_data.trigger?.shakeLimit) {
-          setShakeLimit(_data.trigger?.shakeLimit || DefaultShakeLimit);
-        }
-        if (_data.trigger?.device) {
-          setRequestParams({ trigger: _data.trigger });
-        }
-
-        if (_data.actions) {
-          setActionsData(_data.actions);
-        }
-      }
-    },
-    [triggerRef],
-  );
-
-  useEffect(() => {
-    const params = new URLSearchParams(location.search);
-    const id = params.get('id');
-    const targetType = params.get('targetType');
-    if (id) {
-      getDetail(id);
-    }
-
-    if (targetType) {
-      setTargetTypeDisabled(true);
-    }
-
-    if (location && location.state) {
-      setView(location.state.view);
-    }
-  }, [location]);
-
-  const saveData = useCallback(async () => {
-    const formData = await form.validateFields();
-    let triggerData = undefined;
-    // 获取触发条件数据
-    if (triggerRef.current && formData.trigger) {
-      triggerData = await triggerRef.current.getTriggerForm();
-      if (triggerData) {
-        formData.terms = triggerData.trigger;
-      }
-    }
-    console.log('save', formData);
-    if (formData) {
-      if (shakeLimit.enabled) {
-        formData.trigger = {
-          ...formData.trigger,
-          shakeLimit: shakeLimit,
-        };
-      }
-      setLoading(true);
-      const resp = formData.id ? await service.updateScene(formData) : await service.save(formData);
-
-      // 处理跳转新增
-      if ((window as any).onTabSaveSuccess) {
-        if (resp.result) {
-          (window as any).onTabSaveSuccess(resp);
-          setTimeout(() => window.close(), 300);
-        }
-      }
-
-      setLoading(false);
-      if (resp.status === 200) {
-        onlyMessage('操作成功');
-        const url = getMenuPathByCode('rule-engine/Scene');
-        history.push(url);
-      } else {
-        onlyMessage(resp.message);
-      }
-    }
-  }, [shakeLimit]);
-
-  const AntiShake = (
-    <Space>
-      <TitleComponent data={'触发条件'} style={{ margin: 0 }} />
-      <Switch
-        checked={shakeLimit.enabled}
-        checkedChildren="开启防抖"
-        unCheckedChildren="关闭防抖"
-        onChange={(e) => {
-          const newShake = {
-            ...shakeLimit,
-            enabled: e,
-          };
-          setShakeLimit(newShake);
-        }}
-        style={{ marginRight: 16 }}
-      />
-      {shakeLimit.enabled && (
-        <>
-          <InputNumber
-            value={shakeLimit.time}
-            min={1}
-            max={100}
-            onChange={(e: number) => {
-              const newShake = {
-                ...shakeLimit,
-                time: e,
-              };
-              setShakeLimit(newShake);
-            }}
-          />
-          <span style={{ padding: '0 16px' }}> 秒内发生 </span>
-          <InputNumber
-            value={shakeLimit.threshold}
-            min={1}
-            max={100}
-            onChange={(e: number) => {
-              const newShake = {
-                ...shakeLimit,
-                threshold: e,
-              };
-              setShakeLimit(newShake);
-            }}
-          />
-          <span style={{ padding: '0 16px' }}>次及以上时,处理</span>
-          <Radio.Group
-            value={shakeLimit.alarmFirst}
-            options={[
-              { label: '第一次', value: true },
-              { label: '最后一次', value: false },
-            ]}
-            optionType="button"
-            onChange={(e) => {
-              const newShake = {
-                ...shakeLimit,
-                alarmFirst: e.target.value,
-              };
-              setShakeLimit(newShake);
-            }}
-          ></Radio.Group>
-        </>
-      )}
-    </Space>
-  );
-
-  const hasKeyInObject = (keys: string[], obj: any) => {
-    return keys.some((key) => key in obj);
-  };
+    form.setFieldsValue({
+      ...props.data,
+    });
+  }, [props.data]);
 
   return (
-    <PageContainer>
-      <Card>
-        <div className={'scene-content'}>
-          <div className={'scene-content-left'}>
-            <Form
-              scrollToFirstError={{
-                behavior: 'smooth',
-                block: 'end',
-              }}
-              form={form}
-              colon={false}
-              name="basicForm"
-              layout={'vertical'}
-              preserve={false}
-              className={'scene-save'}
-              onValuesChange={(changeValue, allValues) => {
-                if (changeValue.trigger) {
-                  if (changeValue.trigger.device) {
-                    if (
-                      changeValue.trigger.device.productId ||
-                      changeValue.trigger.device.selectorValues ||
-                      (changeValue.trigger.device.operation &&
-                        hasKeyInObject(
-                          ['operator', 'eventId', 'functionId'],
-                          changeValue.trigger.device.operation,
-                        ))
-                    ) {
-                      setTriggerValue([]);
-                      setRequestParams({ trigger: allValues.trigger });
-                      setTriggerDatas(allValues.trigger);
-                    }
-
-                    if (
-                      hasKeyInObject(['productId'], changeValue.trigger.device) ||
-                      (changeValue.trigger.device.operation &&
-                        hasKeyInObject(
-                          ['operator', 'eventId', 'functionId'],
-                          changeValue.trigger.device.operation,
-                        ))
-                    ) {
-                      setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
-                    }
-                  } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
-                    setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
-                  }
-                }
-                if (allValues.actions) {
-                  // debugger;
-                  console.log(allValues.actions, 'onValuesChange');
-                  setActionsData(allValues.actions);
-                }
-                FormModel = { ...allValues };
-              }}
-            >
-              <Form.Item
-                name={'name'}
-                label={<TitleComponent data={'名称'} style={{ margin: 0 }} />}
-                rules={[
-                  { required: true, message: '请输入名称' },
-                  {
-                    max: 64,
-                    message: intl.formatMessage({
-                      id: 'pages.form.tip.max64',
-                      defaultMessage: '最多输入64个字符',
-                    }),
-                  },
-                ]}
-              >
-                <Input placeholder={'请输入名称'} />
-              </Form.Item>
-              <Form.Item
-                label={<TitleComponent data={'触发方式'} style={{ margin: 0 }} />}
-                required
-              >
-                <Form.Item
-                  name={['trigger', 'type']}
-                  rules={[{ required: true, message: '请选择触发方式' }]}
-                  initialValue={'device'}
-                >
-                  <TriggerWay onSelect={setTriggerType} disabled={isEdit || targetTypeDisabled} />
-                </Form.Item>
-                {triggerType === TriggerWayType.timing && (
-                  <TimingTrigger
-                    name={['trigger']}
-                    form={form}
-                    className={'trigger-type-content'}
-                  />
-                )}
-                {triggerType === TriggerWayType.device && (
-                  <TriggerDevice
-                    value={triggerDatas}
-                    className={'trigger-type-content'}
-                    form={form}
-                  />
-                )}
-              </Form.Item>
-              {triggerType === TriggerWayType.device &&
-              requestParams &&
-              requestParams.trigger?.device?.productId ? (
-                <Form.Item label={AntiShake}>
-                  <TriggerTerm ref={triggerRef} params={requestParams} value={triggerValue} />
-                </Form.Item>
-              ) : null}
-              <Form.Item hidden name={'parallel'} initialValue={true}>
-                <Input />
-              </Form.Item>
-              <Form.Item
-                label={
-                  <Space>
-                    <TitleComponent data={<span>执行动作</span>} style={{ margin: 0 }} />
-                    <Tooltip
-                      title={
-                        <div>
-                          <div>串行:按顺序依次执行动作</div>
-                          <div>并行:同时执行所有动作</div>
-                        </div>
-                      }
-                    >
-                      <QuestionCircleOutlined style={{ margin: '0 8px', fontSize: 14 }} />
-                    </Tooltip>
-                    <Radio.Group
-                      value={parallel}
-                      options={[
-                        { label: '串行', value: false },
-                        { label: '并行', value: true },
-                      ]}
-                      optionType="button"
-                      onChange={(e) => {
-                        setParallel(e.target.value);
-                        form.setFieldsValue({ parallel: e.target.value });
-                      }}
-                    ></Radio.Group>
-                  </Space>
-                }
-              >
-                <Form.List name="actions">
-                  {(fields, { add, remove, move }, { errors }) => (
-                    <>
-                      <div className={'scene-actions'} style={{ paddingBottom: 24 }}>
-                        {fields.map(({ key, name, ...restField }) => (
-                          <ActionItems
-                            key={key}
-                            form={form}
-                            restField={restField}
-                            name={name}
-                            trigger={actionParams}
-                            triggerType={triggerType}
-                            triggerRef={triggerRef.current}
-                            onRemove={() => {
-                              remove(name);
-                              setActionDataCount(actionDataCount - 1);
-                            }}
-                            onMove={(type) => {
-                              if (type === 'up') {
-                                move(name, name - 1);
-                              } else {
-                                move(name, name + 1);
-                              }
-                            }}
-                            actionItemData={actionsData[name]}
-                            isLast={!actionDataCount || actionDataCount - 1 === name}
-                            parallel={parallel}
-                            isEdit={isEdit}
-                          />
-                        ))}
-                        <Form.Item noStyle>
-                          <Button
-                            type="primary"
-                            ghost
-                            style={{
-                              width: '100%',
-                              marginTop: 16,
-                            }}
-                            onClick={() => {
-                              add();
-                              setActionDataCount(actionDataCount + 1);
-                            }}
-                            icon={<PlusOutlined />}
-                          >
-                            新增
-                          </Button>
-                        </Form.Item>
-                      </div>
-                      <Form.ErrorList errors={errors} />
-                    </>
-                  )}
-                </Form.List>
-              </Form.Item>
-              <Form.Item
-                label={<TitleComponent data={'说明'} style={{ margin: 0 }} />}
-                name={'description'}
-              >
-                <Input.TextArea showCount maxLength={200} placeholder={'请输入说明'} rows={4} />
-              </Form.Item>
-              {/*{triggerType === TriggerWayType.device &&*/}
-              {/*requestParams &&*/}
-              {/*requestParams.trigger?.device?.productId ? (*/}
-              {/*  <Form.Item hidden name={['trigger','shakeLimit']}>*/}
-              {/*    <Input />*/}
-              {/*  </Form.Item>*/}
-              {/*) : null}*/}
-              <Form.Item hidden name={'id'}>
-                <Input />
-              </Form.Item>
-              {!view && (
-                <PermissionButton
-                  isPermission={getOtherPermission(['add', 'update'])}
-                  onClick={saveData}
-                  type={'primary'}
-                  loading={loading}
-                  htmlType="submit"
-                >
-                  保存
-                </PermissionButton>
-              )}
-            </Form>
-          </div>
-          <div className={'scene-content-right'}>
-            <Explanation type={triggerType} />
-          </div>
-        </div>
-      </Card>
-    </PageContainer>
+    <Modal
+      title={props.data?.id ? '编辑' : '新增'}
+      maskClosable={false}
+      visible
+      onCancel={() => {
+        props.close();
+      }}
+      onOk={async () => {
+        const values = await form.validateFields();
+        console.log(values);
+      }}
+      width={700}
+    >
+      <Form name="scene-save" layout={'vertical'} form={form} autoComplete="off">
+        <Form.Item
+          name={'name'}
+          label={'名称'}
+          rules={[
+            { required: true, message: '请输入名称' },
+            {
+              max: 64,
+              message: '最多输入64个字符',
+            },
+          ]}
+        >
+          <Input placeholder={'请输入名称'} />
+        </Form.Item>
+        <Form.Item
+          label={'触发方式'}
+          name={['trigger', 'type']}
+          rules={[{ required: true, message: '请选择触发方式' }]}
+          initialValue={'device'}
+        >
+          <TriggerWay
+            // onSelect={(val) => {
+            //   // console.log(val);
+            // }}
+            disabled={!!props.data.id}
+          />
+        </Form.Item>
+      </Form>
+    </Modal>
   );
 };

src/pages/rule-engine/Scene/Save/index.less → src/pages/rule-engine/Scene/Save/old/index.less


+ 446 - 0
src/pages/rule-engine/Scene/Save/old/index.tsx

@@ -0,0 +1,446 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import { Button, Card, Form, Input, InputNumber, Radio, Space, Switch, Tooltip } from 'antd';
+import { useIntl, useHistory } from 'umi';
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { PermissionButton, TitleComponent } from '@/components';
+import ActionItems from '../action/action';
+import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons';
+import { TimingTrigger, TriggerWay } from '../components';
+import { TriggerWayType } from '../components/TriggerWay';
+import TriggerTerm from '@/pages/rule-engine/Scene/TriggerTerm';
+import TriggerDevice from '../trigger';
+import { service } from '../../index';
+import './index.less';
+import { model } from '@formily/reactive';
+import type { FormModelType } from '@/pages/rule-engine/Scene/typings';
+import { onlyMessage } from '@/utils/util';
+import Explanation from '../Explanation';
+import { getMenuPathByCode } from '@/utils/menu';
+import { useLocation } from '@/hooks';
+
+type ShakeLimitType = {
+  enabled: boolean;
+  groupType?: string;
+  time?: number;
+  threshold?: number;
+  alarmFirst?: boolean;
+};
+
+const DefaultShakeLimit = {
+  enabled: false,
+  alarmFirst: false,
+};
+
+export let FormModel = model<FormModelType>({});
+
+export default () => {
+  const location = useLocation();
+  const [form] = Form.useForm();
+  const intl = useIntl();
+  const triggerRef = useRef<any>();
+  const history = useHistory();
+
+  const { getOtherPermission } = PermissionButton.usePermission('rule-engine/Scene');
+  const [triggerType, setTriggerType] = useState('device');
+
+  const [loading, setLoading] = useState(false);
+  const [parallel, setParallel] = useState(true); // 是否并行
+  const [shakeLimit, setShakeLimit] = useState<ShakeLimitType>(DefaultShakeLimit);
+  const [targetTypeDisabled, setTargetTypeDisabled] = useState(false);
+
+  const [requestParams, setRequestParams] = useState<any>(undefined);
+  const [triggerValue, setTriggerValue] = useState<any>([]);
+  const [triggerDatas, setTriggerDatas] = useState<any>({});
+  const [actionParams, setActionParams] = useState<any>(undefined);
+  const [actionDataCount, setActionDataCount] = useState(0);
+
+  const [actionsData, setActionsData] = useState<any[]>([]);
+  const [isEdit, setIsEdit] = useState(false);
+  const [view, setView] = useState<boolean>(false);
+
+  useEffect(() => {
+    FormModel = {};
+  }, []);
+
+  const getDetail = useCallback(
+    async (id: string) => {
+      const resp = await service.detail(id);
+      if (resp.status === 200 && resp.result) {
+        setIsEdit(true);
+        const _data: any = resp.result;
+        FormModel = _data;
+        console.log(_data);
+
+        form.setFieldsValue(_data);
+        // debugger;
+        setParallel(_data.parallel);
+
+        setTriggerValue({ trigger: _data.terms || [] });
+        setTriggerDatas(_data.trigger);
+        setActionParams({ trigger: _data.trigger });
+        if (_data.trigger?.shakeLimit) {
+          setShakeLimit(_data.trigger?.shakeLimit || DefaultShakeLimit);
+        }
+        if (_data.trigger?.device) {
+          setRequestParams({ trigger: _data.trigger });
+        }
+
+        if (_data.actions) {
+          setActionsData(_data.actions);
+        }
+      }
+    },
+    [triggerRef],
+  );
+
+  useEffect(() => {
+    const params = new URLSearchParams(location.search);
+    const id = params.get('id');
+    const targetType = params.get('targetType');
+    if (id) {
+      getDetail(id);
+    }
+
+    if (targetType) {
+      setTargetTypeDisabled(true);
+    }
+
+    if (location && location.state) {
+      setView(location.state.view);
+    }
+  }, [location]);
+
+  const saveData = useCallback(async () => {
+    const formData = await form.validateFields();
+    let triggerData = undefined;
+    // 获取触发条件数据
+    if (triggerRef.current && formData.trigger) {
+      triggerData = await triggerRef.current.getTriggerForm();
+      if (triggerData) {
+        formData.terms = triggerData.trigger;
+      }
+    }
+    console.log('save', formData);
+    if (formData) {
+      if (shakeLimit.enabled) {
+        formData.trigger = {
+          ...formData.trigger,
+          shakeLimit: shakeLimit,
+        };
+      }
+      setLoading(true);
+      const resp = formData.id ? await service.updateScene(formData) : await service.save(formData);
+
+      // 处理跳转新增
+      if ((window as any).onTabSaveSuccess) {
+        if (resp.result) {
+          (window as any).onTabSaveSuccess(resp);
+          setTimeout(() => window.close(), 300);
+        }
+      }
+
+      setLoading(false);
+      if (resp.status === 200) {
+        onlyMessage('操作成功');
+        const url = getMenuPathByCode('rule-engine/Scene');
+        history.push(url);
+      } else {
+        onlyMessage(resp.message);
+      }
+    }
+  }, [shakeLimit]);
+
+  const AntiShake = (
+    <Space>
+      <TitleComponent data={'触发条件'} style={{ margin: 0 }} />
+      <Switch
+        checked={shakeLimit.enabled}
+        checkedChildren="开启防抖"
+        unCheckedChildren="关闭防抖"
+        onChange={(e) => {
+          const newShake = {
+            ...shakeLimit,
+            enabled: e,
+          };
+          setShakeLimit(newShake);
+        }}
+        style={{ marginRight: 16 }}
+      />
+      {shakeLimit.enabled && (
+        <>
+          <InputNumber
+            value={shakeLimit.time}
+            min={1}
+            max={100}
+            onChange={(e: number) => {
+              const newShake = {
+                ...shakeLimit,
+                time: e,
+              };
+              setShakeLimit(newShake);
+            }}
+          />
+          <span style={{ padding: '0 16px' }}> 秒内发生 </span>
+          <InputNumber
+            value={shakeLimit.threshold}
+            min={1}
+            max={100}
+            onChange={(e: number) => {
+              const newShake = {
+                ...shakeLimit,
+                threshold: e,
+              };
+              setShakeLimit(newShake);
+            }}
+          />
+          <span style={{ padding: '0 16px' }}>次及以上时,处理</span>
+          <Radio.Group
+            value={shakeLimit.alarmFirst}
+            options={[
+              { label: '第一次', value: true },
+              { label: '最后一次', value: false },
+            ]}
+            optionType="button"
+            onChange={(e) => {
+              const newShake = {
+                ...shakeLimit,
+                alarmFirst: e.target.value,
+              };
+              setShakeLimit(newShake);
+            }}
+          ></Radio.Group>
+        </>
+      )}
+    </Space>
+  );
+
+  const hasKeyInObject = (keys: string[], obj: any) => {
+    return keys.some((key) => key in obj);
+  };
+
+  return (
+    <PageContainer>
+      <Card>
+        <div className={'scene-content'}>
+          <div className={'scene-content-left'}>
+            <Form
+              scrollToFirstError={{
+                behavior: 'smooth',
+                block: 'end',
+              }}
+              form={form}
+              colon={false}
+              name="basicForm"
+              layout={'vertical'}
+              preserve={false}
+              className={'scene-save'}
+              onValuesChange={(changeValue, allValues) => {
+                if (changeValue.trigger) {
+                  if (changeValue.trigger.device) {
+                    if (
+                      changeValue.trigger.device.productId ||
+                      changeValue.trigger.device.selectorValues ||
+                      (changeValue.trigger.device.operation &&
+                        hasKeyInObject(
+                          ['operator', 'eventId', 'functionId'],
+                          changeValue.trigger.device.operation,
+                        ))
+                    ) {
+                      setTriggerValue([]);
+                      setRequestParams({ trigger: allValues.trigger });
+                      setTriggerDatas(allValues.trigger);
+                    }
+
+                    if (
+                      hasKeyInObject(['productId'], changeValue.trigger.device) ||
+                      (changeValue.trigger.device.operation &&
+                        hasKeyInObject(
+                          ['operator', 'eventId', 'functionId'],
+                          changeValue.trigger.device.operation,
+                        ))
+                    ) {
+                      setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
+                    }
+                  } else if (['timer', 'manual'].includes(changeValue.trigger.type)) {
+                    setActionParams({ trigger: allValues.trigger }); // 用于内置参数请求
+                  }
+                }
+                if (allValues.actions) {
+                  // debugger;
+                  console.log(allValues.actions, 'onValuesChange');
+                  setActionsData(allValues.actions);
+                }
+                FormModel = { ...allValues };
+              }}
+            >
+              <Form.Item
+                name={'name'}
+                label={<TitleComponent data={'名称'} style={{ margin: 0 }} />}
+                rules={[
+                  { required: true, message: '请输入名称' },
+                  {
+                    max: 64,
+                    message: intl.formatMessage({
+                      id: 'pages.form.tip.max64',
+                      defaultMessage: '最多输入64个字符',
+                    }),
+                  },
+                ]}
+              >
+                <Input placeholder={'请输入名称'} />
+              </Form.Item>
+              <Form.Item
+                label={<TitleComponent data={'触发方式'} style={{ margin: 0 }} />}
+                required
+              >
+                <Form.Item
+                  name={['trigger', 'type']}
+                  rules={[{ required: true, message: '请选择触发方式' }]}
+                  initialValue={'device'}
+                >
+                  <TriggerWay onSelect={setTriggerType} disabled={isEdit || targetTypeDisabled} />
+                </Form.Item>
+                {triggerType === TriggerWayType.timing && (
+                  <TimingTrigger
+                    name={['trigger']}
+                    form={form}
+                    className={'trigger-type-content'}
+                  />
+                )}
+                {triggerType === TriggerWayType.device && (
+                  <TriggerDevice
+                    value={triggerDatas}
+                    className={'trigger-type-content'}
+                    form={form}
+                  />
+                )}
+              </Form.Item>
+              {triggerType === TriggerWayType.device &&
+              requestParams &&
+              requestParams.trigger?.device?.productId ? (
+                <Form.Item label={AntiShake}>
+                  <TriggerTerm ref={triggerRef} params={requestParams} value={triggerValue} />
+                </Form.Item>
+              ) : null}
+              <Form.Item hidden name={'parallel'} initialValue={true}>
+                <Input />
+              </Form.Item>
+              <Form.Item
+                label={
+                  <Space>
+                    <TitleComponent data={<span>执行动作</span>} style={{ margin: 0 }} />
+                    <Tooltip
+                      title={
+                        <div>
+                          <div>串行:按顺序依次执行动作</div>
+                          <div>并行:同时执行所有动作</div>
+                        </div>
+                      }
+                    >
+                      <QuestionCircleOutlined style={{ margin: '0 8px', fontSize: 14 }} />
+                    </Tooltip>
+                    <Radio.Group
+                      value={parallel}
+                      options={[
+                        { label: '串行', value: false },
+                        { label: '并行', value: true },
+                      ]}
+                      optionType="button"
+                      onChange={(e) => {
+                        setParallel(e.target.value);
+                        form.setFieldsValue({ parallel: e.target.value });
+                      }}
+                    ></Radio.Group>
+                  </Space>
+                }
+              >
+                <Form.List name="actions">
+                  {(fields, { add, remove, move }, { errors }) => (
+                    <>
+                      <div className={'scene-actions'} style={{ paddingBottom: 24 }}>
+                        {fields.map(({ key, name, ...restField }) => (
+                          <ActionItems
+                            key={key}
+                            form={form}
+                            restField={restField}
+                            name={name}
+                            trigger={actionParams}
+                            triggerType={triggerType}
+                            triggerRef={triggerRef.current}
+                            onRemove={() => {
+                              remove(name);
+                              setActionDataCount(actionDataCount - 1);
+                            }}
+                            onMove={(type) => {
+                              if (type === 'up') {
+                                move(name, name - 1);
+                              } else {
+                                move(name, name + 1);
+                              }
+                            }}
+                            actionItemData={actionsData[name]}
+                            isLast={!actionDataCount || actionDataCount - 1 === name}
+                            parallel={parallel}
+                            isEdit={isEdit}
+                          />
+                        ))}
+                        <Form.Item noStyle>
+                          <Button
+                            type="primary"
+                            ghost
+                            style={{
+                              width: '100%',
+                              marginTop: 16,
+                            }}
+                            onClick={() => {
+                              add();
+                              setActionDataCount(actionDataCount + 1);
+                            }}
+                            icon={<PlusOutlined />}
+                          >
+                            新增
+                          </Button>
+                        </Form.Item>
+                      </div>
+                      <Form.ErrorList errors={errors} />
+                    </>
+                  )}
+                </Form.List>
+              </Form.Item>
+              <Form.Item
+                label={<TitleComponent data={'说明'} style={{ margin: 0 }} />}
+                name={'description'}
+              >
+                <Input.TextArea showCount maxLength={200} placeholder={'请输入说明'} rows={4} />
+              </Form.Item>
+              {/*{triggerType === TriggerWayType.device &&*/}
+              {/*requestParams &&*/}
+              {/*requestParams.trigger?.device?.productId ? (*/}
+              {/*  <Form.Item hidden name={['trigger','shakeLimit']}>*/}
+              {/*    <Input />*/}
+              {/*  </Form.Item>*/}
+              {/*) : null}*/}
+              <Form.Item hidden name={'id'}>
+                <Input />
+              </Form.Item>
+              {!view && (
+                <PermissionButton
+                  isPermission={getOtherPermission(['add', 'update'])}
+                  onClick={saveData}
+                  type={'primary'}
+                  loading={loading}
+                  htmlType="submit"
+                >
+                  保存
+                </PermissionButton>
+              )}
+            </Form>
+          </div>
+          <div className={'scene-content-right'}>
+            <Explanation type={triggerType} />
+          </div>
+        </div>
+      </Card>
+    </PageContainer>
+  );
+};

+ 1 - 1
src/pages/rule-engine/Scene/Save/trigger/index.tsx

@@ -9,7 +9,7 @@ import Operation from './operation';
 import classNames from 'classnames';
 import { observer } from '@formily/reactive-react';
 import OrgTreeSelect from './OrgTreeSelect';
-import { FormModel } from '../index';
+import { FormModel } from '../old';
 import AllDevice from '@/pages/rule-engine/Scene/Save/action/device/AllDevice';
 import encodeQuery from '@/utils/encodeQuery';
 

+ 21 - 6
src/pages/rule-engine/Scene/index.tsx

@@ -20,6 +20,7 @@ import { getMenuPathByCode } from '@/utils/menu';
 import { StatusColorEnum } from '@/components/BadgeStatus';
 import { onlyMessage } from '@/utils/util';
 import useHistory from '@/hooks/route/useHistory';
+import Save from './Save';
 
 export const service = new Service('scene');
 
@@ -34,6 +35,8 @@ const Scene = () => {
   const actionRef = useRef<ActionType>();
   const { permission } = PermissionButton.usePermission('rule-engine/Scene');
   const [searchParams, setSearchParams] = useState<any>({});
+  const [visible, setVisible] = useState<boolean>(false);
+  const [current, setCurrent] = useState<Partial<SceneItem>>({});
   const history = useHistory();
 
   const deleteById = async (id: string) => {
@@ -95,8 +98,8 @@ const Scene = () => {
             : undefined
         }
         onClick={() => {
-          const url = getMenuPathByCode('rule-engine/Scene/Save');
-          history.push(`${url}?id=${record.id}`);
+          setVisible(true);
+          setCurrent(record);
         }}
       >
         <EditOutlined />
@@ -339,8 +342,10 @@ const Scene = () => {
             type="primary"
             isPermission={permission.add}
             onClick={() => {
-              const url = getMenuPathByCode('rule-engine/Scene/Save');
-              history.push(url);
+              // const url = getMenuPathByCode('rule-engine/Scene/Save');
+              // history.push(url);
+              setCurrent({});
+              setVisible(true);
             }}
           >
             {intl.formatMessage({
@@ -362,8 +367,10 @@ const Scene = () => {
                   title: '查看',
                 }}
                 onClick={() => {
-                  const url = getMenuPathByCode('rule-engine/Scene/Save');
-                  history.push(`${url}?id=${record.id}`, { view: true });
+                  // const url = getMenuPathByCode('rule-engine/Scene/Save');
+                  // history.push(`${url}?id=${record.id}`, { view: true });
+                  // setCurrent({})
+                  // setVisible(true)
                 }}
               >
                 <EyeOutlined />
@@ -373,6 +380,14 @@ const Scene = () => {
           />
         )}
       />
+      {visible && (
+        <Save
+          data={current}
+          close={() => {
+            setVisible(false);
+          }}
+        />
+      )}
     </PageContainer>
   );
 };