소스 검색

fix: bug#10264、10420、10476、10913

XieYongHong 2 년 전
부모
커밋
40176878eb
37개의 변경된 파일391개의 추가작업 그리고 198개의 파일을 삭제
  1. 2 2
      docker/build.sh
  2. 1 0
      package.json
  3. 2 2
      src/components/FRuleEditor/Advance/index.tsx
  4. 6 4
      src/components/FRuleEditor/Editor/index.tsx
  5. 5 3
      src/components/FRuleEditor/index.tsx
  6. 41 0
      src/components/FRuleEditor/util.ts
  7. 2 1
      src/components/FUpload/index.tsx
  8. 6 6
      src/components/ProTableCard/CardItems/Scene/index.tsx
  9. 22 16
      src/hooks/document/useDomFullHeight.tsx
  10. 48 6
      src/pages/DataCollect/Collector/components/Point/Save/modbus.tsx
  11. 7 4
      src/pages/Northbound/DuerOS/Detail/index.tsx
  12. 1 1
      src/pages/device/Category/index.tsx
  13. 1 0
      src/pages/device/Firmware/Save/index.tsx
  14. 138 85
      src/pages/device/Instance/Detail/EdgeMap/mapTable/index.tsx
  15. 1 1
      src/pages/device/Instance/Detail/Functions/form.tsx
  16. 4 4
      src/pages/device/Instance/Detail/Functions/index.tsx
  17. 8 13
      src/pages/device/Instance/Detail/Info/index.tsx
  18. 1 1
      src/pages/link/AccessConfig/Detail/Access/index.tsx
  19. 7 4
      src/pages/link/AccessConfig/Detail/components/Protocol/index.tsx
  20. 3 0
      src/pages/link/DashBoard/index.tsx
  21. 3 3
      src/pages/notice/Config/SyncUser/index.tsx
  22. 2 2
      src/pages/notice/Config/service.ts
  23. 16 8
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/TypeModel.tsx
  24. 1 1
      src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/index.tsx
  25. 2 2
      src/pages/rule-engine/Scene/Save/action/index.tsx
  26. 5 6
      src/pages/rule-engine/Scene/Save/terms/index.tsx
  27. 1 2
      src/pages/system/Apply/Api/base.tsx
  28. 1 1
      src/pages/system/Apply/index.tsx
  29. 3 2
      src/pages/system/DataSource/Management/DataTable.tsx
  30. 4 3
      src/pages/system/DataSource/Management/EditTable.tsx
  31. 0 1
      src/pages/system/DataSource/Management/index.less
  32. 4 3
      src/pages/system/DataSource/Management/index.tsx
  33. 16 4
      src/pages/system/Department/Assets/deivce/bind.tsx
  34. 9 2
      src/pages/system/Department/Assets/product/bind.tsx
  35. 1 1
      src/pages/system/Permission/Save/index.tsx
  36. 11 3
      src/pages/system/Platforms/Api/basePage.tsx
  37. 6 1
      yarn.lock

+ 2 - 2
docker/build.sh

@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
-docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-pro:2.0.0-SNAPSHOT .
-docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-pro:2.0.0-SNAPSHOT
+docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-pro:2.0.0 .
+docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-pro:2.0.0

+ 1 - 0
package.json

@@ -96,6 +96,7 @@
     "react-json-view": "^1.21.3",
     "react-markdown": "^8.0.0",
     "react-monaco-editor": "^0.46.0",
+    "resize-observer-polyfill": "^1.5.1",
     "rxjs": "^7.2.0",
     "rxjs-websockets": "8",
     "umi": "^3.5.0",

+ 2 - 2
src/components/FRuleEditor/Advance/index.tsx

@@ -4,7 +4,7 @@ import Operator from '../Operator';
 import styles from './index.less';
 import Editor from '@/components/FRuleEditor/Editor';
 import { useRef, useState } from 'react';
