ソースを参照

feat: 优化执行动作

xieyonghong 3 年 前
コミット
1890774b44

+ 83 - 0
src/pages/rule-engine/Scene/Save/action/Delay/index.tsx

@@ -0,0 +1,83 @@
+import { Modal, Select, InputNumber } from 'antd';
+import { useEffect, useState } from 'react';
+import { observer } from '@formily/react';
+
+export enum TimeUnit {
+  'seconds' = 'seconds',
+  'minutes' = 'minutes',
+  'hours' = 'hours',
+}
+
+export const timeUnitEnum = {
+  seconds: '秒',
+  minutes: '分',
+  hours: '小时',
+};
+
+interface Props {
+  value: {
+    time?: number;
+    unit?: string;
+  };
+  save: (
+    notify: {
+      time?: number;
+      unit?: string;
+    },
+    options: any,
+  ) => void;
+  cancel: () => void;
+}
+
+export default observer((props: Props) => {
+  const [value, setValue] = useState<number>(0);
+  const [unit, setUnit] = useState('seconds');
+  useEffect(() => {
+    if (props.value) {
+      setUnit(props.value.unit || 'seconds');
+      setValue(props.value.time || 0);
+    }
+  }, []);
+
+  const TimeTypeAfter = (
+    <Select
+      options={[
+        { label: '秒', value: 'seconds' },
+        { label: '分', value: 'minutes' },
+        { label: '小时', value: 'hours' },
+      ]}
+      value={unit}
+      onChange={setUnit}
+    />
+  );
+
+  return (
+    <Modal
+      title={'执行动作'}
+      open
+      width={400}
+      onCancel={() => {
+        props.cancel();
+      }}
+      onOk={() => {
+        props.save(
+          {
+            time: value,
+            unit,
+          },
+          { name: `延迟 ${value} ${timeUnitEnum[unit]} 执行` },
+        );
+      }}
+    >
+      <InputNumber
+        placeholder={'请输入时间'}
+        addonAfter={TimeTypeAfter}
+        style={{ maxWidth: 220 }}
+        value={value}
+        onChange={(v) => setValue(v!)}
+        min={0}
+        max={59}
+      />
+    </Modal>
+  );
+});

+ 14 - 19
src/pages/rule-engine/Scene/Save/action/ListItem/Item.tsx

@@ -2,7 +2,6 @@ import { useState } from 'react';
 import Modal from '../Modal/add';
 import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import { DeleteOutlined } from '@ant-design/icons';
-import { FormModel } from '@/pages/rule-engine/Scene/Save';
 import './index.less';
 import TriggerAlarm from '../TriggerAlarm';
 import { AddButton } from '@/pages/rule-engine/Scene/Save/components/Buttons';
@@ -16,6 +15,10 @@ interface ItemProps {
   name: number;
   data: ActionsType;
   type: ParallelType;
+  parallel: boolean;
+  options: any;
+  onUpdate: (data: any, options: any) => void;
+  onDelete: () => void;
 }
 
 const iconMap = new Map();
