Jelajahi Sumber

feat: 新增过滤条件

xieyonghong 3 tahun lalu
induk
melakukan
ce7275554d

+ 231 - 0
src/pages/rule-engine/Scene/Save/action/ListItem/FilterCondition.tsx

@@ -0,0 +1,231 @@
+import type { TermsType, TermsVale } from '@/pages/rule-engine/Scene/typings';
+import { DropdownButton, ParamsDropdown } from '@/pages/rule-engine/Scene/Save/components/Buttons';
+import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
+import { useEffect, useState, useCallback } from 'react';
+import classNames from 'classnames';
+import { observer } from '@formily/react';
+import { queryBuiltInParams } from '@/pages/rule-engine/Scene/Save/action/service';
+import '../index.less';
+import { FormModel } from '../..';
+import { Space } from 'antd';
+
+interface FilterProps {
+  thenName: number;
+  data?: TermsType;
+  onChange: (value: TermsType) => void;
+  onAdd: () => void;
+  onDelete: () => void;
+}
+
+const DoubleFilter = ['nbtw', 'btw'];
+export default observer((props: FilterProps) => {
+  const [value, setValue] = useState<Partial<TermsVale> | undefined>({});
+  const [termType, setTermType] = useState('');
+  const [column, setColumn] = useState('');
+
+  const [columnOptions, setColumnOptions] = useState<any[]>([]);
+  const [ttOptions, setTtOptions] = useState<any[]>([]);
+  const [valueOptions] = useState<any[]>([]);
+  const [valueType, setValueType] = useState('');
+
+  const valueChange = useCallback(
+    (_value: any) => {
+      props.onChange?.({ ..._value });
+    },
+    [column, termType, value],
+  );
+
+  const valueEventChange = useCallback(
+    (_v: any) => {
+      valueChange({
+        column,
+        termType,
+        value: _v,
+      });
+    },
+    [column, termType],
+  );
+
+  const paramChange = (item: any) => {
+    const node = item.node;
+    const _termTypeOptions: any[] =
+      node.termTypes?.map((tItem: any) => ({ title: tItem.name, key: tItem.id })) || [];
+    setTtOptions(_termTypeOptions);
+    setValueType(node.dataType);
+  };
+
+  const handleName = (data: any) => {
+    return (
+      <Space>
+        {data.name}
+        {data.description && (
+          <div style={{ color: 'grey', marginLeft: '5px' }}>({data.description})</div>
+        )}
+      </Space>
+    );
+  };
+
+  const handleTreeData = (data: any): any[] => {
+    if (data.length > 0) {
+      return data.map((item: any) => {
+        const name = handleName(item);
+        if (item.children) {
+          return {
+            ...item,
+            key: item.id,
+            fullName: item.name,
+            title: name,
+            disabled: true,
+            children: handleTreeData(item.children),
+          };
+        }
+        return { ...item, key: item.id, fullName: item.name, title: name };
+      });
+    }
+    return [];
+  };
+
+  const getParmas = () => {
+    queryBuiltInParams(FormModel, { action: props.thenName }).then((res: any) => {
+      if (res.status === 200) {
+        setColumnOptions(handleTreeData(res.result));
+      }
+    });
+  };
+
+  useEffect(() => {
+    if (props.data) {
+      getParmas();
+    }
+  }, []);
+
+  return (
+    <div className="filter-condition-warp">
+      {props.data ? (
+        <div className="filter-condition-content">
+          <div
+            className={classNames('filter-condition-delete denger show')}
+            onClick={props.onDelete}
+          >
+            <DeleteOutlined />
+          </div>
+          <DropdownButton
+            options={columnOptions}
+            type="param"
+            placeholder="请选择参数"
+            value={column}
+            showLabelKey="fullName"
+            isTree={true}
+            onChange={(_value, item) => {
+              setValue({
+                value: undefined,
+                source: 'manual',
+              });
+              paramChange(item);
+              setColumn(_value!);
+              const node = item.node;
+              const _termTypeOptions: any[] =
+                node.termTypes?.map((tItem: any) => ({ title: tItem.name, key: tItem.id })) || [];
+              setTtOptions(_termTypeOptions);
+              // 默认选中第一个
+              let _termTypeValue = undefined;
+              if (_termTypeOptions.length) {
+                _termTypeValue = _termTypeOptions[0].key;
+                setTermType(_termTypeValue);
+              } else {
+                setTermType('');
+              }
+              valueChange({
+                column: _value,
+                value: {
+                  value: undefined,
+                  source: 'manual',
+                },
+                termType: _termTypeValue,
+              });
+            }}
+          />
+          <DropdownButton
+            options={ttOptions}
+            type="termType"
+            placeholder="操作符"
+            value={termType}
+            onChange={(v) => {
+              const _value = {
+                ...value,
+              };
+              if (value && DoubleFilter.includes(v!)) {
+                _value.value = [undefined, undefined];
+              } else {
+                _value.value = undefined;
+              }
+              setValue(_value);
+              setTermType(v!);
+              valueChange({
+                column: props.data!.column,
+                value: value as TermsVale,
+                termType: v,
+              });
+            }}
+          />
+          {DoubleFilter.includes(termType) ? (
+            <>
+              <ParamsDropdown
+                options={valueOptions}
+                type="value"
+                placeholder="参数值"
+                valueType={valueType}
+                value={value}
+                name={0}
+                onChange={(v) => {
+                  setValue({
+                    ...v,
+                  });
+                  valueEventChange(v);
+                }}
+              />
+              <ParamsDropdown
+                options={valueOptions}
+                type="value"
+                placeholder="参数值"
+                valueType={valueType}
+                value={value}
+                name={1}
+                onChange={(v) => {
+                  setValue({
+                    ...v,
+                  });
+                  valueEventChange(v);
+                }}
+              />
+            </>
+          ) : (
+            <ParamsDropdown
+              options={valueOptions}
+              type="value"
+              placeholder="参数值"
+              valueType={valueType}
+              value={value}
+              onChange={(v) => {
+                setValue({
+                  ...v,
+                });
+                valueEventChange(v);
+              }}
+            />
+          )}
+        </div>
+      ) : (
+        <div
+          className="filter-add-button"
+          onClick={() => {
+            props.onAdd();
+            getParmas();
+          }}
+        >
+          <PlusOutlined style={{ paddingRight: 16 }} /> 添加过滤条件
+        </div>
+      )}
+    </div>
+  );
+});

