xieyonghong hace 3 años
padre
commit
0211863181
Se han modificado 52 ficheros con 2250 adiciones y 1628 borrados
  1. 0 0
      public/images/diagnose copy/back.png
  2. 0 0
      public/images/diagnose copy/message-error.png
  3. 0 0
      public/images/diagnose copy/status-error.png
  4. 0 0
      public/images/diagnose copy/status-success-active.png
  5. 0 0
      public/images/diagnose copy/status-success.png
  6. BIN
      public/images/diagnose copy/status/error.png
  7. BIN
      public/images/diagnose copy/status/loading.png
  8. BIN
      public/images/diagnose copy/status/success.png
  9. BIN
      public/images/diagnose copy/status/warning.png
  10. 0 0
      public/images/diagnose copy/waiting.png
  11. BIN
      public/images/diagnose/error.png
  12. BIN
      public/images/diagnose/loading-1.png
  13. BIN
      public/images/diagnose/loading-2.png
  14. BIN
      public/images/diagnose/success.png
  15. 3 0
      src/pages/device/Instance/Detail/Diagnose/Message/index.less
  16. 152 132
      src/pages/device/Instance/Detail/Diagnose/Message/index.tsx
  17. 0 136
      src/pages/device/Instance/Detail/Diagnose/Status/DiagnosticAdvice.tsx
  18. 70 121
      src/pages/device/Instance/Detail/Diagnose/Status/ManualInspection.tsx
  19. 0 7
      src/pages/device/Instance/Detail/Diagnose/Status/index.less
  20. 1195 725
      src/pages/device/Instance/Detail/Diagnose/Status/index.tsx
  21. 324 74
      src/pages/device/Instance/Detail/Diagnose/Status/model.ts
  22. 69 25
      src/pages/device/Instance/Detail/Diagnose/index.less
  23. 106 183
      src/pages/device/Instance/Detail/Diagnose/index.tsx
  24. 87 40
      src/pages/device/Instance/Detail/Parsing/index.tsx
  25. 4 2
      src/pages/device/Instance/Detail/Running/Property/PropertyCard.tsx
  26. 23 13
      src/pages/device/Instance/Detail/Running/Property/index.tsx
  27. 2 1
      src/pages/device/Instance/Detail/index.tsx
  28. 1 1
      src/pages/device/Instance/index.tsx
  29. 10 0
      src/pages/device/Instance/service.ts
  30. 1 0
      src/pages/device/Instance/typings.d.ts
  31. 2 2
      src/pages/device/Product/Detail/Access/index.tsx
  32. 33 84
      src/pages/device/Product/Detail/index.tsx
  33. 1 0
      src/pages/device/Product/Save/index.tsx
  34. 5 0
      src/pages/device/Product/service.ts
  35. 13 9
      src/pages/link/AccessConfig/Detail/Access/index.tsx
  36. 1 1
      src/pages/link/AccessConfig/Detail/Cloud/Finish/index.tsx
  37. 5 0
      src/pages/link/AccessConfig/service.ts
  38. 1 1
      src/pages/link/Type/Detail/index.tsx
  39. 1 1
      src/pages/link/Type/index.tsx
  40. 58 27
      src/pages/media/Device/Save/index.tsx
  41. 33 3
      src/pages/rule-engine/Alarm/Config/index.tsx
  42. 0 1
      src/pages/system/Menu/Detail/index.tsx
  43. 26 26
      src/pages/system/Menu/components/permission.tsx
  44. 1 0
      src/pages/system/Platforms/Api/leftTree.tsx
  45. 3 2
      src/pages/system/Platforms/Home/index.tsx
  46. 3 0
      src/pages/system/Relationship/index.tsx
  47. 6 2
      src/pages/system/Role/Detail/UserManage/BindUser.tsx
  48. 2 3
      src/pages/system/Role/Detail/index.tsx
  49. 3 1
      src/pages/system/Role/index.tsx
  50. 2 3
      src/pages/system/User/index.tsx
  51. 3 1
      src/pages/user/Login/index.less
  52. 1 1
      src/pages/user/Login/index.tsx

public/images/diagnose/back.png → public/images/diagnose copy/back.png


public/images/diagnose/message-error.png → public/images/diagnose copy/message-error.png


public/images/diagnose/status-error.png → public/images/diagnose copy/status-error.png


public/images/diagnose/status-success-active.png → public/images/diagnose copy/status-success-active.png


public/images/diagnose/status-success.png → public/images/diagnose copy/status-success.png


BIN
public/images/diagnose copy/status/error.png


BIN
public/images/diagnose copy/status/loading.png


BIN
public/images/diagnose copy/status/success.png


BIN
public/images/diagnose copy/status/warning.png


public/images/diagnose/waiting.png → public/images/diagnose copy/waiting.png


BIN
public/images/diagnose/error.png


BIN
public/images/diagnose/loading-1.png


BIN
public/images/diagnose/loading-2.png


BIN
public/images/diagnose/success.png


+ 3 - 0
src/pages/device/Instance/Detail/Diagnose/Message/index.less

@@ -1,3 +1,6 @@
+.message-status {
+  padding: 8px 24px;
+}
 .content {
   width: 100%;
 }

+ 152 - 132
src/pages/device/Instance/Detail/Diagnose/Message/index.tsx

@@ -1,8 +1,8 @@
 import TitleComponent from '@/components/TitleComponent';
 import './index.less';
 import Dialog from './Dialog';
-import { Button, Col, DatePicker, Empty, Input, InputNumber, Row, Select } from 'antd';
-import { useEffect, useState } from 'react';
+import { Badge, Button, Col, DatePicker, Empty, Input, InputNumber, Row, Select } from 'antd';
+import { useEffect, useMemo, useState } from 'react';
 import { InstanceModel, service } from '@/pages/device/Instance';
 import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
 import { map } from 'rxjs/operators';
@@ -20,19 +20,13 @@ import {
 } from '@formily/antd';
 import { randomString } from '@/utils/util';
 import Log from './Log';
-import { Store } from 'jetlinks-store';
-
-interface Props {
-  onChange: (type: string) => void;
-}
+import { DiagnoseStatusModel, messageStatusMap, messageStyleMap } from '../Status/model';
+import { observer } from '@formily/reactive-react';
 
 const DatePicker1: any = DatePicker;
 