@@ -170,6 +173,10 @@ export default (props: ItemProps) => {
       );
     } else if (props?.data?.executor === 'notify') {
       return notifyRender(props?.data);
+    } else if (props?.data?.executor === 'delay') {
+      return <div> {props.options.name}</div>;
+    } else if (props.data?.executor === 'device') {
+      return <div></div>;
     }
     return (
       <AddButton
@@ -204,25 +211,11 @@ export default (props: ItemProps) => {
           </div>
         </div>
         <div className="item-number">{props.name + 1}</div>
-        <div
-          className="item-delete"
-          onClick={() => {
-            const indexOf = FormModel.actions.findIndex((item) => item.key === props.data.key);
-            if (props.data.key && indexOf !== -1) {
-              FormModel.actions.splice(indexOf, 1);
-            }
-          }}
-        >
+        <div className="item-delete" onClick={props.onDelete}>
           <DeleteOutlined />
         </div>
       </div>
-      {props.type === 'serial' ? (
-        props.data.terms?.length ? (
-          <div></div>
-        ) : (
-          <div>添加过滤条件</div>
-        )
-      ) : null}
+      {props.type === 'serial' ? props.parallel ? <div>添加过滤条件</div> : <div></div> : null}
       {visible && (
         <Modal
           name={props.name}
@@ -230,10 +223,12 @@ export default (props: ItemProps) => {
           close={() => {
             setVisible(false);
           }}
-          save={(data: ActionsType) => {
-            FormModel.actions[props.name] = data;
+          save={(data: ActionsType, options) => {
+            // FormModel.actions[props.name] = data;
+            props.onUpdate(props, options);
             setVisible(false);
           }}
+          type={props.type}
         />
       )}
       {triggerVisible && (

+ 29 - 7
src/pages/rule-engine/Scene/Save/action/ListItem/List.tsx

@@ -5,10 +5,12 @@ import './index.less';
 import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import Item from './Item';
 import type { ParallelType } from './Item';
-import { FormModel } from '@/pages/rule-engine/Scene/Save';
 interface ListProps {
   type: ParallelType;
   actions: ActionsType[];
+  parallel: boolean;
+  onAdd: (data: any) => void;
+  onDelete: (index: number) => void;
 }
 
 export default (props: ListProps) => {
@@ -22,7 +24,24 @@ export default (props: ListProps) => {
   return (
     <div className="action-list-content">
       {actions.map((item, index) => (
-        <Item name={index} data={item} type={props.type} key={item.key} />
+        <Item
+          name={index}
+          data={item}
+          type={props.type}
+          key={item.key}
+          parallel={props.parallel}
+          options={item.options}
+          onDelete={() => {
+            props.onDelete(index);
+          }}
+          onUpdate={(data, options) => {
+            props.onAdd({
+              ...data,
+              options,
+            });
+            setVisible(false);
+          }}
+        />
       ))}
       <AddButton
         onClick={() => {
@@ -33,6 +52,7 @@ export default (props: ListProps) => {
       </AddButton>
       {visible && (
         <Modal
+          type={props.type}
           name={props.actions.length + 1}
           data={{
             key: `${props.type}_${props.actions.length}`,
@@ -40,7 +60,7 @@ export default (props: ListProps) => {
           close={() => {
             setVisible(false);
           }}
-          save={(data: any) => {
+          save={(data: any, options) => {
             const { type, ...extra } = data;
             const item: ActionsType = {
               ...extra,
@@ -49,11 +69,13 @@ export default (props: ListProps) => {
               alarm: {
                 mode: data.type,
               },
+              options,
             };
-            const index = FormModel?.actions.findIndex((i) => {
-              return i.key === item.key ? item : i;
-            });
-            FormModel.actions[index] = { ...item };
+            // const index = FormModel?.actions.findIndex((i) => {
+            //   return i.key === item.key ? item : i;
+            // });
+            // FormModel.actions[index] = { ...item };
+            props.onAdd(item);
             setVisible(false);
           }}
         />

+ 24 - 2
src/pages/rule-engine/Scene/Save/action/Modal/add.tsx

@@ -2,14 +2,16 @@ import { Modal, Form } from 'antd';
 import ActionsTypeComponent from '@/pages/rule-engine/Scene/Save/components/TriggerWay/actionsType';
 import { useEffect, useState } from 'react';
 import Notify from '../notify';
-import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
+import type { ActionsType, ParallelType } from '@/pages/rule-engine/Scene/typings';
 import Device from '../DeviceOutput';
+import Delay from '../Delay';
 
 interface Props {
   close: () => void;
   save: (data: any, options?: any) => void;
   data: Partial<ActionsType>;
   name: number;
+  type: ParallelType;
 }
 
 export default (props: Props) => {
@@ -55,6 +57,26 @@ export default (props: Props) => {
             }}
           />
         );
+      case 'delay':
+        return (
+          <Delay
+            value={props.data?.delay || {}}
+            save={(data: any, options) => {
+              setActionType('');
+              props.save(
+                {
+                  type: 'delay',
+                  key: props.data.key || `delay_${new Date().getTime()}`,
+                  ...data,
+                },
+                options,
+              );
+            }}
+            cancel={() => {
+              setActionType('');
+            }}
+          />
+        );
       default:
         return null;
     }
@@ -83,7 +105,7 @@ export default (props: Props) => {
           required
           rules={[{ required: true, message: '请选择类型' }]}
         >
-          <ActionsTypeComponent />
+          <ActionsTypeComponent type={props.type} />
         </Form.Item>
       </Form>
       {actionTypeComponent(actionType)}

+ 74 - 17
src/pages/rule-engine/Scene/Save/action/index.tsx

@@ -4,14 +4,15 @@ import { FormModel } from '@/pages/rule-engine/Scene/Save';
 import ShakeLimit from '../components/ShakeLimit';
 import './index.less';
 import { Observer } from '@formily/react';
-import { get } from 'lodash';
-import type { ShakeLimitType } from '../../typings';
+import { get, set } from 'lodash';
+import type { ShakeLimitType, BranchesThen } from '../../typings';
 
 const { Panel } = Collapse;
 
 interface ActionsProps {
-  name?: (string | number)[];
+  name: number;
   openShakeLimit?: boolean;
+  thenOptions: BranchesThen[];
 }
 
 export default (props: ActionsProps) => {
@@ -22,7 +23,10 @@ export default (props: ActionsProps) => {
         {props.openShakeLimit ? (
           <Observer>
             {() => {
-              const data: ShakeLimitType = get(FormModel, [...props.name!, 'shakeLimit']);
+              const data: ShakeLimitType | undefined = get(FormModel.branches, [
+                props.name!,
+                'shakeLimit',
+              ]);
               return (
                 <ShakeLimit
                   enabled={data?.enabled}
@@ -30,7 +34,7 @@ export default (props: ActionsProps) => {
                   threshold={data?.threshold}
                   alarmFirst={data?.alarmFirst}
                   onChange={(type, value) => {
-                    data[type] = value;
+                    data![type] = value;
                   }}
                 />
               );
@@ -50,12 +54,40 @@ export default (props: ActionsProps) => {
           >
             <div className="actions-list">
               <Observer>
-                {() => (
-                  <List
-                    type="serial"
-                    actions={FormModel.actions.filter((item) => 'terms' in item)}
-                  />
-                )}
+                {() => {
+                  const parallelThens = props.thenOptions.filter((item) => !item.parallel);
+                  console.log(parallelThens);
+
+                  return (
+                    <List
+                      type="serial"
+                      parallel={false}
+                      actions={parallelThens.length ? parallelThens[0].actions : []}
+                      onAdd={(actionItem) => {
+                        console.log(parallelThens);
+                        if (parallelThens[0]) {
+                          parallelThens[0].actions = parallelThens[0].actions.map((aItem) => {
+                            if (aItem.key === actionItem.key) {
+                              return actionItem;
+                            }
+                            return aItem;
+                          });
+                          set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                        } else {
+                          parallelThens.push({
+                            parallel: false,
+                            actions: [actionItem],
+                          });
+                          set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                        }
+                      }}
+                      onDelete={(_index) => {
+                        parallelThens[0].actions.splice(_index, 1);
+                        set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                      }}
+                    />
+                  );
+                }}
               </Observer>
             </div>
           </Panel>
@@ -69,12 +101,37 @@ export default (props: ActionsProps) => {
           >
             <div className="actions-list">
               <Observer>
-                {() => (
-                  <List
-                    type="parallel"
-                    actions={FormModel.actions.filter((item) => !('terms' in item))}
-                  />
-                )}
+                {() => {
+                  const parallelThens = props.thenOptions.filter((item) => item.parallel);
+                  return (
+                    <List
+                      type="parallel"
+                      parallel={true}
+                      actions={parallelThens.length ? parallelThens[0].actions : []}
+                      onAdd={(actionItem) => {
+                        if (parallelThens[0]) {
+                          parallelThens[0].actions = parallelThens[0].actions.map((aItem) => {
+                            if (aItem.key === actionItem.key) {
+                              return actionItem;
+                            }
+                            return aItem;
+                          });
+                          set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                        } else {
+                          parallelThens.push({
+                            parallel: true,
+                            actions: [actionItem],
+                          });
+                          set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                        }
+                      }}
+                      onDelete={(_index) => {
+                        parallelThens[0].actions.splice(_index, 1);
+                        set(FormModel, ['branches', props.name, 'then'], parallelThens);
+                      }}
+                    />
+                  );
+                }}
               </Observer>
             </div>
           </Panel>

+ 23 - 19
src/pages/rule-engine/Scene/Save/components/TriggerWay/actionsType.tsx

@@ -1,6 +1,7 @@
 import { useEffect, useState } from 'react';
 import classNames from 'classnames';
 import './index.less';
+import { ParallelType } from '../../../typings';
 
 interface ActionsTypeProps {
   value?: string;
@@ -8,6 +9,7 @@ interface ActionsTypeProps {
   onChange?: (type: string) => void;
   onSelect?: (type: string) => void;
   disabled?: boolean;
+  type: ParallelType;
 }
 
 export enum ActionsTypeEnum {
@@ -68,26 +70,28 @@ export default (props: ActionsTypeProps) => {
 
   return (
     <div className={classNames('trigger-way-warp', props.className, { disabled: props.disabled })}>
-      {TypeList.map((item) => (
-        <div
-          key={item.value}
-          className={classNames('trigger-way-item', {
-            active: type === item.value,
-          })}
-          style={{ width: 237 }}
-          onClick={() => {
-            onSelect(item.value);
-          }}
-        >
-          <div className={'way-item-title'}>
-            <p>{item.label}</p>
-            <span>{item.tip}</span>
+      {TypeList.map((item) =>
+        props.type === 'parallel' && item.value === 'delay' ? null : (
+          <div
+            key={item.value}
+            className={classNames('trigger-way-item', {
+              active: type === item.value,
+            })}
+            style={{ width: 237 }}
+            onClick={() => {
+              onSelect(item.value);
+            }}
+          >
+            <div className={'way-item-title'}>
+              <p>{item.label}</p>
+              <span>{item.tip}</span>
+            </div>
+            <div className={'way-item-image'}>
+              <img width={48} src={item.image} />
+            </div>
           </div>
-          <div className={'way-item-image'}>
-            <img width={48} src={item.image} />
-          </div>
-        </div>
-      ))}
+        ),
+      )}
     </div>
   );
 };

+ 11 - 4
src/pages/rule-engine/Scene/Save/manual/index.tsx

@@ -1,8 +1,15 @@
-import Actions from '../action';
-export default () => {
+import Action from '../action';
+import { Observer, observer } from '@formily/react';
+import { FormModel } from '@/pages/rule-engine/Scene/Save';
+
+export default observer(() => {
   return (
     <div>
-      <Actions />
+      <Observer>
+        {() => (
+          <Action thenOptions={FormModel.branches ? FormModel.branches[0].then : []} name={0} />
+        )}
+      </Observer>
     </div>
   );
-};
+});

+ 1 - 1
src/pages/rule-engine/Scene/Save/terms/branchItem.tsx

@@ -111,7 +111,7 @@ export default observer((props: BranchesItemProps) => {
           )}
         </div>
         <div className="actions-branchs">
-          <Actions openShakeLimit={true} name={['branches', props.name]} />
+          <Actions openShakeLimit={true} name={props.name} thenOptions={props.data.then} />
         </div>
       </div>
     </div>

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

@@ -52,7 +52,11 @@ export default observer(() => {
         </Observer>
       </div>
       <div>
-        <Action />
+        <Observer>
+          {() => (
+            <Action thenOptions={FormModel.branches ? FormModel.branches[0].then : []} name={0} />
+          )}
+        </Observer>
       </div>
       {visible && (
         <TimerTrigger

+ 8 - 1
src/pages/rule-engine/Scene/typings.d.ts

@@ -10,6 +10,13 @@ type Trigger = {
   device: Record<string, unknown>;
 };
 
+export enum ParallelEnum {
+  'parallel' = 'parallel',
+  'serial' = 'serial',
+}
+
+export type ParallelType = keyof typeof ParallelEnum;
+
 export enum Source {
   'manual' = 'manual',
   'metric' = 'metric',
@@ -239,7 +246,7 @@ export interface ActionsDeviceProps {
 
 export interface BranchesThen {
   parallel: boolean;
-  actions: ActionsType;
+  actions: ActionsType[];
   key?: string;
 }