Переглянути джерело

fix: 数据采集和通知管理

100011797 3 роки тому
батько
коміт
d5d5819817
60 змінених файлів з 1867 додано та 1322 видалено
  1. BIN
      public/images/network/01.jpg
  2. BIN
      public/images/network/01.png
  3. BIN
      public/images/network/02.jpg
  4. BIN
      public/images/network/03.png
  5. 0 0
      public/images/network/04.jpg
  6. BIN
      public/images/network/05.jpg
  7. BIN
      public/images/network/06.jpg
  8. 84 0
      src/components/ProTableCard/CardItems/noticeTemplate.tsx
  9. 1 1
      src/components/RadioCard/index.tsx
  10. 1 1
      src/pages/link/DataCollect/components/Channel/Save/index.tsx
  11. 28 19
      src/pages/link/DataCollect/components/Channel/index.tsx
  12. 107 67
      src/pages/link/DataCollect/components/Device/Save/index.tsx
  13. 2 2
      src/pages/link/DataCollect/components/Device/index.tsx
  14. 1 1
      src/pages/link/DataCollect/components/Point/CollectorCard/WritePoint.tsx
  15. 1 1
      src/pages/link/DataCollect/components/Point/CollectorCard/index.less
  16. 2 2
      src/pages/link/DataCollect/components/Point/CollectorCard/index.tsx
  17. 1 1
      src/pages/link/DataCollect/components/Point/Save/BatchUpdate.tsx
  18. 0 0
      src/pages/DataCollect/Collector/components/Point/Save/components/MyInput.tsx
  19. 0 0
      src/pages/DataCollect/Collector/components/Point/Save/components/MySelect.tsx
  20. 0 0
      src/pages/DataCollect/Collector/components/Point/Save/components/RemoveData.tsx
  21. 122 36
      src/pages/link/DataCollect/components/Point/Save/modbus.tsx
  22. 1 1
      src/pages/link/DataCollect/components/Point/Save/opc-ua.tsx
  23. 0 0
      src/pages/DataCollect/Collector/components/Point/Save/scan.less
  24. 3 3
      src/pages/link/DataCollect/components/Point/Save/scan.tsx
  25. 174 172
      src/pages/link/DataCollect/components/Point/index.tsx
  26. 1 2
      src/pages/link/DataCollect/components/Tree/index.less
  27. 257 0
      src/pages/DataCollect/Collector/components/Tree/index.tsx
  28. 0 0
      src/pages/DataCollect/Collector/components/index.less
  29. 0 0
      src/pages/DataCollect/Collector/index.less
  30. 41 0
      src/pages/DataCollect/Collector/index.tsx
  31. 0 0
      src/pages/DataCollect/Dashboard/index.less
  32. 0 0
      src/pages/DataCollect/Dashboard/index.tsx
  33. 3 3
      src/pages/link/DataCollect/service.ts
  34. 0 0
      src/pages/DataCollect/typings.d.ts
  35. 14 13
      src/pages/device/Instance/Detail/MetadataLog/Property/index.tsx
  36. 103 3
      src/pages/device/Instance/Detail/Running/Property/EditProperty.tsx
  37. 37 31
      src/pages/device/Instance/Detail/Tags/Edit.tsx
  38. 16 16
      src/pages/device/components/Metadata/Base/index.tsx
  39. 2 0
      src/pages/home/index.tsx
  40. 1 0
      src/pages/link/AccessConfig/Detail/components/CTWing/index.less
  41. 21 8
      src/pages/link/AccessConfig/Detail/components/CTWing/index.tsx
  42. 49 8
      src/pages/link/AccessConfig/Detail/components/OneNet/index.tsx
  43. 0 79
      src/pages/link/DataCollect/DataGathering/index.tsx
  44. 0 49
      src/pages/link/DataCollect/IntegratedQuery/index.tsx
  45. 0 389
      src/pages/link/DataCollect/components/Tree/index.tsx
  46. 8 6
      src/pages/notice/Config/Debug/index.tsx
  47. 133 52
      src/pages/notice/Config/Detail/index.tsx
  48. 4 4
      src/pages/notice/Config/Log/index.tsx
  49. 4 7
      src/pages/notice/Config/SyncUser/index.tsx
  50. 21 59
      src/pages/notice/Config/index.tsx
  51. 8 9
      src/pages/notice/Template/Debug/index.tsx
  52. 160 43
      src/pages/notice/Template/Detail/index.tsx
  53. 4 4
      src/pages/notice/Template/Log/index.tsx
  54. 27 59
      src/pages/notice/Template/index.tsx
  55. 8 0
      src/pages/notice/Template/service.ts
  56. 131 52
      src/pages/rule-engine/Alarm/Config/index.tsx
  57. 273 107
      src/pages/system/Menu/Setting/baseMenu.ts
  58. 1 0
      src/pages/user/Login/index.tsx
  59. 6 6
      src/utils/menu/index.ts
  60. 6 6
      src/utils/menu/router.ts

BIN
public/images/network/01.jpg


BIN
public/images/network/01.png


BIN
public/images/network/02.jpg


BIN
public/images/network/03.png


public/images/network/03.jpg → public/images/network/04.jpg


BIN
public/images/network/05.jpg


BIN
public/images/network/06.jpg


+ 84 - 0
src/components/ProTableCard/CardItems/noticeTemplate.tsx

@@ -39,6 +39,63 @@ export const imgMap = {
   },
   },
 };
 };
 
 
