xieyonghong преди 3 години
родител
ревизия
0fce7e742b

BIN
public/images/device/button.png


+ 11 - 5
src/components/BindParentDevice/index.tsx

@@ -4,7 +4,7 @@ import SearchComponent from '@/components/SearchComponent';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { useRef, useState } from 'react';
-import { service, statusMap } from '@/pages/device/Instance';
+import { service } from '@/pages/device/Instance';
 import { useIntl } from 'umi';
 import moment from 'moment';
 
@@ -14,6 +14,11 @@ interface Props {
   onOk: (parentId: string) => void;
 }
 
+const statusMap = new Map();
+statusMap.set('online', 'success');
+statusMap.set('offline', 'error');
+statusMap.set('notActive', 'warning');
+
 const BindParentDevice = (props: Props) => {
   const intl = useIntl();
 
@@ -42,6 +47,7 @@ const BindParentDevice = (props: Props) => {
       dataIndex: 'registryTime',
       ellipsis: true,
       width: '200px',
+      valueType: 'dateTime',
       render: (text: any) => (!!text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
       sorter: true,
     },
@@ -59,21 +65,21 @@ const BindParentDevice = (props: Props) => {
             id: 'pages.device.instance.status.notActive',
             defaultMessage: '未启用',
           }),
-          value: 'notActive',
+          status: 'notActive',
         },
         offline: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.offLine',
             defaultMessage: '离线',
           }),
-          value: 'offline',
+          status: 'offline',
         },
         online: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.onLine',
             defaultMessage: '在线',
           }),
-          value: 'online',
+          status: 'online',
         },
       },
     },
@@ -122,7 +128,7 @@ const BindParentDevice = (props: Props) => {
             submitBtn();
           }}
         >
-          确
+          确
         </Button>,
       ]}
     >

+ 1 - 1
src/locales/zh-CN/pages.ts

@@ -197,7 +197,7 @@ export default {
   'pages.device.product.status.all': '全部',
   'pages.device.productDetail': '产品详情',
   'pages.device.productDetail.id': '产品ID',
-  'pages.device.productDetail.classifiedName': '所属品类',
+  'pages.device.productDetail.classifiedName': '产品分类',
   'pages.device.productDetail.protocolName': '消息协议',
   'pages.device.productDetail.transportProtocol': '接入方式',
   'pages.device.productDetail.createTime': '创建时间',

+ 17 - 8
src/pages/device/Instance/Detail/ChildDevice/BindChildDevice/index.tsx

@@ -4,18 +4,21 @@ import SearchComponent from '@/components/SearchComponent';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { useRef, useState } from 'react';
-import { InstanceModel, service, statusMap } from '@/pages/device/Instance';
+import { InstanceModel, service } from '@/pages/device/Instance';
 import { useIntl } from 'umi';
 import moment from 'moment';
 
 interface Props {
-  visible: boolean;
   data: Partial<DeviceInstance>;
   onCancel: () => void;
 }
 
+const statusMap = new Map();
+statusMap.set('online', 'success');
+statusMap.set('offline', 'error');
+statusMap.set('notActive', 'warning');
+
 const BindChildDevice = (props: Props) => {
-  const { visible } = props;
   const intl = useIntl();
 
   const actionRef = useRef<ActionType>();
@@ -42,8 +45,13 @@ const BindChildDevice = (props: Props) => {
       title: '注册时间',
       dataIndex: 'registryTime',
       ellipsis: true,
+      valueType: 'dateTime',
       width: '200px',
-      render: (text: any) => (!!text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
+      render: (text: any, record: any) => {
+        return !record?.registryTime
+          ? ''
+          : moment(record?.registryTime).format('YYYY-MM-DD HH:mm:ss');
+      },
       sorter: true,
     },
     {
@@ -60,21 +68,21 @@ const BindChildDevice = (props: Props) => {
             id: 'pages.device.instance.status.notActive',
             defaultMessage: '未启用',
           }),
-          value: 'notActive',
+          status: 'notActive',
         },
         offline: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.offLine',
             defaultMessage: '离线',
           }),
-          value: 'offline',
+          status: 'offline',
         },
         online: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.onLine',
             defaultMessage: '在线',
           }),
-          value: 'online',
+          status: 'online',
         },
       },
     },