-const Message = (props: Props) => {
+const Message = observer(() => {
   const [subscribeTopic] = useSendWebsocketMessage();
-  const [dialogList, setDialogList] = useState<any[]>([]);
-  const [tempList, setTempList] = useState<any[]>([]);
-  const [logList, setLogList] = useState<any[]>([]);
   const [type, setType] = useState<'property' | 'function'>('function');
   const [input, setInput] = useState<any>({});
   const [inputs, setInputs] = useState<any[]>([]);
@@ -50,17 +44,19 @@ const Message = (props: Props) => {
       ?.pipe(map((res) => res.payload))
       .subscribe((payload: any) => {
         if (payload.type === 'log') {
-          logList.push({
-            key: randomString(),
-            ...payload,
-          });
-          setLogList([...logList]);
+          DiagnoseStatusModel.logList = [
+            ...DiagnoseStatusModel.logList,
+            {
+              key: randomString(),
+              ...payload,
+            },
+          ];
         } else {
-          tempList.push({
-            key: randomString(),
-            ...payload,
-          });
-          const flag = [...tempList]
+          DiagnoseStatusModel.allDialogList = [
+            ...DiagnoseStatusModel.logList,
+            { key: randomString(), ...payload },
+          ];
+          const flag = [...DiagnoseStatusModel.allDialogList]
             .filter(
               (i) =>
                 i.traceId === payload.traceId &&
@@ -69,21 +65,26 @@ const Message = (props: Props) => {
             .every((item) => {
               return !item.error;
             });
-          if (!flag) {
-            props.onChange(!payload.upstream ? 'down-error' : 'up-error');
+          if (!payload.upstream) {
+            DiagnoseStatusModel.message.down = {
+              text: !flag ? '下行消息通信异常' : '下行消息通信正常',
+              status: !flag ? 'error' : 'success',
+            };
           } else {
-            props.onChange(!payload.upstream ? 'down-success' : 'up-success');
+            DiagnoseStatusModel.message.up = {
+              text: !flag ? '上行消息通信异常' : '上行消息通信正常',
+              status: !flag ? 'error' : 'success',
+            };
           }
-          setTempList([...tempList]);
-          Store.set('temp', tempList);
-          const t = dialogList.find(
+          const list = [...DiagnoseStatusModel.dialogList];
+          const t = list.find(
             (item) =>
               item.traceId === payload.traceId &&
               payload.downstream === item.downstream &&
               payload.upstream === item.upstream,
           );
           if (t) {
-            dialogList.map((item) => {
+            list.map((item) => {
               if (item.key === payload.traceId) {
                 item.list.push({
                   key: randomString(),
@@ -92,7 +93,7 @@ const Message = (props: Props) => {
               }
             });
           } else {
-            dialogList.push({
+            list.push({
               key: randomString(),
               traceId: payload.traceId,
               downstream: payload.downstream,
@@ -105,8 +106,7 @@ const Message = (props: Props) => {
               ],
             });
           }
-          setDialogList([...dialogList]);
-          Store.set('diagnose', dialogList);
+          DiagnoseStatusModel.dialogList = [...list];
         }
         const chatBox = document.getElementById('dialog');
         if (chatBox) {
@@ -166,44 +166,46 @@ const Message = (props: Props) => {
     }
   };
   useEffect(() => {
-    subscribeLog();
-    const arr = Store.get('diagnose') || [];
-    setDialogList(arr);
-    const temp = Store.get('temp') || [];
-    setTempList(temp);
-  }, []);
+    if (DiagnoseStatusModel.state === 'success') {
+      subscribeLog();
+    }
+  }, [DiagnoseStatusModel.state]);
 
-  const form = createForm({
-    initialValues: {
-      data: [...inputs],
-    },
-    effects() {
-      onFieldReact('data.*.valueType.type', (field) => {
-        const value = (field as Field).value;
-        const format = field.query('..value').take() as any;
-        if (format) {
-          switch (value) {
-            case 'date':
-              format.setComponent(FDatePicker);
-              break;
-            case 'boolean':
-              format.setComponent(FSelect);
-              format.setDataSource([
-                { label: '是', value: true },
-                { label: '否', value: false },
-              ]);
-              break;
-            case 'int':
-              format.setComponent(NumberPicker);
-              break;
-            default:
-              format.setComponent(FInput);
-              break;
-          }
-        }
-      });
-    },
-  });
+  const form = useMemo(
+    () =>
+      createForm({
+        initialValues: {
+          data: [...inputs],
+        },
+        effects() {
+          onFieldReact('data.*.valueType.type', (field) => {
+            const value = (field as Field).value;
+            const format = field.query('..value').take() as any;
+            if (format) {
+              switch (value) {
+                case 'date':
+                  format.setComponent(FDatePicker);
+                  break;
+                case 'boolean':
+                  format.setComponent(FSelect);
+                  format.setDataSource([
+                    { label: '是', value: true },
+                    { label: '否', value: false },
+                  ]);
+                  break;
+                case 'int':
+                  format.setComponent(NumberPicker);
+                  break;
+                default:
+                  format.setComponent(FInput);
+                  break;
+              }
+            }
+          });
+        },
+      }),
+    [],
+  );
 
   const dataRender = () => {
     switch (type) {
@@ -352,69 +354,87 @@ const Message = (props: Props) => {
   return (
     <Row gutter={24}>
       <Col span={16}>
-        <TitleComponent data="调试" />
-        <div className="content">
-          <div className="dialog" id="dialog">
-            {dialogList.map((item) => (
-              <Dialog data={item} key={item.key} />
-            ))}
+        <div>
+          <div style={{ marginBottom: 20 }}>
+            <Row gutter={24}>
+              {Object.keys(DiagnoseStatusModel.message).map((key) => {
+                const obj = DiagnoseStatusModel.message[key];
+                return (
+                  <Col key={key} span={12}>
+                    <div style={messageStyleMap.get(obj.status)} className="message-status">
+                      <Badge status={messageStatusMap.get(obj.status)} />
+                      {obj.text}
+                    </div>
+                  </Col>
+                );
+              })}
+            </Row>
           </div>
-        </div>
-        <div className="function">
-          <Row gutter={24}>
-            <Col span={5}>
-              <Select
-                value={type}
-                placeholder="请选择"
-                style={{ width: '100%' }}
-                onChange={(value) => {
-                  setType(value);
-                  setInputs([]);
-                  setInput({});
-                }}
-              >
-                <Select.Option value="function">调用功能</Select.Option>
-                <Select.Option value="property">操作属性</Select.Option>
-              </Select>
-            </Col>
-            {dataRender()}
-            <Col span={3}>
-              <Button
-                type="primary"
-                onClick={async () => {
-                  props.onChange('waiting');
-                  if (type === 'function') {
-                    const list = (form?.values?.data || []).filter((it) => !!it.value);
-                    const obj = {};
-                    list.map((it) => {
-                      obj[it.id] = it.value;
-                    });
-                    await service.executeFunctions(InstanceModel.detail?.id || '', input.id, {
-                      ...obj,
-                    });
-                  } else {
-                    if (propertyType === 'read') {
-                      await service.readProperties(InstanceModel.detail?.id || '', [property]);
-                    } else {
-                      await service.settingProperties(InstanceModel.detail?.id || '', {
-                        [property]: propertyValue,
-                      });
-                    }
-                  }
-                }}
-              >
-                发送
-              </Button>
-            </Col>
-          </Row>
-          {inputs.length > 0 && (
-            <div className="parameter">
-              <h4>功能参数</h4>
-              <FormProvider form={form}>
-                <SchemaField schema={schema} />
-              </FormProvider>
+          <div>
+            <TitleComponent data="调试" />
+            <div className="content">
+              <div className="dialog" id="dialog">
+                {DiagnoseStatusModel.dialogList.map((item) => (
+                  <Dialog data={item} key={item.key} />
+                ))}
+              </div>
             </div>
-          )}
+            <div className="function">
+              <Row gutter={24}>
+                <Col span={5}>
+                  <Select
+                    value={type}
+                    placeholder="请选择"
+                    style={{ width: '100%' }}
+                    onChange={(value) => {
+                      setType(value);
+                      setInputs([]);
+                      setInput({});
+                    }}
+                  >
+                    <Select.Option value="function">调用功能</Select.Option>
+                    <Select.Option value="property">操作属性</Select.Option>
+                  </Select>
+                </Col>
+                {dataRender()}
+                <Col span={3}>
+                  <Button
+                    type="primary"
+                    onClick={async () => {
+                      if (type === 'function') {
+                        const list = (form?.values?.data || []).filter((it) => !!it.value);
+                        const obj = {};
+                        list.map((it) => {
+                          obj[it.id] = it.value;
+                        });
+                        await service.executeFunctions(InstanceModel.detail?.id || '', input.id, {
+                          ...obj,
+                        });
+                      } else {
+                        if (propertyType === 'read') {
+                          await service.readProperties(InstanceModel.detail?.id || '', [property]);
+                        } else {
+                          await service.settingProperties(InstanceModel.detail?.id || '', {
+                            [property]: propertyValue,
+                          });
+                        }
+                      }
+                    }}
+                  >
+                    发送
+                  </Button>
+                </Col>
+              </Row>
+              {inputs.length > 0 && (
+                <div className="parameter">
+                  <h4>功能参数</h4>
+                  <FormProvider form={form}>
+                    <SchemaField schema={schema} />
+                  </FormProvider>
+                </div>
+              )}
+            </div>
+          </div>
         </div>
       </Col>
       <Col span={8}>
@@ -430,8 +450,8 @@ const Message = (props: Props) => {
         >
           <TitleComponent data={'日志'} />
           <div style={{ marginTop: 10 }}>
-            {logList.length > 0 ? (
-              logList.map((item) => <Log data={item} key={item.key} />)
+            {DiagnoseStatusModel.logList.length > 0 ? (
+              DiagnoseStatusModel.logList.map((item) => <Log data={item} key={item.key} />)
             ) : (
               <Empty />
             )}
@@ -440,6 +460,6 @@ const Message = (props: Props) => {
       </Col>
     </Row>
   );
-};
+});
 
 export default Message;

+ 0 - 136
src/pages/device/Instance/Detail/Diagnose/Status/DiagnosticAdvice.tsx

@@ -1,136 +0,0 @@
-import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
-import { InfoCircleOutlined } from '@ant-design/icons';
-import { Badge, Modal } from 'antd';
-import styles from './index.less';
-
-interface Props {
-  close: () => void;
-  data: any;
-}
-
-const DiagnosticAdvice = (props: Props) => {
-  const { data } = props;
-  const nameMap = new Map();
-  nameMap.set('mqtt-client-gateway', 'topic');
-  nameMap.set('websocket-server', 'URL');
-  nameMap.set('http-server-gateway', 'URL');
-  nameMap.set('coap-server-gateway', 'URL');
-  nameMap.set('udp-device-gateway', '地址');
-  nameMap.set('tcp-server-gateway', '地址');
-
-  const jumpUrl = () => {
-    const url = getMenuPathByParams(MENUS_CODE['device/Product/Detail'], data.id);
-    const tab: any = window.open(`${origin}/#${url}?key=access`);
-    tab!.onTabSaveSuccess = (value: any) => {
-      if (value) {
-        props.close();
-      }
-    };
-  };
-
-  return (
-    <Modal
-      title="诊断建议"
-      onCancel={() => {
-        props.close();
-      }}
-      onOk={() => {
-        props.close();
-      }}
-      width={700}
-      visible
-    >
-      <div className={styles.advice}>
-        <div className={styles.alert}>
-          <InfoCircleOutlined style={{ marginRight: 10 }} />
-          所有诊断均无异常但设备任未上线,请检查以下内容
-        </div>
-        {(data?.product || []).map((item: any) => (
-          <div className={styles.infoItem} key={item.name}>
-            <Badge
-              status="default"
-              text={
-                <span>
-                  产品-{item.name}规则可能有加密处理,请认真查看
-                  <a
-                    onClick={() => {
-                      jumpUrl();
-                    }}
-                  >
-                    设备接入配置
-                  </a>
-                  中【消息协议】说明
-                </span>
-              }
-            />
-          </div>
-        ))}
-        {(data?.device || []).map((item: any) => (
-          <div className={styles.infoItem} key={item.name}>
-            <Badge
-              status="default"
-              text={
-                <span>
-                  设备-{item.name}规则可能有加密处理,请认真查看
-                  <a
-                    onClick={() => {
-                      jumpUrl();
-                    }}
-                  >
-                    设备接入配置
-                  </a>
-                  中【消息协议】说明
-                </span>
-              }
-            />
-          </div>
-        ))}
-        {!!data?.provider && (
-          <div>
-            {data.routes.length > 0 ? (
-              <div className={styles.infoItem}>
-                <Badge
-                  status="default"
-                  text={
-                    <span>
-                      请根据
-                      <a
-                        onClick={() => {
-                          jumpUrl();
-                        }}
-                      >
-                        设备接入配置
-                      </a>
-                      中{nameMap.get(data.provider)}
-                      信息,任意上报一条数据(无设备接入配置查看权限时:请联系管理员根据设备接入配置中
-                      {URL}信息,任意上报一条数据)。 变量说明:{nameMap.get(data.provider)}
-                      变量根据网关详情中provider类型判断。
-                    </span>
-                  }
-                />
-              </div>
-            ) : (
-              <div className={styles.infoItem}>
-                <Badge
-                  status="default"
-                  text={
-                    <span>
-                      请联系管理员提供{nameMap.get(data.provider)}
-                      信息,并根据URL信息任意上报一条数据 变量说明:{nameMap.get(data.provider)}
-                      变量根据网关详情中provider类型判断。
-                    </span>
-                  }
-                />
-              </div>
-            )}
-          </div>
-        )}
-        <div className={styles.infoItem}>
-          <Badge status="default" text={'请检查设备是否已开机'} />
-        </div>
-      </div>
-    </Modal>
-  );
-};
-
-export default DiagnosticAdvice;

+ 70 - 121
src/pages/device/Instance/Detail/Diagnose/Status/ManualInspection.tsx

@@ -1,99 +1,23 @@
-import { createForm } from '@formily/core';
-import { createSchemaField } from '@formily/react';
-import type { ISchema } from '@formily/json-schema';
-import { Form, FormGrid, FormItem, Input, Password, PreviewText } from '@formily/antd';
-import { Modal } from 'antd';
+import { Button, Descriptions, Modal } from 'antd';
 import styles from './index.less';
 import { InfoCircleOutlined } from '@ant-design/icons';
-
-const componentMap = {
-  string: 'Input',
-  password: 'Password',
-};
-
+import { useHistory } from 'umi';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { InstanceModel } from '@/pages/device/Instance';
 interface Props {
   close: () => void;
   data: any;
-  ok: (data: any) => void;
+  save: (data: any) => void;
 }
 
 const ManualInspection = (props: Props) => {
   const { data } = props;
 
-  const form = createForm({
-    validateFirst: true,
-    initialValues: {},
-  });
-
-  const SchemaField = createSchemaField({
-    components: {
-      FormItem,
-      Input,
-      Password,
-      FormGrid,
-      PreviewText,
-    },
-  });
-
-  const configToSchema = (list: any[]) => {
-    const config = {};
-    list.forEach((item) => {
-      config[item.property] = {
-        type: 'string',
-        title: item.name,
-        require: true,
-        'x-decorator': 'FormItem',
-        'x-component': componentMap[item.type.type],
-        'x-decorator-props': {
-          tooltip: item.description,
-        },
-        'x-component-props': {
-          value: '',
-          placeholder: `请输入${item.name}`,
-        },
-      };
-    });
-    return config;
-  };
-
-  const renderConfigCard = () => {
-    const itemSchema: ISchema = {
-      type: 'object',
-      properties: {
-        grid: {
-          type: 'void',
-          'x-component': 'FormGrid',
-          'x-component-props': {
-            minColumns: [1],
-            maxColumns: [1],
-          },
-          properties: configToSchema(data?.data?.properties),
-        },
-      },
-    };
+  const history = useHistory<Record<string, string>>();
 
-    return (
-      <>
-        <PreviewText.Placeholder value="-">
-          <Form form={form} layout="vertical">
-            <SchemaField schema={itemSchema} />
-          </Form>
-        </PreviewText.Placeholder>
-      </>
-    );
+  const okBtn = () => {
+    props.save(data);
   };
-  const renderComponent = () => (
-    <div style={{ backgroundColor: '#f6f6f6', padding: 10 }}>
-      {(data?.data?.properties || []).map((item: any) => (
-        <div key={item?.property}>
-          <span>{item?.name}</span>:{' '}
-          <span>
-            {data?.check && data?.check[item?.property] ? data?.check[item?.property] : '--'}
-          </span>
-        </div>
-      ))}
-    </div>
-  );
 
   return (
     <Modal
@@ -101,47 +25,72 @@ const ManualInspection = (props: Props) => {
       onCancel={() => {
         props.close();
       }}
-      width={600}
-      onOk={async () => {
-        const values = (await form.submit()) as any;
-        if (!data?.check) {
-          props.ok({
-            status: 'error',
-            data: data,
-          });
-        } else {
-          let flag = true;
-          Object.keys(values).forEach((key) => {
-            if (values[key] !== data?.check[key]) {
-              flag = false;
+      width={800}
+      footer={[
+        <Button
+          key="back"
+          onClick={() => {
+            if (data.type === 'device') {
+              InstanceModel.active = 'detail';
+            } else {
+              history.push(
+                `${getMenuPathByParams(MENUS_CODE['device/Product/Detail'], data.productId)}`,
+                {
+                  tab: 'access',
+                },
+              );
             }
-          });
-          if (flag) {
-            props.ok({
-              status: 'success',
-              data: data,
-            });
-          } else {
-            props.ok({
-              status: 'error',
-              data: data,
-            });
-          }
-        }
-      }}
+            props.close();
+          }}
+        >
+          去修改
+        </Button>,
+        <Button
+          key="submit"
+          onClick={() => {
+            okBtn();
+          }}
+        >
+          确认无误
+        </Button>,
+      ]}
       visible
     >
-      <div className={styles.alert}>
-        <InfoCircleOutlined style={{ marginRight: 10 }} />
-        {data.type === 'product'
-          ? `当前填写的数据将与产品-设备接入配置中的${data.data.name}数据进行比对`
-          : `当前填写的数据将与设备-实例信息配置中的${data.data.name}数据进行比对`}
-      </div>
-      <div style={{ marginTop: 10 }}>
-        已配置参数
-        {renderComponent()}
+      <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' }}>
+            <h4>诊断项说明</h4>
+            <p>{data?.data?.description}</p>
+          </div>
+        ) : (
+          ''
+        )}
       </div>
-      <div style={{ marginTop: 10 }}>{renderConfigCard()}</div>
     </Modal>
   );
 };

+ 0 - 7
src/pages/device/Instance/Detail/Diagnose/Status/index.less

@@ -88,10 +88,3 @@
   line-height: 40px;
   background-color: #f6f6f6;
 }
-
-.advice {
-  .infoItem {
-    width: 100%;
-    margin: 10px;
-  }
-}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1195 - 725
src/pages/device/Instance/Detail/Diagnose/Status/index.tsx


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

@@ -1,92 +1,342 @@
+import type { ProductItem } from '@/pages/device/Product/typings';
 import { model } from '@formily/reactive';
 import type { ReactNode } from 'react';
 
-type StatusProps = {
-  status: 'loading' | 'error' | 'success' | 'warning';
-  text: string;
-  info: null | ReactNode;
-};
+export const StatusMap = new Map();
+StatusMap.set('error', require('/public/images/diagnose/status/error.png'));
+StatusMap.set('success', require('/public/images/diagnose/status/success.png'));
+StatusMap.set('warning', require('/public/images/diagnose/status/warning.png'));
+StatusMap.set('loading', require('/public/images/diagnose/status/loading.png'));
 
-type ListProps = {
+export type ListProps = {
   key: string;
   name: string;
-  data: string;
-  desc: string;
+  desc?: string;
+  status: 'loading' | 'error' | 'success' | 'warning';
+  text?: string;
+  info?: ReactNode;
 };
 
+export const list = [
+  { key: 'status', text: '连接状态' },
+  { key: 'message', text: '消息通信' },
+];
+
+export const textColorMap = new Map();
+textColorMap.set('loading', 'black');
+textColorMap.set('error', 'red');
+textColorMap.set('success', 'green');
+textColorMap.set('warning', 'red');
+
+export const networkInitList: ListProps[] = [
+  // {
+  //   key: 'access',
+  //   name: '设备接入配置',
+  //   desc: '诊断该设备所属产品是否已配置“设备接入”方式,未配置将导致设备连接失败。',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
+  {
+    key: 'network',
+    name: '网络组件',
+    desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'gateway',
+    name: '设备接入网关',
+    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'product',
+    name: '产品状态',
+    desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'device',
+    name: '设备状态',
+    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+];
+
+export const childInitList: ListProps[] = [
+  // {
+  //   key: 'access',
+  //   name: '设备接入配置',
+  //   desc: '诊断该设备所属产品是否已配置“设备接入”方式,未配置将导致设备连接失败。',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
+  {
+    key: 'network',
+    name: '网络组件',
+    desc: '诊断网络组件配置是否正确,配置错误将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'gateway',
+    name: '设备接入网关',
+    desc: '诊断设备接入网关状态是否正常,网关配置是否正确',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'parent-device',
+    name: '网关父设备',
+    desc: '诊断网关父设备状态是否正常,禁用或离线将导致连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'product',
+    name: '产品状态',
+    desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'device',
+    name: '设备状态',
+    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+];
+
+export const cloudInitList: ListProps[] = [
+  // {
+  //   key: 'access',
+  //   name: '设备接入配置',
+  //   desc: '诊断该设备所属产品是否已配置“设备接入”方式,未配置将导致设备连接失败。',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
+  {
+    key: 'gateway',
+    name: '设备接入网关',
+    desc: '诊断设备接入网关状态是否正常,网关配置是否正确',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'product',
+    name: '产品状态',
+    desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'device',
+    name: '设备状态',
+    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+];
+
+export const channelInitList: ListProps[] = [
+  // {
+  //   key: 'access',
+  //   name: '设备接入配置',
+  //   desc: '诊断该设备所属产品是否已配置“设备接入”方式,未配置将导致设备连接失败。',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
+  {
+    key: 'gateway',
+    name: '设备接入网关',
+    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'product',
+    name: '产品状态',
+    desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'device',
+    name: '设备状态',
+    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+];
+
+export const mediaInitList: ListProps[] = [
+  // {
+  //   key: 'access',
+  //   name: '设备接入配置',
+  //   desc: '诊断该设备所属产品是否已配置“设备接入”方式,未配置将导致设备连接失败。',
+  //   status: 'loading',
+  //   text: '正在诊断中...',
+  //   info: null,
+  // },
+  {
+    key: 'gateway',
+    name: '设备接入网关',
+    desc: '诊断设备接入网关状态是否正常,禁用状态将导致连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'product',
+    name: '产品状态',
+    desc: '诊断产品状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+  {
+    key: 'device',
+    name: '设备状态',
+    desc: '诊断设备状态是否正常,禁用状态将导致设备连接失败',
+    status: 'loading',
+    text: '正在诊断中...',
+    info: null,
+  },
+];
+
 export const DiagnoseStatusModel = model<{
-  status: {
-    config?: StatusProps;
-    network?: StatusProps;
-    product?: StatusProps;
-    device?: StatusProps;
-    productAuth?: StatusProps;
-    deviceAuth?: StatusProps;
-    deviceAccess?: StatusProps;
-    other?: StatusProps;
-  };
   list: ListProps[];
-  model: boolean;
+  product: Partial<ProductItem>;
   gateway: any;
+  configuration: {
+    product: any[];
+    device: any[];
+  };
+  percent: number;
+  state: 'loading' | 'success' | 'error'; // 上面的状态
+  status: 'loading' | 'finish'; // 检验是否完成检验过程
+  count: number;
+  logList: any[];
+  dialogList: any[];
+  allDialogList: any[];
+  message: {
+    up: {
+      text: string;
+      status: 'loading' | 'success' | 'error';
+    };
+    down: {
+      text: string;
+      status: 'loading' | 'success' | 'error';
+    };
+  };
 }>({
-  status: {
-    config: {
-      status: 'loading',
-      text: '正在诊断中...',
-      info: null,
-    },
-    network: {
-      status: 'loading',
-      text: '正在诊断中...',
-      info: null,
-    },
-    product: {
-      status: 'loading',
-      text: '正在诊断中...',
-      info: null,
-    },
-    device: {
-      status: 'loading',
-      text: '正在诊断中...',
-      info: null,
-    },
-    deviceAccess: {
+  list: [],
+  product: {},
+  gateway: {},
+  configuration: {
+    product: [],
+    device: [],
+  },
+  state: 'loading',
+  status: 'loading',
+  percent: 0,
+  count: 0,
+  logList: [],
+  dialogList: [],
+  allDialogList: [],
+  message: {
+    up: {
+      text: '上行消息诊断中',
       status: 'loading',
-      text: '正在诊断中...',
-      info: null,
     },
-    other: {
+    down: {
+      text: '下行消息诊断中',
       status: 'loading',
-      text: '正在诊断中...',
-      info: null,
     },
   },
-  list: [
-    {
-      key: 'config',
-      name: '设备接入配置',
-      data: 'config',
-      desc: '诊断设备接入配置是否正确,配置错误将导致连接失败',
-    },
-    {
-      key: 'network',
-      name: '网络信息',
-      data: 'network',
-      desc: '诊断网络组件配置是否正确,配置错误将导致连接失败',
-    },
-    {
-      key: 'product',
-      name: '产品状态',
-      data: 'product',
-      desc: '诊断产品状态是否已发布,未发布的状态将导致连接失败',
-    },
-    {
-      key: 'device',
-      name: '设备状态',
-      data: 'device',
-      desc: '诊断设备状态是否已启用,未启用的状态将导致连接失败',
-    },
-  ],
-  model: true,
-  gateway: {},
 });
+
+export const gatewayList = [
+  'websocket-server',
+  'http-server-gateway',
+  'udp-device-gateway',
+  'coap-server-gateway',
+  'mqtt-client-gateway',
+  'tcp-server-gateway',
+];
+
+export const headerColorMap = new Map();
+headerColorMap.set('loading', 'linear-gradient(89.95deg, #E6F5FF 0.03%, #E9EAFF 99.95%)');
+headerColorMap.set(
+  'error',
+  'linear-gradient(89.95deg, rgba(231, 173, 86, 0.1) 0.03%, rgba(247, 111, 93, 0.1) 99.95%)',
+);
+headerColorMap.set('success', 'linear-gradient(89.95deg, #E8F8F7 0.03%, #EBEFFA 99.95%)');
+
+export const headerTextMap = new Map();
+headerTextMap.set('loading', '正在诊断中');
+headerTextMap.set('error', '发现连接问题');
+headerTextMap.set('success', '连接状态正常');
+
+export const headerDescMap = new Map();
+headerDescMap.set('loading', '已诊断XX个');
+headerDescMap.set('error', '请处理连接异常');
+headerDescMap.set('success', '现在可调试消息通信');
+
+export const headerImgMap = new Map();
+headerImgMap.set('loading', require('/public/images/diagnose/loading-2.png'));
+headerImgMap.set('error', require('/public/images/diagnose/error.png'));
+headerImgMap.set('success', require('/public/images/diagnose/success.png'));
+
+export const progressMap = new Map();
+progressMap.set('loading', '#597EF7');
+progressMap.set('error', '#FAB247');
+progressMap.set('success', '#32D4A4');
+
+export const messageStyleMap = new Map();
+messageStyleMap.set('loading', {
+  background: 'linear-gradient(0deg, rgba(30, 165, 241, 0.03), rgba(30, 165, 241, 0.03)), #FFFFFF',
+  boxShadow: '-2px 0px 0px #1EA5F1',
+});
+messageStyleMap.set('error', {
+  background: 'linear-gradient(0deg, rgba(255, 77, 79, 0.03), rgba(255, 77, 79, 0.03)), #FFFFFF',
+  boxShadow: '-2px 0px 0px #FF4D4F',
+});
+messageStyleMap.set('success', {
+  background: 'linear-gradient(0deg, rgba(50, 212, 164, 0.03), rgba(50, 212, 164, 0.03)), #FFFFFF',
+  boxShadow: '-2px 0px 0px #32D4A4',
+});
+
+export const messageStatusMap = new Map();
+messageStatusMap.set('loading', 'processing');
+messageStatusMap.set('error', 'error');
+messageStatusMap.set('success', 'success');
+
+export const urlMap = new Map();
+urlMap.set('mqtt-client-gateway', 'topic');
+urlMap.set('http-server-gateway', 'url');
+urlMap.set('websocket-server', 'url');
+urlMap.set('coap-server-gateway', 'url');

+ 69 - 25
src/pages/device/Instance/Detail/Diagnose/index.less

@@ -1,40 +1,84 @@
 .diagnose {
-  .header {
+  .diagnose-header {
+    position: relative;
     width: 100%;
-  }
+    height: 150px;
+    margin-bottom: 20px;
+    padding: 15px 25px;
 
-  .header-message {
-    width: 100%;
-    background: url('/images/diagnose/back.png') no-repeat;
-    background-size: 100% 100%;
+    .diagnose-top {
+      display: flex;
+      width: 100%;
+
+      .diagnose-img {
+        width: 65px;
+        height: 65px;
+        margin-right: 20px;
+      }
+
+      .diagnose-text {
+        .diagnose-title {
+          color: #000c;
+          font-weight: 700;
+          font-size: 25px;
+        }
+
+        .diagnose-desc {
+          color: rgba(0, 0, 0, 0.65);
+          font-size: 14px;
+        }
+      }
+    }
+
+    .diagnose-progress {
+      width: 100%;
+    }
+
+    .diagnose-radio {
+      position: absolute;
+      bottom: 0;
+      display: flex;
+
+      .diagnose-radio-item {
+        width: 150px;
+        height: 35px;
+        margin-right: 8px;
+        color: #00000073;
+        line-height: 35px;
+        text-align: center;
+        background: #f2f2f2;
+        border-radius: 2px 2px 0 0;
+        cursor: pointer;
+        &.disabled {
+          cursor: not-allowed;
+        }
+      }
+    }
   }
+}
 
-  .container {
-    margin-top: 20px;
+.diagnose-loading {
+  animation: diagnose-loading 2s linear infinite;
+}
+
+@keyframes diagnose-loading {
+  0% {
+    transform: rotate(0deg);
   }
 
-  .item-box {
-    width: 100%;
-    padding: 10px;
-    background-repeat: no-repeat;
-    background-size: 100% 100%;
-    cursor: pointer;
+  25% {
+    transform: rotate(90deg);
   }
 
-  .item-title {
-    font-weight: 700;
-    font-size: 14px;
+  50% {
+    transform: rotate(180deg);
   }
 
-  .item-context {
-    height: 40px;
-    font-weight: 700;
-    font-size: 24px;
+  75% {
+    transform: rotate(270deg);
   }
 
-  .item-message {
-    color: rgba(0, 0, 0, 0.85);
-    font-weight: 400;
-    font-size: 14px;
+  100% {
+    transform: rotate(360deg);
   }
 }

+ 106 - 183
src/pages/device/Instance/Detail/Diagnose/index.tsx

@@ -1,208 +1,131 @@
-import { Badge, Card, Col, Row, Tooltip } from 'antd';
-import type { ReactNode } from 'react';
+import { Card, Progress } from 'antd';
 import { useEffect, useState } from 'react';
 import Message from './Message';
 import Status from './Status';
 import './index.less';
-import classNames from 'classnames';
-import { Store } from 'jetlinks-store';
-import { DiagnoseStatusModel } from './Status/model';
 import { useDomFullHeight } from '@/hooks';
+import { InstanceModel } from '@/pages/device/Instance';
+import { observer } from '@formily/reactive-react';
+import {
+  DiagnoseStatusModel,
+  headerColorMap,
+  headerDescMap,
+  headerImgMap,
+  headerTextMap,
+  list,
+  progressMap,
+} from './Status/model';
+import classNames from 'classnames';
 
-interface ListProps {
-  key: string;
-  tab: string;
-  component: ReactNode;
-}
-
-const bImageMap = new Map();
-bImageMap.set('m-error', require('/public/images/diagnose/message-error.png'));
-bImageMap.set('s-error', require('/public/images/diagnose/status-error.png'));
-bImageMap.set('s-success-active', require('/public/images/diagnose/status-success-active.png'));
-bImageMap.set('s-success', require('/public/images/diagnose/status-success.png'));
-bImageMap.set('waiting', require('/public/images/diagnose/waiting.png'));
-
-const statusColor = new Map();
-statusColor.set('m-error', '#E50012');
-statusColor.set('s-error', '#E50012');
-statusColor.set('error', '#E50012');
-statusColor.set('s-success-active', '#24B276');
-statusColor.set('s-success', '#24B276');
-statusColor.set('success', '#24B276');
-statusColor.set('waiting', '#FF9000');
-statusColor.set('disabled', 'rgba(0, 0, 0, .8)');
-
-const statusText = new Map();
-statusText.set('s-error', '连接失败');
-statusText.set('s-success-active', '连接成功');
-statusText.set('s-success', '连接成功');
-statusText.set('waiting', '诊断中');
-statusText.set('disabled', '诊断中');
-
-const Diagnose = () => {
+const Diagnose = observer(() => {
+  const { minHeight } = useDomFullHeight(`.diagnose`, 12);
   const [current, setCurrent] = useState<string>('status');
-  const [status, setStatus] = useState<string>('waiting');
-  const [message, setMessage] = useState<string>('waiting');
-  const [active, setActive] = useState<boolean>(false);
+  const [providerType, setProviderType] = useState<
+    'network' | 'child-device' | 'media' | 'cloud' | 'channel'
+  >('network');
 
-  const [up, setUp] = useState<'success' | 'error' | 'waiting'>('waiting');
-  const [down, setDown] = useState<'success' | 'error' | 'waiting'>('waiting');
-
-  const { minHeight } = useDomFullHeight(`.diagnose`, 12);
+  const ViewMap = {
+    status: <Status providerType={providerType} />,
+    message: <Message />,
+  };
 
-  const list = [
-    {
-      key: 'status',
-      tab: '连接状态',
-      component: (
-        <div
-          style={{ backgroundImage: `url(${bImageMap.get(status)}`, backgroundSize: '100% 100%' }}
-          className="item-box"
-        >
-          <div className="item-title">连接状态</div>
-          <div style={{ color: statusColor.get(status) }} className="item-context">
-            <Badge color={statusColor.get(status)} /> {statusText.get(status)}
-          </div>
-        </div>
-      ),
-    },
-    {
-      key: 'message',
-      tab: '消息通信',
-      component: (
-        <div
-          style={
-            message !== 'disabled'
-              ? {
-                  backgroundImage: `url(${bImageMap.get(message)})`,
-                  backgroundSize: '100% 100%',
-                }
-              : {
-                  backgroundColor: 'rgba(0, 0, 0, .08)',
-                  borderLeft: '2px solid rgba(0, 0, 0, .8)',
-                  cursor: 'not-allowed',
-                }
-          }
-          className="item-box"
-        >
-          <div className="item-title">消息通信</div>
-          <div
-            className={classNames('item-context', message !== 'disabled' ? 'item-message' : '')}
-            style={{ fontWeight: 400 }}
-          >
-            {message === 'disabled' ? (
-              <Tooltip title={'设备未上线时消息通信功不能使用'}>
-                <span style={{ color: statusColor.get(message) }}>
-                  <Badge color={statusColor.get(message)} />
-                  {status === 's-error' || status === 'waiting' ? '等待设备连接' : '连接中'}
-                </span>
-              </Tooltip>
-            ) : (
-              <>
-                <div>
-                  <Badge
-                    color={statusColor.get(up)}
-                    text={
-                      up === 'waiting'
-                        ? `上行消息通信诊断中`
-                        : `上行消息通信${up === 'error' ? '异常' : '正常'}`
-                    }
-                  />
-                </div>
-                <div>
-                  <Badge
-                    color={statusColor.get(down)}
-                    text={
-                      down === 'waiting'
-                        ? `下行消息通信诊断中`
-                        : `下行消息通信${down === 'error' ? '异常' : '正常'}`
-                    }
-                  />
-                </div>
-              </>
-            )}
-          </div>
-        </div>
-      ),
-    },
-  ];
   useEffect(() => {
+    setCurrent('status');
+    const provider = InstanceModel.detail?.accessProvider;
+    if (provider === 'fixed-media' || provider === 'gb28181-2016') {
+      setProviderType('media');
+    } else if (provider === 'OneNet' || provider === 'Ctwing') {
+      setProviderType('media');
+    } else if (provider === 'modbus-tcp' || provider === 'opc-ua') {
+      setProviderType('channel');
+    } else if (provider === 'child-device') {
+      setProviderType('child-device');
+    } else {
+      setProviderType('network');
+    }
+    DiagnoseStatusModel.state = 'loading';
+
     return () => {
-      Store.set('diagnose', []);
-      Store.set('diagnose-status', []);
-      DiagnoseStatusModel.model = true;
+      DiagnoseStatusModel.list = [];
+      DiagnoseStatusModel.count = 0;
     };
   }, []);
+
+  const activeStyle = {
+    background: '#FFFFFF',
+    border: '1px solid rgba(0, 0, 0, 0.09)',
+    borderRadius: '2px 2px 0px 0px',
+    color: '#000000BF',
+  };
+
   return (
     <Card className="diagnose" style={{ minHeight }}>
-      <div className={current === 'message' ? 'header-message' : 'header'}>
-        <Row gutter={24} style={{ padding: 10, width: '100%' }}>
-          {list.map((item: ListProps) => (
-            <Col
-              span={8}
-              key={item.key}
+      <div
+        className="diagnose-header"
+        style={{
+          background: headerColorMap.get(DiagnoseStatusModel.state),
+        }}
+      >
+        <div className="diagnose-top">
+          <div className="diagnose-img">
+            {DiagnoseStatusModel.state === 'loading' ? (
+              <div style={{ height: '100%', width: '100%', position: 'relative' }}>
+                <img
+                  style={{ height: '100%', position: 'absolute', zIndex: 2 }}
+                  src={headerImgMap.get(DiagnoseStatusModel.state)}
+                />
+                <img
+                  src={require('/public/images/diagnose/loading-1.png')}
+                  className={'diagnose-loading'}
+                  style={{ height: '100%' }}
+                />
+              </div>
+            ) : (
+              <img style={{ height: '100%' }} src={headerImgMap.get(DiagnoseStatusModel.state)} />
+            )}
+          </div>
+          <div className="diagnose-text">
+            <div className="diagnose-title">{headerTextMap.get(DiagnoseStatusModel.state)}</div>
+            <div className="diagnose-desc">
+              {DiagnoseStatusModel.state !== 'loading'
+                ? headerDescMap.get(DiagnoseStatusModel.state)
+                : `已诊断${DiagnoseStatusModel.count}个`}
+            </div>
+          </div>
+        </div>
+        <div className="diagnose-progress">
+          <Progress
+            strokeColor={progressMap.get(DiagnoseStatusModel.state)}
+            showInfo={false}
+            style={{ width: '100%' }}
+            size="small"
+            percent={DiagnoseStatusModel.percent}
+          />
+        </div>
+        <div className="diagnose-radio">
+          {list.map((i) => (
+            <div
+              key={i.key}
+              className={classNames(
+                'diagnose-radio-item',
+                i.key === 'message' && DiagnoseStatusModel.state !== 'success' ? 'disabled' : '',
+              )}
+              style={current === i.key ? { ...activeStyle } : {}}
               onClick={() => {
-                if (current === item.key) {
-                  return;
-                }
-                if (item.key === 'message' && status === 's-success-active') {
-                  setCurrent(item.key);
-                  setMessage('waiting');
-                }
-                if (item.key === 'status') {
-                  setActive(true);
-                  setCurrent(item.key);
+                if (DiagnoseStatusModel.state === 'success') {
+                  setCurrent(i.key);
                 }
               }}
             >
-              {item.component}
-            </Col>
+              {i.text}
+              {current === i.key ? '(诊断中)' : ''}
+            </div>
           ))}
-        </Row>
-      </div>
-      <div className="container">
-        {current === 'status' ? (
-          <Status
-            flag={active}
-            onChange={(type: string) => {
-              if (type === 'success') {
-                setStatus('s-success-active');
-                setMessage('waiting');
-              } else if (type === 'error') {
-                setStatus('s-error');
-                setMessage('disabled');
-              } else if (type === 'loading') {
-                setStatus('waiting');
-                setMessage('disabled');
-              }
-            }}
-          />
-        ) : (
-          <Message
-            onChange={(data: string) => {
-              if (data === 'waiting') {
-                setMessage('waiting');
-                setDown('waiting');
-                setUp('waiting');
-              } else if (data === 'down-error') {
-                setMessage('m-error');
-                setDown('error');
-              } else if (data === 'down-success') {
-                setMessage('s-success-active');
-                setDown('success');
-              } else if (data === 'up-success') {
-                setMessage('s-success-active');
-                setUp('success');
-              } else if (data === 'up-error') {
-                setMessage('m-error');
-                setUp('error');
-              }
-            }}
-          />
-        )}
+        </div>
       </div>
+      <div>{ViewMap[current]}</div>
     </Card>
   );
-};
+});
 
 export default Diagnose;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 87 - 40
src/pages/device/Instance/Detail/Parsing/index.tsx


+ 4 - 2
src/pages/device/Instance/Detail/Running/Property/PropertyCard.tsx

@@ -41,7 +41,7 @@ const Property = (props: Props) => {
   const [visible, setVisible] = useState<boolean>(false);
   const [editVisible, setEditVisible] = useState<boolean>(false);
   const [indicatorVisible, setIndicatorVisible] = useState<boolean>(false);
-  const [dataValue, setDataValue] = useState<any>(null);
+  const [dataValue, setDataValue] = useState<any>(value);
 
   const renderTitle = (title: string) => {
     return (
@@ -107,7 +107,9 @@ const Property = (props: Props) => {
           <div style={{ marginTop: 10 }}>
             <div style={{ color: 'rgba(0, 0, 0, .65)', fontSize: 12 }}>更新时间</div>
             <div style={{ marginTop: 5, fontSize: 16, color: 'black' }} className="value">
-              {value?.timestamp ? moment(value?.timestamp).format('YYYY-MM-DD HH:mm:ss') : ''}
+              {dataValue?.timestamp
+                ? moment(dataValue?.timestamp).format('YYYY-MM-DD HH:mm:ss')
+                : ''}
             </div>
           </div>
         </div>

+ 23 - 13
src/pages/device/Instance/Detail/Running/Property/index.tsx

@@ -53,6 +53,8 @@ const Property = (props: Props) => {
   const [indicatorVisible, setIndicatorVisible] = useState<boolean>(false);
   const [loading, setLoading] = useState<boolean>(true);
 
+  const [loading1, setLoading1] = useState<boolean>(true); // 使valueChange里面能拿到最新的propertyValue
+
   const [check, setCheck] = useState<boolean>(true);
 
   const refreshProperty = async (id: string) => {
@@ -147,19 +149,21 @@ const Property = (props: Props) => {
 
   const subRef = useRef<any>(null);
 
-  const valueChange = (payload: any) => {
-    (payload || [])
-      .sort((a: any, b: any) => a.timestamp - b.timestamp)
-      .forEach((item: any) => {
-        const { value } = item;
-        propertyValue[value?.property] = { ...item, ...value };
-      });
-    setPropertyValue({ ...propertyValue });
-    list.current = [];
-  };
+  const valueChange = useCallback(
+    (payload: any) => {
+      (payload || [])
+        .sort((a: any, b: any) => a.timestamp - b.timestamp)
+        .forEach((item: any) => {
+          const { value } = item;
+          propertyValue[value?.property] = { ...item, ...value };
+        });
+      setPropertyValue({ ...propertyValue });
+      list.current = [];
+    },
+    [propertyValue],
+  );
 
-  // eslint-disable-next-line react-hooks/exhaustive-deps
-  const throttleFn = useCallback(throttle(valueChange, 500), []);
+  const throttleFn = throttle(valueChange, 500);
 
   /**
    * 订阅属性数据
@@ -219,15 +223,21 @@ const Property = (props: Props) => {
             });
           setPropertyValue({ ...propertyValue, ...obj });
         }
+        setLoading1(false);
         setLoading(false);
       },
     });
   };
 
   useEffect(() => {
+    if (!loading1) {
+      subscribeProperty();
+    }
+  }, [loading1]);
+
+  useEffect(() => {
     if (dataSource.data.length > 0) {
       getDashboard();
-      subscribeProperty();
     } else {
       setLoading(false);
     }

+ 2 - 1
src/pages/device/Instance/Detail/index.tsx

@@ -177,7 +177,8 @@ const InstanceDetail = observer(() => {
           component: <MetadataMap type="device" />,
         });
       }
-      if (response.result.transport === 'MQTT' || response.result.transport === 'HTTP') {
+      const paring = response.result?.features?.find((item: any) => item.id === 'transparentCodec');
+      if (paring) {
         datalist.push({
           key: 'parsing',
           tab: intl.formatMessage({

+ 1 - 1
src/pages/device/Instance/index.tsx

@@ -285,7 +285,7 @@ const Instance = () => {
       filterMultiple: false,
     },
     {
-      dataIndex: 'categoryId',
+      dataIndex: 'classifiedId',
       title: '产品分类',
       valueType: 'treeSelect',
       hideInTable: true,

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

@@ -336,6 +336,16 @@ class Service extends BaseService<DeviceInstance> {
     request(`/${SystemConst.API_BASE}/protocol/${id}/transport/${transport}`, {
       method: 'GET',
     });
+  //删除设备解析规则
+  public delDeviceCode = (productId: string, deviceId: string) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}/${deviceId}`, {
+      method: 'DELETE',
+    });
+  //删除产品解析规则
+  public delProductCode = (productId: string) =>
+    request(`/${SystemConst.API_BASE}/device/transparent-codec/${productId}`, {
+      method: 'DELETE',
+    });
 }
 
 export default Service;

+ 1 - 0
src/pages/device/Instance/typings.d.ts

@@ -43,6 +43,7 @@ export type DeviceInstance = {
   accessProvider?: string;
   accessId?: string;
   features?: any[];
+  parentId?: string;
 };
 
 type Unit = {

+ 2 - 2
src/pages/device/Product/Detail/Access/index.tsx

@@ -35,7 +35,7 @@ const Access = () => {
   const [visible, setVisible] = useState<boolean>(true);
   const [config, setConfig] = useState<any>();
   const [access, setAccess] = useState<any>();
-  const { permission } = usePermissions('link/AccessConfig');
+  const { permission } = usePermissions('device/Product');
   const [dataSource, setDataSource] = useState<any[]>([]);
 
   const MetworkTypeMapping = new Map();
@@ -360,7 +360,7 @@ const Access = () => {
         <div style={{ padding: '100px 0' }}>
           <Empty
             description={
-              permission.add ? (
+              permission.update ? (
                 <span>
                   请先
                   <Button

+ 33 - 84
src/pages/device/Product/Detail/index.tsx

@@ -154,7 +154,29 @@ const ProductDetail = observer(() => {
   };
 
   useEffect(() => {
-    console.log(productModel.current);
+    if (productModel.current?.messageProtocol) {
+      service.getProtocolDetail(productModel.current?.messageProtocol).then((res) => {
+        if (res.status === 200) {
+          const paring = res.result?.transports[0]?.features?.find(
+            (item: any) => item.id === 'transparentCodec',
+          );
+          // console.log(paring)
+          if (paring) {
+            setList([
+              ...initList,
+              {
+                key: 'parsing',
+                tab: intl.formatMessage({
+                  id: 'pages.device.instanceDetail.parsing',
+                  defaultMessage: '数据解析',
+                }),
+                component: <Parsing tag="product" data={productModel.current} />,
+              },
+            ]);
+          }
+        }
+      });
+    }
     if (
       productModel.current?.accessProvider &&
       pList.includes(productModel.current?.accessProvider)
@@ -170,22 +192,6 @@ const ProductDetail = observer(() => {
     } else {
       setList([...initList]);
     }
-    if (
-      productModel.current?.transportProtocol === 'MQTT' ||
-      productModel.current?.transportProtocol === 'HTTP'
-    ) {
-      setList([
-        ...initList,
-        {
-          key: 'parsing',
-          tab: intl.formatMessage({
-            id: 'pages.device.instanceDetail.parsing',
-            defaultMessage: '数据解析',
-          }),
-          component: <Parsing tag="product" data={productModel.current} />,
-        },
-      ]);
-    }
   }, [productModel.current]);
 
   useEffect(() => {
@@ -276,6 +282,7 @@ const ProductDetail = observer(() => {
       extraContent={<Space size={24} />}
       onTabChange={(key) => {
         setMode(key);
+        // console.log(key)
       }}
       tabList={list}
       tabActiveKey={mode}
@@ -373,73 +380,15 @@ const ProductDetail = observer(() => {
         </PermissionButton>,
       ]}
     >
-      <Card className={'product-detail-body'} style={{ minHeight }}>
-        {list.find((k) => k.key === mode)?.component}
-        {/* <Tabs
-          defaultActiveKey={ModelEnum.base}
-          activeKey={mode}
-          onChange={(key) => {
-            setMode(key);
-          }}
-        >
-          <Tabs.TabPane
-            tab={intl.formatMessage({
-              id: 'pages.device.productDetail.base',
-              defaultMessage: '配置信息',
-            })}
-            key={ModelEnum.base}
-          >
-            <BaseInfo />
-          </Tabs.TabPane>
-          <Tabs.TabPane
-            tab={
-              <>
-                {intl.formatMessage({
-                  id: 'pages.device.productDetail.metadata',
-                  defaultMessage: '物模型',
-                })}
-                <Tooltip
-                  placement="right"
-                  title={
-                    <div>
-                      <p>
-                        属性:
-                        <br />
-                        用于描述设备运行时具体信息和状态。
-                        例如,环境监测设备所读取的当前环境温度、智能灯开关状态、电风扇风力等级等。
-                      </p>
-                      功能:
-                      <br />
-                      <p>
-                        指设备可供外部调用的指令或方法。功能调用中可设置输入和输出参数。输入参数是服务执行时的参数,输出参数是服务执行后的结果。
-                        相比于属性,功能可通过一条指令实现更复杂的业务逻辑,例如执行某项特定的任务。
-                        功能分为异步和同步两种调用方式。
-                      </p>
-                      <p> 事件:</p>
-                      <p>
-                        设备运行时,主动上报给云端的信息,一般包含需要被外部感知和处理的信息、告警和故障。事件中可包含多个输出参数。
-                        例如,某项任务完成后的通知信息;设备发生故障时的温度、时间信息;设备告警时的运行状态等。
-                      </p>
-                      <p> 标签:</p>
-                      <p>
-                        统一为设备添加拓展字段,添加后将在设备信息页显示。可用于对设备基本信息描述的补充。
-                      </p>
-                    </div>
-                  }
-                >
-                  <QuestionCircleOutlined style={{ marginLeft: '5px' }} />
-                </Tooltip>
-              </>
-            }
-            key={ModelEnum.metadata}
-          >
-            <Metadata type="product" />
-          </Tabs.TabPane>
-          <Tabs.TabPane tab={'设备接入'} key={ModelEnum.access}>
-            <Access />
-          </Tabs.TabPane>
-        </Tabs> */}
-      </Card>
+      {mode == 'parsing' ? (
+        <>{list.find((k) => k.key === mode)?.component}</>
+      ) : (
+        <>
+          <Card className={'product-detail-body'} style={{ minHeight }}>
+            {list.find((k) => k.key === mode)?.component}
+          </Card>
+        </>
+      )}
     </PageContainer>
   );
 });

+ 1 - 0
src/pages/device/Product/Save/index.tsx

@@ -275,6 +275,7 @@ const Save = (props: Props) => {
             <Form.Item label={'分类'} name={'classifiedId'}>
               <TreeSelect
                 showSearch
+                allowClear
                 onSelect={(_: any, node: any) => {
                   form.setFieldsValue({
                     classifiedName: node.name,

+ 5 - 0
src/pages/device/Product/service.ts

@@ -159,6 +159,11 @@ class Service extends BaseService<ProductItem> {
         paging: false,
       },
     });
+  //获取协议详情
+  public getProtocolDetail = (id: string) =>
+    request(`/${SystemConst.API_BASE}/protocol/${id}/detail`, {
+      method: 'POST',
+    });
 }
 
 export default Service;

+ 13 - 9
src/pages/link/AccessConfig/Detail/Access/index.tsx

@@ -101,13 +101,21 @@ const Access = (props: Props) => {
       if (!procotolCurrent) {
         onlyMessage('请选择消息协议!', 'error');
       } else {
-        service
-          .getConfigView(procotolCurrent, ProcotoleMapping.get(props.provider?.id))
-          .then((resp) => {
+        if (props.provider?.channel !== 'child-device') {
+          service
+            .getConfigView(procotolCurrent, ProcotoleMapping.get(props.provider?.id))
+            .then((resp) => {
+              if (resp.status === 200) {
+                setConfig(resp.result);
+              }
+            });
+        } else {
+          service.getChildConfigView(procotolCurrent).then((resp) => {
             if (resp.status === 200) {
               setConfig(resp.result);
             }
           });
+        }
         setCurrent(current + 1);
       }
     }
@@ -440,13 +448,9 @@ const Access = (props: Props) => {
                         borderColor:
                           procotolCurrent === item.id ? 'var(--ant-primary-color-active)' : '',
                       }}
-                      hoverable={!props.data.id}
+                      hoverable
                       onClick={() => {
-                        if (!props.data.id) {
-                          setProcotolCurrent(item.id);
-                        } else {
-                          onlyMessage('消息协议不可修改', 'warning');
-                        }
+                        setProcotolCurrent(item.id);
                       }}
                     >
                       <div style={{ height: '45px' }}>

+ 1 - 1
src/pages/link/AccessConfig/Detail/Cloud/Finish/index.tsx

@@ -122,7 +122,7 @@ const Finish = (props: Props) => {
               </p>
             ) : (
               <p>
-                3、添加设备,为每一台设备设置唯一的IMEI、SN、PSK码(需与CTWingt平台中填写的值一致,若CTWing平台没有对应的设备,将会通
+                3、添加设备,为每一台设备设置唯一的IMEI、SN、PSK码(需与CTWingt平台中填写的值一致,若CTWing平台没有对应的设备,将会通过CTWing平台提供的LWM2M协议自动创建)
               </p>
             )}
           </div>

+ 5 - 0
src/pages/link/AccessConfig/service.ts

@@ -37,6 +37,11 @@ class Service extends BaseService<AccessItem> {
       params,
     });
   };
+  public getChildConfigView = (id: string) => {
+    return request(`/${SystemConst.API_BASE}/protocol/${id}/transports`, {
+      method: 'GET',
+    });
+  };
   public getConfigView = (id: string, transport: string) =>
     request(`/${SystemConst.API_BASE}/protocol/${id}/transport/${transport}`, {
       method: 'GET',

+ 1 - 1
src/pages/link/Type/Detail/index.tsx

@@ -822,7 +822,7 @@ const Save = observer(() => {
 
   const { getOtherPermission } = usePermissions('link/Type');
   return (
-    <PageContainer className={'page-title-show'} onBack={() => history.back()}>
+    <PageContainer>
       <Card>
         <Form form={form} layout="vertical" style={{ padding: 30 }}>
           <SchemaField

+ 1 - 1
src/pages/link/Type/index.tsx

@@ -330,7 +330,7 @@ const Network = () => {
               </PermissionButton>,
               <PermissionButton
                 type="link"
-                key="other-delete"
+                key="delete"
                 style={{ padding: 0 }}
                 isPermission={networkPermission.delete}
                 disabled={record.state.value === 'enabled'}

+ 58 - 27
src/pages/media/Device/Save/index.tsx

@@ -68,6 +68,12 @@ const Save = () => {
     const formData = await form.validateFields();
     if (formData) {
       const { provider, ...extraFormData } = formData;
+      if (formData.password === oldPassword) {
+        delete extraFormData.password;
+      }
+      if (formData.id === '') {
+        delete extraFormData.id;
+      }
       // if (formData.password === oldPassword) {
       //   delete extraFormData.password;
       // }
@@ -163,30 +169,55 @@ const Save = () => {
                     </Form.Item>
                   </Col>
                   <Col span={16}>
-                    <Form.Item
-                      label={'ID'}
-                      name={'id'}
-                      required
-                      rules={[
-                        { required: true, message: '请输入ID' },
-                        {
-                          pattern: /^[a-zA-Z0-9_\-]+$/,
-                          message: intl.formatMessage({
-                            id: 'pages.form.tip.id',
-                            defaultMessage: '请输入英文或者数字或者-或者_',
-                          }),
-                        },
-                        {
-                          max: 64,
-                          message: intl.formatMessage({
-                            id: 'pages.form.tip.max64',
-                            defaultMessage: '最多输入64个字符',
-                          }),
-                        },
-                      ]}
-                    >
-                      <Input placeholder={'请输入ID'} disabled={!!id} />
-                    </Form.Item>
+                    {accessType === DefaultAccessType ? (
+                      <Form.Item
+                        label={'ID'}
+                        name={'id'}
+                        rules={[
+                          { required: true, message: '请输入ID' },
+                          {
+                            pattern: /^[a-zA-Z0-9_\-]+$/,
+                            message: intl.formatMessage({
+                              id: 'pages.form.tip.id',
+                              defaultMessage: '请输入英文或者数字或者-或者_',
+                            }),
+                          },
+                          {
+                            max: 64,
+                            message: intl.formatMessage({
+                              id: 'pages.form.tip.max64',
+                              defaultMessage: '最多输入64个字符',
+                            }),
+                          },
+                        ]}
+                      >
+                        <Input placeholder={'请输入ID'} disabled={!!id} />
+                      </Form.Item>
+                    ) : (
+                      <Form.Item
+                        label={'ID'}
+                        name={'id'}
+                        rules={[
+                          {
+                            pattern: /^[a-zA-Z0-9_\-]+$/,
+                            message: intl.formatMessage({
+                              id: 'pages.form.tip.id',
+                              defaultMessage: '请输入英文或者数字或者-或者_',
+                            }),
+                          },
+                          {
+                            max: 64,
+                            message: intl.formatMessage({
+                              id: 'pages.form.tip.max64',
+                              defaultMessage: '最多输入64个字符',
+                            }),
+                          },
+                        ]}
+                      >
+                        <Input placeholder={'请输入ID'} disabled={!!id} />
+                      </Form.Item>
+                    )}
+
                     <Form.Item
                       label={'设备名称'}
                       name={'name'}
@@ -357,7 +388,7 @@ const Save = () => {
                   <h1>2.配置说明</h1>
                   <h1>平台端配置</h1>
                   <h2>1、ID</h2>
-                  <div>设备唯一标识,若不填写,系统将自动生成唯一标识</div>
+                  <div>设备唯一标识,请填写设备端配置的设备编号。</div>
                   <h2>2、所属产品</h2>
                   <div>
                     只能选择接入方式为GB/T28281的产品,若当前无对应产品,可点击右侧快速添加按钮,填写产品名称和选择GB/T28181类型的网关完成产品创建
@@ -402,8 +433,8 @@ const Save = () => {
                 <div className={styles.doc} style={{ height: 600 }}>
                   <h1>1.概述</h1>
                   <div>视频设备通过RTSP、RTMP固定地址接入平台分为2步。</div>
-                  <div>1.添加视频设备</div>
-                  <div>2.添加视频下的通道地址。</div>
+                  <div>1添加视频设备</div>
+                  <div>2添加视频下的通道地址。</div>
                   <div>注:当前页面为新增视频设备,新增完成后点击设备的“通道”按钮,添加通道。</div>
                   <h1>2.配置说明</h1>
                   <h2>1、ID</h2>

+ 33 - 3
src/pages/rule-engine/Alarm/Config/index.tsx

@@ -266,7 +266,7 @@ const Config = () => {
     },
   };
 
-  const ioSchema: ISchema = {
+  const outputSchema: ISchema = {
     type: 'object',
     properties: {
       id: {
@@ -333,6 +333,36 @@ const Config = () => {
     },
   };
 
+  const inputSchema: ISchema = {
+    type: 'object',
+    properties: {
+      id: {
+        'x-component': 'Input',
+        'x-hidden': true,
+      },
+      address: {
+        title: 'kafka地址',
+        type: 'string',
+        required: true,
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-component-props': {
+          placeholder: '请输入kafka地址',
+        },
+      },
+      topic: {
+        title: 'topic',
+        type: 'string',
+        required: true,
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-component-props': {
+          placeholder: '请输入topic',
+        },
+      },
+    },
+  };
+
   const handleSaveIO = async () => {
     outputForm.validate();
     inputForm.validate();
@@ -443,7 +473,7 @@ const Config = () => {
               }
             />
             <Form form={outputForm} layout="vertical">
-              <SchemaField schema={ioSchema} />
+              <SchemaField schema={outputSchema} />
             </Form>
             <Divider />
             <TitleComponent
@@ -457,7 +487,7 @@ const Config = () => {
               }
             />
             <Form form={inputForm} layout="vertical">
-              <SchemaField schema={ioSchema} />
+              <SchemaField schema={inputSchema} />
               <FormButtonGroup.Sticky>
                 <FormButtonGroup.FormItem>
                   <Button type="primary" onClick={handleSaveIO}>

+ 0 - 1
src/pages/system/Menu/Detail/index.tsx

@@ -47,7 +47,6 @@ export default () => {
 
   return (
     <PageContainer
-      className={'page-title-show'}
       tabList={[
         {
           tab: intl.formatMessage({

+ 26 - 26
src/pages/system/Menu/components/permission.tsx

@@ -3,7 +3,7 @@ import { Checkbox } from 'antd';
 import './permission.less';
 import type { CheckboxChangeEvent } from 'antd/es/checkbox';
 import type { PermissionInfo } from '../typing';
-import { useIntl } from 'umi';
+// import { useIntl } from 'umi';
 
 type PermissionDataType = {
   action: string;
@@ -121,11 +121,11 @@ const ParentNode = (props: ParentNodeType) => {
 };
 
 export default (props: PermissionType) => {
-  const [indeterminate, setIndeterminate] = useState(false);
-  const [checkAll, setCheckAll] = useState(false);
+  // const [indeterminate, setIndeterminate] = useState(false);
+  // const [checkAll, setCheckAll] = useState(false);
   const [nodes, setNodes] = useState<React.ReactNode>([]);
   const checkListRef = useRef<CheckItem[]>([]);
-  const intl = useIntl();
+  // const intl = useIntl();
 
   const onChange = (list: CheckItem[]) => {
     if (props.onChange) {
@@ -143,22 +143,22 @@ export default (props: PermissionType) => {
    * 全选或者全部取消
    * @param e
    */
-  const onChangeAll = (e: CheckboxChangeEvent) => {
-    const _list = props.data.map((item) => {
-      return {
-        ...item,
-        actions: item.actions.map((a) => ({ ...a, checked: e.target.checked })),
-        state: false,
-        checked: e.target.checked,
-      };
-    });
-    setIndeterminate(false);
-    setCheckAll(e.target.checked);
-    // setCheckedList(_list)
-    checkListRef.current = _list;
-    onChange(_list);
-    setNodes(createContentNode(_list));
-  };
+  // const onChangeAll = (e: CheckboxChangeEvent) => {
+  //   const _list = props.data.map((item) => {
+  //     return {
+  //       ...item,
+  //       actions: item.actions.map((a) => ({ ...a, checked: e.target.checked })),
+  //       state: false,
+  //       checked: e.target.checked,
+  //     };
+  //   });
+  //   setIndeterminate(false);
+  //   setCheckAll(e.target.checked);
+  //   // setCheckedList(_list)
+  //   checkListRef.current = _list;
+  //   onChange(_list);
+  //   setNodes(createContentNode(_list));
+  // };
 
   const parentChange = (value: ParentNodeChange) => {
     let indeterminateCount = 0;
@@ -187,10 +187,10 @@ export default (props: PermissionType) => {
       };
     });
     // 如果全部选中,则取消半选状态
-    const isIndeterminate =
-      _checkAll === list.length && _checkAll !== 0 ? false : !!indeterminateCount;
-    setIndeterminate(isIndeterminate);
-    setCheckAll(_checkAll === list.length && _checkAll !== 0);
+    // const isIndeterminate =
+    //   _checkAll === list.length && _checkAll !== 0 ? false : !!indeterminateCount;
+    // setIndeterminate(isIndeterminate);
+    // setCheckAll(_checkAll === list.length && _checkAll !== 0);
     // setCheckedList(list)
     checkListRef.current = list;
     onChange(list);
@@ -258,7 +258,7 @@ export default (props: PermissionType) => {
         <span>权限操作</span>
       </div>
       <div className="permission-content">
-        <div className="permission-items">
+        {/* <div className="permission-items">
           <div className="permission-parent">
             <Checkbox
               onChange={onChangeAll}
@@ -272,7 +272,7 @@ export default (props: PermissionType) => {
               })}
             </Checkbox>
           </div>
-        </div>
+        </div> */}
         {nodes}
       </div>
     </div>

+ 1 - 0
src/pages/system/Platforms/Api/leftTree.tsx

@@ -156,6 +156,7 @@ export default (props: LeftTreeType) => {
       showIcon
       showLine={{ showLeafIcon: false }}
       height={700}
+      style={{ minWidth: 145 }}
       fieldNames={{
         title: 'name',
         key: 'id',

+ 3 - 2
src/pages/system/Platforms/Home/index.tsx

@@ -91,6 +91,7 @@ const Home = () => {
             <Table
               dataSource={data}
               pagination={false}
+              size="small"
               columns={[
                 {
                   title: '示例数据类型',
@@ -117,7 +118,7 @@ const Home = () => {
         <div>
           <h3>服务器验签流程</h3>
           <div>
-            <img src={require('/public/images/apiHome.png')} />
+            <img src={require('/public/images/apiHome.png')} style={{ width: '80%' }} />
           </div>
         </div>
         <div style={{ width: 400 }}>
@@ -126,7 +127,7 @@ const Home = () => {
             <p>使用和签名相同的算法(不需要对响应结果排序)</p>
             <div>
               <MonacoEditor
-                width={400}
+                width={'100%'}
                 height={744}
                 theme="vs"
                 language={'java'}

+ 3 - 0
src/pages/system/Relationship/index.tsx

@@ -10,6 +10,7 @@ import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
 import Save from './Save';
 import { useDomFullHeight } from '@/hooks';
 import { onlyMessage } from '@/utils/util';
+import { message } from 'antd';
 
 export const service = new Service('relation');
 
@@ -85,6 +86,8 @@ const Relationship = () => {
                   }),
                 );
                 actionRef.current?.reload();
+              } else {
+                message.error(resp.message);
               }
             },
           }}

+ 6 - 2
src/pages/system/Role/Detail/UserManage/BindUser.tsx

@@ -119,10 +119,14 @@ const BindUser = (props: Props) => {
             ],
           });
           return {
-            result: { data: response.result.data },
+            result: {
+              data: response.result.data,
+              pageSize: response.result.pageSize,
+              pageIndex: response.result.pageIndex,
+              total: response.result.total,
+            },
             success: true,
             status: 200,
-            total: response.result.total,
           } as any;
         }}
         columns={columns}

+ 2 - 3
src/pages/system/Role/Detail/index.tsx

@@ -1,7 +1,6 @@
 import { observer } from '@formily/react';
 import { PageContainer } from '@ant-design/pro-layout';
 import { useState } from 'react';
-import { history } from 'umi';
 import UserManage from '@/pages/system/Role/Detail/UserManage';
 import Permission from '@/pages/system/Role/Detail/Permission';
 import { useIntl } from '@@/plugin-locale/localeExports';
@@ -31,8 +30,8 @@ const RoleEdit = observer(() => {
 
   return (
     <PageContainer
-      className={'page-title-show'}
-      onBack={history.goBack}
+      // className={'page-title-show'}
+      // onBack={history.goBack}
       tabList={list}
       onTabChange={setTab}
     >

+ 3 - 1
src/pages/system/Role/index.tsx

@@ -197,14 +197,16 @@ const Role: React.FC = observer(() => {
       CurdModel.add();
     }
     const subscription = Store.subscribe(SystemConst.BASE_UPDATE_DATA, (data) => {
-      console.log('订阅数据');
       if ((window as any).onTabSaveSuccess) {
         (window as any).onTabSaveSuccess(data);
         setTimeout(() => window.close(), 300);
+      } else {
+        history.push(`${getMenuPathByParams(MENUS_CODE['system/Role/Detail'], data.id)}`);
       }
     });
     return () => subscription.unsubscribe();
   }, []);
+
   return (
     <PageContainer>
       <BaseCrud<RoleItem>

+ 2 - 3
src/pages/system/User/index.tsx

@@ -9,14 +9,13 @@ import {
   EditOutlined,
   PlayCircleOutlined,
   PlusOutlined,
-  SafetyOutlined,
   StopOutlined,
 } from '@ant-design/icons';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { useRef, useState } from 'react';
 import Save from './Save';
 import { observer } from '@formily/react';
-import { PermissionButton } from '@/components';
+import { AIcon, PermissionButton } from '@/components';
 import usePermissions from '@/hooks/permission';
 import ResetPassword from '@/pages/system/User/ResetPassword';
 import { useDomFullHeight } from '@/hooks';
@@ -192,7 +191,7 @@ const User = observer(() => {
           }}
           isPermission={userPermission.update}
         >
-          <SafetyOutlined />
+          <AIcon type={'icon-zhongzhimima'} />
         </PermissionButton>,
         <PermissionButton
           type="link"

+ 3 - 1
src/pages/user/Login/index.less

@@ -82,8 +82,10 @@
               margin: auto;
               font-size: 16px;
             }
+            .ant-formily-item-size-large .ant-formily-item-help {
+              text-align: left;
+            }
           }
-
           .icon {
             margin-left: 16px;
             color: rgba(0, 0, 0, 0.2);

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

@@ -107,7 +107,7 @@ const Login: React.FC = () => {
       },
       password: {
         type: 'string',
-        'x-validator': { required: true, message: '请输入用户名!' },
+        'x-validator': { required: true, message: '请输入密码!' },
         'x-decorator': 'FormItem',
         'x-component': 'Password',
         'x-component-props': {