Explorar o código

fix: 修改场景联动12.8

100011797 %!s(int64=3) %!d(string=hai) anos
pai
achega
463fe68c49

+ 9 - 1
src/components/ProTableCard/CardItems/Scene/index.tsx

@@ -129,6 +129,14 @@ enum UnitEnum {
 const notifyRender = (data: ActionsType | undefined) => {
   switch (data?.notify?.notifyType) {
     case 'dingTalk':
+      if (data?.options?.provider === 'dingTalkRobotWebHook') {
+        return (
+          <div>
+            通过<span className={'notify-text-highlight'}>群机器人消息</span>
+            发送<span>{data?.options?.templateName || data?.notify?.templateId}</span>
+          </div>
+        );
+      }
       return (
         <div className={styles['notify-img-highlight']}>
           向<span>{data?.options?.notifierName || data?.notify?.notifierId}</span>
@@ -279,7 +287,7 @@ const conditionsRender = (when: any[], index: number) => {
   if (when.length && when[index]) {
     let str: string = '';
     (when[index]?.terms || []).map((i: any, _index: number) => {
-      str += `${i?.terms[0] || ''}${
+      str += `${i?.terms.join(' ') || ''}${
         i?.termType && when[index]?.terms.length !== _index + 1 ? i?.termType : ''
       }`;
     });

+ 28 - 2
src/pages/rule-engine/Alarm/Configuration/Save/Base/index.tsx

@@ -12,6 +12,7 @@ import styles from '@/pages/rule-engine/Alarm/Configuration/Save/Base/index.less
 import useLocation from '@/hooks/route/useLocation';
 import { getMenuPathByCode } from '@/utils/menu';
 import { useHistory } from 'umi';
+import { service as sceneService } from '@/pages/rule-engine/Scene';
 
 const alarm1 = require('/public/images/alarm/alarm1.png');
 const alarm2 = require('/public/images/alarm/alarm2.png');
@@ -69,6 +70,31 @@ export default () => {
             if (!id) return;
             const resp = await service.detail(id);
             form1.setInitialValues({ ...resp.result });
+            const resp1 = await sceneService.query({
+              terms: [
+                {
+                  terms: [
+                    {
+                      column: 'id',
+                      termType: 'alarm-bind-rule',
+                      value: id,
+                    },
+                  ],
+                  type: 'and',
+                },
+              ],
+              sorts: [
+                {
+                  name: 'createTime',
+                  order: 'desc',
+                },
+              ],
+            });
+            if (resp1.status === 200) {
+              form1.setFieldState('.targetType', (state) => {
+                state.disabled = !!resp1.result.data?.length;
+              });
+            }
           });
         },
       }),
@@ -92,8 +118,8 @@ export default () => {
     const resp: any = await service.update({ ...data });
     if (resp.status === 200) {
       onlyMessage('操作成功');
-      const url = getMenuPathByCode('rule-engine/Alarm/Configuration');
-      history.push(`${url}`);
+      const url = getMenuPathByCode('rule-engine/Alarm/Configuration/Save');
+      history.push(`${url}?id=${resp.result?.id}`);
     }
   };
 

+ 16 - 2
src/pages/rule-engine/Alarm/Configuration/Save/index.tsx

@@ -3,14 +3,26 @@ import { Card, Tabs } from 'antd';
 import Scene from './Scene';
 import Base from './Base';
 import Log from './Log';
+import useLocation from '@/hooks/route/useLocation';
+import { useState } from 'react';
+import { onlyMessage } from '@/utils/util';
 
 export default () => {
+  const location = useLocation();
+  const id = location?.query?.id || '';
+  const [tab, setTab] = useState<string>('1');
   return (
     <PageContainer>
       <Card style={{ minHeight: 600 }}>
         <Tabs
-          defaultActiveKey="1"
-          onChange={() => {}}
+          activeKey={tab}
+          onChange={(key: string) => {
+            if (!id) {
+              onlyMessage('请先保存基础配置', 'error');
+            } else {
+              setTab(key);
+            }
+          }}
           items={[
             {
               label: `基础配置`,
@@ -20,11 +32,13 @@ export default () => {
             {
               label: `关联场景联动`,
               key: '2',
+              // disabled: !id,
               children: <Scene />,
             },
             {
               label: `告警记录`,
               key: '3',
+              // disabled: !id,
               children: <Log />,
             },
           ]}

+ 12 - 1
src/pages/rule-engine/Scene/Save/action/ListItem/Item.tsx

@@ -54,6 +54,17 @@ export default (props: ItemProps) => {
   const notifyRender = (data: ActionsType | undefined, options: any) => {
     switch (data?.notify?.notifyType) {
       case 'dingTalk':
+        if (options.provider === 'dingTalkRobotWebHook') {
+          return (
+            <div>
+              通过<span className={'notify-text-highlight'}>群机器人消息</span>
+              发送
+              <span className={'notify-text-highlight'}>
+                {options?.templateName || data?.notify?.templateId}
+              </span>
+            </div>
+          );
+        }
         return (
           <div>
             向<span className={'notify-text-highlight'}>{options?.orgName || ''}</span>
@@ -207,7 +218,7 @@ export default (props: ItemProps) => {
     } else if (props?.data?.alarm?.mode === 'relieve') {
       return (
         <div className={'item-options-content'}>
-          满足条件后将解除关联
+          满足条件后将解除
           <a
             onClick={() => {
               setTriggerVisible(true);

+ 3 - 2
src/pages/rule-engine/Scene/Save/action/TriggerAlarm/index.tsx

@@ -20,7 +20,7 @@ export default (props: Props) => {
     queryAlarmCount(
       encodeQuery({
         terms: {
-          sceneId: FormModel.current.id,
+          'id$rule-bind-alarm': FormModel.current.id,
         },
       }),
     ).then((resp) => {
@@ -161,8 +161,9 @@ export default (props: Props) => {
               {
                 terms: [
                   {
-                    column: 'sceneId',
+                    column: 'id',
                     value: FormModel.current.id,
+                    termType: 'rule-bind-alarm',
                   },
                 ],
                 type: 'and',

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/notify/NotifyConfig.tsx

@@ -73,7 +73,7 @@ export default observer((props: Props) => {
                 NotifyModel.notify.notifierId = String(selectedRowKeys[selectedRowKeys.length - 1]);
                 NotifyModel.notify.options = {
                   ...NotifyModel.notify.options,
-                  notifierName: list[list.length - 1]?.name,
+                  provider: list[list.length - 1]?.provider,
                 };
               }
             },

+ 58 - 74
src/pages/rule-engine/Scene/Save/action/notify/VariableDefinitions.tsx

@@ -7,7 +7,6 @@ import Tag from './components/variableItem/tag';
 import BuildIn from './components/variableItem/buildIn';
 import InputFile from './components/variableItem/inputFile';
 import { forwardRef, useCallback, useImperativeHandle } from 'react';
-import { onlyMessage } from '@/utils/util';
 
 interface Props {
   name: number;
@@ -21,7 +20,7 @@ export default forwardRef((props: Props, ref) => {
     switch (type) {
       case 'user':
         return <User />;
-      case '      ':
+      case 'org':
         return <Org />;
       case 'tag':
         return <Tag />;
@@ -37,43 +36,24 @@ export default forwardRef((props: Props, ref) => {
   const getRules = useCallback(
     (item: any, type: string): any[] => {
       const rules: any[] = [];
-      if (item?.required) {
-        if (type === 'user') {
-          rules.push({
-            validator: async (_: any, value: any) => {
-              if (!value) {
-                return Promise.reject(new Error('请选择' + item.name));
-              } else {
-                if (value.source === 'fixed' && !value.value) {
-                  return Promise.reject(new Error('请输入' + item.name));
-                } else if (value.source === 'relation' && !value.value && !value.relation) {
-                  return Promise.reject(new Error('请选择' + item.name));
-                }
-              }
-              return Promise.resolve();
-            },
-          });
-        } else {
-          rules.push({
-            validator: async (_: any, value: any) => {
-              if (type === 'file' || type === 'link') {
-                if (!value) {
-                  return Promise.reject(new Error('请输入' + item.name));
-                }
-              } else {
-                if (!value || !value.value) {
-                  if (['date', 'org'].includes(type)) {
-                    return Promise.reject(new Error('请选择' + item.name));
-                  } else {
-                    return Promise.reject(new Error('请输入' + item.name));
-                  }
-                }
-              }
-              return Promise.resolve();
-            },
-          });
-        }
-      }
+      rules.push({
+        validator: async (_: any, value: any) => {
+          if ((type === 'file' || type === 'link') && !value) {
+            return Promise.reject(new Error('请输入' + item.name));
+          } else if (type === 'tag' && !value) {
+            return Promise.reject(new Error('请选择' + item.name));
+          } else if (['date', 'org'].includes(type) && (!value || !value.value)) {
+            return Promise.reject(new Error('请选择' + item.name));
+          } else if (value.source === 'fixed' && !value.value) {
+            return Promise.reject(new Error('请输入' + item.name));
+          } else if (value.source === 'relation' && !value.value && !value.relation) {
+            return Promise.reject(new Error('请选择' + item.name));
+          } else if (value.source === 'upper' && !value.upperKey) {
+            return Promise.reject(new Error('请选择' + item.name));
+          }
+          return Promise.resolve();
+        },
+      });
 
       if (type === 'link') {
         rules.push({ max: 64, message: '最多64个字符' });
@@ -111,7 +91,6 @@ export default forwardRef((props: Props, ref) => {
           });
         }
       }
-
       return rules;
     },
     [NotifyModel.notify?.notifyType],
@@ -123,40 +102,45 @@ export default forwardRef((props: Props, ref) => {
         const formData = await form.validateFields().catch(() => {
           resolve(false);
         });
-        if (
-          NotifyModel.notify.notifyType &&
-          ['dingTalk', 'weixin'].includes(NotifyModel.notify.notifyType)
-        ) {
-          const arr = NotifyModel.variable.map((item) => {
-            return { type: item.expands?.businessType || item?.type, id: item.id };
-          });
-          const org = arr.find((i) => i.type === 'org')?.id;
-          const user = arr.find((i) => i.type === 'user')?.id;
-          if (org && user) {
-            if (
-              (formData[org]?.source && formData[org]?.value) ||
-              (!formData[org]?.source && formData[org]) ||
-              (formData[user]?.source && (formData[user]?.value || formData[user]?.relation)) ||
-              (!formData[user]?.source && formData[user])
-            ) {
-              resolve(formData);
-            } else {
-              onlyMessage('收信人和收信部门必填一个', 'error');
-              resolve(false);
-            }
-          } else {
-            if (formData) {
-              resolve(formData);
-            } else {
-              resolve(false);
-            }
-          }
+        // if (
+        //   NotifyModel.notify.notifyType &&
+        //   ['dingTalk', 'weixin'].includes(NotifyModel.notify.notifyType)
+        // ) {
+        //   const arr = NotifyModel.variable.map((item) => {
+        //     return { type: item.expands?.businessType || item?.type, id: item.id };
+        //   });
+        //   const org = arr.find((i) => i.type === 'org')?.id;
+        //   const user = arr.find((i) => i.type === 'user')?.id;
+        //   if (org && user) {
+        //     if (
+        //       (formData[org]?.source && formData[org]?.value) ||
+        //       (!formData[org]?.source && formData[org]) ||
+        //       (formData[user]?.source && (formData[user]?.value || formData[user]?.relation)) ||
+        //       (!formData[user]?.source && formData[user])
+        //     ) {
+        //       resolve(formData);
+        //     } else {
+        //       onlyMessage('收信人和收信部门必填一个', 'error');
+        //       resolve(false);
+        //     }
+        //   } else {
+        //     if (formData) {
+        //       resolve(formData);
+        //     } else {
+        //       resolve(false);
+        //     }
+        //   }
+        // } else {
+        //   if (formData) {
+        //     resolve(formData);
+        //   } else {
+        //     resolve(false);
+        //   }
+        // }
+        if (formData) {
+          resolve(formData);
         } else {
-          if (formData) {
-            resolve(formData);
-          } else {
-            resolve(false);
-          }
+          resolve(false);
         }
       } else {
         resolve({});
@@ -209,7 +193,7 @@ export default forwardRef((props: Props, ref) => {
               name={item.id}
               label={item.name}
               initialValue={initialValue}
-              required={!!item.required}
+              required={true}
               rules={rules}
             >
               {typeComponents(item)}

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/notify/components/variableItem/org.tsx

@@ -57,7 +57,7 @@ export default (props: OrgProps) => {
         if (props.onChange) {
           NotifyModel.notify.options = {
             ...NotifyModel.notify.options,
-            orgName: label,
+            orgName: label.join(','),
           };
           props.onChange({
             source: 'fixed',

+ 90 - 60
src/pages/rule-engine/Scene/Save/action/notify/components/variableItem/user.tsx

@@ -8,9 +8,9 @@ import {
   queryRelationUsers,
   queryWechatUsers,
 } from '@/pages/rule-engine/Scene/Save/action/service';
-import { useLocation } from '@/hooks';
 import { observer } from '@formily/react';
 import { NotifyModel } from '../../index';
+import { FormModel } from '@/pages/rule-engine/Scene/Save';
 
 type ChangeType = {
   source?: string;
@@ -24,42 +24,79 @@ interface UserProps {
   type?: string;
 }
 
+const labelMap = new Map();
+
 export default observer((props: UserProps) => {
   const [source, setSource] = useState<string | undefined>(props.value?.source || '');
-  const [value, setValue] = useState<string | undefined>(undefined);
+  const [value, setValue] = useState<string | string[] | undefined>(undefined);
   const [relationList, setRelationList] = useState<any[]>([]);
   const [treeData, setTreeData] = useState<any[]>([
     { name: '平台用户', id: 'p1', selectable: false, children: [] },
   ]);
 
-  const location = useLocation();
-
   useEffect(() => {
-    setSource(props.value?.source);
-    if (props.value?.source === 'relation') {
-      const relation = props.value?.relation;
-      if (relation) {
-        if (relation.objectId) {
-          // 平台用户
-          setValue(relation.objectId);
+    if (NotifyModel?.notify?.notifyType === 'email' && Array.isArray(props.value)) {
+      setSource('relation');
+      const arr = (props?.value || []).map((item: any) => {
+        if (item?.source === 'relation') {
+          const relation = item?.relation;
+          if (relation) {
+            if (relation.objectId) {
+              // 平台用户
+              return relation.objectId;
+            } else {
+              // 关系用户
+              return relation.related.relation;
+            }
+          }
         } else {
-          // 关系用户
-          setValue(relation.related?.relation);
+          return item?.value;
         }
-      }
+      });
+      setValue(arr);
     } else {
-      setValue(props.value?.value);
+      setSource(props.value?.source);
+      if (props.value?.source === 'relation') {
+        const relation = props.value?.relation;
+        if (relation) {
+          if (relation.objectId) {
+            // 平台用户
+            setValue(relation.objectId);
+          } else {
+            // 关系用户
+            setValue(relation.related?.relation);
+          }
+        }
+      } else {
+        setValue(props.value?.value);
+      }
     }
   }, [props.value]);
 
   const getPlatformUser = async () => {
-    const newTree = [...treeData];
+    const newTree = [{ name: '平台用户', id: 'p1', selectable: false, children: [] }];
     const platformResp = await queryPlatformUsers();
 
     if (platformResp.status === 200) {
       newTree[0].children = platformResp.result;
     }
-
+    if (FormModel.current?.trigger?.type && source === 'relation') {
+      if (FormModel.current?.trigger?.type === 'device') {
+        const relationResp = await queryRelationUsers();
+        if (relationResp.status === 200) {
+          newTree.push({
+            name: '关系用户',
+            id: 'p2',
+            selectable: false,
+            children: relationResp.result,
+          });
+        }
+      } else {
+        if (newTree.length > 1) {
+          newTree.splice(1, 1);
+        }
+      }
+    }
     setTreeData(newTree);
   };
 
@@ -108,12 +145,7 @@ export default observer((props: UserProps) => {
     },
   ];
 
-  const onchange = (
-    _source: string = 'fixed',
-    _value?: string,
-    isRelation?: boolean,
-    _name?: string,
-  ) => {
+  const getObj = (_source: string = 'fixed', _value?: string, isRelation?: boolean) => {
     const obj: any = {
       source: _source,
     };
@@ -139,44 +171,38 @@ export default observer((props: UserProps) => {
     } else {
       obj.value = _value;
     }
+    return obj;
+  };
 
+  const onchange = (
+    _source: string = 'fixed',
+    _value?: string | string[],
+    isRelation?: boolean,
+    _name?: string,
+  ) => {
+    let _values: any = undefined;
+    const _names: string[] = [_name || ''];
+    if (Array.isArray(_value)) {
+      if (NotifyModel?.notify?.notifyType === 'email' && Array.isArray(_value)) {
+        const arr = _value.map((item) => {
+          const _item = labelMap.get(item);
+          _names.push(_item?.name || '');
+          return getObj('relation', item, _item?.relation);
+        });
+        _values = arr;
+      }
+    } else {
+      _values = getObj(_source, _value, isRelation);
+    }
     if (props.onChange) {
       NotifyModel.notify.options = {
         ...NotifyModel.notify.options,
-        sendTo: _name,
+        sendTo: _names.filter((item) => !!item).join(','),
       };
-      props.onChange(obj);
+      props.onChange(_values);
     }
   };
 
-  useEffect(() => {
-    if (props.type && source === 'relation') {
-      const newTree = [...treeData];
-      if (props.type === 'device') {
-        queryRelationUsers().then((relationResp) => {
-          if (relationResp.status === 200) {
-            newTree.push({
-              name: '关系用户',
-              id: 'p2',
-              selectable: false,
-              children: relationResp.result,
-            });
-            setTreeData(newTree);
-          }
-        });
-      } else {
-        if (newTree.length > 1) {
-          newTree.splice(1, 1);
-          setTreeData(newTree);
-        }
-      }
-
-      if (!location.query?.id) {
-        onchange(props.value?.source, '', false, '');
-      }
-    }
-  }, [props.type, source]);
-
   const filterOption = (input: string, option: any) => {
     return option.name ? option.name.toLowerCase().includes(input.toLowerCase()) : false;
   };
@@ -185,15 +211,18 @@ export default observer((props: UserProps) => {
     return data.map((item: any) => {
       if (item.children) {
         return (
-          <TreeSelect.TreeNode value={item.id} title={item.name} selectable={false}>
+          <TreeSelect.TreeNode key={item.id} value={item.id} title={item.name} selectable={false}>
             {createTreeNode(item.children)}
           </TreeSelect.TreeNode>
         );
       } else {
+        labelMap.set(item.id, item);
         return (
           <TreeSelect.TreeNode
+            {...item}
             name={item.name}
             value={item.id}
+            key={item.id}
             title={
               <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                 <span>{item.name}</span>
@@ -216,7 +245,7 @@ export default observer((props: UserProps) => {
         placeholder={'请选择收信人'}
         onSelect={(key: any, node: any) => {
           setValue(key);
-          onchange(source, key, node.isRelation, node.name);
+          onchange(source, key, node?.relation, node.name);
         }}
         filterTreeNode={filterOption}
       >
@@ -231,7 +260,7 @@ export default observer((props: UserProps) => {
         listHeight={200}
         onChange={(key, option) => {
           setValue(key);
-          onchange(source, key, false, option?.label);
+          onchange(source, key, false, option?.label || option?.name);
         }}
         fieldNames={{ label: 'name', value: 'id' }}
         placeholder={'请选择收信人'}
@@ -247,11 +276,12 @@ export default observer((props: UserProps) => {
         showSearch
         allowClear
         value={value}
+        multiple={true}
         dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
         placeholder={'请选择收信人'}
-        onSelect={(key: any, node: any) => {
-          setValue(key);
-          onchange(source, key, node.isRelation, node.name);
+        onChange={(val) => {
+          setValue(val);
+          onchange(source, val);
         }}
         filterTreeNode={filterOption}
       >
@@ -277,7 +307,7 @@ export default observer((props: UserProps) => {
         placeholder={'请选择收信人'}
         onSelect={(key: any, node: any) => {
           setValue(key);
-          onchange(source, key, node.isRelation, node.name);
+          onchange(source, key, node?.relation, node.name);
         }}
         filterTreeNode={filterOption}
       >

+ 5 - 1
src/pages/rule-engine/Scene/Save/components/TriggerWay/actionsType.tsx

@@ -62,7 +62,11 @@ export default (props: ActionsTypeProps) => {
   };
 
   return (
-    <div className={classNames('trigger-way-warp', props.className, { disabled: props.disabled })}>
+    <div
+      className={classNames('scene-trigger-way-warp', props.className, {
+        disabled: props.disabled,
+      })}
+    >
       {TypeList.map((item) =>
         props.parallel && item.value === 'delay' ? null : (
           <div

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

@@ -1,6 +1,6 @@
 @import '../../../../../../../node_modules/antd/es/style/themes/default.less';
 
-.trigger-way-warp {
+.scene-trigger-way-warp {
   display: flex;
   flex-wrap: wrap;
   gap: 16px 24px;
@@ -13,7 +13,6 @@
     border: 1px solid #e0e4e8;
     border-radius: 2px;
     cursor: pointer;
-    opacity: 0.6;
     transition: all 0.3s;
 
     .way-item-title {
@@ -30,17 +29,25 @@
     }
 
     .way-item-image {
+      display: flex;
+      align-items: center;
+      height: 100%;
       margin: 0 !important;
+      opacity: 0.6;
     }
 
     &:hover {
       color: @primary-color-hover;
-      opacity: 0.8;
+      .way-item-image {
+        opacity: 0.8;
+      }
     }
 
     &.active {
       border-color: @primary-color-active;
-      opacity: 1;
+      .way-item-image {
+        opacity: 1;
+      }
     }
   }
 

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

@@ -37,7 +37,11 @@ export default (props: TriggerWayProps) => {
   };
 
   return (
-    <div className={classNames('trigger-way-warp', props.className, { disabled: props.disabled })}>
+    <div
+      className={classNames('scene-trigger-way-warp', props.className, {
+        disabled: props.disabled,
+      })}
+    >
       <div
         className={classNames('trigger-way-item', {
           active: type === TriggerWayType.device,