@@ -93,7 +101,7 @@ const BindChildDevice = (props: Props) => {
     <Modal
       maskClosable={false}
       title="绑定子设备"
-      visible={visible}
+      visible
       width={1000}
       onOk={() => {
         submitBtn();
@@ -129,6 +137,7 @@ const BindChildDevice = (props: Props) => {
         field={[...columns]}
         target="child-device-bind"
         enableSave={false}
+        model="simple"
         // pattern={'simple'}
         defaultParam={[
           {

+ 24 - 13
src/pages/device/Instance/Detail/ChildDevice/index.tsx

@@ -4,7 +4,7 @@ import type { LogItem } from '@/pages/device/Instance/Detail/Log/typings';
 import { Badge, Button, Card, Popconfirm, Tooltip } from 'antd';
 import { DisconnectOutlined, SearchOutlined } from '@ant-design/icons';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { InstanceModel, service, statusMap } from '@/pages/device/Instance';
+import { InstanceModel, service } from '@/pages/device/Instance';
 import { useRef, useState } from 'react';
 import SearchComponent from '@/components/SearchComponent';
 import BindChildDevice from './BindChildDevice';
@@ -14,6 +14,11 @@ import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { useDomFullHeight } from '@/hooks';
 import { onlyMessage } from '@/utils/util';
 
+const statusMap = new Map();
+statusMap.set('online', 'success');
+statusMap.set('offline', 'error');
+statusMap.set('notActive', 'warning');
+
 const ChildDevice = () => {
   const intl = useIntl();
   const [visible, setVisible] = useState<boolean>(false);
@@ -53,7 +58,12 @@ const ChildDevice = () => {
       title: '注册时间',
       dataIndex: 'registryTime',
       width: '200px',
-      render: (text: any) => (!!text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
+      valueType: 'dateTime',
+      render: (text: any, record: any) => {
+        return !record?.registryTime
+          ? ''
+          : moment(record?.registryTime).format('YYYY-MM-DD HH:mm:ss');
+      },
       sorter: true,
     },
     {
@@ -68,21 +78,21 @@ const ChildDevice = () => {
             id: 'pages.device.instance.status.notActive',
             defaultMessage: '未启用',
           }),
-          value: 'notActive',
+          status: 'notActive',
         },
         offline: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.offLine',
             defaultMessage: '离线',
           }),
-          value: 'offline',
+          status: 'offline',
         },
         online: {
           text: intl.formatMessage({
             id: 'pages.device.instance.status.onLine',
             defaultMessage: '在线',
           }),
-          value: 'online',
+          status: 'online',
         },
       },
     },
@@ -189,14 +199,15 @@ const ChildDevice = () => {
         }}
         request={(params) => service.query(params)}
       />
-      <BindChildDevice
-        visible={visible}
-        data={{}}
-        onCancel={() => {
-          setVisible(false);
-          actionRef.current?.reload?.();
-        }}
-      />
+      {visible && (
+        <BindChildDevice
+          data={{}}
+          onCancel={() => {
+            setVisible(false);
+            actionRef.current?.reload?.();
+          }}
+        />
+      )}
     </Card>
   );
 };

+ 16 - 3
src/pages/device/Instance/Detail/Diagnose/Message/index.tsx

@@ -23,6 +23,21 @@ import Log from './Log';
 import { DiagnoseStatusModel, messageStatusMap, messageStyleMap } from '../Status/model';
 import { observer } from '@formily/reactive-react';
 
+// const DataTypeComponent = (value: string) => {
+//   switch (value) {
+//     case 'array':
+//       return <div>{value}array</div>
+//     // case 'enum':
+//     //   return <div>{value}</div>
+//     case 'geo':
+//       return <div>{value}geo</div>
+//     case 'file':
+//       return <div>{value}file</div>
+//     default:
+//       return <div>{value}</div>
+//   }
+// }
+
 const DatePicker1: any = DatePicker;
 
 const Message = observer(() => {
@@ -287,6 +302,7 @@ const Message = observer(() => {
       FSelect,
       FDatePicker,
       NumberPicker,
+      DataTypeComponent,
     },
   });
 
@@ -328,9 +344,6 @@ const Message = observer(() => {
                   type: 'string',
                   'x-decorator': 'FormItem',
                   'x-component': 'PreviewText.Input',
-                  // 'x-decorator-props': {
-                  //   tooltip: '使用固定的通知配置来发送此通知模版',
-                  // },
                 },
               },
             },

+ 193 - 39
src/pages/device/Instance/Detail/Diagnose/Status/ManualInspection.tsx

@@ -2,8 +2,9 @@ import { Button, Descriptions, Modal } from 'antd';
 import styles from './index.less';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { useHistory } from 'umi';