-import { Store } from 'jetlinks-store';
+import {EventEmitter} from "@/components/FRuleEditor/util";
 
 interface Props {
   model: 'advance' | 'simple';
@@ -26,7 +26,7 @@ const Advance = (props: Props) => {
       title="设置属性规则"
       onCancel={() => onChange('simple')}
       onOk={() => {
-        Store.set('rule-editor-value', cacheRef.current);
+        EventEmitter.set('rule-editor-value', cacheRef.current);
         onChange('simple');
       }}
       // okButtonProps={{

+ 6 - 4
src/components/FRuleEditor/Editor/index.tsx

@@ -5,8 +5,8 @@ import { monaco } from 'react-monaco-editor';
 import { JMonacoEditor } from '@/components/FMonacoEditor';
 import { useCallback, useEffect, useRef, useState } from 'react';
 import type * as monacoEditor from 'monaco-editor';
-import { Store } from 'jetlinks-store';
 import { State } from '@/components/FRuleEditor';
+import {EventEmitter} from "@/components/FRuleEditor/util";
 
 const symbolList = [
   {
@@ -102,11 +102,13 @@ const Editor = (props: Props) => {
   };
 
   useEffect(() => {
+    console.log('props.value', props.value)
     setValue(props.value);
   }, [props.value]);
 
   const handleInsertCode = useCallback(
     (_value: string) => {
+      console.log(_value)
       const editor = editorRef.current;
       if (!editor || !_value) return;
       const position = editor.getPosition()!;
@@ -129,9 +131,9 @@ const Editor = (props: Props) => {
   useEffect(() => {
     let subscription: any = null;
     if (props.mode === 'advance') {
-      subscription = Store.subscribe('add-operator-value', handleInsertCode);
+      subscription = EventEmitter.subscribe('add-operator-value', handleInsertCode);
     }
-    return () => subscription?.unsubscribe();
+    return () => subscription?.unsubscribe('add-operator-value', handleInsertCode);
   }, [props.mode]);
 
   return (
@@ -208,7 +210,7 @@ const Editor = (props: Props) => {
             setValue(c);
             if (props.mode !== 'advance') {
               State.code = c;
-              Store.set('rule-editor-value', State.code);
+              EventEmitter.set('rule-editor-value', State.code);
             }
             props.onValueChange?.(c);
           }}

+ 5 - 3
src/components/FRuleEditor/index.tsx

@@ -3,7 +3,7 @@ import Editor from '@/components/FRuleEditor/Editor';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import { useEffect } from 'react';
-import { Store } from 'jetlinks-store';
+import {EventEmitter} from "@/components/FRuleEditor/util";
 
 export const State = model<{
   model: 'simple' | 'advance';
@@ -29,14 +29,16 @@ interface Props {
 
 const FRuleEditor = observer((props: Props) => {
   const { value, onChange, property, virtualRule } = props;
+  console.log(virtualRule)
   useEffect(() => {
     // console.log(value, 111111111);
     State.property = property;
-    const subscription = Store.subscribe('rule-editor-value', onChange);
+    const subscription = EventEmitter.subscribe('rule-editor-value', onChange);
     State.code = value;
     return () => {
+      console.log('unsubscribe')
+      subscription.unsubscribe('rule-editor-value', onChange);
       State.code = '';
-      subscription.unsubscribe();
     };
   }, []);
   return (

+ 41 - 0
src/components/FRuleEditor/util.ts

@@ -0,0 +1,41 @@
+import {isArray} from "lodash";
+
+export const EventEmitter = {
+  list: {},
+  subscribe: function(events: string[] | string, fn: Function) {
+    const list = this.list
+    const _events = isArray(events) ? events : [events]
+    _events.forEach(event => {
+      (list[event] || (list[event] = [])).push(fn)
+    })
+    return this
+  },
+  set: function(events:string, data?: any) {
+    const list = this.list
+    const fns: Function[] = list[events] ? [...list[events]] : []
+    console.log(events, fns)
+    if (!fns.length) return false;
+
+    fns.forEach(fn => {
+      fn(data)
+    })
+
+    return this
+  },
+  unsubscribe: function(events: string[] |string, fn: Function) {
+    const list = this.list
+    const _events = isArray(events) ? events : [events]
+    _events.forEach(key => {
+      if (key in list) {
+        const fns = list[key]
+        for (let i = 0; i < fns.length; i++) {
+          if (fns[i] === fn) {
+            fns.splice(i, 1)
+            break;
+          }
+        }
+      }
+    })
+    return this
+  }
+}

+ 2 - 1
src/components/FUpload/index.tsx

@@ -12,6 +12,7 @@ interface Props {
   onChange: (value: any) => void;
   placeholder: string;
   beforeUpload: any;
+  showUploadList: boolean
 }
 
 const FUpload = connect((props: Props) => {
@@ -46,7 +47,7 @@ const FUpload = connect((props: Props) => {
       progress={{
         format: (percent) => percent && `${parseFloat(percent.toFixed(2))}%`,
       }}
-      showUploadList={{
+      showUploadList={props.showUploadList !== undefined ? props.showUploadList : {
         removeIcon: (
           <DeleteOutlined
             onClick={() => {

+ 6 - 6
src/components/ProTableCard/CardItems/Scene/index.tsx

@@ -533,11 +533,11 @@ const ActionRender = (data: ActionRenderProps) => {
               >
                 <div className={styles['card-item-content-action-item-right-item']}>
                   {/*触发条件*/}
-                  {type === 'device' && (item.shakeLimit?.enabled || data.options?.when?.[index]) && (
+                  {type === 'device' && (item?.shakeLimit?.enabled || data.options?.when?.[index]) && (
                     <div
                       className={styles['right-item-left']}
                       style={{
-                        maxWidth: Array.isArray(item.then) && item?.then.length ? '15%' : '100%',
+                        maxWidth: Array.isArray(item?.then) && item?.then.length ? '15%' : '100%',
                       }}
                     >
                       <MyTooltip
@@ -548,13 +548,13 @@ const ActionRender = (data: ActionRenderProps) => {
                           {conditionsRender(data.options?.when || [], index)}
                         </div>
                       </MyTooltip>
-                      {item.shakeLimit?.enabled && (
+                      {item?.shakeLimit?.enabled && (
                         <MyTooltip
-                          title={`(${item.shakeLimit?.time}秒内发生${item.shakeLimit?.threshold}
+                          title={`(${item?.shakeLimit?.time}秒内发生${item?.shakeLimit?.threshold}
                             次以上时执行一次)`}
                         >
                           <div className={classNames(styles['trigger-shake'], 'ellipsis')}>
-                            ({item.shakeLimit?.time}秒内发生{item.shakeLimit?.threshold}
+                            ({item?.shakeLimit?.time}秒内发生{item?.shakeLimit?.threshold}
                             次以上时执行一次)
                           </div>
                         </MyTooltip>
@@ -562,7 +562,7 @@ const ActionRender = (data: ActionRenderProps) => {
                     </div>
                   )}
                   {/*执行动作*/}
-                  {Array.isArray(item.then) && item?.then.length ? (
+                  {Array.isArray(item?.then) && item?.then.length ? (
                     <div
                       className={styles['right-item-right']}
                       style={{ maxWidth: type === 'device' ? '85%' : '100%' }}

+ 22 - 16
src/hooks/document/useDomFullHeight.tsx

@@ -1,5 +1,6 @@
 import type { MutableRefObject } from 'react';
-import { useEffect, useState } from 'react';
+import {useEffect, useRef, useState} from 'react';
+import ResizeObserver from 'resize-observer-polyfill';
 
 type TargetValue<T> = T | undefined | null;
 
@@ -29,30 +30,35 @@ const getTargetElement = <T extends TargetType>(target: BasicTarget<T> | string)
 
 const useDomFullHeight = (target: BasicTarget | string, extraHeight: number = 0) => {
   const [state, setState] = useState(100);
+  const resizeObserver = useRef<ResizeObserver | undefined>()
+
+  const cleanup = () => {
+    if (resizeObserver.current) {
+      resizeObserver.current?.disconnect()
+      resizeObserver.current = undefined
+    }
+  }
 
   useEffect(() => {
     const el = getTargetElement(target);
-    let resizeObserver: ResizeObserver | undefined;
+    cleanup()
     if (el) {
-      resizeObserver = new ResizeObserver((entries) => {
-        entries.forEach((entry) => {
-          const bodyClient = document.body.getBoundingClientRect();
-          const domClient = entry.target.getBoundingClientRect();
-          if (domClient.y < 50) {
-            setState(100);
-          } else {
-            setState(bodyClient.height - domClient.y - 24 - extraHeight);
-          }
-        });
+      resizeObserver.current = new ResizeObserver((entries) => {
+        const bodyClient = document.body.getBoundingClientRect();
+        const domClient = el.getBoundingClientRect();
+
+        if (domClient.y < 50) {
+          setState(100);
+        } else {
+          setState(bodyClient.height - domClient.y - 24 - extraHeight);
+        }
       });
 
-      resizeObserver.observe(el);
+      resizeObserver.current.observe(el);
     }
 
     return () => {
-      if (resizeObserver) {
-        resizeObserver.disconnect();
-      }
+      cleanup()
     };
   }, [target]);
 

+ 48 - 6
src/pages/DataCollect/Collector/components/Point/Save/modbus.tsx

@@ -1,5 +1,5 @@
 import { Button, Modal } from 'antd';
-import { createForm, Field, registerValidateRules } from '@formily/core';
+import { createForm, Field, onFieldValueChange, registerValidateRules } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import React, { useEffect, useState } from 'react';
 import * as ICONS from '@ant-design/icons';
@@ -54,6 +54,48 @@ export default (props: Props) => {
   const form = createForm({
     validateFirst: true,
     initialValues: data || {},
+    effects: () => {
+      onFieldValueChange('configuration.function', (field, f) => {
+        const value = (field as Field).value;
+        if (value === 'InputRegisters') {
+          f.setFieldState('configuration.codec.provider', (state) => {
+            state.dataSource = state.dataSource?.filter((item) => item.value !== 'bool');
+          });
+          f.setFieldState('accessModes', (state) => {
+            state.componentProps = {
+              placeholder: '请选择访问类型',
+              model: 'multiple',
+              itemStyle: {
+                display: 'flex',
+                flexDirection: 'column',
+                justifyContent: 'space-around',
+                minWidth: '130px',
+                height: '50px',
+              },
+              options: [{ label: '读', value: 'read' }],
+            };
+          });
+        } else {
+          f.setFieldState('accessModes', (state) => {
+            state.componentProps = {
+              placeholder: '请选择访问类型',
+              model: 'multiple',
+              itemStyle: {
+                display: 'flex',
+                flexDirection: 'column',
+                justifyContent: 'space-around',
+                minWidth: '130px',
+                height: '50px',
+              },
+              options: [
+                { label: '读', value: 'read' },
+                { label: '写', value: 'write' },
+              ],
+            };
+          });
+        }
+      });
+    },
   });
 
   const SchemaField = createSchemaField({
@@ -121,7 +163,7 @@ export default (props: Props) => {
       if (!(Number(value) % 1 === 0)) {
         return {
           type: 'error',
-          message: '请输入0~255之间的正整数',
+          message: '请输入0~999999999之间的正整数',
         };
       }
       return '';
@@ -174,7 +216,7 @@ export default (props: Props) => {
             enum: [
               { label: '01线圈寄存器', value: 'Coils' },
               { label: '03保存寄存器', value: 'HoldingRegisters' },
-              { label: '04输入寄存器', value: 'DiscreteInputs' },
+              { label: '04输入寄存器', value: 'InputRegisters' },
             ],
             'x-validator': [
               {
@@ -199,8 +241,8 @@ export default (props: Props) => {
                 message: '请输入地址',
               },
               {
-                max: 255,
-                message: '请输入0-255之间的正整数',
+                max: 999999999,
+                message: '请输入0-999999999之间的正整数',
               },
               {
                 min: 0,
@@ -290,7 +332,7 @@ export default (props: Props) => {
                 dependencies: ['..function', 'configuration.parameter.quantity'],
                 fulfill: {
                   state: {
-                    visible: '{{$deps[0] === "HoldingRegisters"}}',
+                    visible: '{{$deps[0] === "HoldingRegisters" || $deps[0] === "InputRegisters"}}',
                     selfErrors:
                       '{{$deps[1] && $self.value && {"int8:": 1, "int16": 2, "int32": 4, "int64": 8, "ieee754_float": 4, "ieee754_double": 8, "hex": 1}[$self.value] > $deps[1] * 2 ? "数据类型长度需 <= 寄存器数量 * 2" : ""}}',
                   },

+ 7 - 4
src/pages/Northbound/DuerOS/Detail/index.tsx

@@ -92,15 +92,17 @@ const Save = () => {
         effects() {
           onFormInit(async (form1) => {
             await getTypes();
-            await getProduct();
-            if (id === ':id') return;
+            if (!id || id === ':id') {
+              await getProduct();
+              return;
+            }
+            await getProduct({ value: id } as any);
             const resp = await service.detail(id);
             /// 单独处理一下applianceType
             const _data = resp.result;
             if (_data) {
               _data.applianceType = _data?.applianceType?.value;
             }
-            console.log(_data, 'data');
             form1.setValues(_data);
           });
           onFieldReact('actionMappings.*.layout.action', (field, f) => {
@@ -561,7 +563,8 @@ const Save = () => {
                             dependencies: ['..messageType'],
                             fulfill: {
                               state: {
-                                visible: '{{["INVOKE_FUNCTION"].includes($deps[0])}}',
+                                visible:
+                                  '{{["INVOKE_FUNCTION"].includes($deps[0]) && $self.value && $self.value?.length}}',
                               },
                             },
                           },

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

@@ -206,7 +206,7 @@ const Category = observer(() => {
           if (sorter.order) {
             setSortParam({ name: sorter.columnKey, order: sorter.order.replace('end', '') });
           } else {
-            setSortParam({ name: 'sortIndex', value: 'asc' });
+            setSortParam({ name: 'sortIndex', order: 'asc' });
           }
         }}
         headerTitle={

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

@@ -313,6 +313,7 @@ const Save = (props: Props) => {
             'x-component-props': {
               type: 'file',
               placeholder: '请上传文件',
+              showUploadList: false,
             },
             'x-decorator-props': {
               gridSpan: 2,

+ 138 - 85
src/pages/device/Instance/Detail/EdgeMap/mapTable/index.tsx

@@ -1,6 +1,11 @@
 import PermissionButton from '@/components/PermissionButton';
 import TitleComponent from '@/components/TitleComponent';
-import { DisconnectOutlined, QuestionCircleOutlined } from '@ant-design/icons';
+import {
+  DisconnectOutlined,
+  PlayCircleOutlined,
+  QuestionCircleOutlined,
+  StopOutlined,
+} from '@ant-design/icons';
 import { FormItem, ArrayTable, Editable, Select, NumberPicker } from '@formily/antd';
 import { createForm, Field, FormPath, onFieldReact } from '@formily/core';
 import type { Response } from '@/utils/typings';
@@ -51,35 +56,142 @@ const MapTable = (props: Props) => {
     return <>{text?.metadataName}</>;
   };
   const StatusRender = (propsRender: any) => {
+    // console.log(propsRender.value,'---------')
+    const record = ArrayTable.useRecord?.();
+    const index = ArrayTable.useIndex?.();
+    const state = record(index)?.state;
     if (propsRender.value) {
-      return <Badge status="success" text={'已绑定'} />;
+      if (state.value === 'enabled') {
+        return <Badge status="success" text={'在线'} />;
+      } else {
+        return <Badge status="warning" text={'离线'} />;
+      }
     } else {
       return <Badge status="error" text={'未绑定'} />;
     }
   };
+  const save = async (item: any) => {
+    const res = await service.saveMap(edgeId, item);
+    if (res.status === 200) {
+      onlyMessage('保存成功');
+      if (props.formRef) {
+        props.close();
+      } else {
+        reload('save');
+      }
+    }
+  };
+  const form = createForm({
+    values: {
+      requestList: metaData,
+    },
+    effects: () => {
+      onFieldReact('requestList.*.channelId', async (field, f) => {
+        const value = (field as Field).value;
+        // console.log(field, 'provider')
+        if (value) {
+          const param = channelList.find((item: any) => item.value === value);
+          const providerPath = FormPath.transform(
+            field.path,
+            /\d+/,
+            (index) => `requestList.${parseInt(index)}.provider`,
+          );
+          f.setFieldState(providerPath, (state) => {
+            state.value = param?.provider;
+          });
+        }
+        const path = FormPath.transform(
+          field.path,
+          /\d+/,
+          (index) => `requestList.${parseInt(index)}.collectorId`,
+        );
+        const path1 = FormPath.transform(
+          field.path,
+          /\d+/,
+          (index) => `requestList.${parseInt(index)}.pointId`,
+        );
+        f.setFieldState(path, (state) => {
+          if (value) {
+            state.required = true;
+            form.validate();
+          } else {
+            state.required = false;
+            form.validate();
+          }
+        });
+        f.setFieldState(path1, (state) => {
+          if (value) {
+            state.required = true;
+            form.validate();
+          } else {
+            state.required = false;
+            form.validate();
+          }
+        });
+      });
+    },
+  });
   const ActionButton = () => {
     const record = ArrayTable.useRecord?.();
     const index = ArrayTable.useIndex?.();
     return (
-      <PermissionButton
-        isPermission={permission.update}
-        style={{ padding: 0 }}
-        disabled={!record(index)?.id}
-        tooltip={{
-          title: '解绑',
-        }}
-        popConfirm={{
-          title: '确认解绑',
-          disabled: !record(index)?.id,
-          onConfirm: async () => {
-            remove(record(index)?.id);
-          },
-        }}
-        key="unbind"
-        type="link"
-      >
-        <DisconnectOutlined />
-      </PermissionButton>
+      <>
+        <PermissionButton
+          isPermission={permission.update}
+          style={{ padding: 0 }}
+          disabled={!record(index)?.id}
+          tooltip={{
+            title: '解绑',
+          }}
+          popConfirm={{
+            title: '确认解绑',
+            disabled: !record(index)?.id,
+            onConfirm: async () => {
+              remove(record(index)?.id);
+            },
+          }}
+          key="unbind"
+          type="link"
+        >
+          <DisconnectOutlined />
+        </PermissionButton>
+        {record(index).id && (
+          <PermissionButton
+            isPermission={permission.update}
+            style={{ padding: 0, marginLeft: 10 }}
+            // disabled={!record(index)?.id}
+            tooltip={{
+              title: record(index).state.value === 'enabled' ? '禁用' : '启用',
+            }}
+            popConfirm={{
+              title: record(index).state.value === 'enabled' ? '确认禁用' : '确认启用',
+              disabled: !record(index)?.id,
+              onConfirm: async () => {
+                const value: any = await form.submit();
+                const array = value.requestList.filter((item: any) => item.channelId);
+                const findArray = array.find((item: any) => item.id === record(index)?.id);
+                const arr = {
+                  ...findArray,
+                  state: record(index).state.value === 'enabled' ? 'disabled' : 'enabled',
+                };
+                const filterArray = array.filter((item: any) => item.id !== record(index)?.id);
+                console.log('array----', array, findArray);
+                const submitData = {
+                  deviceId: deviceId,
+                  provider: array[0]?.provider,
+                  requestList: [...filterArray, arr],
+                };
+                console.log('submitData', submitData);
+                save(submitData);
+              },
+            }}
+            key="unbind"
+            type="link"
+          >
+            {record(index).state.value === 'enabled' ? <StopOutlined /> : <PlayCircleOutlined />}
+          </PermissionButton>
+        )}
+      </>
     );
   };
 
@@ -152,68 +264,6 @@ const MapTable = (props: Props) => {
     },
   });
 
-  const save = async (item: any) => {
-    const res = await service.saveMap(edgeId, item);
-    if (res.status === 200) {
-      onlyMessage('保存成功');
-      if (props.formRef) {
-        props.close();
-      } else {
-        reload('save');
-      }
-    }
-  };
-
-  const form = createForm({
-    values: {
-      requestList: metaData,
-    },
-    effects: () => {
-      onFieldReact('requestList.*.channelId', async (field, f) => {
-        const value = (field as Field).value;
-        // console.log(field, 'provider')
-        if (value) {
-          const param = channelList.find((item: any) => item.value === value);
-          const providerPath = FormPath.transform(
-            field.path,
-            /\d+/,
-            (index) => `requestList.${parseInt(index)}.provider`,
-          );
-          f.setFieldState(providerPath, (state) => {
-            state.value = param?.provider;
-          });
-        }
-        const path = FormPath.transform(
-          field.path,
-          /\d+/,
-          (index) => `requestList.${parseInt(index)}.collectorId`,
-        );
-        const path1 = FormPath.transform(
-          field.path,
-          /\d+/,
-          (index) => `requestList.${parseInt(index)}.pointId`,
-        );
-        f.setFieldState(path, (state) => {
-          if (value) {
-            state.required = true;
-            form.validate();
-          } else {
-            state.required = false;
-            form.validate();
-          }
-        });
-        f.setFieldState(path1, (state) => {
-          if (value) {
-            state.required = true;
-            form.validate();
-          } else {
-            state.required = false;
-            form.validate();
-          }
-        });
-      });
-    },
-  });
   const add = async () => {
     const value = await props.formRef.validateFields();
     const mapValue: any = await form.submit();
@@ -457,13 +507,16 @@ const MapTable = (props: Props) => {
               const submitData = {
                 deviceId: deviceId,
                 provider: array[0]?.provider,
-                requestList: array,
+                requestList: array.map((item: any) => ({
+                  ...item,
+                  state: 'enabled',
+                })),
               };
               save(submitData);
             }
           }}
         >
-          保存
+          保存并启用
         </PermissionButton>
       </div>
       <div>

+ 1 - 1
src/pages/device/Instance/Detail/Functions/form.tsx

@@ -219,7 +219,7 @@ export default (props: FunctionProps) => {
     if (id && formData.table) {
       const data = {};
       formData.table.forEach((d: any) => {
-        if (d.value) {
+        if (d.value !== undefined) {
           if (d.type === 'date') {
             data[d.id] = moment(d.value).format(d.format || 'YYYY-MM-DD HH:mm:ss');
           } else if (d.type === 'object') {

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

@@ -3,7 +3,7 @@ import { InstanceModel } from '@/pages/device/Instance';
 import type { FunctionMetadata } from '@/pages/device/Product/typings';
 import FnForm from './form';
 import AModel from './AdvancedMode';
-import { useDomFullHeight } from '@/hooks';
+// import { useDomFullHeight } from '@/hooks';
 import Empty from '@/pages/device/components/Empty';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
 
@@ -11,10 +11,10 @@ const Functions = () => {
   const functionList = JSON.parse(InstanceModel.detail.metadata || '{}')
     .functions as FunctionMetadata[];
 
-  const { minHeight } = useDomFullHeight(`.device-detail-function`);
+  // const { minHeight } = useDomFullHeight(`.device-detail-function`);
 
   return (
-    <Card className={'device-detail-function'} style={{ minHeight: minHeight }}>
+    <Card className={'device-detail-function'}>
       {functionList && functionList.length ? (
         <Tabs>
           <Tabs.TabPane tab={'精简模式'} key={1}>
@@ -68,7 +68,7 @@ const Functions = () => {
           </Tabs.TabPane>
         </Tabs>
       ) : (
-        <div style={{ height: minHeight - 150 }}>
+        <div>
           <Empty />
         </div>
       )}

+ 8 - 13
src/pages/device/Instance/Detail/Info/index.tsx

@@ -93,19 +93,14 @@ const Info = observer(() => {
             {/*  </div>*/}
             {/*</Tooltip>*/}
           </Descriptions.Item>
-          <Descriptions.Item label={'产品分类'}>
-            <Ellipsis
-              title={InstanceModel.detail?.classifiedName}
-              tooltip={{ placement: 'topLeft' }}
-              style={{ maxWidth: 250 }}
-              limitWidth={250}
-            />
-            {/*<Tooltip placement="topLeft" title={InstanceModel.detail?.classifiedName}>*/}
-            {/*  <div className="ellipsis" style={{ maxWidth: 250 }}>*/}
-            {/*    {InstanceModel.detail?.classifiedName}*/}
-            {/*  </div>*/}
-            {/*</Tooltip>*/}
-          </Descriptions.Item>
+          {/*<Descriptions.Item label={'产品分类'}>*/}
+          {/*  <Ellipsis*/}
+          {/*    title={InstanceModel.detail?.classifiedName}*/}
+          {/*    tooltip={{ placement: 'topLeft' }}*/}
+          {/*    style={{ maxWidth: 250 }}*/}
+          {/*    limitWidth={250}*/}
+          {/*  />*/}
+          {/*</Descriptions.Item>*/}
           <Descriptions.Item
             label={intl.formatMessage({
               id: 'pages.device.instanceDetail.deviceType',

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

@@ -60,7 +60,7 @@ const Access = (props: Props) => {
             dt={props.data}
             data={protocol}
             provider={props.provider}
-            prev={prev}
+            prev={props.provider?.id !== 'child-device' ? prev : undefined}
             next={(param) => {
               setProtocol(param);
               next();

+ 7 - 4
src/pages/link/AccessConfig/Detail/components/Protocol/index.tsx

@@ -15,7 +15,7 @@ import { Empty } from '@/components';
 interface Props {
   provider: any;
   data: string;
-  prev: () => void;
+  prev?: () => void;
   next: (data: string) => void;
   view?: boolean;
   dt?: any;
@@ -173,9 +173,12 @@ const Protocol = (props: Props) => {
       </div>
       <div className={styles.action}>
         <Space style={{ marginTop: 20 }}>
-          <Button style={{ margin: '0 8px' }} onClick={() => props.prev()}>
-            上一步
-          </Button>
+          {
+            props.prev !== undefined ?
+            <Button style={{ margin: '0 8px' }} onClick={() => props.prev!()}>
+              上一步
+            </Button> : null
+          }
           <Button
             type="primary"
             onClick={() => {

+ 3 - 0
src/pages/link/DashBoard/index.tsx

@@ -258,6 +258,9 @@ export default () => {
       },
       yAxis: {
         type: 'value',
+        axisLabel: {
+          formatter: (_value: any) => networkValueRender(_value),
+        },
       },
       grid: {
         left: 70,

+ 3 - 3
src/pages/notice/Config/SyncUser/index.tsx

@@ -108,7 +108,7 @@ const SyncUser = observer(() => {
                 );
               }
               setTreeData(_data);
-              setDept(resp.result[0].id);
+              setDept(resp.result?.[0]?.id);
             }
           })
           .finally(() => setLoading(false));
@@ -124,7 +124,7 @@ const SyncUser = observer(() => {
                 );
               }
               setTreeData(__data);
-              setDept(resp.result[0].id);
+              setDept(resp.result?.[0]?.id);
             }
           })
           .finally(() => setLoading(false));
@@ -190,7 +190,7 @@ const SyncUser = observer(() => {
                 request={(params) =>
                   service
                     .queryZipSyncUser(
-                      id === 'dingTalk' ? 'dingTalk' : 'wechat',
+                      id === 'dingTalk' ? 'dingtalk' : 'wechat',
                       id,
                       state.current?.provider || '',
                       state.current?.id || '',

+ 2 - 2
src/pages/notice/Config/service.ts

@@ -42,7 +42,7 @@ class Service extends BaseService<ConfigItem> {
       request(`${SystemConst.API_BASE}/notifier/dingtalk/corp/${configId}/${departmentId}/users`),
     wechatDept: (configId: string) =>
       request(`${SystemConst.API_BASE}/notifier/wechat/corp/${configId}/departments`),
-    getDeptUser: (type: 'wechat' | 'dingTalk', configId: string, departmentId: string) =>
+    getDeptUser: (type: 'wechat' | 'dingtalk', configId: string, departmentId: string) =>
       request(`${SystemConst.API_BASE}/notifier/${type}/corp/${configId}/${departmentId}/users`, {
         method: 'GET',
       }),
@@ -79,7 +79,7 @@ class Service extends BaseService<ConfigItem> {
   };
 
   public queryZipSyncUser = (
-    type: 'wechat' | 'dingTalk',
+    type: 'wechat' | 'dingtalk',
     _type: string,
     provider: string,
     configId: string,

+ 16 - 8
src/pages/rule-engine/Scene/Save/action/DeviceOutput/actions/TypeModel.tsx

@@ -114,7 +114,8 @@ export default observer((props: Props) => {
             min={0}
             precision={type === 'double' || type === 'float' ? 2 : 0}
             onChange={(e: any) => {
-              onChange(e);
+              setValue(e)
+              setLabelValue(e);
             }}
             style={{ width: '100%' }}
             placeholder={'请输入'}
@@ -229,9 +230,9 @@ export default observer((props: Props) => {
             onChange={(e) => {
               setValue(e.target.value);
               setLabelValue(e.target.value);
-              if (props.onChange) {
-                props.onChange(e.target.value, source);
-              }
+              // if (props.onChange) {
+              //   props.onChange(e.target.value, source);
+              // }
             }}
           />
         );
@@ -291,12 +292,17 @@ export default observer((props: Props) => {
           // setOpen(false)
           setValue(val);
           setSource(tabKey);
-          if (props.onChange) {
-            props.onChange(val, tabKey);
-          }
+          // if (props.onChange) {
+          //   props.onChange(val, tabKey);
+          // }
         }}
         open={open}
-        openChange={setOpen}
+        openChange={(val) => {
+          setOpen(val)
+          if (!val) {
+            props.onChange?.(value, source);
+          }
+        }}
         type={props.type}
         labelValue={labelValue}
       />
@@ -311,6 +317,7 @@ export default observer((props: Props) => {
               props.onChange(param);
             }
             setValue(param);
+            setLabelValue(param)
             setVisible(false);
           }}
         />
@@ -328,6 +335,7 @@ export default observer((props: Props) => {
               props.onChange(JSON.parse(param));
             }
             setValue(param);
+            setLabelValue(JSON.parse(param))
             setObjVisable(false);
           }}
         />

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

@@ -156,7 +156,7 @@ export default observer((props: Props) => {
                 }}
               />
             </Form.Item>
-            {functionId && (
+            {functionId && !!functionList.length && (
               <Form.Item
                 name={['message', 'inputs']}
                 rules={[{ required: true, message: '请输入功能值' }]}

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

@@ -29,8 +29,8 @@ export default (props: ActionsProps) => {
   const firstLockRef = useRef(true);
 
   useEffect(() => {
-    const parallelArr = props.thenOptions.filter((item) => item.parallel);
-    const serialArr = props.thenOptions.filter((item) => !item.parallel);
+    const parallelArr = props.thenOptions.filter((item) => item && item.parallel);
+    const serialArr = props.thenOptions.filter((item) => item && !item.parallel);
     setParallelArray(parallelArr);
     setSerialArray(serialArr);
     const isSerialActions = serialArr.some((item) => {

+ 5 - 6
src/pages/rule-engine/Scene/Save/terms/index.tsx

@@ -148,12 +148,11 @@ export default observer((props: Props) => {
                     FormModel.current.options?.when?.splice(index, 1);
                   }}
                   onDeleteAll={() => {
-                    const newBranches: any[] =
-                      FormModel.current.branches?.filter((bItem, bIndex) => {
-                        return bIndex === 0 || (bItem && bItem.key === item.key);
-                      }) || [];
-                    newBranches.push(null);
-                    console.log(FormModel.current.options?.when);
+                    const newBranches: any[] = FormModel.current.branches || []
+                    newBranches.splice(index, FormModel.current.branches?.length - index);
+                    if (FormModel.current.branches?.every(item => item !== null)) {
+                      newBranches.push(null);
+                    }
                     FormModel.current.branches = newBranches;
                     if (FormModel.current.options?.when) {
                       FormModel.current.options.when = [

+ 1 - 2
src/pages/system/Apply/Api/base.tsx

@@ -76,9 +76,8 @@ export default observer((props: ApiPageProps) => {
   }, []);
 
   useEffect(() => {
-    console.log(ApiModel.data);
+    console.log('----------', ApiModel.data);
   }, [ApiModel.data]);
-  console.log(ApiModel.showTable);
 
   return (
     <div className={'platforms-api'}>

+ 1 - 1
src/pages/system/Apply/index.tsx

@@ -425,7 +425,7 @@ const Apply = () => {
                         </Menu.Item>
                       )}
                       {isApiService(record.integrationModes) && (
-                        <Menu.Item key="empowerment">
+                        <Menu.Item key="api">
                           <PermissionButton
                             key={'api'}
                             type={'link'}

+ 3 - 2
src/pages/system/DataSource/Management/DataTable.tsx

@@ -3,6 +3,7 @@ import { createForm, registerValidateRules } from '@formily/core';
 import type { ISchema } from '@formily/react';
 import { createSchemaField } from '@formily/react';
 import { Modal } from 'antd';
+import {useMemo} from "react";
 
 interface Props {
   close: () => void;
@@ -11,10 +12,10 @@ interface Props {
 }
 
 const DataTable = (props: Props) => {
-  const form = createForm({
+  const form = useMemo(() => createForm({
     validateFirst: true,
     initialValues: props.data,
-  });
+  }), [props.data])
 
   const SchemaField = createSchemaField({
     components: {

+ 4 - 3
src/pages/system/DataSource/Management/EditTable.tsx

@@ -4,6 +4,7 @@ import { createForm } from '@formily/core';
 import { createSchemaField } from '@formily/react';
 import { Button } from 'antd';
 import RemoveData from './RemoveData';
+import {useMemo} from "react";
 
 interface Props {
   onChange: (data: any) => void;
@@ -28,11 +29,11 @@ const EditTable = (props: Props) => {
     },
   });
 
-  const form = createForm({
+  const form = useMemo( () => createForm({
     initialValues: {
       array: _data,
     },
-  });
+  }), [props?.data]);
 
   const schema = {
     type: 'object',
@@ -147,7 +148,7 @@ const EditTable = (props: Props) => {
               'x-component': 'ArrayTable.Column',
               'x-component-props': { title: '精度' },
               properties: {
-                precision: {
+                scale: {
                   type: 'number',
                   'x-decorator': 'FormItem',
                   'x-component': 'NumberPicker',

+ 0 - 1
src/pages/system/DataSource/Management/index.less

@@ -1,7 +1,6 @@
 .datasourceBox {
   display: flex;
   width: 100%;
-  min-height: 500px;
   overflow: hidden;
 
   .left {

+ 4 - 3
src/pages/system/DataSource/Management/index.tsx

@@ -24,7 +24,7 @@ const Management = () => {
   const [tableList, setTableList] = useState<any[]>([]);
   const [param, setParam] = useState<string | undefined>(undefined);
   const [loading, setLoading] = useState<boolean>(true);
-  const { minHeight } = useDomFullHeight(`.management`);
+  const { minHeight } = useDomFullHeight(`.management`, 52);
 
   const queryTables = (key: string) => {
     setLoading(true);
@@ -35,6 +35,7 @@ const Management = () => {
       setLoading(false);
     });
   };
+  console.log(minHeight)
 
   const handleSearch = (refresh: boolean) => {
     service.rdbTree(id).then((resp) => {
@@ -91,8 +92,8 @@ const Management = () => {
   return (
     <PageContainer>
       <Spin spinning={loading}>
-        <Card className="management" style={{ minHeight }}>
-          <div className={styles.datasourceBox}>
+        <Card className="management">
+          <div className={styles.datasourceBox} style={{ minHeight }}>
             <div className={styles.left}>
               <Input.Search
                 placeholder="请输入"

+ 16 - 4
src/pages/system/Department/Assets/deivce/bind.tsx

@@ -30,7 +30,7 @@ const Bind = observer((props: Props) => {
   const [searchParam, setSearchParam] = useState({});
   const [loading, setLoading] = useState(false);
   const [checkAssets, setCheckAssets] = useState<string[]>(['read']);
-  const [isAll, setIsAll] = useState<boolean>(false);
+  const [isAll, setIsAll] = useState<boolean>(true);
   const bindChecks = useRef(new Map());
 
   const columns: ProColumns<DeviceItem>[] = [
@@ -354,15 +354,27 @@ const Bind = observer((props: Props) => {
             },
             onSelectAll: (selected, selectedRows, changeRows) => {
               if (selected) {
-                Models.bindKeys = [
-                  ...new Set([...Models.bindKeys, ...getSelectedRowsKey(selectedRows)]),
-                ];
+                const arr = selectedRows.filter(
+                  (item: any) => !!item?.permissionInfoList.find((it: any) => it.id === 'share'),
+                );
+                arr.forEach((e: any) => {
+                  const list = e?.permissionInfoList
+                    .map((it: any) => it.id)
+                    .filter?.((item: any) => checkAssets.includes(item));
+                  bindChecks.current.set(e.id, list);
+                });
+                Models.bindKeys = [...new Set([...Models.bindKeys, ...getSelectedRowsKey(arr)])];
+                console.log('onSelectAll', arr);
               } else {
                 const unChangeRowsKeys = getSelectedRowsKey(changeRows);
+                unChangeRowsKeys.forEach((item: any) => bindChecks.current.delete(item.id));
                 Models.bindKeys = Models.bindKeys
                   .concat(unChangeRowsKeys)
                   .filter((item) => !unChangeRowsKeys.includes(item));
               }
+              AssetsModel.params = {
+                productId: Models.bindKeys,
+              };
             },
           }}
           request={async (params) => {

+ 9 - 2
src/pages/system/Department/Assets/product/bind.tsx

@@ -362,12 +362,19 @@ const Bind = observer((props: Props) => {
               onSelectAll: (selected, selectedRows, changeRows) => {
                 if (selected) {
                   const arr = selectedRows.filter(
-                    (item: any) => !!item.permissionInfoList.find((it: any) => it.id === 'share'),
+                    (item: any) => !!item?.permissionInfoList.find((it: any) => it.id === 'share'),
                   );
-                  // console.log(arr)
+                  arr.forEach((e: any) => {
+                    const list = e?.permissionInfoList
+                      .map((it: any) => it.id)
+                      .filter?.((item: any) => checkAssets.includes(item));
+                    bindChecks.current.set(e.id, list);
+                  });
                   Models.bindKeys = [...new Set([...Models.bindKeys, ...getSelectedRowsKey(arr)])];
+                  console.log('onSelectAll', arr);
                 } else {
                   const unChangeRowsKeys = getSelectedRowsKey(changeRows);
+                  unChangeRowsKeys.forEach((item: any) => bindChecks.current.delete(item.id));
                   Models.bindKeys = Models.bindKeys
                     .concat(unChangeRowsKeys)
                     .filter((item) => !unChangeRowsKeys.includes(item));

+ 1 - 1
src/pages/system/Permission/Save/index.tsx

@@ -94,7 +94,7 @@ const Save = (props: Props) => {
             triggerType: 'onBlur',
             validator: (value: string) => {
               return new Promise((resolve) => {
-                if (!value) resolve('');
+                if (!value) return resolve('');
                 service
                   .validateField({ id: value })
                   .then((resp) => {

+ 11 - 3
src/pages/system/Platforms/Api/basePage.tsx

@@ -107,6 +107,7 @@ export default (props: TableProps) => {
 
     const addOperations = addGrant.map((a: string) => {
       const item = dataSource.find((b) => b.operationId === a);
+      console.log('item', item);
       return {
         id: a,
         permissions: item?.security,
@@ -134,11 +135,19 @@ export default (props: TableProps) => {
         onlyMessage('操作成功');
       }
     } else {
+      // console.log('del',removeOperations);
+      // console.log('add',addOperations,addGrant);
       const resp2 = await service.removeApiGrant(code!, {
-        operations: removeOperations.filter((item: any) => item.permissions),
+        operations: removeOperations.map((item: any) => ({
+          ...item,
+          permissions: item.permissions ? item.permissions : [],
+        })),
       });
       const resp = await service.addApiGrant(code!, {
-        operations: addOperations.filter((item) => item.permissions),
+        operations: addOperations.map((item) => ({
+          ...item,
+          permissions: item.permissions ? item.permissions : [],
+        })),
       });
       if (resp.status === 200 || resp2.status === 200) {
         getApiGrant();
@@ -169,7 +178,6 @@ export default (props: TableProps) => {
                   type={'link'}
                   style={{ padding: 0, width: '100%', textAlign: 'left' }}
                   onClick={() => {
-                    console.log(record);
                     ApiModel.showTable = false;
                     ApiModel.swagger = record;
                   }}

+ 6 - 1
yarn.lock

@@ -16589,11 +16589,16 @@ reserved-words@^0.1.2:
   resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1"
   integrity sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=
 
-resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1:
+resize-observer-polyfill@^1.5.0:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
   integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
 
+resize-observer-polyfill@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
 resolve-cwd@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"