+export const typeObj = {
+  dingTalk: {
+    text: '钉钉',
+    status: 'dingTalk',
+  },
+  weixin: {
+    text: '微信',
+    status: 'weixin',
+  },
+  email: {
+    text: '邮件',
+    status: 'email',
+  },
+  voice: {
+    text: '语音',
+    status: 'voice',
+  },
+  sms: {
+    text: '短信',
+    status: 'sms',
+  },
+  webhook: {
+    text: 'webhook',
+    status: 'webhook',
+  },
+};
+export const providerObj = {
+  corpMessage: {
+    text: '企业消息',
+    status: 'corpMessage',
+  },
+  dingTalkMessage: {
+    text: '钉钉消息',
+    status: 'dingTalkMessage',
+  },
+  dingTalkRobotWebHook: {
+    text: '群机器人消息',
+    status: 'dingTalkRobotWebHook',
+  },
+  aliyun: {
+    text: '阿里云语音',
+    status: 'aliyun',
+  },
+  aliyunSms: {
+    text: '阿里云短信',
+    status: 'aliyunSms',
+  },
+  embedded: {
+    text: '邮件',
+    status: 'embedded',
+  },
+  http: {
+    text: 'Webhook',
+    status: 'http',
+  },
+};
+
 export const typeList = {
 export const typeList = {
   weixin: {
   weixin: {
     corpMessage: '企业消息',
     corpMessage: '企业消息',
@@ -62,6 +119,33 @@ export const typeList = {
   },
   },
 };
 };
 
 
+export const typeArray = [
+  {
+    text: '钉钉',
+    status: 'dingTalk',
+  },
+  {
+    text: '微信',
+    status: 'weixin',
+  },
+  {
+    text: '邮件',
+    status: 'email',
+  },
+  {
+    text: '语音',
+    status: 'voice',
+  },
+  {
+    text: '短信',
+    status: 'sms',
+  },
+  {
+    text: 'webhook',
+    status: 'webhook',
+  },
+];
+
 export const ExtraNoticeTemplateCard = (props: NoticeCardProps) => {
 export const ExtraNoticeTemplateCard = (props: NoticeCardProps) => {
   return (
   return (
     <TableCard
     <TableCard

+ 1 - 1
src/components/RadioCard/index.tsx

@@ -34,7 +34,7 @@ export default (props: RadioCardProps) => {
 
 
   useEffect(() => {
   useEffect(() => {
     // 初始化
     // 初始化
-    setKeys(value ? (isArray(value) ? value : [value]) : []);
+    setKeys(value !== undefined ? (isArray(value) ? value : [value]) : []);
   }, [props.value]);
   }, [props.value]);
 
 
   const getNode = (_keys: string[]) =>
   const getNode = (_keys: string[]) =>

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

@@ -5,7 +5,7 @@ import React, { useEffect, useState } from 'react';
 import * as ICONS from '@ant-design/icons';
 import * as ICONS from '@ant-design/icons';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Password } from '@formily/antd';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Password } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { ISchema } from '@formily/json-schema';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage, testDomain, testIP, testIPv6 } from '@/utils/util';
 import { onlyMessage, testDomain, testIP, testIPv6 } from '@/utils/util';
 import { action } from '@formily/reactive';
 import { action } from '@formily/reactive';
 import { RadioCard } from '@/components';
 import { RadioCard } from '@/components';

+ 28 - 19
src/pages/link/DataCollect/components/Channel/index.tsx

@@ -1,21 +1,18 @@
+import { PageContainer } from '@ant-design/pro-layout';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
-import SearchComponent from '@/components/SearchComponent';
-import { ProColumns } from '@jetlinks/pro-table';
-import { useEffect, useState } from 'react';
+import { model } from '@formily/reactive';
+import { useIntl } from '@@/plugin-locale/localeExports';
 import { useDomFullHeight } from '@/hooks';
 import { useDomFullHeight } from '@/hooks';
-import service from '@/pages/link/DataCollect/service';
-import ChannelCard from '@/components/ProTableCard/CardItems/DataCollect/channel';
+import { useEffect, useState } from 'react';
 import { Empty, PermissionButton } from '@/components';
 import { Empty, PermissionButton } from '@/components';
+import { ProColumns } from '@jetlinks/pro-table';
+import service from '@/pages/DataCollect/service';
+import SearchComponent from '@/components/SearchComponent';
+import { Card, Col, Pagination, Row } from 'antd';
+import ChannelCard from '@/components/ProTableCard/CardItems/DataCollect/channel';
 import { DeleteOutlined, EditOutlined, PlayCircleOutlined, StopOutlined } from '@ant-design/icons';
 import { DeleteOutlined, EditOutlined, PlayCircleOutlined, StopOutlined } from '@ant-design/icons';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
-import { useIntl } from '@@/plugin-locale/localeExports';
-import { Card, Col, Pagination, Row } from 'antd';
-import { model } from '@formily/reactive';
-import Save from '@/pages/link/DataCollect/components/Channel/Save';
-
-interface Props {
-  type: boolean; // true: 综合查询  false: 数据采集
-}
+import Save from '@/pages/DataCollect/Channel/Save';
 
 
 const ChannelModel = model<{
 const ChannelModel = model<{
   visible: boolean;
   visible: boolean;
@@ -27,11 +24,11 @@ const ChannelModel = model<{
   currentPage: 0,
   currentPage: 0,
 });
 });
 
 
-export default observer((props: Props) => {
+export default observer(() => {
   const intl = useIntl();
   const intl = useIntl();
   const { minHeight } = useDomFullHeight(`.data-collect-channel-card`, 24);
   const { minHeight } = useDomFullHeight(`.data-collect-channel-card`, 24);
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
-  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
+  const { permission } = PermissionButton.usePermission('DataCollect/Channel');
   const [loading, setLoading] = useState<boolean>(true);
   const [loading, setLoading] = useState<boolean>(true);
   const [dataSource, setDataSource] = useState<any>({
   const [dataSource, setDataSource] = useState<any>({
     data: [],
     data: [],
@@ -39,7 +36,6 @@ export default observer((props: Props) => {
     pageIndex: 0,
     pageIndex: 0,
     total: 0,
     total: 0,
   });
   });
-
   const columns: ProColumns<ChannelItem>[] = [
   const columns: ProColumns<ChannelItem>[] = [
     {
     {
       title: '通道名称',
       title: '通道名称',
@@ -154,7 +150,7 @@ export default observer((props: Props) => {
   };
   };
 
 
   return (
   return (
-    <div>
+    <PageContainer>
       <SearchComponent<ChannelItem>
       <SearchComponent<ChannelItem>
         field={columns}
         field={columns}
         target="data-collect-channel"
         target="data-collect-channel"
@@ -172,11 +168,24 @@ export default observer((props: Props) => {
         style={{ position: 'relative', minHeight }}
         style={{ position: 'relative', minHeight }}
         className={'data-collect-channel-card'}
         className={'data-collect-channel-card'}
       >
       >
+        <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-start' }}>
+          <PermissionButton
+            isPermission={permission.add}
+            onClick={() => {
+              ChannelModel.visible = true;
+              ChannelModel.current = {};
+            }}
+            key="button"
+            type="primary"
+          >
+            新增通道
+          </PermissionButton>
+        </div>
         <div style={{ height: '100%', paddingBottom: 48 }}>
         <div style={{ height: '100%', paddingBottom: 48 }}>
           {dataSource?.data.length > 0 ? (
           {dataSource?.data.length > 0 ? (
             <Row gutter={[24, 24]} style={{ marginTop: 10 }}>
             <Row gutter={[24, 24]} style={{ marginTop: 10 }}>
               {(dataSource?.data || []).map((record: any) => (
               {(dataSource?.data || []).map((record: any) => (
-                <Col key={record.id} span={props.type ? 8 : 12}>
+                <Col key={record.id} span={8}>
                   <ChannelCard
                   <ChannelCard
                     {...record}
                     {...record}
                     state={getState(record)}
                     state={getState(record)}
@@ -331,6 +340,6 @@ export default observer((props: Props) => {
           }}
           }}
         />
         />
       )}
       )}
-    </div>
+    </PageContainer>
   );
   );
 });
 });

+ 107 - 67
src/pages/link/DataCollect/components/Device/Save/index.tsx

@@ -1,63 +1,92 @@
 import { Button, Modal } from 'antd';
 import { Button, Modal } from 'antd';
-import { createForm, Field, onFieldReact } from '@formily/core';
+import { createForm, Field, onFieldReact, onFieldValueChange, onFormInit } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import { createSchemaField } from '@formily/react';
-import React, { useEffect } from 'react';
+import React, { useMemo, useRef } from 'react';
 import * as ICONS from '@ant-design/icons';
 import * as ICONS from '@ant-design/icons';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Password } from '@formily/antd';
 import { Form, FormGrid, FormItem, Input, Select, NumberPicker, Password } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { ISchema } from '@formily/json-schema';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { RadioCard } from '@/components';
 import { RadioCard } from '@/components';
 
 
 interface Props {
 interface Props {
-  channelId?: string;
   data: Partial<CollectorItem>;
   data: Partial<CollectorItem>;
   close: () => void;
   close: () => void;
   reload: () => void;
   reload: () => void;
-  provider?: 'OPC_UA' | 'MODBUS_TCP';
 }
 }
 
 
 export default (props: Props) => {
 export default (props: Props) => {
-  const form = createForm({
-    validateFirst: true,
-    initialValues: Object.keys(props.data).length
-      ? props.data
-      : {
-          circuitBreaker: {
-            type: 'LowerFrequency',
-          },
-        },
-    effects: () => {
-      onFieldReact('circuitBreaker.type', async (field, f) => {
-        const func = (field as Field).value;
-        f.setFieldState('circuitBreaker.type', (state) => {
-          let tooltip = '';
-          if (func === 'LowerFrequency') {
-            tooltip =
-              '连续20次异常,降低连接频率至原有频率的1/10(重试间隔不超过1分钟),故障处理后自动恢复至设定连接频率';
-          } else if (func === 'Break') {
-            tooltip = '连续10分钟异常,停止采集数据进入熔断状态,设备重新启用后恢复采集状态';
-          } else if (func === 'Ignore') {
-            tooltip = '忽略异常,保持原采集频率超时时间为5s';
-          }
-          state.decoratorProps = {
-            tooltip: tooltip,
-            gridSpan: 2,
-          };
-        });
-      });
-    },
-  });
+  const channelRef = useRef<any>(null);
+  const channelListRef = useRef<any[]>([]);
 
 
-  useEffect(() => {
-    if (props.data?.id) {
-      service.queryCollectorByID(props.data?.id).then((resp) => {
-        if (resp.status === 200) {
-          form.setValues(resp.result);
-        }
-      });
-    }
-  }, [props.data]);
+  const form = useMemo(
+    () =>
+      createForm({
+        validateFirst: true,
+        effects: () => {
+          onFormInit(async (f) => {
+            const response = await service.queryChannelNoPaging({});
+            if (response.status === 200) {
+              channelListRef.current = response.result;
+              f.setFieldState('channelId', (state) => {
+                state.dataSource = (response?.result || []).map((item: ChannelItem) => {
+                  return {
+                    value: item.id,
+                    label: item.name,
+                  };
+                });
+              });
+            }
+            if (props.data?.id) {
+              const resp = await service.queryCollectorByID(props.data?.id);
+              if (resp.status === 200) {
+                form.setInitialValues(resp.result);
+              }
+            } else {
+              f.setInitialValues({
+                circuitBreaker: {
+                  type: 'LowerFrequency',
+                },
+              });
+            }
+          });
+          onFieldValueChange('channelId', (field, f) => {
+            const value = (field as Field).value;
+            if (value) {
+              const dt = channelListRef.current.find((item) => item.id === value);
+              channelRef.current = dt;
+              if (dt?.provider && dt?.provider === 'MODBUS_TCP') {
+                f.setFieldState('configuration.unitId', (state) => {
+                  state.visible = true;
+                });
+                f.setFieldState('configuration.endian', (state) => {
+                  state.visible = true;
+                });
+              }
+            }
+          });
+          onFieldReact('circuitBreaker.type', async (field, f) => {
+            const func = (field as Field).value;
+            f.setFieldState('circuitBreaker.type', (state) => {
+              let tooltip = '';
+              if (func === 'LowerFrequency') {
+                tooltip =
+                  '连续20次异常,降低连接频率至原有频率的1/10(重试间隔不超过1分钟),故障处理后自动恢复至设定连接频率';
+              } else if (func === 'Break') {
+                tooltip = '连续10分钟异常,停止采集数据进入熔断状态,设备重新启用后恢复采集状态';
+              } else if (func === 'Ignore') {
+                tooltip = '忽略异常,保持原采集频率超时时间为5s';
+              }
+              state.decoratorProps = {
+                tooltip: tooltip,
+                gridSpan: 2,
+              };
+            });
+          });
+        },
+      }),
+    [props.data?.id],
+  );
 
 
   const SchemaField = createSchemaField({
   const SchemaField = createSchemaField({
     components: {
     components: {
@@ -88,6 +117,23 @@ export default (props: Props) => {
           columnGap: 24,
           columnGap: 24,
         },
         },
         properties: {
         properties: {
+          channelId: {
+            title: '所属通道',
+            'x-component': 'Select',
+            'x-decorator': 'FormItem',
+            'x-decorator-props': {
+              gridSpan: 2,
+            },
+            'x-component-props': {
+              placeholder: '请选择所属通道',
+            },
+            'x-validator': [
+              {
+                required: true,
+                message: '请选择所属通道',
+              },
+            ],
+          },
           name: {
           name: {
             title: '采集器名称',
             title: '采集器名称',
             'x-component': 'Input',
             'x-component': 'Input',
@@ -119,7 +165,7 @@ export default (props: Props) => {
             'x-component-props': {
             'x-component-props': {
               placeholder: '请输入从机地址',
               placeholder: '请输入从机地址',
             },
             },
-            'x-visible': props.provider === 'MODBUS_TCP',
+            'x-visible': false,
             'x-validator': [
             'x-validator': [
               {
               {
                 required: true,
                 required: true,
@@ -167,15 +213,15 @@ export default (props: Props) => {
             ],
             ],
           },
           },
           'configuration.endian': {
           'configuration.endian': {
-            title: '大小端',
+            title: '高低位切换',
             'x-component': 'RadioCard',
             'x-component': 'RadioCard',
             'x-decorator': 'FormItem',
             'x-decorator': 'FormItem',
             'x-decorator-props': {
             'x-decorator-props': {
               gridSpan: 2,
               gridSpan: 2,
-              tooltip: '统一配置所有点位的大小端',
+              tooltip: '统一配置所有点位的高低位切换',
             },
             },
             'x-component-props': {
             'x-component-props': {
-              placeholder: '请选择大小端',
+              placeholder: '请选择高低位切换',
               model: 'singular',
               model: 'singular',
               itemStyle: {
               itemStyle: {
                 display: 'flex',
                 display: 'flex',
@@ -185,11 +231,11 @@ export default (props: Props) => {
                 height: '50px',
                 height: '50px',
               },
               },
               options: [
               options: [
-                { label: '大端', value: 'BIG' },
-                { label: '小端', value: 'LITTLE' },
+                { label: 'AB', value: 'BIG' },
+                { label: 'BA', value: 'LITTLE' },
               ],
               ],
             },
             },
-            'x-visible': props.provider === 'MODBUS_TCP',
+            'x-visible': false,
             default: 'BIG',
             default: 'BIG',
             'x-validator': [
             'x-validator': [
               {
               {
@@ -223,21 +269,15 @@ export default (props: Props) => {
     if (props.data?.id) {
     if (props.data?.id) {
       response = await service.updateCollector(props.data?.id, { ...props.data, ...value });
       response = await service.updateCollector(props.data?.id, { ...props.data, ...value });
     } else {
     } else {
-      if (props.channelId) {
-        const resp = await service.queryChannelByID(props.channelId);
-        if (resp.status === 200) {
-          const obj = {
-            ...value,
-            provider: resp.result.provider,
-            channelId: props.channelId,
-            channelName: resp.result.name,
-            configuration: {
-              ...value.configuration,
-            },
-          };
-          response = await service.saveCollector({ ...obj });
-        }
-      }
+      const obj = {
+        ...value,
+        provider: channelRef.current?.provider,
+        channelName: channelRef.current?.name,
+        configuration: {
+          ...value.configuration,
+        },
+      };
+      response = await service.saveCollector({ ...obj });
     }
     }
     if (response && response?.status === 200) {
     if (response && response?.status === 200) {
       onlyMessage('操作成功');
       onlyMessage('操作成功');
@@ -249,7 +289,7 @@ export default (props: Props) => {
     <Modal
     <Modal
       title={props?.data?.id ? '编辑' : '新增'}
       title={props?.data?.id ? '编辑' : '新增'}
       maskClosable={false}
       maskClosable={false}
-      visible
+      open
       onCancel={props.close}
       onCancel={props.close}
       width={700}
       width={700}
       footer={[
       footer={[

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

@@ -3,7 +3,7 @@ import SearchComponent from '@/components/SearchComponent';
 import type { ProColumns } from '@jetlinks/pro-table';
 import type { ProColumns } from '@jetlinks/pro-table';
 import { useEffect, useState } from 'react';
 import { useEffect, useState } from 'react';
 import { useDomFullHeight } from '@/hooks';
 import { useDomFullHeight } from '@/hooks';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import CollectorCard from '@/components/ProTableCard/CardItems/DataCollect/device';
 import CollectorCard from '@/components/ProTableCard/CardItems/DataCollect/device';
 import { Empty, PermissionButton } from '@/components';
 import { Empty, PermissionButton } from '@/components';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { useIntl } from '@@/plugin-locale/localeExports';
@@ -17,7 +17,7 @@ import {
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { Card, Col, Pagination, Row } from 'antd';
 import { Card, Col, Pagination, Row } from 'antd';
 import { model } from '@formily/reactive';
 import { model } from '@formily/reactive';
-import Save from '@/pages/link/DataCollect/components/Device/Save/index';
+import Save from '@/pages/DataCollect/Collector/components/Device/Save';
 
 
 interface Props {
 interface Props {
   type: boolean; // true: 综合查询  false: 数据采集
   type: boolean; // true: 综合查询  false: 数据采集

+ 1 - 1
src/pages/link/DataCollect/components/Point/CollectorCard/WritePoint.tsx

@@ -2,7 +2,7 @@ import { Modal } from 'antd';
 import { FormItem, Input, Form } from '@formily/antd';
 import { FormItem, Input, Form } from '@formily/antd';
 import { createForm } from '@formily/core';
 import { createForm } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import { createSchemaField } from '@formily/react';
-import service from '../../../service';
+import service from '../../../../service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 
 
 interface Props {
 interface Props {

+ 1 - 1
src/pages/link/DataCollect/components/Point/CollectorCard/index.less

@@ -1,4 +1,4 @@
-@import '~antd/es/style/themes/default.less';
+@import '../../../../../../../node_modules/antd/es/style/themes/default.less';
 
 
 .card-item {
 .card-item {
   display: flex;
   display: flex;

+ 2 - 2
src/pages/link/DataCollect/components/Point/CollectorCard/index.tsx

@@ -9,7 +9,7 @@ import {
   FormOutlined,
   FormOutlined,
   RedoOutlined,
   RedoOutlined,
 } from '@ant-design/icons';
 } from '@ant-design/icons';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import moment from 'moment';
 import moment from 'moment';
 import classNames from 'classnames';
 import classNames from 'classnames';
@@ -29,7 +29,7 @@ const modbusImage = require('/public/images/DataCollect/device-modbus.png');
 const CollectorCard = (props: PointCardProps) => {
 const CollectorCard = (props: PointCardProps) => {
   const { item, wsValue } = props;
   const { item, wsValue } = props;
   const [spinning, setSpinning] = useState<boolean>(false);
   const [spinning, setSpinning] = useState<boolean>(false);
-  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
+  const { permission } = PermissionButton.usePermission('DataCollect/Collector');
 
 
   const read = async () => {
   const read = async () => {
     if (item?.collectorId && item?.id) {
     if (item?.collectorId && item?.id) {

+ 1 - 1
src/pages/link/DataCollect/components/Point/Save/BatchUpdate.tsx

@@ -3,7 +3,7 @@ import { FormItem, Checkbox, NumberPicker, FormGrid, Form } from '@formily/antd'
 import { createForm, registerValidateRules } from '@formily/core';
 import { createForm, registerValidateRules } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import { createSchemaField } from '@formily/react';
 import RadioCard from '@/components/RadioCard';
 import RadioCard from '@/components/RadioCard';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 
 
 interface Props {
 interface Props {

src/pages/link/DataCollect/components/Point/Save/components/MyInput.tsx → src/pages/DataCollect/Collector/components/Point/Save/components/MyInput.tsx


src/pages/link/DataCollect/components/Point/Save/components/MySelect.tsx → src/pages/DataCollect/Collector/components/Point/Save/components/MySelect.tsx


src/pages/link/DataCollect/components/Point/Save/components/RemoveData.tsx → src/pages/DataCollect/Collector/components/Point/Save/components/RemoveData.tsx


+ 122 - 36
src/pages/link/DataCollect/components/Point/Save/modbus.tsx

@@ -12,9 +12,10 @@ import {
   NumberPicker,
   NumberPicker,
   Password,
   Password,
   Checkbox,
   Checkbox,
+  Switch,
 } from '@formily/antd';
 } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { ISchema } from '@formily/json-schema';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { action } from '@formily/reactive';
 import { action } from '@formily/reactive';
 import { RadioCard } from '@/components';
 import { RadioCard } from '@/components';
@@ -27,7 +28,7 @@ interface Props {
 }
 }
 
 
 export default (props: Props) => {
 export default (props: Props) => {
-  const [data, setData] = useState<Partial<PointItem>>(props.data);
+  const [data, setData] = useState<any>(props.data);
   useEffect(() => {
   useEffect(() => {
     setData({
     setData({
       ...props.data,
       ...props.data,
@@ -37,6 +38,16 @@ export default (props: Props) => {
       features: props.data?.features
       features: props.data?.features
         ? (props.data?.features || []).map((item: any) => item?.value)
         ? (props.data?.features || []).map((item: any) => item?.value)
         : [],
         : [],
+      configuration: {
+        ...props.data?.configuration,
+        parameter: {
+          ...props.data?.configuration?.parameter,
+          writeByteCount: [props.data?.configuration?.parameter?.writeByteCount],
+        },
+      },
+      nspwc:
+        props?.data?.configuration?.parameter?.writeByteCount ||
+        props?.data?.configuration?.parameter?.byteCount,
     });
     });
   }, [props.data]);
   }, [props.data]);
 
 
@@ -55,6 +66,7 @@ export default (props: Props) => {
       FormGrid,
       FormGrid,
       Checkbox,
       Checkbox,
       RadioCard,
       RadioCard,
+      Switch,
     },
     },
     scope: {
     scope: {
       icon(name: any) {
       icon(name: any) {
@@ -197,39 +209,6 @@ export default (props: Props) => {
               },
               },
             ],
             ],
           },
           },
-          // 'configuration.codec.configuration.readIndex': {
-          //   title: '起始位置',
-          //   'x-component': 'NumberPicker',
-          //   'x-decorator': 'FormItem',
-          //   'x-decorator-props': {
-          //     gridSpan: 2,
-          //   },
-          //   'x-component-props': {
-          //     placeholder: '请输入起始位置',
-          //     stringMode: true,
-          //   },
-          //   'x-reactions': {
-          //     dependencies: ['...function'],
-          //     fulfill: {
-          //       state: {
-          //         visible: '{{$deps[0] === "HoldingRegisters"}}',
-          //       },
-          //     },
-          //   },
-          //   'x-validator': [
-          //     {
-          //       required: true,
-          //       message: '请输入起始位置',
-          //     },
-          //     {
-          //       min: 1,
-          //       message: '请输入非0正整数',
-          //     },
-          //     {
-          //       checkLength: true,
-          //     },
-          //   ],
-          // },
           'configuration.parameter.quantity': {
           'configuration.parameter.quantity': {
             title: '寄存器数量',
             title: '寄存器数量',
             'x-component': 'NumberPicker',
             'x-component': 'NumberPicker',
@@ -349,6 +328,111 @@ export default (props: Props) => {
               },
               },
             ],
             ],
           },
           },
+          nspwc: {
+            title: '非标准协议写入配置',
+            'x-component': 'Switch',
+            'x-decorator': 'FormItem',
+            'x-decorator-props': {
+              gridSpan: 2,
+              layout: 'level',
+            },
+            'x-component-props': {
+              placeholder: '请选择非标准协议写入配置',
+            },
+            'x-reactions': {
+              dependencies: ['.accessModes', 'configuration.function'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0].includes("write") && $deps[1] === "HoldingRegisters"}}',
+                },
+              },
+            },
+          },
+          byte: {
+            type: 'void',
+            'x-decorator': 'FormItem',
+            'x-decorator-props': {
+              gridSpan: 2,
+              style: {
+                backgroundColor: '#fafafa',
+                padding: 20,
+              },
+            },
+            'x-component': 'FormGrid',
+            'x-component-props': {
+              maxColumns: 2,
+              minColumns: 2,
+              columnGap: 24,
+            },
+            'x-reactions': {
+              dependencies: ['.nspwc'],
+              fulfill: {
+                state: {
+                  visible: '{{!!$deps[0]}}',
+                },
+              },
+            },
+            properties: {
+              'configuration.parameter.writeByteCount': {
+                title: '是否写入数据区长度',
+                'x-component': 'RadioCard',
+                'x-decorator': 'FormItem',
+                'x-decorator-props': {
+                  gridSpan: 2,
+                  layout: 'vertical',
+                  labelAlign: 'left',
+                },
+                'x-component-props': {
+                  placeholder: '请选择是否写入数据区长度',
+                  model: 'singular',
+                  itemStyle: {
+                    display: 'flex',
+                    flexDirection: 'column',
+                    justifyContent: 'space-around',
+                    minWidth: '130px',
+                    height: '50px',
+                  },
+                  options: [
+                    { label: '是', value: true },
+                    { label: '否', value: false },
+                  ],
+                },
+                'x-validator': [
+                  {
+                    required: true,
+                    message: '请选择是否写入数据区长度',
+                  },
+                ],
+              },
+              'configuration.parameter.byteCount': {
+                title: '自定义数据区长度(byte)',
+                'x-component': 'NumberPicker',
+                'x-decorator': 'FormItem',
+                'x-decorator-props': {
+                  gridSpan: 2,
+                  layout: 'vertical',
+                  labelAlign: 'left',
+                },
+                'x-component-props': {
+                  placeholder: '请输入自定义数据区长度(byte)',
+                },
+                'x-validator': [
+                  {
+                    required: true,
+                    message: '请输入自定义数据区长度(byte)',
+                  },
+                ],
+                'x-reactions': {
+                  dependencies: ['configuration.parameter.quantity'],
+                  fulfill: {
+                    state: {
+                      value: '{{$deps[0]*2}}',
+                    },
+                  },
+                },
+              },
+            },
+          },
           'configuration.interval': {
           'configuration.interval': {
             title: '采集频率',
             title: '采集频率',
             'x-component': 'NumberPicker',
             'x-component': 'NumberPicker',
@@ -425,11 +509,13 @@ export default (props: Props) => {
   };
   };
 
 
   const save = async () => {
   const save = async () => {
-    const value = await form.submit<PointItem>();
+    const value = await form.submit<any>();
+    console.log(value);
     const obj = {
     const obj = {
       provider: props?.collector?.provider || 'MODBUS_TCP',
       provider: props?.collector?.provider || 'MODBUS_TCP',
       collectorId: props?.collector?.id,
       collectorId: props?.collector?.id,
     };
     };
+    delete value.nspwc;
     const response: any = props.data?.id
     const response: any = props.data?.id
       ? await service.updatePoint(props.data?.id, {
       ? await service.updatePoint(props.data?.id, {
           ...props.data,
           ...props.data,

+ 1 - 1
src/pages/link/DataCollect/components/Point/Save/opc-ua.tsx

@@ -14,7 +14,7 @@ import {
   Checkbox,
   Checkbox,
 } from '@formily/antd';
 } from '@formily/antd';
 import type { ISchema } from '@formily/json-schema';
 import type { ISchema } from '@formily/json-schema';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { action } from '@formily/reactive';
 import { action } from '@formily/reactive';
 import { RadioCard } from '@/components';
 import { RadioCard } from '@/components';

src/pages/link/DataCollect/components/Point/Save/scan.less → src/pages/DataCollect/Collector/components/Point/Save/scan.less


+ 3 - 3
src/pages/link/DataCollect/components/Point/Save/scan.tsx

@@ -1,12 +1,12 @@
 import { Button, Col, Modal, Row, Spin, Tree, Checkbox } from 'antd';
 import { Button, Col, Modal, Row, Spin, Tree, Checkbox } from 'antd';
 import { useEffect, useMemo, useState } from 'react';
 import { useEffect, useMemo, useState } from 'react';
-import service from '@/pages/link/DataCollect/service';
+import service from '@/pages/DataCollect/service';
 import './scan.less';
 import './scan.less';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { createSchemaField, FormProvider } from '@formily/react';
 import { createSchemaField, FormProvider } from '@formily/react';
 import { ArrayTable, FormItem, Input, Select } from '@formily/antd';
 import { ArrayTable, FormItem, Input, Select } from '@formily/antd';
-import MyInput from '@/pages/link/DataCollect/components/Point/Save/components/MyInput';
-import MySelect from '@/pages/link/DataCollect/components/Point/Save/components/MySelect';
+import MyInput from '@/pages/DataCollect/Collector/components/Point/Save/components/MyInput';
+import MySelect from '@/pages/DataCollect/Collector/components/Point/Save/components/MySelect';
 import {
 import {
   createForm,
   createForm,
   Field,
   Field,

+ 174 - 172
src/pages/link/DataCollect/components/Point/index.tsx

@@ -3,28 +3,26 @@ import SearchComponent from '@/components/SearchComponent';
 import type { ProColumns } from '@jetlinks/pro-table';
 import type { ProColumns } from '@jetlinks/pro-table';
 import { useEffect, useRef, useState } from 'react';
 import { useEffect, useRef, useState } from 'react';
 import { useDomFullHeight } from '@/hooks';
 import { useDomFullHeight } from '@/hooks';
-import service from '@/pages/link/DataCollect/service';
-import CollectorCard from './CollectorCard/index';
+import service from '@/pages/DataCollect/service';
+import CollectorCard from './CollectorCard';
 import { Empty, PermissionButton } from '@/components';
 import { Empty, PermissionButton } from '@/components';
 import { Button, Card, Checkbox, Col, Dropdown, Menu, Pagination, Row } from 'antd';
 import { Button, Card, Checkbox, Col, Dropdown, Menu, Pagination, Row } from 'antd';
 import { model } from '@formily/reactive';
 import { model } from '@formily/reactive';
-import ModbusSave from '@/pages/link/DataCollect/components/Point/Save/modbus';
-import Scan from '@/pages/link/DataCollect/components/Point/Save/scan';
+import ModbusSave from '@/pages/DataCollect/Collector/components/Point/Save/modbus';
+import Scan from '@/pages/DataCollect/Collector/components/Point/Save/scan';
 import { map } from 'rxjs/operators';
 import { map } from 'rxjs/operators';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
-import OpcSave from '@/pages/link/DataCollect/components/Point/Save/opc-ua';
-import WritePoint from '@/pages/link/DataCollect/components/Point/CollectorCard/WritePoint';
+import OpcSave from '@/pages/DataCollect/Collector/components/Point/Save/opc-ua';
+import WritePoint from '@/pages/DataCollect/Collector/components/Point/CollectorCard/WritePoint';
 import BatchUpdate from './Save/BatchUpdate';
 import BatchUpdate from './Save/BatchUpdate';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
 import { DeleteOutlined, EditOutlined, PlusOutlined, RedoOutlined } from '@ant-design/icons';
 import { DeleteOutlined, EditOutlined, PlusOutlined, RedoOutlined } from '@ant-design/icons';
 interface Props {
 interface Props {
-  type: boolean; // true: 综合查询  false: 数据采集
   data?: Partial<CollectorItem>;
   data?: Partial<CollectorItem>;
   provider?: 'OPC_UA' | 'MODBUS_TCP';
   provider?: 'OPC_UA' | 'MODBUS_TCP';
 }
 }
 
 
 interface PointCardProps {
 interface PointCardProps {
-  type: boolean; // true: 综合查询  false: 数据采集
   data?: Partial<CollectorItem>;
   data?: Partial<CollectorItem>;
   provider?: 'OPC_UA' | 'MODBUS_TCP';
   provider?: 'OPC_UA' | 'MODBUS_TCP';
   reload: boolean; // 变化时刷新
   reload: boolean; // 变化时刷新
@@ -64,7 +62,7 @@ const PointCard = observer((props: PointCardProps) => {
   const { minHeight } = useDomFullHeight(`.data-collect-point`);
   const { minHeight } = useDomFullHeight(`.data-collect-point`);
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
   const [loading, setLoading] = useState<boolean>(true);
   const [loading, setLoading] = useState<boolean>(true);
-  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
+  const { permission } = PermissionButton.usePermission('DataCollect/Collector');
   const [propertyValue, setPropertyValue] = useState<any>({});
   const [propertyValue, setPropertyValue] = useState<any>({});
   const [dataSource, setDataSource] = useState<any>({
   const [dataSource, setDataSource] = useState<any>({
     data: [],
     data: [],
@@ -119,7 +117,9 @@ const PointCard = observer((props: PointCardProps) => {
         terms: [
         terms: [
           ...params?.terms,
           ...params?.terms,
           {
           {
-            terms: [{ column: 'collectorId', value: props.data?.id }],
+            terms: [
+              { column: 'collectorId', value: props.data?.id !== '*' ? props.data?.id : undefined },
+            ],
           },
           },
         ],
         ],
         sorts: [{ name: 'id', order: 'desc' }],
         sorts: [{ name: 'id', order: 'desc' }],
@@ -231,11 +231,11 @@ const PointCard = observer((props: PointCardProps) => {
         bordered={false}
         bordered={false}
         className={'data-collect-point'}
         className={'data-collect-point'}
         style={{ position: 'relative', minHeight }}
         style={{ position: 'relative', minHeight }}
-        bodyStyle={{ paddingTop: !props.type ? 4 : 24 }}
+        bodyStyle={{ paddingTop: 4 }}
       >
       >
         <div>
         <div>
           <div style={{ height: '100%', paddingBottom: 48 }}>
           <div style={{ height: '100%', paddingBottom: 48 }}>
-            {!props.type && (
+            {props.data?.id !== '*' && (
               <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-start' }}>
               <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-start' }}>
                 <PermissionButton
                 <PermissionButton
                   isPermission={permission.add}
                   isPermission={permission.add}
@@ -290,7 +290,7 @@ const PointCard = observer((props: PointCardProps) => {
                   {(dataSource?.data || []).map((record: any) => (
                   {(dataSource?.data || []).map((record: any) => (
                     <Col
                     <Col
                       key={record.id}
                       key={record.id}
-                      xl={props.type ? 12 : 24}
+                      xl={24}
                       xxl={12}
                       xxl={12}
                       span={24}
                       span={24}
                       onClick={() => {
                       onClick={() => {
@@ -377,170 +377,172 @@ const PointCard = observer((props: PointCardProps) => {
 });
 });
 
 
 export default observer((props: Props) => {
 export default observer((props: Props) => {
-  const columns: ProColumns<PointItem>[] = props.type
-    ? [
-        {
-          title: '点位名称',
-          dataIndex: 'name',
-        },
-        {
-          title: '通讯协议',
-          dataIndex: 'provider',
-          valueType: 'select',
-          valueEnum: {
-            OPC_UA: {
-              text: 'OPC_UA',
-              status: 'OPC_UA',
-            },
-            MODBUS_TCP: {
-              text: 'MODBUS_TCP',
-              status: 'MODBUS_TCP',
-            },
+  const columns: ProColumns<PointItem>[] =
+    // props.type
+    // ? [
+    //     {
+    //       title: '点位名称',
+    //       dataIndex: 'name',
+    //     },
+    //     {
+    //       title: '通讯协议',
+    //       dataIndex: 'provider',
+    //       valueType: 'select',
+    //       valueEnum: {
+    //         OPC_UA: {
+    //           text: 'OPC_UA',
+    //           status: 'OPC_UA',
+    //         },
+    //         MODBUS_TCP: {
+    //           text: 'MODBUS_TCP',
+    //           status: 'MODBUS_TCP',
+    //         },
+    //       },
+    //     },
+    //     {
+    //       title: '访问类型',
+    //       dataIndex: 'accessModes$in$any',
+    //       valueType: 'select',
+    //       valueEnum: {
+    //         read: {
+    //           text: '读',
+    //           status: 'read',
+    //         },
+    //         write: {
+    //           text: '写',
+    //           status: 'write',
+    //         },
+    //         subscribe: {
+    //           text: '订阅',
+    //           status: 'subscribe',
+    //         },
+    //       },
+    //       renderText: (_, record) => record.accessModes,
+    //     },
+    //     // {
+    //     //   title: '状态',
+    //     //   dataIndex: 'state',
+    //     //   valueType: 'select',
+    //     //   valueEnum: {
+    //     //     enabled: {
+    //     //       text: '正常',
+    //     //       status: 'enabled',
+    //     //     },
+    //     //     disabled: {
+    //     //       text: '禁用',
+    //     //       status: 'disabled',
+    //     //     },
+    //     //   },
+    //     // },
+    //     {
+    //       title: '运行状态',
+    //       dataIndex: 'runningState',
+    //       valueType: 'select',
+    //       valueEnum: {
+    //         running: {
+    //           text: '运行中',
+    //           status: 'running',
+    //         },
+    //         partialError: {
+    //           text: '部分错误',
+    //           status: 'partialError',
+    //         },
+    //         failed: {
+    //           text: '错误',
+    //           status: 'failed',
+    //         },
+    //         stopped: {
+    //           text: '已停止',
+    //           status: 'stopped',
+    //         },
+    //       },
+    //     },
+    //     {
+    //       title: '说明',
+    //       dataIndex: 'description',
+    //     },
+    //   ]
+    // :
+    [
+      {
+        title: '点位名称',
+        dataIndex: 'name',
+      },
+      {
+        title: '访问类型',
+        dataIndex: 'accessModes$in$any',
+        valueType: 'select',
+        renderText: (_, record) => record.accessModes,
+        valueEnum:
+          props?.provider === 'MODBUS_TCP'
+            ? {
+                read: {
+                  text: '读',
+                  status: 'read',
+                },
+                write: {
+                  text: '写',
+                  status: 'write',
+                },
+              }
+            : {
+                read: {
+                  text: '读',
+                  status: 'read',
+                },
+                write: {
+                  text: '写',
+                  status: 'write',
+                },
+                subscribe: {
+                  text: '订阅',
+                  status: 'subscribe',
+                },
+              },
+      },
+      // {
+      //   title: '状态',
+      //   dataIndex: 'state',
+      //   valueType: 'select',
+      //   valueEnum: {
+      //     enabled: {
+      //       text: '正常',
+      //       status: 'enabled',
+      //     },
+      //     disabled: {
+      //       text: '禁用',
+      //       status: 'disabled',
+      //     },
+      //   },
+      // },
+      {
+        title: '运行状态',
+        dataIndex: 'runningState',
+        valueType: 'select',
+        valueEnum: {
+          running: {
+            text: '运行中',
+            status: 'running',
           },
           },
-        },
-        {
-          title: '访问类型',
-          dataIndex: 'accessModes$in$any',
-          valueType: 'select',
-          valueEnum: {
-            read: {
-              text: '读',
-              status: 'read',
-            },
-            write: {
-              text: '写',
-              status: 'write',
-            },
-            subscribe: {
-              text: '订阅',
-              status: 'subscribe',
-            },
+          partialError: {
+            text: '部分错误',
+            status: 'partialError',
           },
           },
-          renderText: (_, record) => record.accessModes,
-        },
-        // {
-        //   title: '状态',
-        //   dataIndex: 'state',
-        //   valueType: 'select',
-        //   valueEnum: {
-        //     enabled: {
-        //       text: '正常',
-        //       status: 'enabled',
-        //     },
-        //     disabled: {
-        //       text: '禁用',
-        //       status: 'disabled',
-        //     },
-        //   },
-        // },
-        {
-          title: '运行状态',
-          dataIndex: 'runningState',
-          valueType: 'select',
-          valueEnum: {
-            running: {
-              text: '运行中',
-              status: 'running',
-            },
-            partialError: {
-              text: '部分错误',
-              status: 'partialError',
-            },
-            failed: {
-              text: '错误',
-              status: 'failed',
-            },
-            stopped: {
-              text: '已停止',
-              status: 'stopped',
-            },
+          failed: {
+            text: '错误',
+            status: 'failed',
           },
           },
-        },
-        {
-          title: '说明',
-          dataIndex: 'description',
-        },
-      ]
-    : [
-        {
-          title: '点位名称',
-          dataIndex: 'name',
-        },
-        {
-          title: '访问类型',
-          dataIndex: 'accessModes$in$any',
-          valueType: 'select',
-          renderText: (_, record) => record.accessModes,
-          valueEnum:
-            props?.provider === 'MODBUS_TCP'
-              ? {
-                  read: {
-                    text: '读',
-                    status: 'read',
-                  },
-                  write: {
-                    text: '写',
-                    status: 'write',
-                  },
-                }
-              : {
-                  read: {
-                    text: '读',
-                    status: 'read',
-                  },
-                  write: {
-                    text: '写',
-                    status: 'write',
-                  },
-                  subscribe: {
-                    text: '订阅',
-                    status: 'subscribe',
-                  },
-                },
-        },
-        // {
-        //   title: '状态',
-        //   dataIndex: 'state',
-        //   valueType: 'select',
-        //   valueEnum: {
-        //     enabled: {
-        //       text: '正常',
-        //       status: 'enabled',
-        //     },
-        //     disabled: {
-        //       text: '禁用',
-        //       status: 'disabled',
-        //     },
-        //   },
-        // },
-        {
-          title: '运行状态',
-          dataIndex: 'runningState',
-          valueType: 'select',
-          valueEnum: {
-            running: {
-              text: '运行中',
-              status: 'running',
-            },
-            partialError: {
-              text: '部分错误',
-              status: 'partialError',
-            },
-            failed: {
-              text: '错误',
-              status: 'failed',
-            },
-            stopped: {
-              text: '已停止',
-              status: 'stopped',
-            },
+          stopped: {
+            text: '已停止',
+            status: 'stopped',
           },
           },
         },
         },
-        {
-          title: '说明',
-          dataIndex: 'description',
-        },
-      ];
+      },
+      {
+        title: '说明',
+        dataIndex: 'description',
+      },
+    ];
   return (
   return (
     <div>
     <div>
       <PointCard columns={columns} {...props} reload={PointModel.reload} />
       <PointCard columns={columns} {...props} reload={PointModel.reload} />

+ 1 - 2
src/pages/link/DataCollect/components/Tree/index.less

@@ -8,14 +8,13 @@
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
   justify-content: space-between;
   justify-content: space-between;
-  width: 240px;
+  width: 220px;
   overflow: hidden;
   overflow: hidden;
 }
 }
 
 
 .title {
 .title {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
-  width: 200px;
 }
 }
 
 
 .iconColor {
 .iconColor {

+ 257 - 0
src/pages/DataCollect/Collector/components/Tree/index.tsx

@@ -0,0 +1,257 @@
+import {
+  PlusOutlined,
+  FormOutlined,
+  DeleteOutlined,
+  StopOutlined,
+  PlayCircleOutlined,
+  DownOutlined,
+} from '@ant-design/icons';
+import { Button, Input, Tree, Space, Popconfirm, Tooltip, Tag } from 'antd';
+import { observer } from '@formily/react';
+import { model } from '@formily/reactive';
+import { Empty, PermissionButton } from '@/components';
+import styles from './index.less';
+import service from '@/pages/DataCollect/service';
+import { useEffect } from 'react';
+import CollectorSave from '../Device/Save';
+import { onlyMessage } from '@/utils/util';
+import { useIntl } from '@@/plugin-locale/localeExports';
+
+const TreeModel = model<{
+  selectedKeys: string[];
+  dataSource: any[];
+  loading: boolean;
+  param: any;
+  visible: boolean;
+  current: any;
+}>({
+  selectedKeys: ['*'],
+  dataSource: [],
+  loading: true,
+  param: {},
+  visible: false,
+  current: {},
+});
+interface Props {
+  change: (data?: any) => void;
+}
+
+export default observer((props: Props) => {
+  // const deviceImg = require('/public/images/DataCollect/tree-device.png');
+  const { permission } = PermissionButton.usePermission('DataCollect/Collector');
+  const intl = useIntl();
+
+  const handleSearch = (params: any) => {
+    TreeModel.loading = true;
+    TreeModel.param = params;
+    service
+      .queryCollector({ ...params, paging: false, sorts: [{ name: 'createTime', order: 'desc' }] })
+      .then((resp) => {
+        if (resp.status === 200) {
+          TreeModel.dataSource = [
+            {
+              id: '*',
+              name: '全部',
+              children: resp.result,
+            },
+          ];
+          props.change(TreeModel.dataSource[0]);
+        }
+        TreeModel.loading = false;
+      });
+  };
+
+  useEffect(() => {
+    handleSearch(TreeModel.param);
+  }, [TreeModel.param]);
+
+  const getState = (record: any) => {
+    if (record) {
+      const colorMap = new Map();
+      colorMap.set('running', 'success');
+      colorMap.set('partialError', 'warning');
+      colorMap.set('failed', 'error');
+      colorMap.set('stopped', 'default');
+      if (record?.state?.value === 'enabled') {
+        return (
+          record?.runningState && (
+            <Tag color={colorMap.get(record?.runningState?.value)}>
+              {record?.runningState?.text}
+            </Tag>
+          )
+        );
+      } else {
+        return <Tag color="processing">禁用</Tag>;
+      }
+    } else {
+      return '';
+    }
+  };
+
+  return (
+    <div>
+      <div>
+        <Input.Search
+          placeholder="请输入名称"
+          allowClear
+          onSearch={(val) => {
+            TreeModel.param = {
+              terms: [{ column: 'name', value: `%${val}%`, termType: 'like' }],
+            };
+          }}
+          style={{ width: '100%' }}
+        />
+      </div>
+      <div style={{ margin: '16px 0' }}>
+        <Button
+          type="primary"
+          ghost
+          style={{ width: '100%' }}
+          icon={<PlusOutlined />}
+          onClick={() => {
+            TreeModel.visible = true;
+            TreeModel.current = {};
+          }}
+        >
+          新增采集器
+        </Button>
+      </div>
+      <div>
+        {TreeModel.dataSource.length ? (
+          <Tree
+            style={{ overflow: 'hidden' }}
+            className={styles['data-collect-tree']}
+            showIcon
+            height={500}
+            selectedKeys={TreeModel.selectedKeys}
+            defaultExpandAll
+            switcherIcon={<DownOutlined />}
+            fieldNames={{
+              title: 'name',
+              key: 'id',
+            }}
+            titleRender={(i) => (
+              <div className={i.id !== '*' ? styles.treeTitle : {}}>
+                <div
+                  className={styles.title}
+                  onClick={() => {
+                    TreeModel.selectedKeys = [i.id];
+                    props.change(i);
+                  }}
+                >
+                  {/*{*/}
+                  {/*  i.id !== '*' && <img width={'20px'} style={{ marginRight: 5, width: 10 }} src={deviceImg} />*/}
+                  {/*}*/}
+                  <div style={{ display: 'flex' }}>
+                    <span
+                      className={'ellipsis'}
+                      style={{
+                        marginRight: 5,
+                        maxWidth: 85,
+                        color: 'rgba(0, 0, 0, 0.6)',
+                      }}
+                    >
+                      {i.name}
+                    </span>
+                    {i.id !== '*' && getState(i)}
+                  </div>
+                </div>
+                {i.id !== '*' && (
+                  <div>
+                    <Space className={styles.iconColor}>
+                      <Tooltip title={!permission.update ? '暂无权限,请联系管理员' : ''}>
+                        <FormOutlined
+                          onClick={() => {
+                            if (permission.update) {
+                              TreeModel.current = i;
+                              TreeModel.visible = true;
+                            }
+                          }}
+                        />
+                      </Tooltip>
+                      <Popconfirm
+                        title={intl.formatMessage({
+                          id: `pages.data.option.${
+                            i?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
+                          }.tips`,
+                          defaultMessage: '确认禁用?',
+                        })}
+                        onConfirm={async () => {
+                          const resp =
+                            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 = {};
+                            handleSearch(TreeModel.param);
+                            onlyMessage('操作成功');
+                          } else {
+                            onlyMessage('操作失败!', 'error');
+                          }
+                        }}
+                      >
+                        <Tooltip title={!permission.action ? '暂无权限,请联系管理员' : ''}>
+                          {i?.state?.value !== 'disabled' ? (
+                            <StopOutlined />
+                          ) : (
+                            <PlayCircleOutlined />
+                          )}
+                        </Tooltip>
+                      </Popconfirm>
+                      <Popconfirm
+                        title={'该操作将会删除下属点位,确定删除?'}
+                        disabled={i?.state?.value !== 'disabled'}
+                        onConfirm={async () => {
+                          const resp = await service.removeCollector(i.id);
+                          if (resp.status === 200) {
+                            TreeModel.param = {};
+                            handleSearch(TreeModel.param);
+                            onlyMessage('操作成功');
+                          }
+                        }}
+                      >
+                        <Tooltip
+                          title={
+                            !permission.delete
+                              ? '暂无权限,请联系管理员'
+                              : i?.state?.value !== 'disabled'
+                              ? '正常的采集器不能删除'
+                              : ''
+                          }
+                        >
+                          <DeleteOutlined />
+                        </Tooltip>
+                      </Popconfirm>
+                    </Space>
+                  </div>
+                )}
+              </div>
+            )}
+            treeData={TreeModel.dataSource}
+          ></Tree>
+        ) : (
+          <Empty />
+        )}
+      </div>
+      {TreeModel.visible && (
+        <CollectorSave
+          data={TreeModel.current}
+          close={() => {
+            TreeModel.visible = false;
+          }}
+          reload={() => {
+            TreeModel.visible = false;
+            TreeModel.param = {};
+            handleSearch(TreeModel.param);
+          }}
+        />
+      )}
+    </div>
+  );
+});

src/pages/link/DataCollect/components/index.less → src/pages/DataCollect/Collector/components/index.less


src/pages/link/DataCollect/DataGathering/index.less → src/pages/DataCollect/Collector/index.less


+ 41 - 0
src/pages/DataCollect/Collector/index.tsx

@@ -0,0 +1,41 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import { Card } from 'antd';
+import styles from './index.less';
+import CollectorTree from './components/Tree';
+import { observer } from '@formily/reactive-react';
+import { model } from '@formily/reactive';
+import Point from './components/Point';
+
+export const DataCollectModel = model<{
+  provider: 'OPC_UA' | 'MODBUS_TCP';
+  data: any;
+  reload: boolean;
+  refresh: boolean;
+}>({
+  provider: 'MODBUS_TCP',
+  data: {},
+  reload: false,
+  refresh: false,
+});
+
+export default observer(() => {
+  return (
+    <PageContainer>
+      <Card bordered={false} bodyStyle={{ paddingTop: 0 }}>
+        <div className={styles.container}>
+          <div className={styles.left}>
+            <CollectorTree
+              change={(data) => {
+                DataCollectModel.provider = data.provider;
+                DataCollectModel.data = data || {};
+              }}
+            />
+          </div>
+          <div className={styles.right}>
+            <Point provider={DataCollectModel.provider} data={DataCollectModel.data} />
+          </div>
+        </div>
+      </Card>
+    </PageContainer>
+  );
+});

src/pages/link/DataCollect/Dashboard/index.less → src/pages/DataCollect/Dashboard/index.less


src/pages/link/DataCollect/Dashboard/index.tsx → src/pages/DataCollect/Dashboard/index.tsx


+ 3 - 3
src/pages/link/DataCollect/service.ts

@@ -53,7 +53,7 @@ class Service {
       data: params,
       data: params,
     });
     });
   public queryCollector = (params: any) =>
   public queryCollector = (params: any) =>
-    request(`/${SystemConst.API_BASE}/data-collect/collector/_query`, {
+    request(`/${SystemConst.API_BASE}/data-collect/collector/_query/no-paging?paging=false`, {
       method: 'POST',
       method: 'POST',
       data: params,
       data: params,
     });
     });
@@ -104,8 +104,8 @@ class Service {
     request(`/${SystemConst.API_BASE}/data-collect/channel/${id}`, {
     request(`/${SystemConst.API_BASE}/data-collect/channel/${id}`, {
       method: 'DELETE',
       method: 'DELETE',
     });
     });
-  public queryChannelTree = (params: ChannelItem) =>
-    request(`/${SystemConst.API_BASE}/data-collect/channel/_all/tree`, {
+  public queryChannelNoPaging = (params: any) =>
+    request(`/${SystemConst.API_BASE}/data-collect/channel/_query/no-paging?paging=false`, {
       method: 'POST',
       method: 'POST',
       data: params,
       data: params,
     });
     });

src/pages/link/DataCollect/typings.d.ts → src/pages/DataCollect/typings.d.ts


+ 14 - 13
src/pages/device/Instance/Detail/MetadataLog/Property/index.tsx

@@ -68,9 +68,9 @@ const PropertyLog = (props: Props) => {
       title: '操作',
       title: '操作',
       dataIndex: 'action',
       dataIndex: 'action',
       key: 'action',
       key: 'action',
-      render: (text: any, record: any) => (
-        <a>
-          {data.valueType?.type === 'file' && data?.valueType?.fileType == 'url' ? (
+      render: (text: any, record: any) => [
+        data.valueType?.type === 'file' ? (
+          <a style={{ marginRight: 20 }}>
             <ATooltip title="下载">
             <ATooltip title="下载">
               <DownloadOutlined
               <DownloadOutlined
                 onClick={() => {
                 onClick={() => {
@@ -89,16 +89,17 @@ const PropertyLog = (props: Props) => {
                 }}
                 }}
               />
               />
             </ATooltip>
             </ATooltip>
-          ) : (
-            <SearchOutlined
-              onClick={() => {
-                setDetailVisible(true);
-                setCurrent(record);
-              }}
-            />
-          )}
-        </a>
-      ),
+          </a>
+        ) : null,
+        <a>
+          <SearchOutlined
+            onClick={() => {
+              setDetailVisible(true);
+              setCurrent(record);
+            }}
+          />
+        </a>,
+      ],
     },
     },
   ];
   ];
 
 

+ 103 - 3
src/pages/device/Instance/Detail/Running/Property/EditProperty.tsx

@@ -1,11 +1,13 @@
 import { Alert, Modal } from 'antd';
 import { Alert, Modal } from 'antd';
-import { FormItem, Input } from '@formily/antd';
-import { createForm } from '@formily/core';
+import { ArrayTable, DatePicker, FormItem, Input, NumberPicker, Select } from '@formily/antd';
+import { createForm, onFormInit } from '@formily/core';
 import { createSchemaField, FormProvider } from '@formily/react';
 import { createSchemaField, FormProvider } from '@formily/react';
 import { service } from '@/pages/device/Instance';
 import { service } from '@/pages/device/Instance';
 import { useParams } from 'umi';
 import { useParams } from 'umi';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
+import GeoComponent from '@/pages/device/Instance/Detail/Tags/location/GeoComponent';
+import { MetadataJsonInput } from '@/components';
 
 
 interface Props {
 interface Props {
   data: Partial<PropertyMetadata>;
   data: Partial<PropertyMetadata>;
@@ -20,10 +22,108 @@ const EditProperty = (props: Props) => {
     components: {
     components: {
       Input,
       Input,
       FormItem,
       FormItem,
+      Select,
+      ArrayTable,
+      DatePicker,
+      NumberPicker,
+      GeoComponent,
+      MetadataJsonInput,
     },
     },
   });
   });
 
 
-  const form = createForm();
+  const form = createForm({
+    effects() {
+      onFormInit((f) => {
+        const valueType = data?.valueType?.type || data?.dataType;
+        switch (valueType) {
+          case 'enum':
+            f.setFieldState('propertyValue', async (state) => {
+              state.dataSource = (data?.valueType?.elements || []).map((i: any) => {
+                return {
+                  label: i?.text,
+                  value: i?.value,
+                };
+              });
+              state.componentProps = {
+                placeholder: '请选择',
+              };
+              state.componentType = 'Select';
+            });
+            break;
+          case 'boolean':
+            f.setFieldState('propertyValue', async (state) => {
+              state.dataSource = [
+                {
+                  label: data?.valueType?.trueText || '是',
+                  value: data?.valueType?.trueValue || true,
+                },
+                {
+                  label: data?.valueType?.falseText || '否',
+                  value: data?.valueType?.falseValue || false,
+                },
+              ];
+              state.componentProps = {
+                placeholder: '请选择',
+              };
+              state.componentType = 'Select';
+            });
+            break;
+          case 'int':
+          case 'long':
+          case 'float':
+          case 'double':
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'NumberPicker';
+              state.componentProps = {
+                placeholder: '请输入',
+              };
+            });
+            break;
+          case 'geoPoint':
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'GeoComponent';
+              state.componentProps = {
+                placeholder: '请输入',
+              };
+            });
+            break;
+          case 'object':
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'MetadataJsonInput';
+              state.componentProps = {
+                placeholder: '请输入',
+              };
+            });
+            break;
+          case 'array':
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'Input';
+              state.componentProps = {
+                placeholder: '多个数据用英文,分割',
+              };
+            });
+            break;
+          case 'date':
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'DatePicker';
+              state.componentProps = {
+                placeholder: '请选择',
+                format: 'YYYY-MM-DD HH:mm:ss',
+              };
+            });
+            break;
+          default:
+            f.setFieldState('propertyValue', (state) => {
+              state.componentType = 'Input';
+              state.componentProps = {
+                placeholder: '请输入',
+              };
+            });
+            break;
+        }
+      });
+    },
+  });
   const schema = {
   const schema = {
     type: 'object',
     type: 'object',
     properties: {
     properties: {

+ 37 - 31
src/pages/device/Instance/Detail/Tags/Edit.tsx

@@ -147,6 +147,9 @@ const Edit = (props: Props) => {
                   type: 'string',
                   type: 'string',
                   'x-decorator': 'FormItem',
                   'x-decorator': 'FormItem',
                   'x-component': 'Input',
                   'x-component': 'Input',
+                  'x-component-props': {
+                    readOnly: true,
+                  },
                 },
                 },
               },
               },
             },
             },
@@ -165,6 +168,9 @@ const Edit = (props: Props) => {
                   type: 'string',
                   type: 'string',
                   'x-decorator': 'FormItem',
                   'x-decorator': 'FormItem',
                   'x-component': 'Input',
                   'x-component': 'Input',
+                  'x-component-props': {
+                    readOnly: true,
+                  },
                 },
                 },
               },
               },
             },
             },
@@ -201,39 +207,39 @@ const Edit = (props: Props) => {
                 },
                 },
               },
               },
             },
             },
-            column4: {
-              type: 'void',
-              'x-component': 'ArrayTable.Column',
-              'x-component-props': {
-                width: 100,
-                title: '操作',
-                dataIndex: 'operations',
-              },
-              properties: {
-                item: {
-                  type: 'void',
-                  'x-component': 'FormItem',
-                  properties: {
-                    remove: {
-                      type: 'void',
-                      'x-component': 'RemoveData',
-                      // 'x-component-props': {
-                      //   tags: tags,
-                      // },
-                    },
-                  },
-                },
-              },
-            },
-          },
-        },
-        properties: {
-          add: {
-            type: 'void',
-            'x-component': 'ArrayTable.Addition',
-            title: '添加',
+            // column4: {
+            //   type: 'void',
+            //   'x-component': 'ArrayTable.Column',
+            //   'x-component-props': {
+            //     width: 100,
+            //     title: '操作',
+            //     dataIndex: 'operations',
+            //   },
+            //   properties: {
+            //     item: {
+            //       type: 'void',
+            //       'x-component': 'FormItem',
+            //       properties: {
+            //         remove: {
+            //           type: 'void',
+            //           'x-component': 'RemoveData',
+            //           // 'x-component-props': {
+            //           //   tags: tags,
+            //           // },
+            //         },
+            //       },
+            //     },
+            //   },
+            // },
           },
           },
         },
         },
+        // properties: {
+        //   add: {
+        //     type: 'void',
+        //     'x-component': 'ArrayTable.Addition',
+        //     title: '添加',
+        //   },
+        // },
       },
       },
     },
     },
   };
   };

+ 16 - 16
src/pages/device/components/Metadata/Base/index.tsx

@@ -5,14 +5,14 @@ import { useParams } from 'umi';
 import DB from '@/db';
 import DB from '@/db';
 import type { MetadataItem, MetadataType } from '@/pages/device/Product/typings';
 import type { MetadataItem, MetadataType } from '@/pages/device/Product/typings';
 import MetadataMapping from './columns';
 import MetadataMapping from './columns';
-import { DeleteOutlined, EditOutlined, ImportOutlined, PlusOutlined } from '@ant-design/icons';
+import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
 import Edit from './Edit';
 import Edit from './Edit';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
 import MetadataModel from './model';
 import MetadataModel from './model';
 import { Store } from 'jetlinks-store';
 import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
 import SystemConst from '@/utils/const';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import PropertyImport from '@/pages/device/Product/Detail/PropertyImport';
+// import PropertyImport from '@/pages/device/Product/Detail/PropertyImport';
 import { productModel } from '@/pages/device/Product';
 import { productModel } from '@/pages/device/Product';
 import { InstanceModel } from '@/pages/device/Instance';
 import { InstanceModel } from '@/pages/device/Instance';
 import { asyncUpdateMedata, removeMetadata } from '../metadata';
 import { asyncUpdateMedata, removeMetadata } from '../metadata';
@@ -185,19 +185,19 @@ const BaseMetadata = observer((props: Props) => {
           },
           },
         }}
         }}
         toolBarRender={() => [
         toolBarRender={() => [
-          props.type === 'properties' && target === 'device' && (
-            <PermissionButton
-              isPermission={props.permission.update}
-              onClick={() => {
-                MetadataModel.importMetadata = true;
-              }}
-              key="button"
-              icon={<ImportOutlined />}
-              type="ghost"
-            >
-              导入属性
-            </PermissionButton>
-          ),
+          // props.type === 'properties' && target === 'device' && (
+          //   <PermissionButton
+          //     isPermission={props.permission.update}
+          //     onClick={() => {
+          //       MetadataModel.importMetadata = true;
+          //     }}
+          //     key="button"
+          //     icon={<ImportOutlined />}
+          //     type="ghost"
+          //   >
+          //     导入属性
+          //   </PermissionButton>
+          // ),
           <PermissionButton
           <PermissionButton
             isPermission={props.permission.update}
             isPermission={props.permission.update}
             key={'add'}
             key={'add'}
@@ -221,7 +221,7 @@ const BaseMetadata = observer((props: Props) => {
           </PermissionButton>,
           </PermissionButton>,
         ]}
         ]}
       />
       />
-      {MetadataModel.importMetadata && <PropertyImport type={target} />}
+      {/*{MetadataModel.importMetadata && <PropertyImport type={target} />}*/}
       {MetadataModel.edit && <Edit type={target} tabs={type} />}
       {MetadataModel.edit && <Edit type={target} tabs={type} />}
     </>
     </>
   );
   );

+ 2 - 0
src/pages/home/index.tsx

@@ -9,6 +9,7 @@ import Service from './service';
 import { Skeleton } from 'antd';
 import { Skeleton } from 'antd';
 import { useModel } from '@@/plugin-model/useModel';
 import { useModel } from '@@/plugin-model/useModel';
 import { isNoCommunity } from '@/utils/util';
 import { isNoCommunity } from '@/utils/util';
+import SystemConst from '@/utils/const';
 
 
 export const service = new Service();
 export const service = new Service();
 const Home = () => {
 const Home = () => {
@@ -49,6 +50,7 @@ const Home = () => {
         });
         });
       }
       }
     });
     });
+    console.log('版本:' + localStorage.getItem(SystemConst.Version_Code));
   }, []);
   }, []);
   useEffect(() => {
   useEffect(() => {
     if (isNoCommunity) {
     if (isNoCommunity) {

+ 1 - 0
src/pages/link/AccessConfig/Detail/components/CTWing/index.less

@@ -1,6 +1,7 @@
 .doc {
 .doc {
   height: 550px;
   height: 550px;
   padding: 24px;
   padding: 24px;
+  overflow-x: hidden;
   overflow-y: auto;
   overflow-y: auto;
   color: rgba(#000, 0.8);
   color: rgba(#000, 0.8);
   font-size: 14px;
   font-size: 14px;

+ 21 - 8
src/pages/link/AccessConfig/Detail/components/CTWing/index.tsx

@@ -1,6 +1,7 @@
 import { Button, Col, Form, Input, Row, Image } from 'antd';
 import { Button, Col, Form, Input, Row, Image } from 'antd';
 import { useEffect } from 'react';
 import { useEffect } from 'react';
 import styles from './index.less';
 import styles from './index.less';
+import { randomString } from '@/utils/util';
 
 
 interface Props {
 interface Props {
   next: (data: any) => void;
   next: (data: any) => void;
@@ -9,10 +10,10 @@ interface Props {
 
 
 const CTWing = (props: Props) => {
 const CTWing = (props: Props) => {
   const [form] = Form.useForm();
   const [form] = Form.useForm();
-  // const img = require('/public/images/network/CTWing.jpg');
-  const img1 = require('/public/images/network/01.jpg');
+  const img1 = require('/public/images/network/01.png');
   const img2 = require('/public/images/network/02.jpg');
   const img2 = require('/public/images/network/02.jpg');
-  const img3 = require('/public/images/network/03.jpg');
+  const img3 = require('/public/images/network/03.png');
+  const img4 = require('/public/images/network/04.jpg');
 
 
   useEffect(() => {
   useEffect(() => {
     form.setFieldsValue({
     form.setFieldsValue({
@@ -81,24 +82,36 @@ const CTWing = (props: Props) => {
       <Col span={8}>
       <Col span={8}>
         <div className={styles.doc}>
         <div className={styles.doc}>
           <h1>操作指引:</h1>
           <h1>操作指引:</h1>
-          <div>1、创建类型为CTWing的设备接入网关。</div>
+          <div>1、CTWing端创建产品、设备,以及一个第三方应用</div>
           <div>
           <div>
-            2、创建产品,并选中接入方式为CTWing,选中后需填写CTWing平台中的产品ID、Master-APIkey。
+            2、CTWing端配置产品/设备/分组级订阅,订阅方URL地址请填写:
+            <div style={{ wordWrap: 'break-word' }}>
+              {origin}/api/ctwing/{randomString()}/notify
+            </div>
           </div>
           </div>
           <div className={styles.image}>
           <div className={styles.image}>
             <Image width="100%" src={img1} />
             <Image width="100%" src={img1} />
           </div>
           </div>
+          <div>3、IOT端创建类型为CTWing的设备接入网关</div>
           <div>
           <div>
-            3、添加设备,为每一台设备设置唯一的IMEI、SN、IMSI、PSK码(需与CTWing平台中填写的值一致,若CTWing平台没有对应的设备,将会通过CTWing平台提供的LWM2M协议自动创建)
+            4、IOT端创建产品,选中接入方式为CTWing,填写CTWing平台中的产品ID、Master-APIkey。
           </div>
           </div>
           <div className={styles.image}>
           <div className={styles.image}>
             <Image width="100%" src={img2} />
             <Image width="100%" src={img2} />
           </div>
           </div>
-          <h1>配置说明</h1>
-          <div>1.请将CTWing的AEP平台-应用管理中的App Key和App Secret复制到当前页面</div>
+          <div>5、IOT端添加设备,为每一台设备设置唯一的IMEI(需与CTWing平台中填写的值一致)</div>
           <div className={styles.image}>
           <div className={styles.image}>
             <Image width="100%" src={img3} />
             <Image width="100%" src={img3} />
           </div>
           </div>
+          <h1>设备接入网关配置说明</h1>
+          <div>1.请将CTWing的AEP平台-应用管理中的App Key和App Secret复制到当前页面</div>
+          <div className={styles.image}>
+            <Image width="100%" src={img4} />
+          </div>
+          <h1>其他说明</h1>
+          <div>
+            1.在IOT端启用设备时,若CTWing平台没有与之对应的设备,则将在CTWing端自动创建新设备
+          </div>
         </div>
         </div>
       </Col>
       </Col>
     </Row>
     </Row>

+ 49 - 8
src/pages/link/AccessConfig/Detail/components/OneNet/index.tsx

@@ -1,7 +1,8 @@
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import { QuestionCircleOutlined } from '@ant-design/icons';
-import { Button, Col, Form, Image, Input, Row, Tooltip } from 'antd';
+import { Button, Col, Descriptions, Form, Image, Input, Row, Tooltip } from 'antd';
 import { useEffect } from 'react';
 import { useEffect } from 'react';
 import styles from './index.less';
 import styles from './index.less';
+import { randomString } from '@/utils/util';
 
 
 interface Props {
 interface Props {
   next: (data: any) => void;
   next: (data: any) => void;
@@ -10,6 +11,8 @@ interface Props {
 
 
 const OneNet = (props: Props) => {
 const OneNet = (props: Props) => {
   const img = require('/public/images/network/OneNet.jpg');
   const img = require('/public/images/network/OneNet.jpg');
+  const img1 = require('/public/images/network/05.jpg');
+  const img2 = require('/public/images/network/06.jpg');
 
 
   const [form] = Form.useForm();
   const [form] = Form.useForm();
 
 
@@ -109,18 +112,56 @@ const OneNet = (props: Props) => {
       <Col span={8}>
       <Col span={8}>
         <div className={styles.doc}>
         <div className={styles.doc}>
           <h1>操作指引:</h1>
           <h1>操作指引:</h1>
-          <div>1、创建类型为OneNet的设备接入网关</div>
-          <div>2、创建产品,并选中接入方式为OneNet</div>
+          <div>1、OneNet端创建产品、设备,并配置HTTP推送</div>
+          <div>2、IOT端创建类型为OneNet的设备接入网关</div>
           <div>
           <div>
-            3、添加设备,为每一台设备设置唯一的IMEI、IMSI码(需与OneNet平台中填写的值一致,若OneNet平台没有对应的设备,将会通过OneNet平台提供的LWM2M协议自动创建
+            3、IOT端创建产品,选中接入方式为OneNet类型的设备接入网关,填写Master-APIkey(OneNet端的产品Key
           </div>
           </div>
           <div className={styles.image}>
           <div className={styles.image}>
+            <Image width="100%" src={img1} />
+          </div>
+          <div>
+            4、IOT端添加设备,在设备实例页面为每一台设备设置唯一的IMEI、IMSI码(需与OneNet平台中的值一致)
+          </div>
+          <div className={styles.image}>
+            <Image width="100%" src={img2} />
+          </div>
+          <h1>HTTP推送配置说明</h1>
+          <div className={styles.image}>
             <Image width="100%" src={img} />
             <Image width="100%" src={img} />
           </div>
           </div>
-          <h1>配置说明</h1>
-          <div>1.接口地址需要与OneNet数据推送配置中地址一致</div>
-          <div>2.通知Token需要与OneNet数据推送配置中Token一致</div>
-          <div>3.aesKey需要与OneNet数据推送配置中aesKey一致</div>
+          <div>HTTP推送配置路径:应用开发&gt;数据推送</div>
+          <Descriptions bordered size={'small'} column={1} labelStyle={{ width: 100 }}>
+            <Descriptions.Item label="参数">说明</Descriptions.Item>
+            <Descriptions.Item label="实例名称">推送实例的名称</Descriptions.Item>
+            <Descriptions.Item label="推送地址">
+              用于接收OneNet推送设备数据的地址物联网平台地址:
+              <div style={{ wordWrap: 'break-word' }}>
+                {origin}/api/one-net/{randomString()}/notify
+              </div>
+            </Descriptions.Item>
+            <Descriptions.Item label="Token">
+              自定义token,可用于验证请求是否来自OneNet
+            </Descriptions.Item>
+            <Descriptions.Item label="消息加密">
+              采用AES加密算法对推送的数据进行数据加密,AesKey为加密秘钥
+            </Descriptions.Item>
+          </Descriptions>
+          <h1>设备接入网关配置说明</h1>
+          <Descriptions bordered size={'small'} column={1} labelStyle={{ width: 100 }}>
+            <Descriptions.Item label="参数">说明</Descriptions.Item>
+            <Descriptions.Item label="apiKey">OneNet平台中具体产品的Key</Descriptions.Item>
+            <Descriptions.Item label="通知Token">
+              填写OneNet数据推送配置中设置的Token
+            </Descriptions.Item>
+            <Descriptions.Item label="aesKey">
+              若OneNet数据推送配置了消息加密,此处填写OneNet端数据推送配置中设置的aesKey
+            </Descriptions.Item>
+          </Descriptions>
+          <h1>其他说明</h1>
+          <div>
+            1.在IOT端启用设备时,若OneNet平台没有与之对应的设备,则将在OneNet端自动创建新设备
+          </div>
         </div>
         </div>
       </Col>
       </Col>
     </Row>
     </Row>

+ 0 - 79
src/pages/link/DataCollect/DataGathering/index.tsx

@@ -1,79 +0,0 @@
-import { PageContainer } from '@ant-design/pro-layout';
-import { Card } from 'antd';
-import styles from './index.less';
-import ChannelTree from '../components/Tree';
-import { observer } from '@formily/reactive-react';
-import { model } from '@formily/reactive';
-import Device from '../components/Device';
-import Point from '../components/Point';
-import { Empty } from '@/components';
-
-export const DataCollectModel = model<{
-  id: Partial<string>;
-  type: 'channel' | 'device' | undefined;
-  provider: 'OPC_UA' | 'MODBUS_TCP';
-  data: any;
-  reload: boolean;
-  refresh: boolean;
-}>({
-  type: 'channel',
-  id: '',
-  provider: 'MODBUS_TCP',
-  data: {},
-  reload: false,
-  refresh: false,
-});
-
-export default observer(() => {
-  const onReload = () => {
-    DataCollectModel.reload = !DataCollectModel.reload;
-  };
-
-  const obj = {
-    channel: (
-      <Device
-        reload={onReload}
-        type={false}
-        id={DataCollectModel.id}
-        provider={DataCollectModel.provider}
-        refresh={DataCollectModel.refresh}
-      />
-    ),
-    device: (
-      <Point type={false} provider={DataCollectModel.provider} data={DataCollectModel.data} />
-    ),
-  };
-
-  return (
-    <PageContainer>
-      <Card bordered={false} bodyStyle={{ paddingTop: 0 }}>
-        <div className={styles.container}>
-          <div className={styles.left}>
-            <ChannelTree
-              change={(key, type, provider, data) => {
-                DataCollectModel.type = undefined;
-                DataCollectModel.id = key;
-                DataCollectModel.provider = provider;
-                DataCollectModel.data = data || {};
-                setTimeout(() => {
-                  DataCollectModel.type = type;
-                }, 0);
-              }}
-              reload={DataCollectModel.reload}
-              onReload={() => {
-                DataCollectModel.refresh = !DataCollectModel.refresh;
-              }}
-            />
-          </div>
-          {DataCollectModel?.id ? (
-            <div className={styles.right}>
-              {DataCollectModel.type ? obj[DataCollectModel.type] : ''}
-            </div>
-          ) : (
-            <Empty style={{ marginTop: 100 }} />
-          )}
-        </div>
-      </Card>
-    </PageContainer>
-  );
-});

+ 0 - 49
src/pages/link/DataCollect/IntegratedQuery/index.tsx

@@ -1,49 +0,0 @@
-import { PageContainer } from '@ant-design/pro-layout';
-import { observer } from '@formily/reactive-react';
-import { model } from '@formily/reactive';
-import Point from '../components/Point';
-import Device from '../components/Device';
-import Channel from '../components/Channel';
-import { useEffect } from 'react';
-
-const dataModel = model<{
-  tab: string;
-}>({
-  tab: 'channel',
-});
-
-export default observer(() => {
-  const list = [
-    {
-      key: 'channel',
-      tab: '通道',
-      component: <Channel type={true} />,
-    },
-    {
-      key: 'device',
-      tab: '采集器',
-      component: <Device type={true} />,
-    },
-    {
-      key: 'point',
-      tab: '点位',
-      component: <Point type={true} />,
-    },
-  ];
-
-  useEffect(() => {
-    dataModel.tab = 'channel';
-  }, []);
-
-  return (
-    <PageContainer
-      tabList={list}
-      tabActiveKey={dataModel.tab}
-      onTabChange={(key: string) => {
-        dataModel.tab = key;
-      }}
-    >
-      {list.find((item) => item.key === dataModel.tab)?.component}
-    </PageContainer>
-  );
-});

+ 0 - 389
src/pages/link/DataCollect/components/Tree/index.tsx

@@ -1,389 +0,0 @@
-import {
-  DownOutlined,
-  PlusOutlined,
-  FormOutlined,
-  DeleteOutlined,
-  StopOutlined,
-  PlayCircleOutlined,
-} from '@ant-design/icons';
-import { Button, Input, Tree, Space, Popconfirm, Tooltip, Tag } from 'antd';
-import { observer } from '@formily/react';
-import { model } from '@formily/reactive';
-import { Ellipsis, Empty, PermissionButton } from '@/components';
-import styles from './index.less';
-import service from '@/pages/link/DataCollect/service';
-import { useEffect } from 'react';
-import Save from '../../components/Channel/Save/index';
-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[];
-  dataSource: any[];
-  loading: boolean;
-  param: any;
-  visible: boolean;
-  current: any;
-  c_visible: boolean;
-  c_current: any;
-}>({
-  selectedKeys: [],
-  dataSource: [],
-  loading: true,
-  param: {},
-  visible: false,
-  current: {},
-  c_visible: false,
-  c_current: {},
-});
-interface Props {
-  change: (
-    key: string,
-    type: 'channel' | 'device',
-    provider: 'OPC_UA' | 'MODBUS_TCP',
-    data?: any,
-  ) => void;
-  reload?: boolean;
-  onReload: () => void;
-}
-
-export default observer((props: Props) => {
-  const channelImg = require('/public/images/DataCollect/tree-channel.png');
-  const deviceImg = require('/public/images/DataCollect/tree-device.png');
-  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
-  const intl = useIntl();
-
-  const handleSearch = (params: any, reload?: boolean) => {
-    TreeModel.loading = true;
-    TreeModel.param = params;
-    service
-      .queryChannelTree({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
-      .then((resp) => {
-        if (resp.status === 200) {
-          TreeModel.dataSource = resp.result;
-          if (resp.result.length) {
-            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;
-      });
-  };
-
-  useEffect(() => {
-    handleSearch(TreeModel.param, false);
-  }, [TreeModel.param]);
-
-  useEffect(() => {
-    handleSearch(TreeModel.param, true);
-  }, [props.reload]);
-
-  const getState = (record: any) => {
-    if (record) {
-      const colorMap = new Map();
-      colorMap.set('running', 'success');
-      colorMap.set('partialError', 'warning');
-      colorMap.set('failed', 'error');
-      colorMap.set('stopped', 'default');
-      if (record?.state?.value === 'enabled') {
-        return (
-          record?.runningState && (
-            <Tag color={colorMap.get(record?.runningState?.value)}>
-              {record?.runningState?.text}
-            </Tag>
-          )
-        );
-      } else {
-        return <Tag color="processing">禁用</Tag>;
-      }
-    } else {
-      return '';
-    }
-  };
-
-  return (
-    <div>
-      <div>
-        <Input.Search
-          placeholder="请输入名称"
-          allowClear
-          onSearch={(val) => {
-            TreeModel.param = {
-              terms: [{ column: 'name', value: `%${val}%`, termType: 'like' }],
-            };
-          }}
-          style={{ width: '100%' }}
-        />
-      </div>
-      <div style={{ margin: '16px 0' }}>
-        <Button
-          type="primary"
-          ghost
-          style={{ width: '100%' }}
-          icon={<PlusOutlined />}
-          onClick={() => {
-            TreeModel.visible = true;
-            TreeModel.current = {};
-          }}
-        >
-          新增通道
-        </Button>
-      </div>
-      <div>
-        {TreeModel.dataSource.length ? (
-          <Tree
-            style={{ overflow: 'hidden' }}
-            className={styles['data-collect-tree']}
-            showIcon
-            height={500}
-            selectedKeys={TreeModel.selectedKeys}
-            switcherIcon={<DownOutlined />}
-          >
-            {(TreeModel.dataSource || []).map((item: any) => (
-              <Tree.TreeNode
-                key={item.id}
-                title={() => {
-                  return (
-                    <div className={styles.treeTitle}>
-                      <div
-                        className={styles.title}
-                        onClick={() => {
-                          TreeModel.selectedKeys = [item.id];
-                          props.change(item.id, 'channel', item.provider);
-                        }}
-                      >
-                        <img width={'20px'} style={{ marginRight: 5 }} src={channelImg} />
-                        <div style={{ display: 'flex' }}>
-                          <Ellipsis title={item.name} style={{ marginRight: 5, maxWidth: 120 }} />
-                          {getState(item)}
-                        </div>
-                      </div>
-                      <div>
-                        <Space className={styles.iconColor}>
-                          <Tooltip title={!permission.update ? '暂无权限,请联系管理员' : ''}>
-                            <FormOutlined
-                              onClick={() => {
-                                if (permission.update) {
-                                  TreeModel.current = item;
-                                  TreeModel.visible = true;
-                                }
-                              }}
-                            />
-                          </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) {
-                                TreeModel.param = {};
-                                handleSearch(TreeModel.param);
-                                onlyMessage('操作成功');
-                              }
-                            }}
-                          >
-                            <Tooltip
-                              title={
-                                !permission.delete
-                                  ? '暂无权限,请联系管理员'
-                                  : item?.state?.value !== 'disabled'
-                                  ? '正常的通道不能删除'
-                                  : ''
-                              }
-                            >
-                              <DeleteOutlined />
-                            </Tooltip>
-                          </Popconfirm>
-                        </Space>
-                      </div>
-                    </div>
-                  );
-                }}
-              >
-                {(item?.collectors || []).map((i: any) => (
-                  <Tree.TreeNode
-                    key={i.id}
-                    title={() => {
-                      return (
-                        <div className={styles.treeTitle} style={{ paddingRight: 24 }}>
-                          <div
-                            className={styles.title}
-                            onClick={() => {
-                              TreeModel.selectedKeys = [i.id];
-                              props.change(i.id, 'device', item.provider, i);
-                            }}
-                          >
-                            <img width={'20px'} style={{ marginRight: 5 }} src={deviceImg} />
-                            <div style={{ display: 'flex' }}>
-                              <span
-                                className={'ellipsis'}
-                                style={{
-                                  marginRight: 5,
-                                  maxWidth: 90,
-                                  color: 'rgba(0, 0, 0, 0.6)',
-                                }}
-                              >
-                                {i.name}
-                              </span>
-                              {getState(i)}
-                            </div>
-                          </div>
-                          <div>
-                            <Space className={styles.iconColor}>
-                              <Tooltip title={!permission.update ? '暂无权限,请联系管理员' : ''}>
-                                <FormOutlined
-                                  onClick={() => {
-                                    if (permission.update) {
-                                      TreeModel.current = item;
-                                      TreeModel.c_visible = true;
-                                      TreeModel.c_current = i;
-                                    }
-                                  }}
-                                />
-                              </Tooltip>
-                              <Popconfirm
-                                title={intl.formatMessage({
-                                  id: `pages.data.option.${
-                                    i?.state?.value !== 'disabled' ? 'disabled' : 'enabled'
-                                  }.tips`,
-                                  defaultMessage: '确认禁用?',
-                                })}
-                                onConfirm={async () => {
-                                  const resp =
-                                    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 = {};
-                                    handleSearch(TreeModel.param);
-                                    props.onReload();
-                                    onlyMessage('操作成功');
-                                  } else {
-                                    onlyMessage('操作失败!', 'error');
-                                  }
-                                }}
-                              >
-                                <Tooltip title={!permission.action ? '暂无权限,请联系管理员' : ''}>
-                                  {i?.state?.value !== 'disabled' ? (
-                                    <StopOutlined />
-                                  ) : (
-                                    <PlayCircleOutlined />
-                                  )}
-                                </Tooltip>
-                              </Popconfirm>
-                              <Popconfirm
-                                title={'该操作将会删除下属点位,确定删除?'}
-                                disabled={i?.state?.value !== 'disabled'}
-                                onConfirm={async () => {
-                                  const resp = await service.removeCollector(i.id);
-                                  if (resp.status === 200) {
-                                    TreeModel.param = {};
-                                    handleSearch(TreeModel.param);
-                                    onlyMessage('操作成功');
-                                  }
-                                }}
-                              >
-                                <Tooltip
-                                  title={
-                                    !permission.delete
-                                      ? '暂无权限,请联系管理员'
-                                      : i?.state?.value !== 'disabled'
-                                      ? '正常的采集器不能删除'
-                                      : ''
-                                  }
-                                >
-                                  <DeleteOutlined />
-                                </Tooltip>
-                              </Popconfirm>
-                            </Space>
-                          </div>
-                        </div>
-                      );
-                    }}
-                  />
-                ))}
-              </Tree.TreeNode>
-            ))}
-          </Tree>
-        ) : (
-          <Empty />
-        )}
-      </div>
-      {TreeModel.visible && (
-        <Save
-          data={TreeModel.current}
-          close={() => {
-            TreeModel.visible = false;
-          }}
-          reload={() => {
-            TreeModel.visible = false;
-            handleSearch(TreeModel.param);
-          }}
-        />
-      )}
-      {TreeModel.c_visible && (
-        <CollectorSave
-          data={TreeModel.c_current}
-          channelId={TreeModel.current.id}
-          provider={TreeModel.current.provider}
-          close={() => {
-            TreeModel.c_visible = false;
-          }}
-          reload={() => {
-            TreeModel.c_visible = false;
-            TreeModel.param = {};
-            handleSearch(TreeModel.param);
-          }}
-        />
-      )}
-    </div>
-  );
-});

+ 8 - 6
src/pages/notice/Config/Debug/index.tsx

@@ -15,15 +15,15 @@ import {
 import { ISchema } from '@formily/json-schema';
 import { ISchema } from '@formily/json-schema';
 import { service, state } from '@/pages/notice/Config';
 import { service, state } from '@/pages/notice/Config';
 import { service as TemplateService } from '@/pages/notice/Template';
 import { service as TemplateService } from '@/pages/notice/Template';
-import { useLocation } from 'umi';
+// import { useLocation } from 'umi';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { Store } from 'jetlinks-store';
 import { Store } from 'jetlinks-store';
 import FUpload from '@/components/Upload';
 import FUpload from '@/components/Upload';
 import { FDatePicker } from '@/components';
 import { FDatePicker } from '@/components';
 
 
 const Debug = observer(() => {
 const Debug = observer(() => {
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  const id = state.current?.type; // (location as any).query?.id;
   const variableRef = useRef<any>([]);
   const variableRef = useRef<any>([]);
 
 
   const form = useMemo(
   const form = useMemo(
@@ -95,19 +95,21 @@ const Debug = observer(() => {
                 switch (businessType) {
                 switch (businessType) {
                   case 'org':
                   case 'org':
                     // 获取org
                     // 获取org
-                    const orgList = await TemplateService[id].getDepartments(state.current?.id);
+                    const orgList = await TemplateService[id].getDepartments(
+                      state.current?.id || '',
+                    );
                     format.setComponent(Select);
                     format.setComponent(Select);
                     format.setDataSource(orgList);
                     format.setDataSource(orgList);
                     break;
                     break;
                   case 'user':
                   case 'user':
                     // 获取user
                     // 获取user
-                    const userList = await TemplateService[id].getUser(state.current?.id);
+                    const userList = await TemplateService[id].getUser(state.current?.id || '');
                     format.setComponent(Select);
                     format.setComponent(Select);
                     format.setDataSource(userList);
                     format.setDataSource(userList);
                     break;
                     break;
                   case 'tag':
                   case 'tag':
                     // 获取user
                     // 获取user
-                    const tagList = await TemplateService[id].getTags(state.current?.id);
+                    const tagList = await TemplateService[id]?.getTags(state.current?.id || '');
                     format.setComponent(Select);
                     format.setComponent(Select);
                     format.setDataSource(tagList);
                     format.setDataSource(tagList);
                     break;
                     break;

+ 133 - 52
src/pages/notice/Config/Detail/index.tsx

@@ -1,8 +1,8 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { PageContainer } from '@ant-design/pro-layout';
-import { createForm, onFieldValueChange } from '@formily/core';
+import { createForm, onFieldValueChange, onFormInit } from '@formily/core';
 import { Card, Col, Input, Row } from 'antd';
 import { Card, Col, Input, Row } from 'antd';
 import { ISchema } from '@formily/json-schema';
 import { ISchema } from '@formily/json-schema';
-import { useEffect, useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
 import { createSchemaField, observer } from '@formily/react';
 import { createSchemaField, observer } from '@formily/react';
 import {
 import {
   ArrayTable,
   ArrayTable,
@@ -19,7 +19,7 @@ import {
   Switch,
   Switch,
 } from '@formily/antd';
 } from '@formily/antd';
 import styles from './index.less';
 import styles from './index.less';
-import { service, state } from '@/pages/notice/Config';
+import { service } from '@/pages/notice/Config';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { useParams } from 'umi';
 import { useParams } from 'umi';
 import { typeList } from '@/pages/notice';
 import { typeList } from '@/pages/notice';
@@ -35,7 +35,8 @@ import { PermissionButton } from '@/components';
 import usePermissions from '@/hooks/permission';
 import usePermissions from '@/hooks/permission';
 import FAutoComplete from '@/components/FAutoComplete';
 import FAutoComplete from '@/components/FAutoComplete';
 import Webhook from './doc/Webhook';
 import Webhook from './doc/Webhook';
-import { useModel } from '@@/plugin-model/useModel';
+// import { useModel } from '@@/plugin-model/useModel';
+import { typeArray } from '@/components/ProTableCard/CardItems/noticeTemplate';
 
 
 export const docMap = {
 export const docMap = {
   weixin: {
   weixin: {
@@ -62,50 +63,64 @@ export const docMap = {
 
 
 const Detail = observer(() => {
 const Detail = observer(() => {
   const { id } = useParams<{ id: string }>();
   const { id } = useParams<{ id: string }>();
-  const { initialState } = useModel('@@initialState');
-  const [provider, setProvider] = useState<string>('embedded');
+  // const { initialState } = useModel('@@initialState');
+  const [typeItem, setTypeItem] = useState<string>('email');
+  const [providerItem, setProviderItem] = useState<string>('embedded');
+  const [loading, setLoading] = useState<boolean>(false);
+
   const form = useMemo(
   const form = useMemo(
     () =>
     () =>
       createForm({
       createForm({
         validateFirst: true,
         validateFirst: true,
         effects() {
         effects() {
-          onFieldValueChange('type', async (field) => {
-            const type = field.value;
-            if (!type) return;
-            // f.setFieldState('provider', (state1) => {
-            // state1.value = undefined;
-            // state.dataSource = providerRef.current
-            //   .find((item) => type === item.id)
-            //   ?.providerInfos.map((i) => ({ label: i.name, value: i.id }));
-            // });
+          onFormInit(async (form1) => {
+            if (id === ':id' || !id) {
+              form1.setValues({
+                type: 'email',
+                provider: 'embedded',
+              });
+            } else {
+              const resp = await service.detail(id);
+              if (resp.status === 200) {
+                setTypeItem(resp.result.type);
+                setProviderItem(resp.result.provider);
+                form1.setValues(resp.result);
+              }
+            }
+          });
+          onFieldValueChange('type', async (field, f) => {
+            const value = field.value;
+            setTypeItem(value);
+            if (!value) return;
+            f.setFieldState('provider', (state1) => {
+              if (id === ':id' || !id) {
+                state1.value = typeList[value][0].value;
+              }
+              state1.dataSource = typeList[value];
+            });
           });
           });
           onFieldValueChange('provider', async (field) => {
           onFieldValueChange('provider', async (field) => {
-            if (id === 'email') {
-              setProvider('embedded');
+            const _type = field.query('.type').get('value');
+            if (_type === 'email') {
+              setProviderItem('embedded');
             } else {
             } else {
-              setProvider(field.value);
+              setProviderItem(field.value);
             }
             }
           });
           });
         },
         },
       }),
       }),
-    [id],
+    [],
   );
   );
 
 
-  useEffect(() => {
-    setTimeout(() => {
-      if (initialState?.settings?.title) {
-        document.title = `通知配置 - ${initialState?.settings?.title}`;
-      } else {
-        document.title = '通知配置';
-      }
-    }, 0);
-    if (id === 'webhook') {
-      setProvider('http');
-    }
-    if (state.current) {
-      form.setValues(state.current);
-    }
-  }, []);
+  // useEffect(() => {
+  //   setTimeout(() => {
+  //     if (initialState?.settings?.title) {
+  //       document.title = `通知配置 - ${initialState?.settings?.title}`;
+  //     } else {
+  //       document.title = '通知配置';
+  //     }
+  //   }, 0);
+  // }, []);
 
 
   const SchemaField = createSchemaField({
   const SchemaField = createSchemaField({
     components: {
     components: {
@@ -136,6 +151,24 @@ const Detail = observer(() => {
   const schema: ISchema = {
   const schema: ISchema = {
     type: 'object',
     type: 'object',
     properties: {
     properties: {
+      type: {
+        title: '通知方式',
+        'x-component': 'Select',
+        'x-decorator': 'FormItem',
+        'x-component-props': {
+          placeholder: '请选择通知方式',
+        },
+        'x-disabled': !!id && id !== ':id',
+        'x-validator': [
+          {
+            required: true,
+            message: '请选择通知方式',
+          },
+        ],
+        enum: typeArray.map((item) => {
+          return { label: item.text, value: item.status };
+        }),
+      },
       name: {
       name: {
         title: '名称',
         title: '名称',
         required: true,
         required: true,
@@ -146,17 +179,15 @@ const Detail = observer(() => {
         },
         },
         'x-validator': [
         'x-validator': [
           {
           {
+            required: true,
+            message: '请输入名称',
+          },
+          {
             max: 64,
             max: 64,
             message: '最多可输入64个字符',
             message: '最多可输入64个字符',
           },
           },
         ],
         ],
       },
       },
-      type: {
-        title: '分类',
-        'x-component': 'Input',
-        'x-value': id,
-        'x-hidden': true,
-      },
       provider: {
       provider: {
         title: '类型',
         title: '类型',
         type: 'string',
         type: 'string',
@@ -165,17 +196,34 @@ const Detail = observer(() => {
         'x-component-props': {
         'x-component-props': {
           optionType: 'button',
           optionType: 'button',
         },
         },
-        required: true,
-        'x-visible': typeList[id]?.length > 0,
-        'x-hidden': id === 'email' || id === 'webhook',
-        'x-value': typeList[id]?.[0]?.value,
-        enum: typeList[id] || [],
+        'x-reactions': {
+          dependencies: ['type'],
+          fulfill: {
+            state: {
+              visible: '{{!!$deps[0] && $deps[0] !== "email"}}',
+            },
+          },
+        },
+        'x-validator': [
+          {
+            required: true,
+            message: '请选择类型',
+          },
+        ],
       },
       },
       configuration: {
       configuration: {
         type: 'object',
         type: 'object',
         properties: {
         properties: {
           weixin: {
           weixin: {
             type: 'void',
             type: 'void',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="weixin"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               corpId: {
               corpId: {
                 title: 'corpId',
                 title: 'corpId',
@@ -259,11 +307,18 @@ const Detail = observer(() => {
                 },
                 },
               },
               },
             },
             },
-            'x-visible': id === 'weixin',
           },
           },
           dingTalk: {
           dingTalk: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'dingTalk',
+            // 'x-visible': id === 'dingTalk',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="dingTalk"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               appKey: {
               appKey: {
                 title: 'AppKey',
                 title: 'AppKey',
@@ -333,7 +388,15 @@ const Detail = observer(() => {
           // 阿里云语音/短信
           // 阿里云语音/短信
           voiceOrSms: {
           voiceOrSms: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'voice' || id === 'sms',
+            // 'x-visible': id === 'voice' || id === 'sms',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="voice" || $deps[0]==="sms"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               regionId: {
               regionId: {
                 title: 'RegionId',
                 title: 'RegionId',
@@ -384,7 +447,15 @@ const Detail = observer(() => {
           },
           },
           email: {
           email: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'email',
+            // 'x-visible': id === 'email',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="email"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               space: {
               space: {
                 title: '服务器地址',
                 title: '服务器地址',
@@ -513,7 +584,15 @@ const Detail = observer(() => {
             },
             },
           },
           },
           webhook: {
           webhook: {
-            'x-visible': id === 'webhook',
+            // 'x-visible': id === 'webhook',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="webhook"}}',
+                },
+              },
+            },
             type: 'void',
             type: 'void',
             properties: {
             properties: {
               url: {
               url: {
@@ -630,13 +709,14 @@ const Detail = observer(() => {
 
 
   const handleSave = async () => {
   const handleSave = async () => {
     const data: ConfigItem = await form.submit();
     const data: ConfigItem = await form.submit();
+    setLoading(true);
     let response;
     let response;
     if (data.id) {
     if (data.id) {
       response = await service.update(data);
       response = await service.update(data);
     } else {
     } else {
       response = await service.save(data);
       response = await service.save(data);
     }
     }
-
+    setLoading(false);
     if (response?.status === 200) {
     if (response?.status === 200) {
       onlyMessage('保存成功');
       onlyMessage('保存成功');
       history.back();
       history.back();
@@ -657,6 +737,7 @@ const Detail = observer(() => {
                   <PermissionButton
                   <PermissionButton
                     type="primary"
                     type="primary"
                     onClick={handleSave}
                     onClick={handleSave}
+                    loading={loading}
                     isPermission={getOtherPermission(['add', 'update'])}
                     isPermission={getOtherPermission(['add', 'update'])}
                   >
                   >
                     保存
                     保存
@@ -666,7 +747,7 @@ const Detail = observer(() => {
             </Form>
             </Form>
           </Col>
           </Col>
           <Col span={12} push={2}>
           <Col span={12} push={2}>
-            {docMap?.[id]?.[provider]}
+            {docMap?.[typeItem]?.[providerItem]}
           </Col>
           </Col>
         </Row>
         </Row>
       </Card>
       </Card>

+ 4 - 4
src/pages/notice/Config/Log/index.tsx

@@ -3,13 +3,13 @@ import { observer } from '@formily/react';
 import { service, state } from '..';
 import { service, state } from '..';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
 import SearchComponent from '@/components/SearchComponent';
 import SearchComponent from '@/components/SearchComponent';
-import { useLocation } from 'umi';
+// import { useLocation } from 'umi';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { useRef, useState } from 'react';
 import { useRef, useState } from 'react';
 
 
 const Log = observer(() => {
 const Log = observer(() => {
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  // const id = (location as any).query?.id;
 
 
   const columns: ProColumns<LogItem>[] = [
   const columns: ProColumns<LogItem>[] = [
     {
     {
@@ -99,7 +99,7 @@ const Log = observer(() => {
     >
     >
       <SearchComponent
       <SearchComponent
         model="simple"
         model="simple"
-        defaultParam={[{ column: 'notifyType$IN', value: id }]}
+        defaultParam={[{ column: 'notifyType$IN', value: state.current?.type || '' }]}
         field={columns}
         field={columns}
         onSearch={(data) => {
         onSearch={(data) => {
           actionRef.current?.reset?.();
           actionRef.current?.reset?.();

+ 4 - 7
src/pages/notice/Config/SyncUser/index.tsx

@@ -4,7 +4,7 @@ import { service, state } from '..';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { useEffect, useRef, useState } from 'react';
 import { useEffect, useRef, useState } from 'react';
-import { history, useLocation } from 'umi';
+import { history } from 'umi';
 import { DisconnectOutlined, EditOutlined } from '@ant-design/icons';
 import { DisconnectOutlined, EditOutlined } from '@ant-design/icons';
 import BindUser from '../BindUser';
 import BindUser from '../BindUser';
 import { onlyMessage } from '@/utils/util';
 import { onlyMessage } from '@/utils/util';
@@ -12,8 +12,8 @@ import { Empty } from '@/components';
 
 
 const SyncUser = observer(() => {
 const SyncUser = observer(() => {
   const [dept, setDept] = useState<string>();
   const [dept, setDept] = useState<string>();
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  const id = state.current?.type || 'dingtalk'; // (location as any).query?.id;
   const [visible, setVisible] = useState<boolean>(false);
   const [visible, setVisible] = useState<boolean>(false);
   const [current, setCurrent] = useState<any>({});
   const [current, setCurrent] = useState<any>({});
   const [list, setList] = useState<any[]>([]);
   const [list, setList] = useState<any[]>([]);
@@ -190,10 +190,7 @@ const SyncUser = observer(() => {
                 request={(params) =>
                 request={(params) =>
                   service
                   service
                     .queryZipSyncUser(
                     .queryZipSyncUser(
-                      {
-                        dingTalk: 'dingtalk',
-                        weixin: 'wechat',
-                      }[id],
+                      id === 'dingTalk' ? 'dingTalk' : 'wechat',
                       id,
                       id,
                       state.current?.provider || '',
                       state.current?.provider || '',
                       state.current?.id || '',
                       state.current?.id || '',

+ 21 - 59
src/pages/notice/Config/index.tsx

@@ -20,14 +20,14 @@ import Service from '@/pages/notice/Config/service';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
 import SearchComponent from '@/components/SearchComponent';
 import SearchComponent from '@/components/SearchComponent';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
-import { history, useLocation } from 'umi';
+import { history } from 'umi';
 import { model } from '@formily/reactive';
 import { model } from '@formily/reactive';
 import moment from 'moment';
 import moment from 'moment';
 import { PermissionButton, ProTableCard } from '@/components';
 import { PermissionButton, ProTableCard } from '@/components';
 import NoticeConfig from '@/components/ProTableCard/CardItems/noticeConfig';
 import NoticeConfig from '@/components/ProTableCard/CardItems/noticeConfig';
 import Debug from '@/pages/notice/Config/Debug';
 import Debug from '@/pages/notice/Config/Debug';
 import Log from '@/pages/notice/Config/Log';
 import Log from '@/pages/notice/Config/Log';
-import { typeList } from '@/components/ProTableCard/CardItems/noticeTemplate';
+import { providerObj, typeList, typeObj } from '@/components/ProTableCard/CardItems/noticeTemplate';
 import usePermissions from '@/hooks/permission';
 import usePermissions from '@/hooks/permission';
 import SyncUser from '@/pages/notice/Config/SyncUser';
 import SyncUser from '@/pages/notice/Config/SyncUser';
 
 
@@ -43,60 +43,14 @@ export const state = model<{
   log: false,
   log: false,
   syncUser: false,
   syncUser: false,
 });
 });
-const list = {
-  weixin: {
-    corpMessage: {
-      text: '企业消息',
-      status: 'corpMessage',
-    },
-    // officialMessage: {
-    //   text: '服务号消息',
-    //   status: 'officialMessage',
-    // },
-  },
-  dingTalk: {
-    dingTalkMessage: {
-      text: '钉钉消息',
-      status: 'dingTalkMessage',
-    },
-    dingTalkRobotWebHook: {
-      text: '群机器人消息',
-      status: 'dingTalkRobotWebHook',
-    },
-  },
-  voice: {
-    aliyun: {
-      text: '阿里云语音',
-      status: 'aliyun',
-    },
-  },
-  sms: {
-    aliyunSms: {
-      text: '阿里云短信',
-      status: 'aliyunSms',
-    },
-  },
-  email: {
-    embedded: {
-      text: '邮件',
-      status: 'embedded',
-    },
-  },
-  webhook: {
-    http: {
-      text: 'Webhook',
-      status: 'http',
-    },
-  },
-};
 
 
 const Config = observer(() => {
 const Config = observer(() => {
   const intl = useIntl();
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
   const actionRef = useRef<ActionType>();
-  const location = useLocation<{ id: string }>();
+  // const location = useLocation<{ id: string }>();
 
 
   const { permission: configPermission } = usePermissions('notice');
   const { permission: configPermission } = usePermissions('notice');
-  const id = (location as any).query?.id;
+  // const id = (location as any).query?.id;
 
 
   const columns: ProColumns<ConfigItem>[] = [
   const columns: ProColumns<ConfigItem>[] = [
     {
     {
@@ -107,11 +61,20 @@ const Config = observer(() => {
       width: '25%',
       width: '25%',
     },
     },
     {
     {
-      dataIndex: 'provider',
+      dataIndex: 'type',
       title: '通知方式',
       title: '通知方式',
-      renderText: (text, record) => typeList[record.type][record.provider],
+      renderText: (text, record) => typeObj?.[record.type]?.text || record.type,
+      valueType: 'select',
+      valueEnum: typeObj,
+    },
+    {
+      dataIndex: 'provider',
+      title: '类型',
+      renderText: (text, record) => {
+        return typeList[record?.type][record?.provider];
+      },
       valueType: 'select',
       valueType: 'select',
-      valueEnum: list[id],
+      valueEnum: providerObj,
     },
     },
     {
     {
       dataIndex: 'description',
       dataIndex: 'description',
@@ -151,7 +114,7 @@ const Config = observer(() => {
           onClick={async () => {
           onClick={async () => {
             // setLoading(true);
             // setLoading(true);
             state.current = record;
             state.current = record;
-            history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], id));
+            history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], record.id));
           }}
           }}
           tooltip={{
           tooltip={{
             title: intl.formatMessage({
             title: intl.formatMessage({
@@ -251,7 +214,7 @@ const Config = observer(() => {
   return (
   return (
     <PageContainer>
     <PageContainer>
       <SearchComponent
       <SearchComponent
-        defaultParam={[{ column: 'type$IN', value: id }]}
+        // defaultParam={[{ column: 'type$IN', value: id }]}
         field={columns}
         field={columns}
         onSearch={(data) => {
         onSearch={(data) => {
           actionRef.current?.reset?.();
           actionRef.current?.reset?.();
@@ -272,7 +235,7 @@ const Config = observer(() => {
               isPermission={configPermission.add}
               isPermission={configPermission.add}
               onClick={() => {
               onClick={() => {
                 state.current = undefined;
                 state.current = undefined;
-                history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], id));
+                history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail']));
               }}
               }}
               key="button"
               key="button"
               icon={<PlusOutlined />}
               icon={<PlusOutlined />}
@@ -341,13 +304,12 @@ const Config = observer(() => {
         cardRender={(record) => (
         cardRender={(record) => (
           <NoticeConfig
           <NoticeConfig
             {...record}
             {...record}
-            type={id}
             detail={
             detail={
               <div
               <div
                 style={{ fontSize: 18, padding: 8 }}
                 style={{ fontSize: 18, padding: 8 }}
                 onClick={() => {
                 onClick={() => {
                   state.current = record;
                   state.current = record;
-                  history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], id));
+                  history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], record.id));
                 }}
                 }}
               >
               >
                 <EyeOutlined />
                 <EyeOutlined />
@@ -374,7 +336,7 @@ const Config = observer(() => {
                 key="edit"
                 key="edit"
                 onClick={async () => {
                 onClick={async () => {
                   state.current = record;
                   state.current = record;
-                  history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], id));
+                  history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], record.id));
                 }}
                 }}
               >
               >
                 <EditOutlined />
                 <EditOutlined />

+ 8 - 9
src/pages/notice/Template/Debug/index.tsx

@@ -13,15 +13,15 @@ import {
 } from '@formily/antd';
 } from '@formily/antd';
 import { ISchema } from '@formily/json-schema';
 import { ISchema } from '@formily/json-schema';
 import { configService, service, state } from '@/pages/notice/Template';
 import { configService, service, state } from '@/pages/notice/Template';
-import { useLocation } from 'umi';
+// import { useLocation } from 'umi';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { onlyMessage, useAsyncDataSource } from '@/utils/util';
 import { Store } from 'jetlinks-store';
 import { Store } from 'jetlinks-store';
 import { FDatePicker } from '@/components';
 import { FDatePicker } from '@/components';
 import FUpload from '@/components/Upload';
 import FUpload from '@/components/Upload';
 
 
 const Debug = observer(() => {
 const Debug = observer(() => {
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  // const id = (location as any).query?.id;
 
 
   const variableRef = useRef<any>([]);
   const variableRef = useRef<any>([]);
 
 
@@ -78,27 +78,26 @@ const Debug = observer(() => {
             }
             }
             if (variableRef.current) {
             if (variableRef.current) {
               const a = variableRef.current?.find((i: any) => i.id === _id.value);
               const a = variableRef.current?.find((i: any) => i.id === _id.value);
-              console.log(a, 'a');
               const _configId = configId.value();
               const _configId = configId.value();
               const businessType = a?.expands?.businessType;
               const businessType = a?.expands?.businessType;
-              if (id === 'dingTalk' || id === 'weixin') {
+              if (state.current?.type === 'dingTalk' || state.current?.type === 'weixin') {
                 if (_configId) {
                 if (_configId) {
                   switch (businessType) {
                   switch (businessType) {
                     case 'org':
                     case 'org':
                       // 获取org
                       // 获取org
-                      const orgList = await service[id].getDepartments(_configId);
+                      const orgList = await service[state.current?.type].getDepartments(_configId);
                       format.setComponent(Select);
                       format.setComponent(Select);
                       format.setDataSource(orgList);
                       format.setDataSource(orgList);
                       break;
                       break;
                     case 'user':
                     case 'user':
                       // 获取user
                       // 获取user
-                      const userList = await service[id].getUser(_configId);
+                      const userList = await service[state.current?.type].getUser(_configId);
                       format.setComponent(Select);
                       format.setComponent(Select);
                       format.setDataSource(userList);
                       format.setDataSource(userList);
                       break;
                       break;
                     case 'tag':
                     case 'tag':
                       // 获取user
                       // 获取user
-                      const tagList = await service[id].getTags(_configId);
+                      const tagList = await service[state.current?.type].getTags(_configId);
                       format.setComponent(Select);
                       format.setComponent(Select);
                       format.setDataSource(tagList);
                       format.setDataSource(tagList);
                       break;
                       break;
@@ -164,7 +163,7 @@ const Debug = observer(() => {
     configService
     configService
       .queryNoPagingPost({
       .queryNoPagingPost({
         terms: [
         terms: [
-          { column: 'type$IN', value: id },
+          { column: 'type$IN', value: state.current?.type },
           { column: 'provider', value: state.current?.provider },
           { column: 'provider', value: state.current?.provider },
         ],
         ],
       })
       })

+ 160 - 43
src/pages/notice/Template/Detail/index.tsx

@@ -21,18 +21,19 @@ import {
   onFieldInit,
   onFieldInit,
   onFieldReact,
   onFieldReact,
   onFieldValueChange,
   onFieldValueChange,
+  onFormInit,
   registerValidateRules,
   registerValidateRules,
 } from '@formily/core';
 } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import { createSchemaField, observer } from '@formily/react';
 import type { ISchema } from '@formily/json-schema';
 import type { ISchema } from '@formily/json-schema';
 import styles from './index.less';
 import styles from './index.less';
-import { useEffect, useMemo, useRef, useState } from 'react';
+import { useMemo, useRef, useState } from 'react';
 import FUpload from '@/components/Upload';
 import FUpload from '@/components/Upload';
 import { useParams } from 'umi';
 import { useParams } from 'umi';
 import { PageContainer } from '@ant-design/pro-layout';
 import { PageContainer } from '@ant-design/pro-layout';
 import { Card, Col, Row, Tooltip } from 'antd';
 import { Card, Col, Row, Tooltip } from 'antd';
 import { typeList } from '@/pages/notice';
 import { typeList } from '@/pages/notice';
-import { configService, service, state } from '@/pages/notice/Template';
+import { configService, service } from '@/pages/notice/Template';
 import FBraftEditor from '@/components/FBraftEditor';
 import FBraftEditor from '@/components/FBraftEditor';
 import { onlyMessage, phoneRegEx, useAsyncDataSource } from '@/utils/util';
 import { onlyMessage, phoneRegEx, useAsyncDataSource } from '@/utils/util';
 import WeixinCorp from '@/pages/notice/Template/Detail/doc/WeixinCorp';
 import WeixinCorp from '@/pages/notice/Template/Detail/doc/WeixinCorp';
@@ -48,8 +49,9 @@ import { PermissionButton } from '@/components';
 import usePermissions from '@/hooks/permission';
 import usePermissions from '@/hooks/permission';
 import FMonacoEditor from '@/components/FMonacoEditor';
 import FMonacoEditor from '@/components/FMonacoEditor';
 import Webhook from './doc/Webhook';
 import Webhook from './doc/Webhook';
-import { useModel } from '@@/plugin-model/useModel';
+// import { useModel } from '@@/plugin-model/useModel';
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import { QuestionCircleOutlined } from '@ant-design/icons';
+import { typeArray } from '@/components/ProTableCard/CardItems/noticeTemplate';
 
 
 export const docMap = {
 export const docMap = {
   weixin: {
   weixin: {
@@ -76,19 +78,21 @@ export const docMap = {
 
 
 const Detail = observer(() => {
 const Detail = observer(() => {
   const { id } = useParams<{ id: string }>();
   const { id } = useParams<{ id: string }>();
-  const [provider, setProvider] = useState<string>('embedded');
-  const { initialState } = useModel('@@initialState');
+  const [typeItem, setTypeItem] = useState<string>('email');
+  const [providerItem, setProviderItem] = useState<string>('embedded');
+  const [loading, setLoading] = useState<boolean>(false);
+  // const { initialState } = useModel('@@initialState');
   // 正则提取${}里面的值
   // 正则提取${}里面的值
   const pattern = /(?<=\$\{).*?(?=\})/g;
   const pattern = /(?<=\$\{).*?(?=\})/g;
 
 
   // 提取微信服务号里面的值 {{}}
   // 提取微信服务号里面的值 {{}}
   const weixinPattern = /(?<=\{\{).*?(?=\.DATA}})/g;
   const weixinPattern = /(?<=\{\{).*?(?=\.DATA}})/g;
 
 
-  const getConfig = (provider1: string) =>
+  const getConfig = (type1: string, provider1: string) =>
     configService
     configService
       .queryNoPagingPost({
       .queryNoPagingPost({
         terms: [
         terms: [
-          { column: 'type$IN', value: id },
+          { column: 'type$IN', value: type1 },
           { column: 'provider', value: provider1 },
           { column: 'provider', value: provider1 },
         ],
         ],
       })
       })
@@ -122,7 +126,20 @@ const Detail = observer(() => {
       createForm({
       createForm({
         validateFirst: true,
         validateFirst: true,
         effects() {
         effects() {
-          onFieldInit('template.message', (field) => {
+          onFormInit(async (form1) => {
+            if (id === ':id' || !id) {
+              form1.setValues({
+                type: 'email',
+                provider: 'embedded',
+              });
+            } else {
+              const resp = await service.detail(id);
+              if (resp.status === 200) {
+                form1.setValues(resp.result);
+              }
+            }
+          });
+          onFieldInit('template.message', async (field) => {
             if (id === 'email') {
             if (id === 'email') {
               field.setComponent(FBraftEditor, {
               field.setComponent(FBraftEditor, {
                 placeholder:
                 placeholder:
@@ -146,17 +163,34 @@ const Detail = observer(() => {
             //   field.disabled = false
             //   field.disabled = false
             // }
             // }
           });
           });
+          onFieldValueChange('type', async (field, f) => {
+            const value = field.value;
+            setTypeItem(value);
+            if (!value) return;
+            f.setFieldState('provider', (state1) => {
+              if (id === ':id' || !id) {
+                state1.value = typeList[value][0].value;
+              }
+              state1.dataSource = typeList[value];
+            });
+          });
           onFieldValueChange('provider', (field, form1) => {
           onFieldValueChange('provider', (field, form1) => {
             const value = field.value;
             const value = field.value;
-            setProvider(value);
             if (field.modified) {
             if (field.modified) {
               form1.setValuesIn('configId', null);
               form1.setValuesIn('configId', null);
               form1.setValuesIn('template', null);
               form1.setValuesIn('template', null);
             }
             }
+            const _type = field.query('type').value();
             // 设置绑定配置的数据
             // 设置绑定配置的数据
             form1.setFieldState('configId', async (state1) => {
             form1.setFieldState('configId', async (state1) => {
-              state1.dataSource = await getConfig(value);
+              state1.dataSource = await getConfig(_type, value);
             });
             });
+            console.log(_type, value);
+            if (_type === 'email') {
+              setProviderItem('embedded');
+            } else {
+              setProviderItem(value);
+            }
 
 
             if (value === 'officialMessage') {
             if (value === 'officialMessage') {
               form1.setFieldState('template.message', (state5) => {
               form1.setFieldState('template.message', (state5) => {
@@ -336,7 +370,7 @@ const Detail = observer(() => {
           onFieldValueChange('template.body', (field, form1) => {
           onFieldValueChange('template.body', (field, form1) => {
             const value = (field as Field).value;
             const value = (field as Field).value;
             // console.log(value);
             // console.log(value);
-            const idList = value.match(pattern)?.filter((i: string) => i);
+            const idList = (value || '').match(pattern)?.filter((i: string) => i);
             form1.setFieldState('variableDefinitions', (state1) => {
             form1.setFieldState('variableDefinitions', (state1) => {
               state1.visible = !!idList && idList.length > 0;
               state1.visible = !!idList && idList.length > 0;
             });
             });
@@ -440,18 +474,18 @@ const Detail = observer(() => {
     [id],
     [id],
   );
   );
 
 
-  useEffect(() => {
-    setTimeout(() => {
-      if (initialState?.settings?.title) {
-        document.title = `通知模板 - ${initialState?.settings?.title}`;
-      } else {
-        document.title = '通知模板';
-      }
-    }, 0);
-    if (state.current) {
-      form.setValues(state.current);
-    }
-  }, []);
+  // useEffect(() => {
+  //   setTimeout(() => {
+  //     if (initialState?.settings?.title) {
+  //       document.title = `通知模板 - ${initialState?.settings?.title}`;
+  //     } else {
+  //       document.title = '通知模板';
+  //     }
+  //   }, 0);
+  //   // if (state.current) {
+  //   //   form.setValues(state.current);
+  //   // }
+  // }, []);
 
 
   const SchemaField = createSchemaField({
   const SchemaField = createSchemaField({
     components: {
     components: {
@@ -476,7 +510,7 @@ const Detail = observer(() => {
 
 
   const handleSave = async () => {
   const handleSave = async () => {
     const data: TemplateItem = await form.submit();
     const data: TemplateItem = await form.submit();
-
+    setLoading(true);
     // dingTalkRobotWebHook
     // dingTalkRobotWebHook
 
 
     // 提交的时候处理内容
     // 提交的时候处理内容
@@ -503,7 +537,7 @@ const Detail = observer(() => {
           data.template.link.text = data.template.message;
           data.template.link.text = data.template.message;
       }
       }
     }
     }
-    if (id === 'email') {
+    if (data.type === 'email') {
       data.provider = 'embedded';
       data.provider = 'embedded';
       data.template.text = data.template.message;
       data.template.text = data.template.message;
     }
     }
@@ -514,7 +548,7 @@ const Detail = observer(() => {
     } else {
     } else {
       response = await service.save(data);
       response = await service.save(data);
     }
     }
-
+    setLoading(false);
     if (response?.status === 200) {
     if (response?.status === 200) {
       onlyMessage('保存成功');
       onlyMessage('保存成功');
       history.back();
       history.back();
@@ -540,6 +574,24 @@ const Detail = observer(() => {
   const schema: ISchema = {
   const schema: ISchema = {
     type: 'object',
     type: 'object',
     properties: {
     properties: {
+      type: {
+        title: '通知方式',
+        'x-component': 'Select',
+        'x-decorator': 'FormItem',
+        'x-component-props': {
+          placeholder: '请选择通知方式',
+        },
+        'x-disabled': !!id && id !== ':id',
+        'x-validator': [
+          {
+            required: true,
+            message: '请选择通知方式',
+          },
+        ],
+        enum: typeArray.map((item) => {
+          return { label: item.text, value: item.status };
+        }),
+      },
       name: {
       name: {
         title: '名称',
         title: '名称',
         type: 'string',
         type: 'string',
@@ -560,11 +612,6 @@ const Detail = observer(() => {
           },
           },
         ],
         ],
       },
       },
-      type: {
-        title: '类型',
-        'x-value': id,
-        'x-hidden': true,
-      },
       provider: {
       provider: {
         title: '类型',
         title: '类型',
         type: 'string',
         type: 'string',
@@ -574,11 +621,24 @@ const Detail = observer(() => {
           optionType: 'button',
           optionType: 'button',
           placeholder: '请选择类型',
           placeholder: '请选择类型',
         },
         },
-        required: true,
-        'x-visible': typeList[id]?.length > 0,
-        'x-hidden': id === 'email' || id === 'webhook',
-        'x-value': typeList[id]?.[0]?.value,
-        enum: typeList[id] || [],
+        'x-validator': [
+          {
+            required: true,
+            message: '请选择类型',
+          },
+        ],
+        // 'x-visible': typeList[typeItem]?.length > 0,
+        // 'x-hidden': typeItem === 'email' || typeItem === 'webhook',
+        // 'x-value': typeList[typeItem]?.[0]?.value,
+        // enum: typeList[typeItem] || [],
+        'x-reactions': {
+          dependencies: ['type'],
+          fulfill: {
+            state: {
+              visible: '{{!!$deps[0] && $deps[0] !== "email" && $deps[0] !== "webhook"}}',
+            },
+          },
+        },
       },
       },
       configId: {
       configId: {
         title: '绑定配置',
         title: '绑定配置',
@@ -592,14 +652,30 @@ const Detail = observer(() => {
         'x-decorator-props': {
         'x-decorator-props': {
           tooltip: '使用固定的通知配置来发送此通知模版',
           tooltip: '使用固定的通知配置来发送此通知模版',
         },
         },
-        'x-visible': id !== 'email',
+        // 'x-visible': id !== 'email',
+        'x-reactions': {
+          dependencies: ['type'],
+          fulfill: {
+            state: {
+              visible: '{{$deps[0] !=="email"}}',
+            },
+          },
+        },
       },
       },
       template: {
       template: {
         type: 'object',
         type: 'object',
         properties: {
         properties: {
           weixin: {
           weixin: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'weixin',
+            // 'x-visible': id === 'weixin',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="weixin"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               corpMessage: {
               corpMessage: {
                 type: 'void',
                 type: 'void',
@@ -829,7 +905,15 @@ const Detail = observer(() => {
           },
           },
           dingTalk: {
           dingTalk: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'dingTalk',
+            // 'x-visible': id === 'dingTalk',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="dingTalk"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               dingTalkMessage: {
               dingTalkMessage: {
                 type: 'void',
                 type: 'void',
@@ -1019,7 +1103,15 @@ const Detail = observer(() => {
             type: 'void',
             type: 'void',
             properties: {
             properties: {
               voice: {
               voice: {
-                'x-visible': id === 'voice',
+                // 'x-visible': id === 'voice',
+                'x-reactions': {
+                  dependencies: ['type'],
+                  fulfill: {
+                    state: {
+                      visible: '{{$deps[0]==="voice"}}',
+                    },
+                  },
+                },
                 type: 'void',
                 type: 'void',
                 properties: {
                 properties: {
                   templateType: {
                   templateType: {
@@ -1156,7 +1248,15 @@ const Detail = observer(() => {
                 },
                 },
               },
               },
               sms: {
               sms: {
-                'x-visible': id === 'sms',
+                // 'x-visible': id === 'sms',
+                'x-reactions': {
+                  dependencies: ['type'],
+                  fulfill: {
+                    state: {
+                      visible: '{{$deps[0]==="sms"}}',
+                    },
+                  },
+                },
                 type: 'void',
                 type: 'void',
                 properties: {
                 properties: {
                   layout: {
                   layout: {
@@ -1225,7 +1325,15 @@ const Detail = observer(() => {
           },
           },
           email: {
           email: {
             type: 'void',
             type: 'void',
-            'x-visible': id === 'email',
+            // 'x-visible': id === 'email',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="email"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               subject: {
               subject: {
                 'x-component': 'Input',
                 'x-component': 'Input',
@@ -1318,6 +1426,14 @@ const Detail = observer(() => {
           webhook: {
           webhook: {
             type: 'void',
             type: 'void',
             'x-visible': id === 'webhook',
             'x-visible': id === 'webhook',
+            'x-reactions': {
+              dependencies: ['type'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0]==="webhook"}}',
+                },
+              },
+            },
             properties: {
             properties: {
               contextAsBody: {
               contextAsBody: {
                 title: '请求体',
                 title: '请求体',
@@ -1565,6 +1681,7 @@ const Detail = observer(() => {
                 <FormButtonGroup.FormItem>
                 <FormButtonGroup.FormItem>
                   <PermissionButton
                   <PermissionButton
                     type="primary"
                     type="primary"
+                    loading={loading}
                     isPermission={permission.add || permission.update}
                     isPermission={permission.add || permission.update}
                     onClick={handleSave}
                     onClick={handleSave}
                   >
                   >
@@ -1575,7 +1692,7 @@ const Detail = observer(() => {
             </Form>
             </Form>
           </Col>
           </Col>
           <Col span={12} push={2}>
           <Col span={12} push={2}>
-            {docMap?.[id]?.[provider]}
+            {docMap?.[typeItem]?.[providerItem]}
           </Col>
           </Col>
         </Row>
         </Row>
       </Card>
       </Card>

+ 4 - 4
src/pages/notice/Template/Log/index.tsx

@@ -3,13 +3,13 @@ import { observer } from '@formily/react';
 import { service, state } from '..';
 import { service, state } from '..';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
 import SearchComponent from '@/components/SearchComponent';
 import SearchComponent from '@/components/SearchComponent';
-import { useLocation } from 'umi';
+// import { useLocation } from 'umi';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { useRef, useState } from 'react';
 import { useRef, useState } from 'react';
 
 
 const Log = observer(() => {
 const Log = observer(() => {
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  // const id = (location as any).query?.id;
 
 
   const columns: ProColumns<LogItem>[] = [
   const columns: ProColumns<LogItem>[] = [
     {
     {
@@ -100,7 +100,7 @@ const Log = observer(() => {
       visible={state.log && !!state.current?.id}
       visible={state.log && !!state.current?.id}
     >
     >
       <SearchComponent
       <SearchComponent
-        defaultParam={[{ column: 'notifyType$IN', value: id }]}
+        defaultParam={[{ column: 'notifyType$IN', value: state.current?.type || '' }]}
         field={columns}
         field={columns}
         model="simple"
         model="simple"
         onSearch={(data) => {
         onSearch={(data) => {

+ 27 - 59
src/pages/notice/Template/index.tsx

@@ -15,7 +15,7 @@ import { useIntl } from '@@/plugin-locale/localeExports';
 import Service from '@/pages/notice/Template/service';
 import Service from '@/pages/notice/Template/service';
 import ConfigService from '@/pages/notice/Config/service';
 import ConfigService from '@/pages/notice/Config/service';
 import SearchComponent from '@/components/SearchComponent';
 import SearchComponent from '@/components/SearchComponent';
-import { history, useLocation } from 'umi';
+import { history } from 'umi';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { model } from '@formily/reactive';
 import { model } from '@formily/reactive';
 import Debug from './Debug';
 import Debug from './Debug';
@@ -23,7 +23,11 @@ import Log from '@/pages/notice/Template/Log';
 import { downloadObject, onlyMessage } from '@/utils/util';
 import { downloadObject, onlyMessage } from '@/utils/util';
 import moment from 'moment';
 import moment from 'moment';
 import { PermissionButton, ProTableCard } from '@/components';
 import { PermissionButton, ProTableCard } from '@/components';
-import NoticeCard, { typeList } from '@/components/ProTableCard/CardItems/noticeTemplate';
+import NoticeCard, {
+  typeList,
+  typeObj,
+  providerObj,
+} from '@/components/ProTableCard/CardItems/noticeTemplate';
 import { observer } from '@formily/react';
 import { observer } from '@formily/react';
 import usePermissions from '@/hooks/permission';
 import usePermissions from '@/hooks/permission';
 
 
@@ -39,57 +43,10 @@ export const state = model<{
   log: false,
   log: false,
 });
 });
 
 
-const list = {
-  weixin: {
-    corpMessage: {
-      text: '企业消息',
-      status: 'corpMessage',
-    },
-    // officialMessage: {
-    //   text: '服务号消息',
-    //   status: 'officialMessage',
-    // },
-  },
-  dingTalk: {
-    dingTalkMessage: {
-      text: '钉钉消息',
-      status: 'dingTalkMessage',
-    },
-    dingTalkRobotWebHook: {
-      text: '群机器人消息',
-      status: 'dingTalkRobotWebHook',
-    },
-  },
-  voice: {
-    aliyun: {
-      text: '阿里云语音',
-      status: 'aliyun',
-    },
-  },
-  sms: {
-    aliyunSms: {
-      text: '阿里云短信',
-      status: 'aliyunSms',
-    },
-  },
-  email: {
-    embedded: {
-      text: '邮件',
-      status: 'embedded',
-    },
-  },
-  webhook: {
-    http: {
-      text: 'Webhook',
-      status: 'http',
-    },
-  },
-};
-
 const Template = observer(() => {
 const Template = observer(() => {
   const intl = useIntl();
   const intl = useIntl();
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
+  // const location = useLocation<{ id: string }>();
+  // const id = (location as any).query?.id;
   const actionRef = useRef<ActionType>();
   const actionRef = useRef<ActionType>();
 
 
   const { permission: templatePermission } = usePermissions('notice');
   const { permission: templatePermission } = usePermissions('notice');
@@ -101,13 +58,20 @@ const Template = observer(() => {
       ellipsis: true,
       ellipsis: true,
     },
     },
     {
     {
-      dataIndex: 'provider',
+      dataIndex: 'type',
       title: '通知方式',
       title: '通知方式',
+      renderText: (text, record) => typeObj?.[record.type]?.text || record.type,
+      valueType: 'select',
+      valueEnum: typeObj,
+    },
+    {
+      dataIndex: 'provider',
+      title: '类型',
       renderText: (text, record) => {
       renderText: (text, record) => {
         return typeList[record?.type][record?.provider];
         return typeList[record?.type][record?.provider];
       },
       },
       valueType: 'select',
       valueType: 'select',
-      valueEnum: list[id],
+      valueEnum: providerObj,
     },
     },
     {
     {
       dataIndex: 'description',
       dataIndex: 'description',
@@ -130,7 +94,7 @@ const Template = observer(() => {
           isPermission={templatePermission.update}
           isPermission={templatePermission.update}
           onClick={() => {
           onClick={() => {
             state.current = record;
             state.current = record;
-            history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], id));
+            history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], record.id));
           }}
           }}
           tooltip={{
           tooltip={{
             title: intl.formatMessage({
             title: intl.formatMessage({
@@ -216,7 +180,7 @@ const Template = observer(() => {
   return (
   return (
     <PageContainer>
     <PageContainer>
       <SearchComponent
       <SearchComponent
-        defaultParam={[{ column: 'type$IN', value: id }]}
+        // defaultParam={[{ column: 'type$IN', value: id }]}
         field={columns}
         field={columns}
         onSearch={(data) => {
         onSearch={(data) => {
           actionRef.current?.reset?.();
           actionRef.current?.reset?.();
@@ -237,7 +201,7 @@ const Template = observer(() => {
               isPermission={templatePermission.add}
               isPermission={templatePermission.add}
               onClick={() => {
               onClick={() => {
                 state.current = undefined;
                 state.current = undefined;
-                history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], id));
+                history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail']));
               }}
               }}
               key="button"
               key="button"
               icon={<PlusOutlined />}
               icon={<PlusOutlined />}
@@ -304,13 +268,15 @@ const Template = observer(() => {
         cardRender={(record) => (
         cardRender={(record) => (
           <NoticeCard
           <NoticeCard
             {...record}
             {...record}
-            type={id}
+            // type={id}
             detail={
             detail={
               <div
               <div
                 style={{ fontSize: 18, padding: 8 }}
                 style={{ fontSize: 18, padding: 8 }}
                 onClick={() => {
                 onClick={() => {
                   state.current = record;
                   state.current = record;
-                  history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], id));
+                  history.push(
+                    getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], record.id),
+                  );
                 }}
                 }}
               >
               >
                 <EyeOutlined />
                 <EyeOutlined />
@@ -322,7 +288,9 @@ const Template = observer(() => {
                 key="edit"
                 key="edit"
                 onClick={() => {
                 onClick={() => {
                   state.current = record;
                   state.current = record;
-                  history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], id));
+                  history.push(
+                    getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], record.id),
+                  );
                 }}
                 }}
               >
               >
                 <EditOutlined />
                 <EditOutlined />

+ 8 - 0
src/pages/notice/Template/service.ts

@@ -73,6 +73,14 @@ class Service extends BaseService<TemplateItem> {
           value: item.id,
           value: item.id,
         }));
         }));
       }),
       }),
+
+    getTags: (id: string) =>
+      request(`${SystemConst.API_BASE}/notifier/dingtalk/corp/${id}/tags`).then((resp: any) => {
+        return resp.result?.map((item: any) => ({
+          label: item.name,
+          value: item.id,
+        }));
+      }),
   };
   };
 
 
   weixin = {
   weixin = {

+ 131 - 52
src/pages/rule-engine/Alarm/Config/index.tsx

@@ -28,60 +28,98 @@ const Config = () => {
 
 
   const outputData = [
   const outputData = [
     {
     {
-      key: 'alarmName',
-      name: '告警名称',
+      key: 'alarmConfigName',
+      name: '告警配置名称',
       type: 'string',
       type: 'string',
-      desc: '推送的告警名称',
+      desc: '推送的告警配置名称',
+      example: '烟感告警',
     },
     },
     {
     {
-      key: 'id',
-      name: '告警ID',
+      key: 'alarmConfigId',
+      name: '告警配置ID',
+      type: 'string',
+      desc: '推送的告警配置ID',
+      example: '1605111722418597888',
+    },
+    {
+      key: 'Id',
+      name: '告警数据ID',
       type: 'string',
       type: 'string',
       desc: '告警唯一性标识',
       desc: '告警唯一性标识',
+      example: '1515992841393119232',
+    },
+    {
+      key: 'alarmRecordId',
+      name: '告警记录ID',
+      type: 'string',
+      desc: '告警记录的唯一标识,可根据此ID处理告警',
+      example: 'ba33a59ca5ebe3dccfcd75fd0575be4e',
     },
     },
     {
     {
       key: 'targetType',
       key: 'targetType',
-      name: '告警类型',
+      name: '告警目标类型',
       type: 'string',
       type: 'string',
-      desc: '告警所属的业务类型,具体有产品、设备、组织、其他',
+      desc: '告警所属的业务类型,具体有产品、设备、部门、其他',
+      example: '产品',
     },
     },
     {
     {
       key: 'targetId',
       key: 'targetId',
       name: '告警目标ID',
       name: '告警目标ID',
       type: 'string',
       type: 'string',
       desc: '告警目标唯一性标识',
       desc: '告警目标唯一性标识',
+      example: '1583300346713661440',
     },
     },
     {
     {
       key: 'targetName',
       key: 'targetName',
       name: '告警目标名称',
       name: '告警目标名称',
       type: 'string',
       type: 'string',
       desc: '告警目标实例名称',
       desc: '告警目标实例名称',
+      example: '海康烟感',
+    },
+    {
+      key: 'alarmTime',
+      name: '告警时间',
+      type: 'long',
+      desc: '告警触发时间',
+      example: '1651233650840',
+    },
+    {
+      key: 'sourceType',
+      name: '告警源类型',
+      type: 'string',
+      desc: '触发告警的源类型。当前只有device',
+      example: 'device',
     },
     },
     {
     {
-      key: 'alarmDate',
-      name: '最近告警时间',
-      type: 'date',
-      desc: '最近一次的告警触发时间',
+      key: 'sourceId',
+      name: '告警源ID',
+      type: 'string',
+      desc: '触发告警的源Id。如设备Id',
+      example: '1605138218826821632',
+    },
+    {
+      key: 'sourceName',
+      name: '告警源名称',
+      type: 'string',
+      desc: '触发告警的源名称。如设备名称',
+      example: '1楼烟感S01',
     },
     },
     {
     {
       key: 'level',
       key: 'level',
       name: '告警级别',
       name: '告警级别',
       type: 'int',
       type: 'int',
       desc: '告警严重程度指标',
       desc: '告警严重程度指标',
-    },
-    {
-      key: 'state',
-      name: '告警状态',
-      type: 'object',
-      desc: 'value:告警状态 text:告警值',
+      example: 1,
     },
     },
     {
     {
       key: 'description',
       key: 'description',
       name: '告警说明',
       name: '告警说明',
       type: 'string',
       type: 'string',
       desc: '告警规则说明',
       desc: '告警规则说明',
+      example: '1楼烟感统一告警规则设置',
     },
     },
   ];
   ];
+
   const outputColumns = [
   const outputColumns = [
     {
     {
       title: '名称',
       title: '名称',
@@ -105,49 +143,85 @@ const Config = () => {
       title: '说明',
       title: '说明',
       dataIndex: 'desc',
       dataIndex: 'desc',
       key: 'desc',
       key: 'desc',
+      width: 100,
+      ellipsis: true,
+    },
+    {
+      title: '示例值',
+      dataIndex: 'example',
+      key: 'example',
+      width: 100,
       ellipsis: true,
       ellipsis: true,
     },
     },
   ];
   ];
 
 
+  const subColumns = [...outputColumns];
+  subColumns.splice(3, 0, {
+    title: '必填',
+    dataIndex: 'require',
+    key: 'require',
+    ellipsis: true,
+  });
+
   const subData = [
   const subData = [
     {
     {
-      key: 'id',
-      name: '告警ID',
+      key: 'alarmRecordId',
+      name: '告警记录ID',
       type: 'string',
       type: 'string',
       require: '是',
       require: '是',
-      desc: '订阅的告警唯一性标识',
+      desc: '告警记录的唯一标识,可根据此ID处理告警',
+      example: 'ba33a59ca5ebe3dccfcd75fd0575be4e',
     },
     },
     {
     {
-      key: 'describe',
-      name: '处理内容',
+      key: 'alarmConfigId',
+      name: '告警配置ID',
       type: 'string',
       type: 'string',
       require: '是',
       require: '是',
-      desc: '告警处理内容详细描述说明',
+      desc: '推送的告警配置ID',
+      example: '1605111722418597888',
     },
     },
     {
     {
-      key: 'state',
-      name: '告警状态',
-      type: 'string',
+      key: 'alarmTime',
+      name: '告警时间',
+      type: 'long',
       require: '是',
       require: '是',
-      desc: '告警中, 无告警',
+      desc: '告警触发时间',
+      example: '1651233650840',
     },
     },
     {
     {
       key: 'handleTime',
       key: 'handleTime',
       name: '处理时间',
       name: '处理时间',
       type: 'long',
       type: 'long',
-      require: '',
+      require: '',
       desc: '告警处理时间,不填是默认为消息处理时间',
       desc: '告警处理时间,不填是默认为消息处理时间',
+      example: '1651233650840',
+    },
+    {
+      key: 'describe',
+      name: '处理说明',
+      type: 'string',
+      require: '是',
+      desc: '告警处理内容详细描述说明',
+      example: '已联系第三方人员进行告警处理,现告警已恢复',
+    },
+    {
+      key: 'type',
+      name: '处理类型',
+      type: 'enum',
+      require: '是',
+      desc: '支持system、user',
+      example: 'user',
+    },
+    {
+      key: 'state',
+      name: '处理后的状态',
+      type: 'enum',
+      require: '是',
+      desc: 'warning、normal',
+      example: 'normal',
     },
     },
   ];
   ];
 
 
-  const subColumns = [...outputColumns];
-  subColumns.splice(3, 0, {
-    title: '必填',
-    dataIndex: 'require',
-    key: 'require',
-    ellipsis: true,
-  });
-
   const SchemaField = createSchemaField({
   const SchemaField = createSchemaField({
     components: {
     components: {
       FormItem,
       FormItem,
@@ -280,19 +354,20 @@ const Config = () => {
   const outputText = `
   const outputText = `
   ~~~json
   ~~~json
   {
   {
-    "id": "1518055745863864320",
-    "alarmConfigId": "1511601633016569856",
-    "alarmName": "一楼烟感告警",
-    "targetType": "product",
-    "targetId": "product-01",
-    "targetName": "产品-001",
-    "alarmTime": "1651233650840",
-    "level": 3,
-    "state": {
-      "text": "告警中",
-      "value": "warning"
-    },
-    "description": "一楼烟感告警设置"
+    "alarmConfigId": "1605111722418597888",
+    "id": "1515992841393119232",
+    "alarmConfigId": "1586989804257853441",
+    "alarmConfigName": "烟感告警",
+    "alarmRecordId": "ba33a59ca5ebe3dccfcd75fd0575be4e",
+    "level": "3",
+    "description": "设备温度过高",
+    "alarmTime": "1667202964007",
+    "sourceType": "device",
+    "sourceId": "1605138218826821632",
+    "sourceName": "1楼烟感S01",
+    "targetType": "device",
+    "targetName": "温度探测设备",
+    "targetId": "1583300346713661440"
   }
   }
   ~~~
   ~~~
   `;
   `;
@@ -300,9 +375,13 @@ const Config = () => {
   const subText = `
   const subText = `
   ~~~json
   ~~~json
   {
   {
-    "id": "1518055745863864320",
-    "state": "normal",
-     "describe": "已处理"
+    "alarmRecordId": "ba33a59ca5ebe3dccfcd75fd0575be4e",
+    "alarmConfigId": "1605111722418597888",
+    "alarmTime": "1651233650840",
+    "handleTime": "1651233650841",
+    "describe": "已联系第三方人员进行告警处理,现告警已恢复",
+    "type": "user",
+    "state": "normal"
   }
   }
   ~~~
   ~~~
   `;
   `;

+ 273 - 107
src/pages/system/Menu/Setting/baseMenu.ts

@@ -49,147 +49,313 @@ export default [
         owner: 'iot',
         owner: 'iot',
         //parentId: '1',
         //parentId: '1',
         //id: '1-2',
         //id: '1-2',
-        url: '/iot/notice/Type',
+        url: '/iot/notice',
         icon: 'icon-tongzhiguanli',
         icon: 'icon-tongzhiguanli',
         sortIndex: 2,
         sortIndex: 2,
         showPage: ['template', 'notifier'],
         showPage: ['template', 'notifier'],
         permissions: [],
         permissions: [],
-        buttons: [
-          {
-            id: 'bind',
-            name: '同步用户',
-            permissions: [
-              {
-                permission: 'notifier',
-                actions: ['query'],
-              },
-              {
-                permission: 'template',
-                actions: ['query'],
-              },
-              {
-                permission: 'user-third-party-manager',
-                actions: ['query', 'save'],
-              },
-              {
-                permission: 'user',
-                actions: ['query'],
-              },
-            ],
-          },
+        children: [
           {
           {
-            id: 'view',
-            name: '查看',
-            permissions: [
+            code: 'notice',
+            name: '通知配置',
+            owner: 'iot',
+            //parentId: '1',
+            //id: '1-2',
+            url: '/iot/notice/Config',
+            icon: 'icon-tongzhiguanli',
+            sortIndex: 1,
+            showPage: ['notifier'],
+            permissions: [],
+            buttons: [
               {
               {
-                permission: 'notifier',
-                actions: ['query'],
+                id: 'bind',
+                name: '同步用户',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'user-third-party-manager',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'user',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query'],
+                id: 'view',
+                name: '查看',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'log',
-            name: '通知记录',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query'],
+                id: 'log',
+                name: '通知记录',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query'],
+                id: 'debug',
+                name: '调试',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'send'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'user',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'debug',
-            name: '调试',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query', 'send'],
+                id: 'export',
+                name: '导出',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query'],
+                id: 'import',
+                name: '导入',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'user',
-                actions: ['query'],
+                id: 'delete',
+                name: '删除',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'delete'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'delete'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'export',
-            name: '导出',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query'],
+                id: 'update',
+                name: '编辑',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query'],
+                id: 'add',
+                name: '新增',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
             ],
             ],
           },
           },
           {
           {
-            id: 'import',
-            name: '导入',
-            permissions: [
+            code: 'notice',
+            name: '通知模板',
+            owner: 'iot',
+            //parentId: '1',
+            //id: '1-2',
+            url: '/iot/notice/Template',
+            icon: 'icon-tongzhiguanli',
+            sortIndex: 2,
+            showPage: ['template'],
+            permissions: [],
+            buttons: [
+              // {
+              //   id: 'bind',
+              //   name: '同步用户',
+              //   permissions: [
+              //     {
+              //       permission: 'notifier',
+              //       actions: ['query'],
+              //     },
+              //     {
+              //       permission: 'template',
+              //       actions: ['query'],
+              //     },
+              //     {
+              //       permission: 'user-third-party-manager',
+              //       actions: ['query', 'save'],
+              //     },
+              //     {
+              //       permission: 'user',
+              //       actions: ['query'],
+              //     },
+              //   ],
+              // },
               {
               {
-                permission: 'notifier',
-                actions: ['query', 'save'],
+                id: 'view',
+                name: '查看',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query', 'save'],
+                id: 'log',
+                name: '通知记录',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'delete',
-            name: '删除',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query', 'delete'],
+                id: 'debug',
+                name: '调试',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'send'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'user',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query', 'delete'],
+                id: 'export',
+                name: '导出',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'update',
-            name: '编辑',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query', 'save'],
+                id: 'import',
+                name: '导入',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query', 'save'],
+                id: 'delete',
+                name: '删除',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'delete'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'delete'],
+                  },
+                ],
               },
               },
-            ],
-          },
-          {
-            id: 'add',
-            name: '新增',
-            permissions: [
               {
               {
-                permission: 'notifier',
-                actions: ['query', 'save'],
+                id: 'update',
+                name: '编辑',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
               {
               {
-                permission: 'template',
-                actions: ['query', 'save'],
+                id: 'add',
+                name: '新增',
+                permissions: [
+                  {
+                    permission: 'notifier',
+                    actions: ['query', 'save'],
+                  },
+                  {
+                    permission: 'template',
+                    actions: ['query', 'save'],
+                  },
+                ],
               },
               },
             ],
             ],
           },
           },
@@ -1375,7 +1541,7 @@ export default [
         permissions: [],
         permissions: [],
         children: [
         children: [
           {
           {
-            code: 'link/DataCollect/Dashboard',
+            code: 'DataCollect/Dashboard',
             name: '仪表盘',
             name: '仪表盘',
             owner: 'iot',
             owner: 'iot',
             sortIndex: 1,
             sortIndex: 1,
@@ -1398,11 +1564,11 @@ export default [
             buttons: [],
             buttons: [],
           },
           },
           {
           {
-            code: 'link/DataCollect/DataGathering',
-            name: '数据采集',
+            code: 'DataCollect/Channel',
+            name: '通道管理',
             owner: 'iot',
             owner: 'iot',
             sortIndex: 2,
             sortIndex: 2,
-            url: '/iot/DataCollect/DataGathering',
+            url: '/iot/DataCollect/Channel',
             icon: 'icon-rizhifuwu',
             icon: 'icon-rizhifuwu',
             showPage: [
             showPage: [
               'data-collect-channel',
               'data-collect-channel',
@@ -1529,11 +1695,11 @@ export default [
             ],
             ],
           },
           },
           {
           {
-            code: 'link/DataCollect/IntegratedQuery',
-            name: '综合查询',
+            code: 'DataCollect/Collector',
+            name: '采集器',
             owner: 'iot',
             owner: 'iot',
             sortIndex: 3,
             sortIndex: 3,
-            url: '/iot/DataCollect/IntegratedQuery',
+            url: '/iot/DataCollect/Collector',
             icon: 'icon-yingyongguanli',
             icon: 'icon-yingyongguanli',
             showPage: [
             showPage: [
               'data-collect-channel',
               'data-collect-channel',

+ 1 - 0
src/pages/user/Login/index.tsx

@@ -87,6 +87,7 @@ const Login: React.FC = () => {
   useEffect(getCode, []);
   useEffect(getCode, []);
 
 
   useEffect(() => {
   useEffect(() => {
+    console.log('版本:' + localStorage.getItem(SystemConst.Version_Code));
     localStorage.clear();
     localStorage.clear();
     Service.getSystemVersion().then((resp) => {
     Service.getSystemVersion().then((resp) => {
       if (resp && resp.status === 200 && resp.result) {
       if (resp && resp.status === 200 && resp.result) {

+ 6 - 6
src/utils/menu/index.ts

@@ -12,12 +12,12 @@ const DetailCode = 'detail';
 
 
 // 额外子级路由F
 // 额外子级路由F
 const extraRouteObj = {
 const extraRouteObj = {
-  notice: {
-    children: [
-      { code: 'Config', name: '通知配置' },
-      { code: 'Template', name: '通知模版' },
-    ],
-  },
+  // notice: {
+  //   children: [
+  //     { code: 'Config', name: '通知配置' },
+  //     { code: 'Template', name: '通知模版' },
+  //   ],
+  // },
   'media/Cascade': {
   'media/Cascade': {
     children: [
     children: [
       { code: 'Save', name: '新增' },
       { code: 'Save', name: '新增' },

+ 6 - 6
src/utils/menu/router.ts

@@ -37,9 +37,9 @@ export enum MENUS_CODE {
   'link/Protocol' = 'link/Protocol',
   'link/Protocol' = 'link/Protocol',
   'link/Type' = 'link/Type',
   'link/Type' = 'link/Type',
   'link/AccessConfig' = 'link/AccessConfig',
   'link/AccessConfig' = 'link/AccessConfig',
-  'link/DataCollect/Dashboard' = 'link/DataCollect/Dashboard',
-  'link/DataCollect/DataGathering' = 'link/DataCollect/DataGathering',
-  'link/DataCollect/IntegratedQuery' = 'link/DataCollect/IntegratedQuery',
+  'DataCollect/Dashboard' = 'DataCollect/Dashboard',
+  'DataCollect/Channel' = 'DataCollect/Channel',
+  'DataCollect/Collector' = 'DataCollect/Collector',
   'edge/Device' = 'edge/Device',
   'edge/Device' = 'edge/Device',
   'edge/Resource' = 'edge/Resource',
   'edge/Resource' = 'edge/Resource',
   'Log' = 'Log',
   'Log' = 'Log',
@@ -55,10 +55,10 @@ export enum MENUS_CODE {
   'media/Stream' = 'media/Stream',
   'media/Stream' = 'media/Stream',
   'media/Stream/Detail' = 'media/Stream/Detail',
   'media/Stream/Detail' = 'media/Stream/Detail',
   'media/DashBoard' = 'media/DashBoard',
   'media/DashBoard' = 'media/DashBoard',
-  'notice/Type' = 'notice/Type',
-  'notice/Config' = 'notice/Config',
   'media/SplitScreen' = 'media/SplitScreen',
   'media/SplitScreen' = 'media/SplitScreen',
-  'notice/Type/Config' = 'notice/Config',
+  // 'notice/Type' = 'notice/Type',
+  // 'notice/Type/Config' = 'notice/Config',
+  'notice/Config' = 'notice/Config',
   'notice/Config/Detail' = 'notice/Config/Detail',
   'notice/Config/Detail' = 'notice/Config/Detail',
   'notice/Template' = 'notice/Template',
   'notice/Template' = 'notice/Template',
   'notice/Template/Detail' = 'notice/Template/Detail',
   'notice/Template/Detail' = 'notice/Template/Detail',