-import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { getMenuPathByCode, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { InstanceModel } from '@/pages/device/Instance';
+import { randomString } from '@/utils/util';
 interface Props {
   close: () => void;
   data: any;
@@ -19,6 +20,189 @@ const ManualInspection = (props: Props) => {
     props.save(data);
   };
 
+  const dataRender = () => {
+    if (data.type === 'device' || data.type === 'product') {
+      return (
+        <>
+          <div style={{ flex: 1 }}>
+            <div className={styles.alert}>
+              <InfoCircleOutlined style={{ marginRight: 10 }} />
+              请检查配置项是否填写正确,若您确定该项无需诊断可
+              <a
+                onClick={() => {
+                  okBtn();
+                }}
+              >
+                忽略
+              </a>
+            </div>
+            <div style={{ marginTop: 10 }}>
+              <Descriptions title={data?.data?.name} layout="vertical" bordered>
+                {(data?.data?.properties || []).map((item: any) => (
+                  <Descriptions.Item
+                    key={item.property}
+                    label={`${item.name}${item?.description ? `(${item.description})` : ''}`}
+                  >
+                    {data?.configuration[item.property] || ''}
+                  </Descriptions.Item>
+                ))}
+              </Descriptions>
+            </div>
+          </div>
+          {data?.data?.description ? (
+            <div
+              style={{ width: '50%', border: '1px solid #f0f0f0', padding: 10, borderLeft: 'none' }}
+            >
+              <h4>诊断项说明</h4>
+              <p>{data?.data?.description}</p>
+            </div>
+          ) : (
+            ''
+          )}
+        </>
+      );
+    } else if (data.type === 'cloud') {
+      return (
+        <>
+          <div style={{ flex: 1 }}>
+            <div className={styles.alert}>
+              <InfoCircleOutlined style={{ marginRight: 10 }} />
+              请检查配置项是否填写正确,若您确定该项无需诊断可
+              <a
+                onClick={() => {
+                  okBtn();
+                }}
+              >
+                忽略
+              </a>
+            </div>
+            <div style={{ marginTop: 10 }}>
+              <Descriptions title={data?.data?.name} layout="vertical" bordered>
+                {data.configuration?.provider === 'OneNet' ? (
+                  <>
+                    <Descriptions.Item label={'接口地址'}>
+                      {data?.configuration?.configuration?.apiAddress || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'apiKey'}>
+                      {data?.configuration?.configuration?.apiKey || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'通知Token'}>
+                      {data?.configuration?.configuration?.validateToken || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'aesKey'}>
+                      {data?.configuration?.configuration?.aesKey || ''}
+                    </Descriptions.Item>
+                  </>
+                ) : (
+                  <>
+                    <Descriptions.Item label={'接口地址'}>
+                      {data?.configuration?.configuration?.apiAddress || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'appKey'}>
+                      {data?.configuration?.configuration?.appKey || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'appSecret'}>
+                      {data?.configuration?.configuration?.appSecret || ''}
+                    </Descriptions.Item>
+                  </>
+                )}
+              </Descriptions>
+            </div>
+          </div>
+          {data?.configuration?.configuration?.description ? (
+            <div
+              style={{ width: '50%', border: '1px solid #f0f0f0', padding: 10, borderLeft: 'none' }}
+            >
+              <h4>诊断项说明</h4>
+              <p>{data?.configuration?.configuration?.description}</p>
+            </div>
+          ) : (
+            ''
+          )}
+        </>
+      );
+    } else if (data.type === 'media') {
+      return (
+        <>
+          <div style={{ flex: 1 }}>
+            <div className={styles.alert}>
+              <InfoCircleOutlined style={{ marginRight: 10 }} />
+              请检查配置项是否填写正确,若您确定该项无需诊断可
+              <a
+                onClick={() => {
+                  okBtn();
+                }}
+              >
+                忽略
+              </a>
+            </div>
+            <div style={{ marginTop: 10 }}>
+              <Descriptions title={data?.data?.name} layout="vertical" bordered>
+                {data?.configuration?.configuration?.shareCluster ? (
+                  <>
+                    <Descriptions.Item label={'SIP 域'}>
+                      {data?.configuration?.configuration?.domain || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'SIP ID'}>
+                      {data?.configuration?.configuration?.sipId || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'集群'}>
+                      {data?.configuration?.configuration?.shareCluster ? '共享配置' : '独立配置'}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'SIP 地址'}>
+                      {`${data?.configuration?.configuration?.hostPort?.host}:${data?.configuration?.configuration?.hostPort?.port}`}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'公网 Host'}>
+                      {`${data?.configuration?.configuration?.hostPort?.publicHost}:${data?.configuration?.configuration?.hostPort?.publicPort}`}
+                    </Descriptions.Item>
+                  </>
+                ) : (
+                  <>
+                    <Descriptions.Item label={'SIP 域'}>
+                      {data?.configuration?.configuration?.domain || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'SIP ID'}>
+                      {data?.configuration?.configuration?.sipId || ''}
+                    </Descriptions.Item>
+                    <Descriptions.Item label={'集群'}>
+                      {data?.configuration?.configuration?.shareCluster ? '共享配置' : '独立配置'}
+                    </Descriptions.Item>
+                    {data?.configuration?.configuration?.cluster.map((i: any, it: number) => (
+                      <div key={randomString()}>
+                        <div>节点{it + 1}</div>
+                        <Descriptions.Item label={'节点名称'}>
+                          {i?.clusterNodeId || ''}
+                        </Descriptions.Item>
+                        <Descriptions.Item label={'SIP 地址'}>
+                          {`${i.host}:${i?.port}`}
+                        </Descriptions.Item>
+                        <Descriptions.Item label={'公网 Host'}>
+                          {`${i?.publicHost}:${i?.publicPort}`}
+                        </Descriptions.Item>
+                      </div>
+                    ))}
+                  </>
+                )}
+              </Descriptions>
+            </div>
+          </div>
+          {data?.configuration?.configuration.description ? (
+            <div
+              style={{ width: '50%', border: '1px solid #f0f0f0', padding: 10, borderLeft: 'none' }}
+            >
+              <h4>诊断项说明</h4>
+              <p>{data?.configuration?.description}</p>
+            </div>
+          ) : (
+            ''
+          )}
+        </>
+      );
+    } else {
+      return null;
+    }
+  };
+
   return (
     <Modal
       title="人工检查"
@@ -32,13 +216,19 @@ const ManualInspection = (props: Props) => {
           onClick={() => {
             if (data.type === 'device') {
               InstanceModel.active = 'detail';
-            } else {
+            } else if (data.type === 'product') {
               history.push(
                 `${getMenuPathByParams(MENUS_CODE['device/Product/Detail'], data.productId)}`,
                 {
                   tab: 'access',
                 },
               );
+            } else {
+              history.push(
+                `${getMenuPathByCode(MENUS_CODE['link/AccessConfig/Detail'])}?id=${
+                  data.configuration?.id
+                }`,
+              );
             }
             props.close();
           }}
@@ -56,43 +246,7 @@ const ManualInspection = (props: Props) => {
       ]}
       visible
     >
-      <div style={{ display: 'flex' }}>
-        <div style={{ flex: 1 }}>
-          <div className={styles.alert}>
-            <InfoCircleOutlined style={{ marginRight: 10 }} />
-            请检查配置项是否填写正确,若您确定该项无需诊断可
-            <a
-              onClick={() => {
-                okBtn();
-              }}
-            >
-              忽略
-            </a>
-          </div>
-          <div style={{ marginTop: 10 }}>
-            <Descriptions title={data?.data?.name} layout="vertical" bordered>
-              {(data?.data?.properties || []).map((item: any) => (
-                <Descriptions.Item
-                  key={item.property}
-                  label={`${item.name}${item?.description ? `(${item.description})` : ''}`}
-                >
-                  {data?.configuration[item.property] || ''}
-                </Descriptions.Item>
-              ))}
-            </Descriptions>
-          </div>
-        </div>
-        {data?.data?.description ? (
-          <div
-            style={{ width: '50%', border: '1px solid #f0f0f0', padding: 10, borderLeft: 'none' }}
-          >
-            <h4>诊断项说明</h4>
-            <p>{data?.data?.description}</p>
-          </div>
-        ) : (
-          ''
-        )}
-      </div>
+      <div style={{ display: 'flex' }}>{dataRender()}</div>
     </Modal>
   );
 };