+ 40 - 2
src/pages/rule-engine/Scene/Save/action/ListItem/Item.tsx

@@ -1,10 +1,12 @@
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
 import Modal from '../Modal/add';
 import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import { DeleteOutlined } from '@ant-design/icons';
 import './index.less';
 import TriggerAlarm from '../TriggerAlarm';
 import { AddButton } from '@/pages/rule-engine/Scene/Save/components/Buttons';
+import FilterCondition from './FilterCondition';
+
 export enum ParallelEnum {
   'parallel' = 'parallel',
   'serial' = 'serial',
@@ -12,6 +14,7 @@ export enum ParallelEnum {
 
 export type ParallelType = keyof typeof ParallelEnum;
 interface ItemProps {
+  thenName: number;
   name: number;
   data: ActionsType;
   type: ParallelType;
@@ -39,6 +42,11 @@ itemNotifyIconMap.set('webhook', require('/public/images/scene/notify-item-img/w
 export default (props: ItemProps) => {
   const [visible, setVisible] = useState<boolean>(false);
   const [triggerVisible, setTriggerVisible] = useState<boolean>(false);
+  const [op, setOp] = useState<any>(props.options);
+
+  useEffect(() => {
+    setOp(props.options);
+  }, [props.options]);
 
   const notifyRender = (data: ActionsType | undefined) => {
     switch (data?.notify?.notifyType) {
@@ -207,7 +215,36 @@ export default (props: ItemProps) => {
           <DeleteOutlined />
         </div>
       </div>
-      {props.type === 'serial' ? props.parallel ? <div>添加过滤条件</div> : <div></div> : null}
+      {props.parallel ? null : (
+        <FilterCondition
+          thenName={props.thenName}
+          data={props.data.terms?.[0]}
+          onAdd={() => {
+            let _data = props.data;
+            if (!_data.terms) {
+              _data = {
+                ..._data,
+                terms: [{}],
+              };
+              props.onUpdate(_data, op);
+            }
+          }}
+          onChange={(termsData) => {
+            const _data = props.data;
+            if (_data.terms) {
+              _data.terms = [termsData];
+              props.onUpdate(_data, op);
+            }
+          }}
+          onDelete={() => {
+            const _data = props.data;
+            if (_data.terms) {
+              delete _data.terms;
+              props.onUpdate(_data, op);
+            }
+          }}
+        />
+      )}
       {visible && (
         <Modal
           name={props.name}
@@ -217,6 +254,7 @@ export default (props: ItemProps) => {
           }}
           save={(data: ActionsType, options) => {
             // FormModel.actions[props.name] = data;
+            setOp(options);
             props.onUpdate(data, options);
             setVisible(false);
           }}

+ 10 - 3
src/pages/rule-engine/Scene/Save/action/ListItem/List.tsx

@@ -6,6 +6,7 @@ import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import Item from './Item';
 import type { ParallelType } from './Item';
 interface ListProps {
+  thenName: number;
   type: ParallelType;
   actions: ActionsType[];
   parallel: boolean;
@@ -25,6 +26,7 @@ export default (props: ListProps) => {
     <div className="action-list-content">
       {actions.map((item, index) => (
         <Item
+          thenName={props.thenName}
           name={index}
           data={item}
           type={props.type}
@@ -61,16 +63,21 @@ export default (props: ListProps) => {
             setVisible(false);
           }}
           save={(data: any, options) => {
+            console.log(data);
+
             const { type, ...extra } = data;
             const item: ActionsType = {
               ...extra,
               executor: data.type === 'trigger' || data.type === 'relieve' ? 'alarm' : data.type,
               key: data.key,
-              alarm: {
-                mode: data.type,
-              },
               options,
             };
+
+            if (data.type === 'trigger' || data.type === 'relieve') {
+              item.alarm = {
+                mode: data.type,
+              };
+            }
             // const index = FormModel?.actions.findIndex((i) => {
             //   return i.key === item.key ? item : i;
             // });

+ 39 - 0
src/pages/rule-engine/Scene/Save/action/ListItem/index.less

@@ -83,3 +83,42 @@
     }
   }
 }
+
+.filter-condition-warp {
+  margin-bottom: 16px;
+
+  .filter-condition-content {
+    position: relative;
+    padding: 8px;
+    background-color: #fafafa;
+    border: 1px dashed rgba(0, 0, 0, 0.3);
+    row-gap: 16px;
+
+    .filter-condition-delete {
+      position: absolute;
+      top: -10px;
+      right: -10px;
+      display: none;
+      width: 20px;
+      height: 20px;
+      color: #999;
+      line-height: 20px;
+      text-align: center;
+      background-color: #f1f1f1;
+      border-radius: 50%;
+      cursor: pointer;
+
+      &.show {
+        display: block;
+      }
+
+      &:hover {
+        background-color: #f3f3f3;
+      }
+    }
+  }
+  .filter-add-button {
+    color: #2f54eb;
+    cursor: pointer;
+  }
+}

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

@@ -34,7 +34,7 @@ export default (props: Props) => {
             value={props.data?.device}
             save={(data: any, options: any) => {
               setActionType('');
-              // console.log(data,options)
+              console.log(data, options);
               props.save(data, options);
             }}
             name={props.name}
@@ -67,7 +67,9 @@ export default (props: Props) => {
                 {
                   type: 'delay',
                   key: props.data.key || `delay_${new Date().getTime()}`,
-                  ...data,
+                  delay: {
+                    ...data,
+                  },
                 },
                 options,
               );

+ 26 - 13
src/pages/rule-engine/Scene/Save/action/index.tsx

@@ -56,22 +56,28 @@ export default (props: ActionsProps) => {
               <Observer>
                 {() => {
                   const parallelThens = props.thenOptions.filter((item) => !item.parallel);
-                  console.log(parallelThens);
 
                   return (
                     <List
+                      thenName={props.name}
                       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;
-                          });
+                          if (
+                            parallelThens[0].actions.some((aItem) => aItem.key === actionItem.key)
+                          ) {
+                            parallelThens[0].actions = parallelThens[0].actions.map((aItem) => {
+                              if (aItem.key === actionItem.key) {
+                                return actionItem;
+                              }
+                              return aItem;
+                            });
+                          } else {
+                            parallelThens[0].actions.push(actionItem);
+                          }
                           set(FormModel, ['branches', props.name, 'then'], parallelThens);
                         } else {
                           parallelThens.push({
@@ -105,17 +111,24 @@ export default (props: ActionsProps) => {
                   const parallelThens = props.thenOptions.filter((item) => item.parallel);
                   return (
                     <List
+                      thenName={props.name}
                       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;
-                          });
+                          if (
+                            parallelThens[0].actions.some((aItem) => aItem.key === actionItem.key)
+                          ) {
+                            parallelThens[0].actions = parallelThens[0].actions.map((aItem) => {
+                              if (aItem.key === actionItem.key) {
+                                return actionItem;
+                              }
+                              return aItem;
+                            });
+                          } else {
+                            parallelThens[0].actions.push(actionItem);
+                          }
                           set(FormModel, ['branches', props.name, 'then'], parallelThens);
                         } else {
                           parallelThens.push({

+ 3 - 3
src/pages/rule-engine/Scene/Save/components/ParamsSelect/index.tsx

@@ -63,9 +63,9 @@ export default (props: Props) => {
     };
   });
 
-  useEffect(() => {
-    props.onChange(value, tabKey);
-  }, [value, tabKey]);
+  // useEffect(() => {
+  //   props.onChange(value, tabKey);
+  // }, [value, tabKey]);
 
   return (
     <div className={'select-wrapper'} ref={wrapperRef} style={props.style}>