Browse Source

feat: merge

xieyonghong 3 năm trước cách đây
mục cha
commit
e98a1213ea
34 tập tin đã thay đổi với 637 bổ sung263 xóa
  1. 0 1
      src/components/ProTableCard/CardItems/DataCollect/channel.tsx
  2. 16 7
      src/components/ProTableCard/CardItems/Scene/index.less
  3. 63 19
      src/components/ProTableCard/CardItems/Scene/index.tsx
  4. 1 1
      src/components/ProTableCard/CardItems/edge/Resource.tsx
  5. 5 4
      src/pages/edge/Resource/index.tsx
  6. 1 0
      src/pages/edge/Resource/typings.d.ts
  7. 4 4
      src/pages/link/DashBoard/index.tsx
  8. 1 1
      src/pages/link/DataCollect/DataGathering/index.tsx
  9. 57 15
      src/pages/link/DataCollect/components/Channel/index.tsx
  10. 1 0
      src/pages/link/DataCollect/components/Device/Save/index.tsx
  11. 11 9
      src/pages/link/DataCollect/components/Device/index.tsx
  12. 70 26
      src/pages/link/DataCollect/components/Tree/index.tsx
  13. 34 0
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/ReadProperty.tsx
  14. 23 3
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/TypeModel.tsx
  15. 6 3
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/WriteProperty.tsx
  16. 22 4
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/index.tsx
  17. 11 5
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/device/TopCard.tsx
  18. 9 1
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/device/index.tsx
  19. 50 17
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/index.less
  20. 21 9
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/index.tsx
  21. 4 0
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/model.ts
  22. 2 6
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/product/index.tsx
  23. 31 15
      src/pages/rule-engine/Scene/Save/action/ListItem/Item.tsx
  24. 97 81
      src/pages/rule-engine/Scene/Save/action/Modal/add.tsx
  25. 1 1
      src/pages/rule-engine/Scene/Save/action/notify/NotifyWay.tsx
  26. 9 1
      src/pages/rule-engine/Scene/Save/action/notify/VariableDefinitions.tsx
  27. 2 2
      src/pages/rule-engine/Scene/Save/action/notify/components/variableItem/buildIn.tsx
  28. 1 4
      src/pages/rule-engine/Scene/Save/components/ParamsSelect/index.tsx
  29. 7 3
      src/pages/rule-engine/Scene/Save/device/TopCard.tsx
  30. 17 13
      src/pages/rule-engine/Scene/Save/device/deviceList.tsx
  31. 4 4
      src/pages/rule-engine/Scene/Save/device/index.less
  32. 1 1
      src/pages/rule-engine/Scene/Save/device/org.tsx
  33. 1 1
      src/pages/rule-engine/Scene/Save/device/type.tsx
  34. 54 2
      src/pages/system/Menu/Setting/baseMenu.ts

+ 0 - 1
src/components/ProTableCard/CardItems/DataCollect/channel.tsx

@@ -26,7 +26,6 @@ export default (props: ChannelCardProps) => {
     <TableCard
       actions={props.actions}
       status={props.state?.value}
-      showStatus={false}
       statusText={props.state?.text}
       showMask={false}
       statusNames={{

+ 16 - 7
src/components/ProTableCard/CardItems/Scene/index.less

@@ -22,11 +22,20 @@
   }
   .card-item-content-box {
     .card-item-content-trigger {
-      color: rgba(0, 0, 0, 0.85);
-      font-weight: bold;
-      font-size: 15px;
+      display: flex;
+      .card-item-content-trigger-item {
+        width: max-content;
+        color: rgba(0, 0, 0, 0.85);
+        font-weight: bold;
+        font-size: 15px;
+        &:not(:last-child) {
+          margin-right: 10px;
+        }
+      }
       .trigger-device {
         color: rgba(47, 84, 235);
+        font-weight: bold;
+        font-size: 15px;
       }
     }
     .card-item-content-action-item {
@@ -48,7 +57,6 @@
           width: 100%;
           .trigger-contents {
             color: rgba(0, 0, 0, 0.85);
-            //width: calc(85% - 110px);
           }
           .right-item-left {
             width: 15%;
@@ -61,13 +69,11 @@
           }
           .right-item-right {
             width: 85%;
-            padding-left: 20px;
             .right-item-right-item {
               display: flex;
               width: 100%;
               .trigger-ways {
-                width: 75px;
-                margin-right: 20px;
+                width: 70px;
                 color: rgba(0, 0, 0, 0.85);
                 font-size: 16px;
               }
@@ -82,6 +88,9 @@
                 }
               }
             }
+            &:not(:first-child) {
+              padding-left: 20px;
+            }
           }
         }
       }

+ 63 - 19
src/components/ProTableCard/CardItems/Scene/index.tsx