+ 154 - 32
src/pages/device/Instance/Detail/Diagnose/Status/index.tsx

@@ -208,16 +208,19 @@ const Status = observer((props: Props) => {
         }
       }
     });
-
   // 设备接入网关
   const diagnoseGateway = () =>
     new Promise((resolve) => {
+      const desc =
+        providerType && ['child-device', 'cloud'].includes(providerType)
+          ? '诊断设备接入网关状态是否正常,网关配置是否正确'
+          : '诊断设备接入网关状态是否正常,禁用状态将导致连接失败';
       if (device.state?.value === 'online') {
         setTimeout(() => {
           DiagnoseStatusModel.list = modifyArrayList(DiagnoseStatusModel.list, {
             key: 'gateway',
             name: '设备接入网关',
-            desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+            desc: desc,
             status: 'success',
             text: '正常',
             info: null,
@@ -233,19 +236,81 @@ const Status = observer((props: Props) => {
               if (response.status === 200) {
                 DiagnoseStatusModel.gateway = response.result;
                 if (response.result?.state?.value === 'enabled') {
-                  item = {
-                    key: 'gateway',
-                    name: '设备接入网关',
-                    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
-                    status: 'success',
-                    text: '正常',
-                    info: null,
-                  };
+                  if (providerType === 'cloud' || device?.accessProvider === 'gb28181-2016') {
+                    item = {
+                      key: 'gateway',
+                      name: '设备接入网关',
+                      desc: desc,
+                      status: 'error',
+                      text: '可能存在异常',
+                      info: (
+                        <div>
+                          <div className={styles.infoItem}>
+                            <Badge
+                              status="default"
+                              text={
+                                <span>
+                                  请
+                                  <a
+                                    onClick={async () => {
+                                      const config = await service.getGatewayDetail(
+                                        response.result?.id || '',
+                                      );
+                                      if (config.status === 200) {
+                                        manualInspection({
+                                          type: providerType,
+                                          key: `gateway`,
+                                          name: `设备接入网关`,
+                                          desc: desc,
+                                          data: { name: `${device?.accessProvider}配置` },
+                                          configuration: { ...config.result },
+                                        });
+                                      }
+                                    }}
+                                  >
+                                    人工检查
+                                  </a>
+                                  网关配置是否已填写正确,若您确定该项无需诊断可
+                                  <Popconfirm
+                                    title="确认忽略?"
+                                    onConfirm={() => {
+                                      DiagnoseStatusModel.list = modifyArrayList(
+                                        DiagnoseStatusModel.list,
+                                        {
+                                          key: 'gateway',
+                                          name: '设备接入网关',
+                                          desc: desc,
+                                          status: 'success',
+                                          text: '正常',
+                                          info: null,
+                                        },
+                                      );
+                                    }}
+                                  >
+                                    <a>忽略</a>
+                                  </Popconfirm>
+                                </span>
+                              }
+                            />
+                          </div>
+                        </div>
+                      ),
+                    };
+                  } else {
+                    item = {
+                      key: 'gateway',
+                      name: '设备接入网关',
+                      desc: desc,
+                      status: 'success',
+                      text: '正常',
+                      info: null,
+                    };
+                  }
                 } else {
                   item = {
                     key: 'gateway',
                     name: '设备接入网关',
-                    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+                    desc: desc,
                     status: 'error',
                     text: '异常',
                     info: (
@@ -270,7 +335,7 @@ const Status = observer((props: Props) => {
                                           {
                                             key: 'gateway',
                                             name: '设备接入网关',
-                                            desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+                                            desc: desc,
                                             status: 'success',
                                             text: '正常',
                                             info: null,
@@ -306,19 +371,81 @@ const Status = observer((props: Props) => {
           }
         } else {
           if (DiagnoseStatusModel.gateway?.state?.value === 'enabled') {
-            item = {
-              key: 'gateway',
-              name: '设备接入网关',
-              desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
-              status: 'success',
-              text: '正常',
-              info: null,
-            };
+            if (providerType === 'cloud' || device?.accessProvider === 'gb28181-2016') {
+              item = {
+                key: 'gateway',
+                name: '设备接入网关',
+                desc: desc,
+                status: 'error',
+                text: '可能存在异常',
+                info: (
+                  <div>
+                    <div className={styles.infoItem}>
+                      <Badge
+                        status="default"
+                        text={
+                          <span>
+                            请
+                            <a
+                              onClick={async () => {
+                                const config = await service.getGatewayDetail(
+                                  DiagnoseStatusModel.gateway?.id || '',
+                                );
+                                if (config.status === 200) {
+                                  manualInspection({
+                                    type: providerType,
+                                    key: `gateway`,
+                                    name: `设备接入网关`,
+                                    desc: desc,
+                                    data: { name: `${device?.accessProvider}配置` },
+                                    configuration: { ...config.result },
+                                  });
+                                }
+                              }}
+                            >
+                              人工检查
+                            </a>
+                            网关配置是否已填写正确,若您确定该项无需诊断可
+                            <Popconfirm
+                              title="确认忽略?"
+                              onConfirm={() => {
+                                DiagnoseStatusModel.list = modifyArrayList(
+                                  DiagnoseStatusModel.list,
+                                  {
+                                    key: 'gateway',
+                                    name: '设备接入网关',
+                                    desc: desc,
+                                    status: 'success',
+                                    text: '正常',
+                                    info: null,
+                                  },
+                                );
+                              }}
+                            >
+                              <a>忽略</a>
+                            </Popconfirm>
+                          </span>
+                        }
+                      />
+                    </div>
+                  </div>
+                ),
+              };
+            } else {
+              item = {
+                key: 'gateway',
+                name: '设备接入网关',
+                desc: desc,
+                status: 'success',
+                text: '正常',
+                info: null,
+              };
+            }
           } else {
             item = {
               key: 'gateway',
               name: '设备接入网关',
-              desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+              desc: desc,
               status: 'error',
               text: '异常',
               info: (
@@ -341,7 +468,7 @@ const Status = observer((props: Props) => {
                                     {
                                       key: 'gateway',
                                       name: '设备接入网关',
-                                      desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+                                      desc: desc,
                                       status: 'success',
                                       text: '正常',
                                       info: null,
@@ -428,7 +555,7 @@ const Status = observer((props: Props) => {
         } else {
           let item: ListProps | undefined = undefined;
           const response = await service.detail(device?.parentId);
-          DiagnoseStatusModel.parent = resp.result;
+          DiagnoseStatusModel.parent = response.result;
           if (response.status === 200) {
             if (response?.result?.state?.value === 'notActive') {
               item = {
@@ -704,7 +831,7 @@ const Status = observer((props: Props) => {
   const diagnoseProductAuthConfig = () =>
     new Promise(async (resolve) => {
       if (device?.productId) {
-        const response = await service.queryDeviceConfig(device.productId);
+        const response = await service.queryProductConfig(device.productId);
         if (response.status === 200 && response.result.length > 0) {
           DiagnoseStatusModel.configuration.product = response.result;
           const list = [...DiagnoseStatusModel.list];
@@ -1758,21 +1885,15 @@ const Status = observer((props: Props) => {
       await diagnoseDeviceAuthConfig();
     } else if (providerType === 'child-device') {
       DiagnoseStatusModel.list = [...childInitList];
-      await diagnoseNetwork();
       await diagnoseGateway();
       DiagnoseStatusModel.percent = 20;
       await diagnoseParentDevice();
       await diagnoseProduct();
-      await diagnoseDevice();
       DiagnoseStatusModel.percent = 40;
+      await diagnoseDevice();
+      DiagnoseStatusModel.percent = 60;
       await diagnoseProductAuthConfig();
       await diagnoseDeviceAuthConfig();
-      DiagnoseStatusModel.percent = 60;
-      // await diagnoseModbus();
-      // await diagnoseOpcua();
-      // await diagnoseModbusState();
-      // await diagnoseOpcuaState();
-      // await diagnoseDataPointBind();
       DiagnoseStatusModel.percent = 80;
     } else if (providerType === 'media') {
       DiagnoseStatusModel.list = [...mediaInitList];
@@ -1981,6 +2102,7 @@ const Status = observer((props: Props) => {
               info: null,
             });
             InstanceModel.detail.parentId = parentId;
+            setBindParentVisible(false);
           }}
         />
       )}

+ 8 - 8
src/pages/device/Instance/Detail/Diagnose/Status/model.ts

@@ -81,14 +81,14 @@ export const childInitList: ListProps[] = [
   //   text: '正在诊断中...',
   //   info: null,
   // },
-  {
-    key: 'network',
-    name: '网络组件',
-    desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
-    status: 'loading',
-    text: '正在诊断中...',
-    info: null,
-  },
+  // {
+  //   key: 'network',
+  //   name: '网络组件',
+  //   desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
   {
     key: 'gateway',
     name: '设备接入网关',

+ 17 - 4
src/pages/device/Instance/Detail/index.tsx

@@ -24,7 +24,7 @@ import SystemConst from '@/utils/const';
 import { getMenuPathByCode, getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 import { PermissionButton } from '@/components';
-import { QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons';
+import { QuestionCircleOutlined } from '@ant-design/icons';
 import Service from '@/pages/device/Instance/service';
 import useLocation from '@/hooks/route/useLocation';
 import { onlyMessage } from '@/utils/util';
@@ -426,7 +426,9 @@ const InstanceDetail = observer(() => {
         //     defaultMessage: '应用配置',
         //   })}
         // </Button>,
-        <SyncOutlined
+        <img
+          style={{ marginRight: 20, cursor: 'pointer' }}
+          src={require('/public/images/device/button.png')}
           onClick={() => {
             getDetail(params.id);
             service.getConfigMetadata(params.id).then((config) => {
@@ -436,9 +438,20 @@ const InstanceDetail = observer(() => {
               }
             });
           }}
-          style={{ fontSize: 20, marginRight: 20 }}
-          key="1"
         />,
+        // <SyncOutlined
+        //   onClick={() => {
+        //     getDetail(params.id);
+        //     service.getConfigMetadata(params.id).then((config) => {
+        //       if (config.status === 200) {
+        //         InstanceModel.config = config?.result || [];
+        //         message.success('操作成功!');
+        //       }
+        //     });
+        //   }}
+        //   style={{ fontSize: 20, marginRight: 20 }}
+        //   key="1"
+        // />,
       ]}
     >
       {list.find((k) => k.key === InstanceModel.active)?.component}

+ 4 - 0
src/pages/device/Instance/service.ts

@@ -361,6 +361,10 @@ class Service extends BaseService<DeviceInstance> {
       method: 'POST',
       data,
     });
+  public getGatewayDetail = (id: string) =>
+    request(`/${SystemConst.API_BASE}/gateway/device/${id}`, {
+      method: 'GET',
+    });
 }
 
 export default Service;

+ 1 - 1
src/pages/device/components/Metadata/Import/index.tsx

@@ -192,7 +192,7 @@ const Import = (props: Props) => {
       obj.events = old?.event || [];
     }
     if (fid.includes('propertyNotModifiable')) {
-      obj.properties = old?.properties || {};
+      obj.properties = old?.properties || [];
     }
     return obj;
   };

+ 126 - 0
src/pages/home/Api/index.tsx

@@ -0,0 +1,126 @@
+import { Button, Card, Col, Input, Popover, Row } from 'antd';
+import { useEffect, useState } from 'react';
+import { service } from '@/pages/system/Platforms';
+import Service from '../service';
+import * as moment from 'moment';
+import ApiPage from '@/pages/system/Platforms/Api/base';
+
+const defaultHeight = 50;
+
+export default () => {
+  const api = new Service();
+  const [clientId, setClientId] = useState('');
+  const [secureKey, setSecureKey] = useState('');
+  const [sdkDetail, setSdkDetail] = useState<any>({});
+
+  const getDetail = async (id: string) => {
+    const resp = await service.getDetail(id);
+    if (resp.status === 200) {
+      setClientId(resp.result?.id);
+      setSecureKey(resp.result?.secureKey);
+    }
+  };
+
+  const getSDKDetail = async () => {
+    const resp = await service.getSdk();
+    if (resp.status === 200) {
+      setSdkDetail(resp.result[0]);
+    }
+  };
+
+  const downLoad = (url: string) => {
+    if (url) {
+      const downNode = document.createElement('a');
+      downNode.href = url;
+      downNode.download = `${moment(new Date()).format('YYYY-MM-DD-HH-mm-ss')}.sdk`;
+      downNode.style.display = 'none';
+      downNode.setAttribute('target', '_blank');
+      document.body.appendChild(downNode);
+      downNode.click();
+      document.body.removeChild(downNode);
+    }
+  };
+
+  useEffect(() => {
+    //  请求SDK下载地址
+    getSDKDetail();
+    api.userDetail().then((res) => {
+      if (res.status === 200) {
+        api
+          .apiDetail({
+            terms: [
+              {
+                column: 'userId',
+                value: res.result.id,
+              },
+            ],
+          })
+          .then((response) => {
+            if (response.status === 200) {
+              getDetail(response.result.data[0].id);
+            }
+          });
+      }
+    });
+  }, []);
+
+  const downLoadJDK = (
+    <div>
+      <div
+        style={{
+          width: 500,
+          borderRadius: 2,
+          marginBottom: 12,
+        }}
+      >
+        <Input.TextArea value={sdkDetail?.dependency} rows={6} readOnly />
+      </div>
+      <Button
+        type={'primary'}
+        style={{ width: '100%' }}
+        onClick={() => {
+          downLoad(sdkDetail.sdk);
+        }}
+      >
+        jar下载
+      </Button>
+    </div>
+  );
+
+  return (
+    <Row gutter={[16, 16]}>
+      <Col span={24}>
+        <Row gutter={16}>
+          <Col span={12}>
+            <Card title="基本信息">
+              <div style={{ height: defaultHeight }}>
+                <div>
+                  <span style={{ fontWeight: 'bold', fontSize: 16 }}>clientId: </span>
+                  {clientId}
+                </div>
+                <div>
+                  <span style={{ fontWeight: 'bold', fontSize: 16 }}>secureKey: </span>
+                  {secureKey}
+                </div>
+              </div>
+            </Card>
+          </Col>
+          <Col span={12}>
+            <Card title="SDK下载">
+              <div style={{ height: defaultHeight }}>
+                <Popover trigger="click" title={'POM依赖'} content={downLoadJDK}>
+                  <Button> Java </Button>
+                </Popover>
+              </div>
+            </Card>
+          </Col>
+        </Row>
+      </Col>
+      <Col span={24}>
+        <Card title={'API文档'}>
+          <ApiPage type={'authorize'} showDebugger={true} isShowGranted={true} showHome={true} />
+        </Card>
+      </Col>
+    </Row>
+  );
+};

+ 24 - 1
src/pages/home/index.tsx

@@ -4,6 +4,7 @@ import Comprehensive from './comprehensive';
 import Device from './device';
 import Init from './init';
 import Ops from './ops';
+import Api from './Api';
 import Service from './service';
 import { Skeleton } from 'antd';
 
@@ -12,6 +13,7 @@ const Home = () => {
   type ViewType = keyof typeof ViewMap;
   const [current, setCurrent] = useState<ViewType>('init'); // 默认为初始化
   const [loading, setLoading] = useState(true);
+  const [detail, setDetail] = useState<any>({});
 
   const ViewMap = {
     init: <Init changeView={(value: ViewType) => setCurrent(value)} />,
@@ -32,10 +34,31 @@ const Home = () => {
       }
     });
   }, []);
+  useEffect(() => {
+    service.userDetail().then((res) => {
+      if (res.status === 200) {
+        service
+          .apiDetail({
+            terms: [
+              {
+                column: 'userId',
+                value: res.result.id,
+              },
+            ],
+          })
+          .then((response) => {
+            if (response.status === 200) {
+              setDetail(response.result?.data);
+            }
+          });
+      }
+    });
+  }, []);
+
   return (
     <PageContainer>
       <Skeleton loading={loading} active>
-        {ViewMap[current]}
+        {detail && detail.length > 0 ? <Api /> : <>{ViewMap[current]}</>}
       </Skeleton>
     </PageContainer>
   );

+ 9 - 0
src/pages/home/service.ts

@@ -21,6 +21,15 @@ class Service {
       method: 'POST',
       data,
     });
+  userDetail = () =>
+    request(`/${SystemConst.API_BASE}/user/detail`, {
+      method: 'GET',
+    });
+  apiDetail = (data: any) =>
+    request(`/${SystemConst.API_BASE}/api-client/_query`, {
+      method: 'POST',
+      data,
+    });
 }
 
 export default Service;

+ 19 - 14
src/pages/link/Type/Detail/index.tsx

@@ -135,6 +135,9 @@ const Save = observer(() => {
               f.setFieldState('grid.configuration.panel1.layout2.secure', (state) => {
                 state.value = false;
               });
+              f.setFieldState('shareCluster', (state) => {
+                state.value = true;
+              });
             }
             const _host = filterConfigByType(_.cloneDeep(configRef.current), value);
             f.setFieldState('grid.configuration.panel1.layout2.host', (state) => {
@@ -157,17 +160,19 @@ const Save = observer(() => {
           });
           onFieldValueChange('shareCluster', (field, f5) => {
             const value = (field as Field).value;
-            if (value) {
-              // 共享配置
-              f5.setFieldState('grid.configuration.panel1.layout2.host', (state) => {
-                state.value = '0.0.0.0';
-                state.disabled = true;
-              });
-            } else {
-              // 独立配置
-              f5.setFieldState('grid.cluster.cluster', (state) => {
-                state.value = [{}];
-              });
+            if (f5.modified) {
+              if (value) {
+                // 共享配置
+                f5.setFieldState('grid.configuration.panel1.layout2.host', (state) => {
+                  state.value = '0.0.0.0';
+                  state.disabled = true;
+                });
+              } else {
+                // 独立配置
+                f5.setFieldState('grid.cluster.cluster', (state) => {
+                  state.value = [{}];
+                });
+              }
             }
           });
           onFieldValueChange('grid.cluster.cluster.*.layout2.serverId', async (field, f3) => {
@@ -180,8 +185,8 @@ const Save = observer(() => {
           });
           onFieldValueChange('grid.cluster.cluster.*.layout2.host', async (field, f4) => {
             const host = (field as Field).value;
-            const value = (field.query('.serverId').take() as Field).value;
-            const type = (field.query('type').take() as Field).value;
+            const value = (field.query('.serverId').take() as Field)?.value;
+            const type = (field.query('type').take() as Field)?.value;
             const response = await getResourceById(value, type);
             const _ports = response.find((item) => item.host === host);
             f4.setFieldState(field.query('.port').take(), async (state) => {
@@ -212,7 +217,7 @@ const Save = observer(() => {
       if (!_data.shareCluster) {
         _data.cluster = _data.cluster?.map((item: any) => ({ ...item.configuration }));
       }
-      form.setValues(_data);
+      form.setValues({ ..._data });
     });
     return () => {
       subscription.unsubscribe();

+ 2 - 2
src/pages/notice/Config/BindUser/index.tsx

@@ -22,10 +22,10 @@ const BindUser = (props: Props) => {
 
   const getUsers = async (id: string) => {
     const resp = await service.syncUser.noBindUser({
-      pagign: false,
+      paging: false,
       terms: [
         {
-          column: `id$user-third${state.current?.type}_${state.current?.provider}$not`,
+          column: `id$user-third$${state.current?.type}_${state.current?.provider}$not`,
           value: id,
         },
       ],

+ 2 - 0
src/pages/notice/Config/Log/index.tsx

@@ -65,6 +65,8 @@ const Log = observer(() => {
     {
       dataIndex: 'action',
       title: '操作',
+      valueType: 'option',
+      hideInSearch: true,
       render: (text, record) => [
         <a
           onClick={() => {

+ 1 - 0
src/pages/notice/Template/Log/index.tsx

@@ -65,6 +65,7 @@ const Log = observer(() => {
     {
       dataIndex: 'action',
       title: '操作',
+      hideInSearch: true,
       render: (text, record) => [
         <a
           key="info"

+ 1 - 1
src/pages/system/Platforms/Api/base.tsx

@@ -103,7 +103,7 @@ export default observer((props: ApiPageProps) => {
           showHome={props.showHome}
           type={props.type}
           onSelect={(data) => {
-            console.log(data);
+            // console.log(data);
             ApiModel.data = data;
             ApiModel.showTable = true;
           }}

+ 3 - 3
src/pages/system/Platforms/Api/leftTree.tsx

@@ -33,7 +33,7 @@ export default (props: LeftTreeType) => {
   const updateTreeData = useCallback(
     (list: DataNode[], parentItem: any): DataNode[] => {
       let newArray: any[] = list;
-      console.log(list, props.grantKeys);
+      // console.log(list, props.grantKeys);
       if (props.type === 'empowerment') {
         newArray = list.filter(
           (item: any) =>
@@ -102,7 +102,7 @@ export default (props: LeftTreeType) => {
     });
 
     forkJoin(ofArray).subscribe((res) => {
-      console.log(res);
+      // console.log(res);
       setLoading(false);
       setTreeData(extraData ? [extraData, ...res] : res);
     });
@@ -169,7 +169,7 @@ export default (props: LeftTreeType) => {
     }
   }, [props.operations, props.grantKeys, props.type]);
 
-  console.log(treeData);
+  // console.log(treeData);
   return (
     <div
       style={{

+ 17 - 3
src/pages/system/Role/Detail/Permission/Allocate/MenuPermission.tsx

@@ -27,10 +27,14 @@ const MenuPermission = (props: Props) => {
     setIndeterminate(props.value?.check === 2);
     const val =
       (props.value?.assetAccesses || []).filter((i: any) => i?.granted)[0]?.supportId || '';
+    // if (!val && props.value?.check === 1) {
+    //   setCheckValue('creator');
+    // } else {
     setCheckValue(val);
+    // }
   }, [props.value]);
 
-  const checkAllData: any = (data: any[], check: boolean) => {
+  const checkAllData: any = (data: any[], check: boolean, cvalue?: any) => {
     if (Array.isArray(data) && data.length > 0) {
       return data.map((item) => {
         const buttons = (item?.buttons || []).map((i: any) => {
@@ -41,9 +45,15 @@ const MenuPermission = (props: Props) => {
         });
         return {
           ...item,
+          assetAccesses: (item?.assetAccesses || []).map((i: any) => {
+            return {
+              ...i,
+              granted: !cvalue ? false : !i.granted ? i.supportId === cvalue : i.granted,
+            };
+          }),
           check: check ? 1 : 3, // 1: 全选 2: 只选了部分 3: 一个都没选
           buttons: [...buttons],
-          children: item?.children ? checkAllData(item?.children || [], check) : [],
+          children: item?.children ? checkAllData(item?.children || [], check, cvalue) : [],
         };
       });
     }
@@ -100,8 +110,10 @@ const MenuPermission = (props: Props) => {
               }}
               onChange={(e) => {
                 let access: any[] = [];
+                let cvalue: any = checkValue;
                 if (e.target.checked && !checkValue) {
                   setCheckValue('creator');
+                  cvalue = 'creator';
                   access = (value?.assetAccesses || []).map((i: any) => {
                     return {
                       ...i,
@@ -110,6 +122,7 @@ const MenuPermission = (props: Props) => {
                   });
                 } else if (!e.target.checked) {
                   setCheckValue('');
+                  cvalue = '';
                   access = (value?.assetAccesses || []).map((i: any) => {
                     return {
                       ...i,
@@ -117,6 +130,7 @@ const MenuPermission = (props: Props) => {
                     };
                   });
                 } else {
+                  cvalue = checkValue;
                   access = value?.assetAccesses || [];
                 }
                 setCheckAll(e.target.checked);
@@ -132,7 +146,7 @@ const MenuPermission = (props: Props) => {
                   assetAccesses: [...access],
                   check: e.target.checked ? 1 : 3, // 1: 全选 2: 只选了部分 3: 一个都没选
                   buttons: [...buttons],
-                  children: checkAllData(value.children || [], e.target.checked),
+                  children: checkAllData(value.children || [], e.target.checked, cvalue),
                 });
               }}
             >