@@ -318,25 +318,65 @@ const ContentRender = (data: SceneCardProps) => {
   const type = data.triggerType;
   if (!!type && (data.branches || [])?.length) {
     const trigger = data?.options?.trigger;
-    const text =
-      (trigger?.name || '') +
-      (trigger?.productName || '') +
-      (trigger?.when || '') +
-      (trigger?.time || '') +
-      (trigger?.extraTime || '') +
-      (trigger?.type || '');
     return (
       <div className={styles['card-item-content-box']}>
-        <MyTooltip placement="topLeft" title={text}>
-          <div className={classNames(styles['card-item-content-trigger'], 'ellipsis')}>
-            {trigger?.name || ''}
-            <span className={styles['trigger-device']}>{trigger?.productName || ''}</span>
-            {(trigger?.when || '') +
-              (trigger?.time || '') +
-              (trigger?.extraTime || '') +
-              (trigger?.type || '')}
-          </div>
-        </MyTooltip>
+        <div className={classNames(styles['card-item-content-trigger'])}>
+          {trigger?.name && (
+            <MyTooltip placement="topLeft" title={trigger?.name || ''}>
+              <div
+                className={classNames(styles['card-item-content-trigger-item'], 'ellipsis')}
+                style={{ maxWidth: '15%', color: 'rgba(47, 84, 235)' }}
+              >
+                {trigger?.name || ''}
+              </div>
+            </MyTooltip>
+          )}
+          {trigger?.productName && (
+            <MyTooltip placement="topLeft" title={trigger?.productName || ''}>
+              <div
+                className={classNames(styles['card-item-content-trigger-item'], 'ellipsis')}
+                style={{ maxWidth: '15%', color: 'rgba(47, 84, 235)' }}
+              >
+                {trigger?.productName || ''}
+              </div>
+            </MyTooltip>
+          )}
+          {trigger?.when && (
+            <MyTooltip placement="topLeft" title={trigger?.when || ''}>
+              <div
+                className={classNames(styles['card-item-content-trigger-item'], 'ellipsis')}
+                style={{ maxWidth: '15%' }}
+              >
+                {trigger?.when || ''}
+              </div>
+            </MyTooltip>
+          )}
+          {trigger?.time && (
+            <div className={classNames(styles['card-item-content-trigger-item'])}>
+              {trigger?.time || ''}
+            </div>
+          )}
+          {trigger?.extraTime && (
+            <div className={classNames(styles['card-item-content-trigger-item'])}>
+              {trigger?.extraTime || ''}
+            </div>
+          )}
+          {trigger?.action && (
+            <MyTooltip placement="topLeft" title={trigger?.action || ''}>
+              <div
+                className={classNames(styles['card-item-content-trigger-item'], 'ellipsis')}
+                style={{ maxWidth: '15%' }}
+              >
+                {trigger?.action || ''}
+              </div>
+            </MyTooltip>
+          )}
+          {trigger?.type && (
+            <div className={classNames(styles['card-item-content-trigger-item'])}>
+              {trigger?.type || ''}
+            </div>
+          )}
+        </div>
         <div className={styles['card-item-content-action']}>
           {(visible ? data.branches || [] : (data?.branches || []).slice(0, 2)).map(
             (item: any, index) => {
@@ -350,7 +390,9 @@ const ContentRender = (data: SceneCardProps) => {
                       {type === 'device' && (
                         <div
                           className={styles['right-item-left']}
-                          style={{ width: item?.then && item?.then.length ? '15%' : '100%' }}
+                          style={{
+                            width: Array.isArray(item.then) && item?.then.length ? '15%' : '100%',
+                          }}
                         >
                           <MyTooltip
                             placement={'topLeft'}
@@ -373,7 +415,7 @@ const ContentRender = (data: SceneCardProps) => {
                           )}
                         </div>
                       )}
-                      {item?.then && item?.then.length && (
+                      {Array.isArray(item.then) && item?.then.length ? (
                         <div
                           className={styles['right-item-right']}
                           style={{ width: type === 'device' ? '85%' : '100%' }}
@@ -389,6 +431,8 @@ const ContentRender = (data: SceneCardProps) => {
                             </div>
                           ))}
                         </div>
+                      ) : (
+                        ''
                       )}
                     </div>
                   </div>

+ 1 - 1
src/components/ProTableCard/CardItems/edge/Resource.tsx

@@ -44,7 +44,7 @@ export default (props: ResourceCardProps) => {
             </div>
             <div>
               <label>所属边缘网关</label>
-              <Ellipsis title={props?.category || ''} />
+              <Ellipsis title={props?.sourceName || ''} />
             </div>
           </div>
         </div>

+ 5 - 4
src/pages/edge/Resource/index.tsx

@@ -28,11 +28,12 @@ export default () => {
   const [current, setCurrent] = useState<Partial<ResourceItem>>({});
   const [visible, setVisible] = useState<boolean>(false);
   const [issueVisible, setIssueVisible] = useState<boolean>(false);
+  const { permission } = PermissionButton.usePermission('edge/Resource');
 
   const tools = (record: ResourceItem, type: 'card' | 'list') => [
     <PermissionButton
       type={'link'}
-      isPermission={true}
+      isPermission={permission.update}
       onClick={() => {
         setCurrent(record);
         setVisible(true);
@@ -56,7 +57,7 @@ export default () => {
         title: type !== 'list' ? '' : '下发',
       }}
       style={{ padding: 0 }}
-      isPermission={true}
+      isPermission={permission.setting}
       key={'reset'}
     >
       <DownSquareOutlined />
@@ -99,7 +100,7 @@ export default () => {
           }
         },
       }}
-      isPermission={true}
+      isPermission={permission.action}
       tooltip={{
         title: type === 'list' ? (record.state.value !== 'disabled' ? '禁用' : '启用') : '',
       }}
@@ -117,7 +118,7 @@ export default () => {
       type={'link'}
       key={'delete'}
       style={{ padding: 0 }}
-      isPermission={true}
+      isPermission={permission.delete}
       tooltip={record.state.value !== 'notActive' ? { title: '请先禁用,再删除。' } : undefined}
       disabled={record.state.value !== 'notActive'}
       popConfirm={{

+ 1 - 0
src/pages/edge/Resource/typings.d.ts

@@ -5,6 +5,7 @@ type ResourceItem = {
   targetType: string;
   sourceId: string;
   sourceType: string;
+  sourceName: string;
   metadata: string;
   state: {
     value: string;

+ 4 - 4
src/pages/link/DashBoard/index.tsx

@@ -676,7 +676,7 @@ export default () => {
   return (
     <PageContainer>
       <div className={'link-dash-board'}>
-        {serverNode && serverNode.length ? (
+        {serverNode && serverNode.length > 1 ? (
           <div style={{ backgroundColor: '#fff', padding: '24px 24px 0 24px' }}>
             <Select
               value={serverId}
@@ -691,7 +691,7 @@ export default () => {
         <div className={'echarts-items'}>
           <TopEchartsItemNode title={'CPU使用率'} value={topValues.cpu} />
           <TopEchartsItemNode
-            title={'JVM内存'}
+            title={'JVM内存占用'}
             formatter={'G'}
             value={topValues.jvm}
             max={topValues.jvmTotal}
@@ -705,11 +705,11 @@ export default () => {
             bottom={`总磁盘大小  ${topValues.usageTotal}G`}
           />
           <TopEchartsItemNode
-            title={'系统内存'}
+            title={'系统内存占用'}
             formatter={'G'}
             value={topValues.systemUsage}
             max={topValues.systemUsageTotal}
-            bottom={`系统内存  ${topValues.systemUsageTotal}G`}
+            bottom={`系统内存  ${topValues.systemUsageTotal}G`}
           />
         </div>
         <div style={{ marginBottom: 24 }}>

+ 1 - 1
src/pages/link/DataCollect/DataGathering/index.tsx

@@ -8,7 +8,7 @@ import Device from '../components/Device';
 import Point from '../components/Point';
 import { Empty } from '@/components';
 
-const DataCollectModel = model<{
+export const DataCollectModel = model<{
   id: Partial<string>;
   type: 'channel' | 'device' | undefined;
   provider: 'OPC_UA' | 'MODBUS_TCP';

+ 57 - 15
src/pages/link/DataCollect/components/Channel/index.tsx

@@ -6,7 +6,7 @@ import { useDomFullHeight } from '@/hooks';
 import service from '@/pages/link/DataCollect/service';
 import ChannelCard from '@/components/ProTableCard/CardItems/DataCollect/channel';
 import { Empty, PermissionButton } from '@/components';
-import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
+import { DeleteOutlined, EditOutlined, PlayCircleOutlined, StopOutlined } from '@ant-design/icons';
 import { onlyMessage } from '@/utils/util';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { Card, Col, Pagination, Row } from 'antd';
@@ -62,7 +62,6 @@ export default observer((props: Props) => {
       title: '状态',
       dataIndex: 'state',
       valueType: 'select',
-      hideInSearch: true,
       valueEnum: {
         enabled: {
           text: '正常',
@@ -78,7 +77,6 @@ export default observer((props: Props) => {
       title: '运行状态',
       dataIndex: 'runningState',
       valueType: 'select',
-      hideInSearch: true,
       valueEnum: {
         running: {
           text: '运行中',
@@ -92,10 +90,10 @@ export default observer((props: Props) => {
           text: '错误',
           status: 'failed',
         },
-        stopped: {
-          text: '已停止',
-          status: 'stopped',
-        },
+        // stopped: {
+        //   text: '已停止',
+        //   status: 'stopped',
+        // },
       },
     },
     {
@@ -179,18 +177,62 @@ export default observer((props: Props) => {
                         })}
                       </PermissionButton>,
                       <PermissionButton
+                        key={'action'}
+                        type={'link'}
+                        style={{ padding: 0 }}
+                        isPermission={permission.action}
+                        popConfirm={{
+                          title: intl.formatMessage({
+                            id: `pages.data.option.${
+                              record?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
+                            }.tips`,
+                            defaultMessage: '确认禁用?',
+                          }),
+                          onConfirm: async () => {
+                            const resp =
+                              record?.state?.value !== 'disabled'
+                                ? await service.updateChannel(record.id, {
+                                    state: 'disabled',
+                                    runningState: 'stopped',
+                                  })
+                                : await service.updateChannel(record.id, {
+                                    state: 'enabled',
+                                    runningState: 'running',
+                                  });
+                            if (resp.status === 200) {
+                              onlyMessage('操作成功!');
+                              handleSearch(param);
+                            } else {
+                              onlyMessage('操作失败!', 'error');
+                            }
+                          },
+                        }}
+                      >
+                        {record?.state?.value !== 'disabled' ? (
+                          <StopOutlined />
+                        ) : (
+                          <PlayCircleOutlined />
+                        )}
+                        {intl.formatMessage({
+                          id: `pages.data.option.${
+                            record?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
+                          }`,
+                          defaultMessage: record?.state?.value !== 'disabled' ? '禁用' : '启用',
+                        })}
+                      </PermissionButton>,
+                      <PermissionButton
                         key="delete"
                         isPermission={permission.delete}
                         type={'link'}
                         style={{ padding: 0 }}
-                        // disabled={record?.state?.value !== 'disabled'}
-                        // tooltip={
-                        //   record?.state?.value !== 'disabled'
-                        //     ? {
-                        //         title: '正常的通道不能删除',
-                        //       }
-                        //     : undefined
-                        // }
+                        disabled={record?.state?.value !== 'disabled'}
+                        tooltip={
+                          record?.state?.value !== 'disabled'
+                            ? {
+                                title: '正常的通道不能删除',
+                              }
+                            : undefined
+                        }
                         popConfirm={{
                           title: '该操作将会删除下属采集器与点位,确定删除?',
                           placement: 'topRight',

+ 1 - 0
src/pages/link/DataCollect/components/Device/Save/index.tsx

@@ -172,6 +172,7 @@ export default (props: Props) => {
             'x-decorator': 'FormItem',
             'x-decorator-props': {
               gridSpan: 2,
+              tooltip: '统一配置所有点位的大小端',
             },
             'x-component-props': {
               placeholder: '请选择大小端',

+ 11 - 9
src/pages/link/DataCollect/components/Device/index.tsx

@@ -101,10 +101,10 @@ export default observer((props: Props) => {
               text: '错误',
               status: 'failed',
             },
-            stopped: {
-              text: '已停止',
-              status: 'stopped',
-            },
+            // stopped: {
+            //   text: '已停止',
+            //   status: 'stopped',
+            // },
           },
         },
         {
@@ -149,10 +149,10 @@ export default observer((props: Props) => {
               text: '错误',
               status: 'failed',
             },
-            stopped: {
-              text: '已停止',
-              status: 'stopped',
-            },
+            // stopped: {
+            //   text: '已停止',
+            //   status: 'stopped',
+            // },
           },
         },
         {
@@ -279,9 +279,11 @@ export default observer((props: Props) => {
                                   record?.state?.value !== 'disabled'
                                     ? await service.updateCollector(record.id, {
                                         state: 'disabled',
+                                        runningState: 'stopped',
                                       })
                                     : await service.updateCollector(record.id, {
                                         state: 'enabled',
+                                        runningState: 'running',
                                       });
                                 if (resp.status === 200) {
                                   onlyMessage('操作成功!');
@@ -315,7 +317,7 @@ export default observer((props: Props) => {
                             tooltip={
                               record?.state?.value !== 'disabled'
                                 ? {
-                                    title: '已启用的采集器不能删除',
+                                    title: '正常的采集器不能删除',
                                   }
                                 : undefined
                             }

+ 70 - 26
src/pages/link/DataCollect/components/Tree/index.tsx

@@ -18,6 +18,7 @@ import CollectorSave from '../../components/Device/Save/index';
 import { onlyMessage } from '@/utils/util';
 // import { StatusColorEnum } from '@/components/BadgeStatus';
 import { useIntl } from '@@/plugin-locale/localeExports';
+import { DataCollectModel } from '../../DataGathering';
 
 const TreeModel = model<{
   selectedKeys: string[];
@@ -55,7 +56,7 @@ export default observer((props: Props) => {
   const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
   const intl = useIntl();
 
-  const handleSearch = (params: any) => {
+  const handleSearch = (params: any, reload?: boolean) => {
     TreeModel.loading = true;
     TreeModel.param = params;
     service
@@ -64,8 +65,11 @@ export default observer((props: Props) => {
         if (resp.status === 200) {
           TreeModel.dataSource = resp.result;
           if (resp.result.length) {
-            TreeModel.selectedKeys = [resp.result[0].id];
-            props.change(resp.result[0].id, 'channel', resp.result[0].provider);
+            if (!reload) {
+              TreeModel.selectedKeys = [resp.result[0].id];
+            }
+            const provider = !reload ? resp.result[0].provider : DataCollectModel.provider;
+            props.change(TreeModel.selectedKeys[0], 'channel', provider);
           }
         }
         TreeModel.loading = false;
@@ -73,28 +77,12 @@ export default observer((props: Props) => {
   };
 
   useEffect(() => {
-    handleSearch(TreeModel.param);
-  }, [TreeModel.param, props.reload]);
+    handleSearch(TreeModel.param, false);
+  }, [TreeModel.param]);
 
-  // const getState = (record: Partial<ChannelItem>): { text: string; value: string } => {
-  //   if (record) {
-  //     if (record?.state?.value === 'enabled') {
-  //       return {
-  //         text: record?.runningState?.text || '',
-  //         value: record?.runningState?.value || '',
-  //       };
-  //     } else {
-  //       return {
-  //         text: '禁用',
-  //         value: 'disabled',
-  //       };
-  //     }
-  //   }
-  //   return {
-  //     text: '',
-  //     value: '',
-  //   };
-  // };
+  useEffect(() => {
+    handleSearch(TreeModel.param, true);
+  }, [props.reload]);
 
   const getState = (record: any) => {
     if (record) {
@@ -187,7 +175,44 @@ export default observer((props: Props) => {
                             />
                           </Tooltip>
                           <Popconfirm
+                            title={intl.formatMessage({
+                              id: `pages.data.option.${
+                                item?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
+                              }.tips`,
+                              defaultMessage: '确认禁用?',
+                            })}
+                            onConfirm={async () => {
+                              const resp =
+                                item?.state?.value !== 'disabled'
+                                  ? await service.updateChannel(item.id, {
+                                      state: 'disabled',
+                                      runningState: 'stopped',
+                                    })
+                                  : await service.updateChannel(item.id, {
+                                      state: 'enabled',
+                                      runningState: 'running',
+                                    });
+                              if (resp.status === 200) {
+                                TreeModel.param = {};
+                                handleSearch(TreeModel.param);
+                                props.onReload();
+                                onlyMessage('操作成功');
+                              } else {
+                                onlyMessage('操作失败!', 'error');
+                              }
+                            }}
+                          >
+                            <Tooltip title={!permission.action ? '暂无权限,请联系管理员' : ''}>
+                              {item?.state?.value !== 'disabled' ? (
+                                <StopOutlined />
+                              ) : (
+                                <PlayCircleOutlined />
+                              )}
+                            </Tooltip>
+                          </Popconfirm>
+                          <Popconfirm
                             title={'该操作将会删除下属采集器与点位,确定删除?'}
+                            disabled={item?.state?.value !== 'disabled'}
                             onConfirm={async () => {
                               const resp = await service.removeChannel(item.id);
                               if (resp.status === 200) {
@@ -197,7 +222,15 @@ export default observer((props: Props) => {
                               }
                             }}
                           >
-                            <Tooltip title={!permission.delete ? '暂无权限,请联系管理员' : ''}>
+                            <Tooltip
+                              title={
+                                !permission.delete
+                                  ? '暂无权限,请联系管理员'
+                                  : item?.state?.value !== 'disabled'
+                                  ? '正常的通道不能删除'
+                                  : ''
+                              }
+                            >
                               <DeleteOutlined />
                             </Tooltip>
                           </Popconfirm>
@@ -260,9 +293,11 @@ export default observer((props: Props) => {
                                     i?.state?.value !== 'disabled'
                                       ? await service.updateCollector(i.id, {
                                           state: 'disabled',
+                                          runningState: 'stopped',
                                         })
                                       : await service.updateCollector(i.id, {
                                           state: 'enabled',
+                                          runningState: 'running',
                                         });
                                   if (resp.status === 200) {
                                     TreeModel.param = {};
@@ -284,6 +319,7 @@ export default observer((props: Props) => {
                               </Popconfirm>
                               <Popconfirm
                                 title={'该操作将会删除下属点位,确定删除?'}
+                                disabled={i?.state?.value !== 'disabled'}
                                 onConfirm={async () => {
                                   const resp = await service.removeCollector(i.id);
                                   if (resp.status === 200) {
@@ -293,7 +329,15 @@ export default observer((props: Props) => {
                                   }
                                 }}
                               >
-                                <Tooltip title={!permission.delete ? '暂无权限,请联系管理员' : ''}>
+                                <Tooltip
+                                  title={
+                                    !permission.delete
+                                      ? '暂无权限,请联系管理员'
+                                      : i?.state?.value !== 'disabled'
+                                      ? '正常的采集器不能删除'
+                                      : ''
+                                  }
+                                >
                                   <DeleteOutlined />
                                 </Tooltip>
                               </Popconfirm>

+ 34 - 0
src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/ReadProperty.tsx

@@ -0,0 +1,34 @@
+import { Select } from 'antd';
+
+interface ReadPropertyProps {
+  properties: any[];
+  value?: any;
+  onChange?: (value?: any, text?: any) => void;
+  propertiesChange?: (value?: string) => void;
+  id?: string;
+}
+
+export default (props: ReadPropertyProps) => {
+  return (
+    <Select
+      id={props.id}
+      value={props.value ? props.value[0] : undefined}
+      options={props.properties?.filter((item) => {
+        if (item.expands && item.expands.type) {
+          return item.expands.type.includes('read');
+        }
+        return false;
+      })}
+      fieldNames={{ label: 'name', value: 'id' }}
+      style={{ width: '100%' }}
+      onSelect={(key: any, option: any) => {
+        // console.log(key,option)
+        if (props.onChange) {
+          props.onChange([key], option.name);
+          props.propertiesChange?.(key);
+        }
+      }}
+      placeholder={'请选择属性'}
+    ></Select>
+  );
+};

+ 23 - 3
src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/TypeModel.tsx

@@ -35,14 +35,17 @@ export default (props: Props) => {
     });
     return lable?.description;
   };
+
   const filterTree = (nodes: any[]) => {
     if (!nodes?.length) {
       return nodes;
     }
     return nodes.filter((it) => {
-      if (it.children.find((item: any) => item.type === props.type)) {
+      const children = it.children.filter((item: any) => item.type === props.type);
+      if (children && children.length !== 0) {
         return true;
       }
+      it.children = filterTree(it.children);
       return false;
     });
   };
@@ -53,7 +56,8 @@ export default (props: Props) => {
       if (res.status === 200) {
         const _data = BuiltInParamsHandleTreeData(res.result);
         const filterData = filterTree(_data);
-        // console.log('_data',_data,)
+        console.log('_data', _data);
+        console.log('filterData', filterData);
         // console.log('type',props.type)
         setBuiltInList(filterData);
         const label = filterLabel(filterData);
@@ -76,6 +80,10 @@ export default (props: Props) => {
     }
   }, [source]);
 
+  useEffect(() => {
+    setValue(props.value);
+  }, [props.value]);
+
   const renderNode = (type: string) => {
     switch (type) {
       case 'int':
@@ -174,6 +182,17 @@ export default (props: Props) => {
             }}
           />
         );
+      case 'password':
+        return (
+          <Input.Password
+            value={value}
+            style={{ width: '100%', textAlign: 'left' }}
+            placeholder={'请输入'}
+            onChange={(e) => {
+              onChange(e.target.value);
+            }}
+          />
+        );
       default:
         return (
           <Input
@@ -208,7 +227,8 @@ export default (props: Props) => {
             defaultExpandAll
             fieldNames={{ title: 'name', key: 'id' }}
             onSelect={(selectedKeys, e) => {
-              // console.log(e.node);
+              console.log(e.node);
+              setDateOpen(false);
               setLabelValue(e.node.description);
               setValue(selectedKeys[0]);
               if (props.onChange) {

+ 6 - 3
src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/WriteProperty.tsx

@@ -1,5 +1,5 @@
 import { Col, Row, Select } from 'antd';
-import { useEffect, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import TypeModel from './TypeModel';
 // import { useEffect, useState } from "react";
 
@@ -7,7 +7,7 @@ interface Props {
   properties: any[];
   value?: any;
   id?: string;
-  onChange?: (value?: any) => void;
+  onChange?: (value?: any, text?: any) => void;
   propertiesChange?: (value?: string) => void;
   name?: any;
 }
@@ -24,6 +24,7 @@ export default (props: Props) => {
   const [propertiesValue, setPropertiesValue] = useState(undefined);
   const [propertiesType, setPropertiesType] = useState('');
   const [source, setSource] = useState<string>('fixed');
+  const textRef = useRef<any>('');
 
   useEffect(() => {
     console.log(props.value);
@@ -58,7 +59,7 @@ export default (props: Props) => {
           source: source,
         },
       };
-      props.onChange(obj);
+      props.onChange(obj, textRef.current);
     }
   }, [propertiesValue, source]);
 
@@ -80,7 +81,9 @@ export default (props: Props) => {
           onChange={(e, option) => {
             setPropertiesId(e);
             setPropertiesType(option.valueType.type);
+            textRef.current = option.name;
             console.log(option);
+            setPropertiesValue(undefined);
           }}
         ></Select>
       </Col>

+ 22 - 4
src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/index.tsx

@@ -1,10 +1,10 @@
 import { observer } from '@formily/reactive-react';
 import { Form, Select } from 'antd';
 import { useEffect, useState } from 'react';
-import ReadProperty from '../../device/readProperty';
 import TopCard from '../device/TopCard';
 import DeviceModel from '../model';
 import FunctionCall from './functionCall';
+import ReadProperty from './ReadProperty';
 import WriteProperty from './WriteProperty';
 
 interface Props {
@@ -131,8 +131,10 @@ export default observer((props: Props) => {
                 filterOption={(input: string, option: any) =>
                   option.name.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }
-                onChange={(value) => {
+                onChange={(value, option) => {
                   setFunctionId(value);
+                  // console.log(option.name)
+                  DeviceModel.propertiesName = option.name;
                 }}
               />
             </Form.Item>
@@ -152,7 +154,13 @@ export default observer((props: Props) => {
             label="读取属性"
             rules={[{ required: true, message: '请选择读取属性' }]}
           >
-            <ReadProperty properties={properties} />
+            <ReadProperty
+              properties={properties}
+              onChange={(_, text) => {
+                console.log(text);
+                DeviceModel.propertiesName = text;
+              }}
+            />
           </Form.Item>
         )}
         {deviceMessageType === 'WRITE_PROPERTY' && (
@@ -161,7 +169,17 @@ export default observer((props: Props) => {
             label="设置属性"
             rules={[{ required: true, message: '请选择属性' }]}
           >
-            <WriteProperty properties={properties} name={props.name} />
+            <WriteProperty
+              properties={properties}
+              name={props.name}
+              onChange={(value, text) => {
+                console.log(Object.keys(value));
+                const item = value[Object.keys(value)?.[0]]?.value;
+                console.log(item);
+                DeviceModel.propertiesName = text;
+                DeviceModel.propertiesValue = item;
+              }}
+            />
           </Form.Item>
         )}
       </Form>

+ 11 - 5
src/pages/rule-engine/Scene/Save/action/DeviceOutput/device/TopCard.tsx

@@ -1,6 +1,8 @@
 import classNames from 'classnames';
 import { useEffect, useState } from 'react';
 import '../index.less';
+import { QuestionCircleOutlined } from '@ant-design/icons';
+import { Popover } from 'antd';
 
 interface Props {
   typeList: any[];
@@ -9,6 +11,7 @@ interface Props {
   onChange?: (type: string) => void;
   onSelect?: (type: string) => void;
   disabled?: boolean;
+  labelBottom?: boolean;
 }
 
 const TopCard = (props: Props) => {
@@ -21,6 +24,7 @@ const TopCard = (props: Props) => {
   const onSelect = (_type: string) => {
     if (!props.disabled) {
       setType(_type);
+
       if (props.onChange) {
         props.onChange(_type);
       }
@@ -34,17 +38,19 @@ const TopCard = (props: Props) => {
           key={item.value}
           className={classNames('trigger-way-item', {
             active: type === item.value,
+            labelBottom: props.labelBottom,
           })}
           onClick={() => {
             onSelect(item.value);
-            if (props.onChange) {
-              props.onChange(item.value);
-            }
           }}
         >
           <div className={'way-item-title'}>
-            <p>{item.label}</p>
-            <span>{item.tip}</span>
+            <span className={'way-item-label'}>{item.label}</span>
+            {item.tip && (
+              <Popover content={item.tip}>
+                <QuestionCircleOutlined className={'way-item-icon'} />
+              </Popover>
+            )}
           </div>
           <div className={'way-item-image'}>
             <img width={48} src={item.image} />

+ 9 - 1
src/pages/rule-engine/Scene/Save/action/DeviceOutput/device/index.tsx

@@ -323,6 +323,7 @@ export default observer((props: Props) => {
             <SearchComponent
               field={columns}
               model={'simple'}
+              bodyStyle={{ padding: 0, paddingBottom: 16 }}
               enableSave={false}
               onSearch={async (data) => {
                 actionRef.current?.reset?.();
@@ -456,7 +457,14 @@ export default observer((props: Props) => {
       form.setFieldsValue({ selector: DeviceModel.selector });
     }
     sourceChangeEvent();
-    console.log('-----deviceid-----', DeviceModel.deviceId);
+    // console.log('-----deviceid-----', DeviceModel.deviceId);
+    if (DeviceModel.deviceId) {
+      service.detail(DeviceModel.deviceId).then((res) => {
+        if (res.status === 200) {
+          DeviceModel.deviceDetail = res.result || {};
+        }
+      });
+    }
   }, []);
 
   useEffect(() => {

+ 50 - 17
src/pages/rule-engine/Scene/Save/action/DeviceOutput/index.less

@@ -1,4 +1,5 @@
-@import '../../../../../../../node_modules/antd/es/style/themes/default.less';
+@import '~antd/es/style/themes/default.less';
+@import '~@/global.less';
 
 .steps-steps {
   width: 100%;
@@ -14,46 +15,64 @@
 .trigger-way-warp {
   display: flex;
   flex-wrap: wrap;
-  gap: 8px;
+  gap: 16px 24px;
   width: 100%;
 
   .trigger-way-item {
     display: flex;
+    align-items: center;
     justify-content: space-between;
     width: 237px;
     //width: 100%;
-    padding: 16px;
-    border: 1px solid #e0e4e8;
+    padding: 12px 16px;
+    border: 1px solid rgba(#e0e4e8, 0.6);
     border-radius: 2px;
     cursor: pointer;
-    opacity: 0.6;
     transition: all 0.3s;
 
     .way-item-title {
-      p {
-        margin-bottom: 8px;
-        font-weight: bold;
+      span {
         font-size: 16px;
       }
+      .way-item-label {
+        padding-right: 6px;
+        color: rgba(#000, 0.64);
+      }
 
-      span {
-        color: rgba(#000, 0.35);
-        font-size: 12px;
+      .way-item-icon {
+        color: rgba(#000, 0.5);
       }
     }
 
     .way-item-image {
       margin: 0 !important;
+      opacity: 0.6;
     }
 
     &:hover {
-      color: @primary-color-hover;
-      opacity: 0.8;
+      //color: @primary-color-hover;
+      .way-item-image {
+        opacity: 0.8;
+      }
     }
 
     &.active {
       border-color: @primary-color-active;
-      opacity: 1;
+      .way-item-image {
+        opacity: 1;
+      }
+    }
+
+    &.labelBottom {
+      flex-direction: column-reverse;
+      grid-gap: 16px;
+      gap: 0;
+      align-items: center;
+      width: auto;
+      padding: 8px 16px;
+      p {
+        margin: 0;
+      }
     }
   }
 
@@ -74,10 +93,10 @@
 }
 
 .device-title {
-  top: 5px;
-  left: 0;
-  width: 760px;
+  width: 720px;
   height: 38px;
+  margin-top: 5px;
+  margin-bottom: 10px;
   padding: 8px 16px 8px 16px;
   background: rgba(250, 178, 71, 0.1);
   border: 1px solid rgba(250, 178, 71, 0.4);
@@ -88,3 +107,17 @@
     color: #fab247;
   }
 }
+
+.trigger-options-content {
+  .trigger-options-name {
+    .ellipsisFn(1, 30%);
+  }
+
+  .trigger-options-type {
+    .ellipsisFn(1, 10%);
+  }
+
+  .trigger-options-when {
+    .ellipsisFn(1, 15%);
+  }
+}

+ 21 - 9
src/pages/rule-engine/Scene/Save/action/DeviceOutput/index.tsx

@@ -64,6 +64,15 @@ export default observer((props: Props) => {
     DeviceModel.current -= 1;
   };
 
+  const init = () => {
+    DeviceModel.selector = 'fixed';
+    DeviceModel.source = 'fixed';
+    DeviceModel.selectorValues = [];
+    DeviceModel.productId = '';
+    DeviceModel.message = {};
+    DeviceModel.current = 0;
+  };
+
   const save = async () => {
     const value = await formRef.current?.validateFields();
     const item = {
@@ -79,26 +88,29 @@ export default observer((props: Props) => {
       name: '-', //设备名称
       type: '', //类型
       properties: '', //属性功能
+      propertiesValue: '', //设置功能
       selector: DeviceModel.selector, //选择器标识
       productName: DeviceModel.productDetail.name,
       relationName: DeviceModel.relationName,
       taglist: [],
     };
-    _options.name = DeviceModel.deviceDetail.name;
+    _options.name = DeviceModel.deviceDetail?.name;
     const _type = value.message.messageType;
     if (_type === 'INVOKE_FUNCTION') {
       _options.type = '执行';
-      _options.properties = value.message.functionId;
+      // _options.properties = value.message.functionId;
+      _options.properties = DeviceModel.propertiesName;
     }
     if (_type === 'READ_PROPERTY') {
       _options.type = '读取';
-      _options.properties = value.message.properties?.[0];
+      _options.properties = DeviceModel.propertiesName;
       // _options.name = DeviceModel.selectorValues[0].name;
     }
     if (_type === 'WRITE_PROPERTY') {
       _options.type = '设置';
-      _options.properties = Object.keys(value.message.properties)?.[0];
-      // _options.name = DeviceModel.selectorValues[0].name;
+      // _options.properties = Object.keys(value.message.properties)?.[0];
+      _options.properties = DeviceModel.propertiesName;
+      _options.propertiesValue = DeviceModel.propertiesValue;
     }
     if (_options.selector === 'tag') {
       _options.taglist = DeviceModel.selectorValues?.[0]?.value.map((it: any) => ({
@@ -108,14 +120,14 @@ export default observer((props: Props) => {
       }));
       // console.log(_options.taglist, 'taglist')
     }
-    console.log(item);
+    // console.log(item);
     props.save(item, _options);
-    DeviceModel.current = 0;
+
+    init();
   };
 
   useEffect(() => {
     if (props.value) {
-      console.log('----------', props.value);
       DeviceModel.selector = props.value.selector;
       DeviceModel.productId = props.value.productId;
       DeviceModel.selector = props.value.selector;
@@ -132,7 +144,7 @@ export default observer((props: Props) => {
     <Modal
       title={'执行动作'}
       open
-      width={880}
+      width={810}
       onCancel={() => {
         props.cancel();
         DeviceModel.current = 0;

+ 4 - 0
src/pages/rule-engine/Scene/Save/action/DeviceOutput/model.ts

@@ -22,6 +22,8 @@ type ModelType = {
   source: string;
   relationName: string;
   message: any;
+  propertiesName: string;
+  propertiesValue: string;
 };
 
 const DeviceModel = model<ModelType>({
@@ -39,6 +41,8 @@ const DeviceModel = model<ModelType>({
   source: 'fixed',
   relationName: '',
   message: {},
+  propertiesName: '',
+  propertiesValue: '',
 });
 
 export default DeviceModel;

+ 2 - 6
src/pages/rule-engine/Scene/Save/action/DeviceOutput/product/index.tsx

@@ -210,18 +210,14 @@ export default observer((props: Props) => {
         field={columns}
         model={'simple'}
         enableSave={false}
+        bodyStyle={{ padding: 0, paddingBottom: 16 }}
         onSearch={async (data) => {
           actionRef.current?.reset?.();
           setSearchParam(data);
         }}
         target="department-assets-product"
       />
-      <div
-        style={{
-          height: 'calc(100vh - 440px)',
-          overflowY: 'auto',
-        }}
-      >
+      <div>
         <ProTableCard<ProductItem>
           noPadding
           cardScrollY={460}

+ 31 - 15
src/pages/rule-engine/Scene/Save/action/ListItem/Item.tsx

@@ -1,5 +1,5 @@
 import { useEffect, useState, useRef } from 'react';
-import Modal from '../Modal/add';
+import Modal, { ActionTypeComponent } from '../Modal/add';
 import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import { DeleteOutlined } from '@ant-design/icons';
 import './index.less';
@@ -45,6 +45,7 @@ export default (props: ItemProps) => {
   const [triggerVisible, setTriggerVisible] = useState<boolean>(false);
   const [op, setOp] = useState<any>(props.options);
   const cacheValueRef = useRef<any>({});
+  const [actionType, setActionType] = useState<string>('');
 
   useEffect(() => {
     setOp(props.options);
@@ -152,9 +153,12 @@ export default (props: ItemProps) => {
       case 'fixed':
         return (
           <div>
-            {data?.options?.type}
+            {`${data?.options?.type} ${data?.options?.name} ${data?.options?.properties} ${
+              data?.options?.propertiesValue || ''
+            }`}
+            {/* {data?.options?.type}
             <span>{data?.options?.name}</span>
-            {data?.options?.properties}
+            {data?.options?.properties} */}
           </div>
         );
       case 'tag':
@@ -186,7 +190,6 @@ export default (props: ItemProps) => {
   };
 
   const contentRender = () => {
-    // console.log('props.data', props.data)
     if (props?.data?.alarm?.mode === 'trigger') {
       return (
         <div className={'item-options-content'}>
@@ -203,12 +206,7 @@ export default (props: ItemProps) => {
       );
     } else if (props?.data?.alarm?.mode === 'relieve') {
       return (
-        <div
-          className={'item-options-content'}
-          onClick={() => {
-            setVisible(true);
-          }}
-        >
+        <div className={'item-options-content'}>
           满足条件后将解除关联
           <a
             onClick={() => {
@@ -224,7 +222,7 @@ export default (props: ItemProps) => {
         <div
           className={'item-options-content'}
           onClick={() => {
-            setVisible(true);
+            setActionType(props?.data?.executor);
           }}
         >
           {notifyRender(props?.data, props?.options)}
@@ -235,7 +233,7 @@ export default (props: ItemProps) => {
         <div
           className={'item-options-content'}
           onClick={() => {
-            setVisible(true);
+            setActionType(props?.data?.executor);
           }}
         >
           {props.options.name}
@@ -246,7 +244,7 @@ export default (props: ItemProps) => {
         <div
           className={'item-options-content'}
           onClick={() => {
-            setVisible(true);
+            setActionType(props?.data?.executor);
           }}
         >
           {deviceRender(props?.data)}
@@ -272,7 +270,12 @@ export default (props: ItemProps) => {
     <div className="actions-item-warp">
       <div className="actions-item">
         <div className="item-options-warp">
-          <div className="item-options-type">
+          <div
+            className="item-options-type"
+            onClick={() => {
+              setVisible(true);
+            }}
+          >
             <img
               style={{ width: 18 }}
               src={iconMap.get(
@@ -337,7 +340,6 @@ export default (props: ItemProps) => {
             setVisible(false);
           }}
           save={(data: ActionsType, options) => {
-            // FormModel.actions[props.name] = data;
             setOp(options);
             props.onUpdate(data, options);
             setVisible(false);
@@ -352,6 +354,20 @@ export default (props: ItemProps) => {
           }}
         />
       )}
+      <ActionTypeComponent
+        name={props.name}
+        data={props.data}
+        type={actionType}
+        close={() => {
+          setActionType('');
+        }}
+        save={(data: ActionsType, options) => {
+          setOp(options);
+          props.onUpdate(data, options);
+          setActionType('');
+        }}
+        parallel={props.parallel}
+      />
     </div>
   );
 };

+ 97 - 81
src/pages/rule-engine/Scene/Save/action/Modal/add.tsx

@@ -6,6 +6,90 @@ import type { ActionsType } from '@/pages/rule-engine/Scene/typings';
 import Device from '../DeviceOutput';
 import Delay from '../Delay';
 
+interface ActionTypeProps {
+  type: string;
+  name: number;
+  save: (data: any, options?: any) => void;
+  data: Partial<ActionsType>;
+  close: () => void;
+  parallel: boolean;
+}
+
+export const ActionTypeComponent = (props: ActionTypeProps) => {
+  const { type } = props;
+  switch (type) {
+    case 'device':
+      return (
+        <Device
+          value={props.data?.device}
+          save={(data: any, options: any) => {
+            props.save(
+              {
+                type: 'device',
+                executor: 'device',
+                key: props.data.key || `device_${new Date().getTime()}`,
+                device: {
+                  ...data,
+                },
+              },
+              options,
+            );
+          }}
+          name={props.name}
+          cancel={() => {
+            props.close();
+          }}
+          parallel={props.parallel}
+        />
+      );
+    case 'notify':
+      return (
+        <Notify
+          value={props.data?.notify || {}}
+          options={props.data?.options || {}}
+          save={(data: any, option: any) => {
+            props.save(
+              {
+                ...data,
+                executor: 'notify',
+                key: props.data.key || `notify_${new Date().getTime()}`,
+              },
+              option,
+            );
+          }}
+          name={props.name}
+          cancel={() => {
+            props.close();
+          }}
+        />
+      );
+    case 'delay':
+      return (
+        <Delay
+          value={props.data?.delay || {}}
+          save={(data: any, options) => {
+            props.save(
+              {
+                type: 'delay',
+                executor: 'delay',
+                key: props.data.key || `delay_${new Date().getTime()}`,
+                delay: {
+                  ...data,
+                },
+              },
+              options,
+            );
+          }}
+          cancel={() => {
+            props.close();
+          }}
+        />
+      );
+    default:
+      return null;
+  }
+};
+
 interface Props {
   close: () => void;
   save: (data: any, options?: any) => void;
@@ -22,88 +106,11 @@ export default (props: Props) => {
   useEffect(() => {
     if (props.data?.executor) {
       form.setFieldsValue({
-        type: props.data.executor,
+        type: props.data.executor === 'alarm' ? props.data.alarm?.mode : props.data.executor,
       });
     }
   }, [props.data]);
 
-  const actionTypeComponent = (type: string) => {
-    switch (type) {
-      case 'device':
-        return (
-          <Device
-            value={props.data?.device}
-            save={(data: any, options: any) => {
-              setActionType('');
-              props.save(
-                {
-                  type: 'device',
-                  executor: 'device',
-                  key: props.data.key || `device_${new Date().getTime()}`,
-                  device: {
-                    ...data,
-                  },
-                },
-                options,
-              );
-            }}
-            name={props.name}
-            cancel={() => {
-              setActionType('');
-            }}
-            parallel={props.parallel}
-          />
-        );
-      case 'notify':
-        return (
-          <Notify
-            value={props.data?.notify || {}}
-            options={props.data?.options || {}}
-            save={(data: any, option: any) => {
-              setActionType('');
-              props.save(
-                {
-                  ...data,
-                  executor: 'notify',
-                  key: props.data.key || `notify_${new Date().getTime()}`,
-                },
-                option,
-              );
-            }}
-            name={props.name}
-            cancel={() => {
-              setActionType('');
-            }}
-          />
-        );
-      case 'delay':
-        return (
-          <Delay
-            value={props.data?.delay || {}}
-            save={(data: any, options) => {
-              setActionType('');
-              props.save(
-                {
-                  type: 'delay',
-                  executor: 'delay',
-                  key: props.data.key || `delay_${new Date().getTime()}`,
-                  delay: {
-                    ...data,
-                  },
-                },
-                options,
-              );
-            }}
-            cancel={() => {
-              setActionType('');
-            }}
-          />
-        );
-      default:
-        return null;
-    }
-  };
-
   return (
     <Modal
       title="类型"
@@ -116,8 +123,7 @@ export default (props: Props) => {
         const values = await form.validateFields();
         setActionType(values.type);
         if (values.type === 'relieve' || values.type === 'trigger') {
-          console.log(values.type, props.data);
-          props.save({ ...props.data, type: values.type, executor: values.type });
+          props.save({ ...props.data, type: values.type, executor: 'alarm' });
         }
       }}
     >
@@ -131,7 +137,17 @@ export default (props: Props) => {
           <ActionsTypeComponent parallel={props.parallel} />
         </Form.Item>
       </Form>
-      {actionTypeComponent(actionType)}
+      <ActionTypeComponent
+        {...props}
+        type={actionType}
+        save={(data: any, options?: any) => {
+          props.save(data, options);
+          setActionType('');
+        }}
+        close={() => {
+          setActionType('');
+        }}
+      />
     </Modal>
   );
 };

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

@@ -53,7 +53,7 @@ export default forwardRef((props: NotifyWayProps, ref) => {
           name="notifyType"
           label="应用"
           required
-          rules={[{ required: true, message: '请选择类型' }]}
+          rules={[{ required: true, message: '请选择通知方式' }]}
         >
           <NotifyType options={list} />
         </Form.Item>

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

@@ -21,7 +21,7 @@ export default forwardRef((props: Props, ref) => {
     switch (type) {
       case 'user':
         return <User />;
-      case 'org':
+      case '      ':
         return <Org />;
       case 'tag':
         return <Tag />;
@@ -191,6 +191,14 @@ export default forwardRef((props: Props, ref) => {
                     source: 'fixed',
                     value: undefined,
                   };
+          } else if (!['org', 'tag', 'file', 'link'].includes(type)) {
+            initialValue =
+              props?.value && item?.id && props?.value[item.id]
+                ? props?.value[item.id]
+                : {
+                    source: 'fixed',
+                    value: undefined,
+                  };
           } else {
             initialValue =
               props?.value && item?.id && props?.value[item.id] ? props?.value[item.id] : undefined;

+ 2 - 2
src/pages/rule-engine/Scene/Save/action/notify/components/variableItem/buildIn.tsx

@@ -20,7 +20,7 @@ interface BuiltInProps {
 }
 
 export default (props: BuiltInProps) => {
-  const [source, setSource] = useState(props.value?.source);
+  const [source, setSource] = useState(props.value?.source || 'fixed');
   const [value, setValue] = useState(props.value?.value);
   const [upperKey, setUpperKey] = useState(props.value?.upperKey);
 
@@ -58,7 +58,7 @@ export default (props: BuiltInProps) => {
   }, [source]);
 
   useEffect(() => {
-    setSource(props.value?.source);
+    setSource(props.value?.source || 'fixed');
     setValue(props.value?.value);
     setUpperKey(props.value?.upperKey);
   }, [props.value]);

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

@@ -42,6 +42,7 @@ export default (props: Props) => {
   }, [props.value]);
 
   useEffect(() => {
+    // console.log(props.open)
     if (props.open !== undefined) {
       setOpen(props.open);
     }
@@ -88,10 +89,6 @@ export default (props: Props) => {
             setValue(e.target.value);
             props.onChange(value, tabKey);
           }}
-          onFocus={() => {
-            // setOpen(true);
-            props.openChange?.(true);
-          }}
         />
       )}
     </Dropdown>

+ 7 - 3
src/pages/rule-engine/Scene/Save/device/TopCard.tsx

@@ -1,8 +1,8 @@
 import classNames from 'classnames';
 import { useEffect, useState } from 'react';
 import './index.less';
-import {QuestionCircleOutlined} from "@ant-design/icons";
-import { Popover } from 'antd'
+import { QuestionCircleOutlined } from '@ant-design/icons';
+import { Popover } from 'antd';
 
 interface Props {
   typeList: any[];
@@ -46,7 +46,11 @@ const TopCard = (props: Props) => {
         >
           <div className={'way-item-title'}>
             <span className={'way-item-label'}>{item.label}</span>
-            { item.tip && <Popover content={item.tip}><QuestionCircleOutlined className={'way-item-icon'} /></Popover> }
+            {item.tip && (
+              <Popover content={item.tip}>
+                <QuestionCircleOutlined className={'way-item-icon'} />
+              </Popover>
+            )}
           </div>
           <div className={'way-item-image'}>
             <img width={48} src={item.image} />

+ 17 - 13
src/pages/rule-engine/Scene/Save/device/deviceList.tsx

@@ -223,27 +223,31 @@ export default observer(() => {
             tableAlertRender={false}
             rowSelection={{
               selectedRowKeys: [...TriggerDeviceModel.deviceKeys],
-              onSelect: (record, selected, selectedRows) => {
-                console.log(record)
+              onSelect: (record, selected) => {
+                console.log(record);
                 if (selected) {
-                  TriggerDeviceModel.deviceKeys.push(record.id)
+                  TriggerDeviceModel.deviceKeys.push(record.id);
                   if (TriggerDeviceModel.selectorValues) {
                     TriggerDeviceModel.selectorValues?.push({
                       name: record.name,
-                      value: record.id
-                    })
+                      value: record.id,
+                    });
                   } else {
-                    TriggerDeviceModel.selectorValues = [{
-                      name: record.name,
-                      value: record.id
-                    }]
+                    TriggerDeviceModel.selectorValues = [
+                      {
+                        name: record.name,
+                        value: record.id,
+                      },
+                    ];
                   }
                 } else {
-                  const newArray = TriggerDeviceModel.selectorValues?.filter((item) => item.value !== record.id);
-                  TriggerDeviceModel.deviceKeys = newArray?.map(item => item.value) || []
-                  TriggerDeviceModel.selectorValues = newArray || []
+                  const newArray = TriggerDeviceModel.selectorValues?.filter(
+                    (item) => item.value !== record.id,
+                  );
+                  TriggerDeviceModel.deviceKeys = newArray?.map((item) => item.value) || [];
+                  TriggerDeviceModel.selectorValues = newArray || [];
                 }
-              }
+              },
             }}
             onPageChange={(page, size) => {
               TriggerDeviceModel.devicePage = page;

+ 4 - 4
src/pages/rule-engine/Scene/Save/device/index.less

@@ -20,15 +20,15 @@
 
   .trigger-way-item {
     display: flex;
+    align-items: center;
     justify-content: space-between;
     width: 237px;
     //width: 100%;
     padding: 12px 16px;
-    border: 1px solid rgba(#e0e4e8, .6);
+    border: 1px solid rgba(#e0e4e8, 0.6);
     border-radius: 2px;
     cursor: pointer;
     transition: all 0.3s;
-    align-items: center;
 
     .way-item-title {
       span {
@@ -36,11 +36,11 @@
       }
       .way-item-label {
         padding-right: 6px;
-        color: rgba(#000, .64);
+        color: rgba(#000, 0.64);
       }
 
       .way-item-icon {
-        color: rgba(#000, .5);
+        color: rgba(#000, 0.5);
       }
     }
 

+ 1 - 1
src/pages/rule-engine/Scene/Save/device/org.tsx

@@ -50,7 +50,7 @@ export default observer(() => {
         tableAlertRender={false}
         options={false}
         scroll={{
-          y: 350
+          y: 350,
         }}
         rowSelection={{
           type: 'radio',

+ 1 - 1
src/pages/rule-engine/Scene/Save/device/type.tsx

@@ -166,7 +166,7 @@ export default forwardRef((props: Props, ref) => {
       style={{
         maxHeight: 'calc(100vh - 350px)',
         overflowY: 'auto',
-        overflowX: 'hidden'
+        overflowX: 'hidden',
       }}
     >
       <Form form={form} layout={'vertical'}>

+ 54 - 2
src/pages/system/Menu/Setting/baseMenu.ts

@@ -2334,8 +2334,8 @@ export default [
             owner: 'iot',
             sortIndex: 1,
             url: '/iot/edge/Devic',
-            icon: 'icon-changjingliandong',
-            showPage: ['device-instance'],
+            icon: 'icon-bumenguanli',
+            showPage: ['edge-operations'],
             permissions: [],
             buttons: [
               {
@@ -2420,6 +2420,58 @@ export default [
               },
             ],
           },
+          {
+            code: 'edge/Resource',
+            name: '资源库',
+            owner: 'iot',
+            sortIndex: 2,
+            url: '/iot/edge/Resource',
+            icon: 'icon-Vector',
+            showPage: ['edge-operations'],
+            permissions: [],
+            buttons: [
+              {
+                id: 'action',
+                name: '启/禁用',
+                permissions: [
+                  {
+                    permission: 'device-instance',
+                    actions: ['query', 'save'],
+                  },
+                ],
+              },
+              {
+                id: 'delete',
+                name: '删除',
+                permissions: [
+                  {
+                    permission: 'device-instance',
+                    actions: ['query', 'delete'],
+                  },
+                ],
+              },
+              {
+                id: 'update',
+                name: '编辑',
+                permissions: [
+                  {
+                    permission: 'rule-instance',
+                    actions: ['query', 'save'],
+                  },
+                ],
+              },
+              {
+                id: 'setting',
+                name: '下发',
+                permissions: [
+                  {
+                    permission: 'rule-instance',
+                    actions: ['query', 'save'],
+                  },
+                ],
+              },
+            ],
+          },
         ],
       },
     ],