Quellcode durchsuchen

fix: merge next

wzyyy vor 3 Jahren
Ursprung
Commit
a217dc26b5

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

@@ -30,7 +30,8 @@ export default (props: ChannelCardProps) => {
       showMask={false}
       statusNames={{
         enabled: StatusColorEnum.success,
-        disabled: StatusColorEnum.error,
+        disabled: StatusColorEnum.default,
+        error: StatusColorEnum.error,
       }}
     >
       <div className={'pro-table-card-item'}>

+ 1 - 1
src/components/ProTableCard/CardItems/DataCollect/device.tsx

@@ -53,7 +53,7 @@ export default (props: CollectorCardProps) => {
             </div>
             <div>
               <label>所属通道</label>
-              <Ellipsis title={props?.channelName || ''} />
+              <Ellipsis title={props?.channelName || props?.channelId || ''} />
             </div>
           </div>
         </div>

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

@@ -53,7 +53,7 @@ const DiagnosticAdvice = (props: Props) => {
                 title={
                   <div className="serverItem">
                     {(data?.info?.address || []).map((i: any) => (
-                      <div key={i.address} className="eellipsiss">
+                      <div key={i.address} className="ellipsis">
                         <Badge color={i.health === -1 ? 'red' : 'green'} />
                         {i.address}
                       </div>
@@ -63,7 +63,7 @@ const DiagnosticAdvice = (props: Props) => {
               >
                 <div className="serverItem">
                   {(data?.info?.address || []).slice(0, 1).map((i: any) => (
-                    <div key={i.address} className="eellipsiss">
+                    <div key={i.address} className="ellipsis">
                       <Badge color={i.health === -1 ? 'red' : 'green'} />
                       {i.address}
                     </div>

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

@@ -12,7 +12,7 @@ import Functions from '@/pages/device/Instance/Detail/Functions';
 import Running from '@/pages/device/Instance/Detail/Running';
 import ChildDevice from '@/pages/device/Instance/Detail/ChildDevice';
 import Diagnose from '@/pages/device/Instance/Detail/Diagnose';
-import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
+// import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
 import Opcua from '@/pages/device/Instance/Detail/Opcua';
 import Modbus from '@/pages/device/Instance/Detail/Modbus';
 import { useIntl } from '@@/plugin-locale/localeExports';
@@ -27,7 +27,7 @@ import { Ellipsis, PermissionButton } from '@/components';
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import Service from '@/pages/device/Instance/service';
 import useLocation from '@/hooks/route/useLocation';
-import { onlyMessage, isNoCommunity } from '@/utils/util';
+import { onlyMessage } from '@/utils/util';
 import Parsing from './Parsing';
 import EdgeMap from './EdgeMap';
 // import EdgeMap from './EdgeMap';
@@ -152,15 +152,15 @@ const InstanceDetail = observer(() => {
     },
   ];
 
-  const pList = [
-    'websocket-server',
-    'http-server-gateway',
-    'udp-device-gateway',
-    'coap-server-gateway',
-    'mqtt-client-gateway',
-    'mqtt-server-gateway',
-    'tcp-server-gateway',
-  ];
+  // const pList = [
+  //   'websocket-server',
+  //   'http-server-gateway',
+  //   'udp-device-gateway',
+  //   'coap-server-gateway',
+  //   'mqtt-client-gateway',
+  //   'mqtt-server-gateway',
+  //   'tcp-server-gateway',
+  // ];
   const [list, setList] =
     useState<{ key: string; tab: string | ReactNode; component: ReactNode }[]>(baseList);
 
@@ -169,18 +169,18 @@ const InstanceDetail = observer(() => {
     if (response.status === 200) {
       InstanceModel.detail = response?.result;
       const datalist = [...baseList];
-      if (
-        InstanceModel.detail?.accessProvider &&
-        pList.includes(InstanceModel.detail?.accessProvider)
-      ) {
-        if (isNoCommunity) {
-          datalist.push({
-            key: 'metadata-map',
-            tab: '物模型映射',
-            component: <MetadataMap type="device" />,
-          });
-        }
-      }
+      // if (
+      //   InstanceModel.detail?.accessProvider &&
+      //   pList.includes(InstanceModel.detail?.accessProvider)
+      // ) {
+      //   if (isNoCommunity) {
+      //     datalist.push({
+      //       key: 'metadata-map',
+      //       tab: '物模型映射',
+      //       component: <MetadataMap type="device" />,
+      //     });
+      //   }
+      // }
       const paring = response.result?.features?.find((item: any) => item.id === 'transparentCodec');
       if (paring) {
         datalist.push({

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

@@ -16,7 +16,7 @@ interface Props {
   data?: Partial<DeviceInstance>;
 }
 
-const defaultImage = '/images/device-product.png';
+const defaultImage = '/images/device-type-3-big.png';
 
 const Save = (props: Props) => {
   const { visible, close, data } = props;

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

@@ -283,7 +283,7 @@ const Access = () => {
     const driver = new Driver({
       allowClose: false,
       doneBtnText: '我知道了',
-      closeBtnText: '不提示',
+      closeBtnText: '不提示',
       nextBtnText: '下一步',
       prevBtnText: '上一步',
       onNext: () => {
@@ -305,7 +305,7 @@ const Access = () => {
     const driver1 = new Driver({
       allowClose: false,
       doneBtnText: '我知道了',
-      closeBtnText: '不提示',
+      closeBtnText: '不提示',
       nextBtnText: '下一步',
       prevBtnText: '上一步',
       onNext: () => {

+ 23 - 23
src/pages/device/Product/Detail/index.tsx

@@ -13,11 +13,11 @@ import { Store } from 'jetlinks-store';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import encodeQuery from '@/utils/encodeQuery';
-import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
+// import MetadataMap from '@/pages/device/Instance/Detail/MetadataMap';
 import SystemConst from '@/utils/const';
 import { Ellipsis, PermissionButton } from '@/components';
 import { QuestionCircleOutlined } from '@ant-design/icons';
-import { isNoCommunity, onlyMessage } from '@/utils/util';
+import { onlyMessage } from '@/utils/util';
 import Parsing from '../../Instance/Detail/Parsing';
 
 export const ModelEnum = {
@@ -93,15 +93,15 @@ const ProductDetail = observer(() => {
     },
   ];
 
-  const pList = [
-    'websocket-server',
-    'http-server-gateway',
-    'udp-device-gateway',
-    'coap-server-gateway',
-    'mqtt-client-gateway',
-    'mqtt-server-gateway',
-    'tcp-server-gateway',
-  ];
+  // const pList = [
+  //   'websocket-server',
+  //   'http-server-gateway',
+  //   'udp-device-gateway',
+  //   'coap-server-gateway',
+  //   'mqtt-client-gateway',
+  //   'mqtt-server-gateway',
+  //   'tcp-server-gateway',
+  // ];
   const [list, setList] = useState<any[]>([]);
 
   const { minHeight } = useDomFullHeight('.product-detail-body');
@@ -153,18 +153,18 @@ const ProductDetail = observer(() => {
     });
   };
   const getDetail = async () => {
-    if (
-      productModel.current?.accessProvider &&
-      pList.includes(productModel.current?.accessProvider)
-    ) {
-      if (isNoCommunity) {
-        initList.push({
-          key: 'metadata-map',
-          tab: '物模型映射',
-          component: <MetadataMap type="product" />,
-        });
-      }
-    }
+    // if (
+    //   productModel.current?.accessProvider &&
+    //   pList.includes(productModel.current?.accessProvider)
+    // ) {
+    //   if (isNoCommunity) {
+    //     initList.push({
+    //       key: 'metadata-map',
+    //       tab: '物模型映射',
+    //       component: <MetadataMap type="product" />,
+    //     });
+    //   }
+    // }
     if (productModel.current?.messageProtocol) {
       const res = await service.getProtocolDetail(productModel.current?.messageProtocol);
       if (res.status === 200) {

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

@@ -13,20 +13,34 @@ const DataCollectModel = model<{
   type: 'channel' | 'device';
   provider: 'OPC_UA' | 'MODBUS_TCP';
   data: any;
+  reload: boolean;
 }>({
   type: 'channel',
   id: '',
   provider: 'MODBUS_TCP',
   data: {},
+  reload: false,
 });
 
 export default observer(() => {
+  const onReload = () => {
+    DataCollectModel.reload = !DataCollectModel.reload;
+  };
+
   const obj = {
-    channel: <Device type={false} id={DataCollectModel.id} provider={DataCollectModel.provider} />,
+    channel: (
+      <Device
+        reload={onReload}
+        type={false}
+        id={DataCollectModel.id}
+        provider={DataCollectModel.provider}
+      />
+    ),
     device: (
       <Point type={false} provider={DataCollectModel.provider} data={DataCollectModel.data} />
     ),
   };
+
   return (
     <PageContainer>
       <Card bordered={false}>
@@ -39,6 +53,7 @@ export default observer(() => {
                 DataCollectModel.provider = provider;
                 DataCollectModel.data = data || {};
               }}
+              reload={DataCollectModel.reload}
             />
           </div>
           {DataCollectModel?.id ? (

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

@@ -319,7 +319,7 @@ export default (props: Props) => {
                 dependencies: ['.securityMode'],
                 fulfill: {
                   state: {
-                    visible: '{{$deps[0]==="SingAndEncrypt" || $deps[0]==="Sign"}}',
+                    visible: '{{$deps[0]==="SignAndEncrypt" || $deps[0]==="Sign"}}',
                   },
                 },
               },
@@ -332,6 +332,7 @@ export default (props: Props) => {
             'x-decorator-props': {
               gridSpan: 2,
             },
+            default: 'anonymous',
             'x-component-props': {
               model: 'singular',
               itemStyle: {

+ 53 - 17
src/pages/link/DataCollect/components/Channel/index.tsx

@@ -29,7 +29,7 @@ export default observer((props: Props) => {
   const intl = useIntl();
   const { minHeight } = useDomFullHeight(`.data-collect-channel`, 24);
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
-  const { permission } = PermissionButton.usePermission('device/Instance');
+  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
   const [loading, setLoading] = useState<boolean>(true);
   const [dataSource, setDataSource] = useState<any>({
     data: [],
@@ -38,6 +38,13 @@ export default observer((props: Props) => {
     total: 0,
   });
 
+  const test = (value: string) => {
+    if (value === 'error') {
+      return '';
+    }
+    return value;
+  };
+
   const columns: ProColumns<ChannelItem>[] = [
     {
       title: '名称',
@@ -60,18 +67,25 @@ export default observer((props: Props) => {
     },
     {
       title: '状态',
-      dataIndex: 'state',
+      dataIndex: 'runningState',
       valueType: 'select',
       valueEnum: {
         enabled: {
           text: '正常',
-          status: 'enabled',
+          status: 'running',
         },
         disabled: {
+          text: '禁用',
+          status: 'stopped',
+        },
+        error: {
           text: '异常',
-          status: 'disabled',
+          status: 'error',
         },
       },
+      search: {
+        transform: test,
+      },
     },
     {
       title: '说明',
@@ -96,6 +110,30 @@ export default observer((props: Props) => {
     handleSearch(param);
   }, []);
 
+  const getState = (record: Partial<ChannelItem>) => {
+    if (record) {
+      if (record?.state?.value === 'enabled') {
+        if (record?.runningState?.value === 'running') {
+          return {
+            text: '正常',
+            value: 'enabled',
+          };
+        } else {
+          return {
+            text: '异常',
+            value: 'error',
+          };
+        }
+      } else {
+        return {
+          text: '禁用',
+          value: 'disabled',
+        };
+      }
+    } else {
+      return {};
+    }
+  };
   return (
     <div>
       <SearchComponent<ChannelItem>
@@ -103,7 +141,7 @@ export default observer((props: Props) => {
         target="data-collect-channel"
         onSearch={(data) => {
           const dt = {
-            pageSize: 10,
+            pageSize: 12,
             terms: [...data?.terms],
           };
           handleSearch(dt);
@@ -119,6 +157,7 @@ export default observer((props: Props) => {
                     <Col key={record.id} span={props.type ? 8 : 12}>
                       <ChannelCard
                         {...record}
+                        status={getState(record)}
                         actions={[
                           <PermissionButton
                             type={'link'}
@@ -140,19 +179,16 @@ export default observer((props: Props) => {
                             isPermission={permission.delete}
                             type={'link'}
                             style={{ padding: 0 }}
-                            disabled={record?.state?.value !== 'disabled'}
-                            tooltip={
-                              record?.state?.value !== 'disabled'
-                                ? {
-                                    title: '正常的通道不能删除',
-                                  }
-                                : undefined
-                            }
+                            // disabled={record?.state?.value !== 'disabled'}
+                            // tooltip={
+                            //   record?.state?.value !== 'disabled'
+                            //     ? {
+                            //         title: '正常的通道不能删除',
+                            //       }
+                            //     : undefined
+                            // }
                             popConfirm={{
-                              title: intl.formatMessage({
-                                id: 'pages.data.option.remove.tips',
-                                defaultMessage: '是否删除?',
-                              }),
+                              title: '该操作将会删除下属采集器与点位,确定删除?',
                               onConfirm: async () => {
                                 await service.removeChannel(record.id);
                                 onlyMessage(

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

@@ -17,6 +17,7 @@ interface Props {
   type: boolean; // true: 综合查询  false: 数据采集
   id?: any;
   provider?: 'OPC_UA' | 'MODBUS_TCP';
+  reload?: () => void;
 }
 
 const CollectorModel = model<{
@@ -32,7 +33,7 @@ export default observer((props: Props) => {
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
   const [loading, setLoading] = useState<boolean>(true);
   const intl = useIntl();
-  const { permission } = PermissionButton.usePermission('device/Instance');
+  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
   const [dataSource, setDataSource] = useState<any>({
     data: [],
     pageSize: 12,
@@ -40,42 +41,72 @@ export default observer((props: Props) => {
     total: 0,
   });
 
-  const columns: ProColumns<CollectorItem>[] = [
-    {
-      title: '名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '通讯协议',
-      dataIndex: 'provider',
-      valueType: 'select',
-      valueEnum: {
-        OPC_UA: {
-          text: 'OPC_UA',
-          status: 'OPC_UA',
+  const columns: ProColumns<CollectorItem>[] = props.type
+    ? [
+        {
+          title: '名称',
+          dataIndex: 'name',
         },
-        MODBUS_TCP: {
-          text: 'MODBUS_TCP',
-          status: 'MODBUS_TCP',
+        {
+          title: '通讯协议',
+          dataIndex: 'provider',
+          valueType: 'select',
+          valueEnum: {
+            OPC_UA: {
+              text: 'OPC_UA',
+              status: 'OPC_UA',
+            },
+            MODBUS_TCP: {
+              text: 'MODBUS_TCP',
+              status: 'MODBUS_TCP',
+            },
+          },
+        },
+        {
+          title: '状态',
+          dataIndex: 'state',
+          valueType: 'select',
+          valueEnum: {
+            enabled: {
+              text: '正常',
+              status: 'enabled',
+            },
+            disabled: {
+              text: '禁用',
+              status: 'disabled',
+            },
+          },
+        },
+        {
+          title: '说明',
+          dataIndex: 'description',
         },
-      },
-    },
-    {
-      title: '状态',
-      dataIndex: 'state',
-      valueType: 'select',
-      valueEnum: {
-        enabled: {
-          text: '正常',
-          status: 'enabled',
+      ]
+    : [
+        {
+          title: '名称',
+          dataIndex: 'name',
         },
-        disabled: {
-          text: '禁用',
-          status: 'disabled',
+        {
+          title: '状态',
+          dataIndex: 'state',
+          valueType: 'select',
+          valueEnum: {
+            enabled: {
+              text: '正常',
+              status: 'enabled',
+            },
+            disabled: {
+              text: '禁用',
+              status: 'disabled',
+            },
+          },
+        },
+        {
+          title: '说明',
+          dataIndex: 'description',
         },
-      },
-    },
-  ];
+      ];
   const handleSearch = (params: any) => {
     setLoading(true);
     setParam(params);
@@ -109,7 +140,7 @@ export default observer((props: Props) => {
         target="data-collect-collector"
         onSearch={(data) => {
           const dt = {
-            pageSize: 10,
+            pageSize: 12,
             terms: [...data?.terms],
           };
           handleSearch(dt);
@@ -206,15 +237,13 @@ export default observer((props: Props) => {
                             tooltip={
                               record?.state?.value !== 'disabled'
                                 ? {
-                                    title: '正常的采集器不能删除',
+                                    title: '已启用的采集器不能删除',
                                   }
                                 : undefined
                             }
                             disabled={record?.state?.value !== 'disabled'}
                             popConfirm={{
-                              title: intl.formatMessage({
-                                id: 'pages.data.option.remove.tips',
-                              }),
+                              title: '该操作将会删除下属点位,确定删除?',
                               disabled: record?.state?.value !== 'disabled',
                               onConfirm: async () => {
                                 if (record?.state?.value === 'disabled') {
@@ -292,6 +321,9 @@ export default observer((props: Props) => {
           reload={() => {
             CollectorModel.visible = false;
             handleSearch(param);
+            if (props?.reload) {
+              props.reload();
+            }
           }}
         />
       )}

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

@@ -55,8 +55,8 @@
         flex-direction: row-reverse;
         align-items: flex-start;
         justify-content: space-around;
-        min-width: calc(50% - 40px);
-        max-width: calc(50% - 20px);
+        //min-width: calc(50% - 40px);
+        width: calc(50% - 20px);
 
         .card-item-content-item-empty {
           margin-top: 10px;

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

@@ -1,14 +1,8 @@
 import { useState } from 'react';
-import { Ellipsis } from '@/components';
+import { Ellipsis, PermissionButton } from '@/components';
 import './index.less';
-import { Badge, Popconfirm, Spin } from 'antd';
-import {
-  DeleteOutlined,
-  EditOutlined,
-  FormOutlined,
-  MinusOutlined,
-  RedoOutlined,
-} from '@ant-design/icons';
+import { Badge, Popconfirm, Spin, Tooltip } from 'antd';
+import { DeleteOutlined, EditOutlined, FormOutlined, RedoOutlined } from '@ant-design/icons';
 import OpcSave from '../Save/opc-ua';
 import ModbusSave from '../Save/modbus';
 import service from '@/pages/link/DataCollect/service';
@@ -30,6 +24,7 @@ export default (props: PointCardProps) => {
   const [editVisible, setEditVisible] = useState<boolean>(false);
   const [spinning, setSpinning] = useState<boolean>(false);
   const [writeVisible, setWriteVisible] = useState<boolean>(false);
+  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
 
   const read = async () => {
     if (item?.collectorId && item?.id) {
@@ -61,6 +56,7 @@ export default (props: PointCardProps) => {
         close={() => {
           setEditVisible(false);
         }}
+        collector={{}}
         reload={() => {
           setEditVisible(false);
         }}
@@ -98,6 +94,7 @@ export default (props: PointCardProps) => {
               <div className={'card-item-right-action'}>
                 <Popconfirm
                   title={'确认删除'}
+                  disabled={!permission.delete}
                   onConfirm={async () => {
                     if (item.id) {
                       const resp = await service.removePoint(item.id);
@@ -108,13 +105,19 @@ export default (props: PointCardProps) => {
                     }
                   }}
                 >
-                  <DeleteOutlined style={{ marginRight: 10 }} />
+                  <Tooltip title={!permission.delete ? '暂无权限,请联系管理员' : ''}>
+                    <DeleteOutlined style={{ marginRight: 10 }} />
+                  </Tooltip>
                 </Popconfirm>
-                <FormOutlined
-                  onClick={() => {
-                    setEditVisible(true);
-                  }}
-                />
+                <Tooltip title={!permission.update ? '暂无权限,请联系管理员' : ''}>
+                  <FormOutlined
+                    onClick={() => {
+                      if (permission.update) {
+                        setEditVisible(true);
+                      }
+                    }}
+                  />
+                </Tooltip>
               </div>
             </div>
             <div className={'card-item-content'}>
@@ -154,7 +157,9 @@ export default (props: PointCardProps) => {
               ) : (
                 <div className={'card-item-content-item'}>
                   <div className={'card-item-content-item-empty'}>
-                    <MinusOutlined className={'action'} />
+                    <span className={'action'} style={{ fontWeight: 600, color: '#000' }}>
+                      --
+                    </span>
                     <EditOutlined
                       className={'action'}
                       style={{ margin: '0 15px' }}

+ 71 - 27
src/pages/link/DataCollect/components/Point/Save/modbus.tsx

@@ -23,6 +23,7 @@ interface Props {
   data: Partial<PointItem>;
   close: () => void;
   reload: () => void;
+  collector: Partial<CollectorItem>;
 }
 
 export default (props: Props) => {
@@ -82,7 +83,7 @@ export default (props: Props) => {
           message: '最多可输入64个字符',
         };
       }
-      if (!(value % 1 === 0)) {
+      if (!(Number(value) % 1 === 0) || Number(value) <= 0) {
         return {
           type: 'error',
           message: '请输入非0正整数',
@@ -90,6 +91,24 @@ export default (props: Props) => {
       }
       return '';
     },
+    checkScaleFactor(value) {
+      if (String(value).length > 64) {
+        return {
+          type: 'error',
+          message: '最多可输入64个字符',
+        };
+      }
+      return '';
+    },
+    checkAddressLength(value) {
+      if (!(Number(value) % 1 === 0)) {
+        return {
+          type: 'error',
+          message: '请输入0~255之间的正整数',
+        };
+      }
+      return '';
+    },
   });
 
   const schema: ISchema = {
@@ -136,9 +155,9 @@ export default (props: Props) => {
               placeholder: '请选择功能码',
             },
             enum: [
-              { label: '离散输入寄存器', value: 'DiscreteInputs' },
+              { label: '线圈寄存器', value: 'Coils' },
               { label: '保存寄存器', value: 'HoldingRegisters' },
-              { label: '输入寄存器', value: 'InputRegisters' },
+              { label: '输入寄存器', value: 'DiscreteInputs' },
             ],
             'x-validator': [
               {
@@ -149,7 +168,7 @@ export default (props: Props) => {
           },
           'configuration.parameter.address': {
             title: '地址',
-            'x-component': 'Input',
+            'x-component': 'NumberPicker',
             'x-decorator': 'FormItem',
             'x-decorator-props': {
               gridSpan: 2,
@@ -171,7 +190,7 @@ export default (props: Props) => {
                 message: '请输入0-255之间的正整数',
               },
               {
-                checkLength: true,
+                checkAddressLength: true,
               },
             ],
           },
@@ -184,6 +203,15 @@ export default (props: Props) => {
             },
             'x-component-props': {
               placeholder: '请输入起始位置',
+              stringMode: true,
+            },
+            'x-reactions': {
+              dependencies: ['...function'],
+              fulfill: {
+                state: {
+                  visible: '{{$deps[0] === "HoldingRegisters"}}',
+                },
+              },
             },
             'x-validator': [
               {
@@ -191,7 +219,7 @@ export default (props: Props) => {
                 message: '请输入起始位置',
               },
               {
-                min: 0,
+                min: 1,
                 message: '请输入非0正整数',
               },
               {
@@ -208,14 +236,16 @@ export default (props: Props) => {
             },
             'x-component-props': {
               placeholder: '请输入寄存器数量',
+              stringMode: true,
             },
+            default: 1,
             'x-validator': [
               {
                 required: true,
                 message: '请输入寄存器数量',
               },
               {
-                min: 0,
+                min: 1,
                 message: '请输入非0正整数',
               },
               {
@@ -233,7 +263,17 @@ export default (props: Props) => {
             'x-component-props': {
               placeholder: '请选择数据类型',
             },
-            'x-reactions': '{{useAsyncDataSource(getCodecProvider)}}',
+            'x-reactions': [
+              '{{useAsyncDataSource(getCodecProvider)}}',
+              {
+                dependencies: ['..function'],
+                fulfill: {
+                  state: {
+                    visible: '{{$deps[0] === "HoldingRegisters"}}',
+                  },
+                },
+              },
+            ],
             'x-validator': [
               {
                 required: true,
@@ -251,12 +291,16 @@ export default (props: Props) => {
             default: 1,
             'x-component-props': {
               placeholder: '请输入缩放因子',
+              stringMode: true,
             },
             'x-validator': [
               {
                 required: true,
                 message: '请输入缩放因子',
               },
+              {
+                checkScaleFactor: true,
+              },
             ],
           },
           accessModes: {
@@ -280,7 +324,7 @@ export default (props: Props) => {
               options: [
                 { label: '读', value: 'read' },
                 { label: '写', value: 'write' },
-                { label: '订阅', value: 'subscribe' },
+                // { label: '订阅', value: 'subscribe' },
               ],
             },
             'x-validator': [
@@ -298,17 +342,10 @@ export default (props: Props) => {
               gridSpan: 2,
             },
             default: 3000,
-            'x-reactions': {
-              dependencies: ['..accessModes'],
-              fulfill: {
-                state: {
-                  visible: '{{($deps[0] || []).includes("subscribe")}}',
-                },
-              },
-            },
             'x-component-props': {
               placeholder: '请输入采集频率',
               addonAfter: '毫秒',
+              stringMode: true,
               style: {
                 width: '100%',
               },
@@ -319,6 +356,10 @@ export default (props: Props) => {
                 message: '请输入采集频率',
               },
               {
+                min: 1,
+                message: '请输入非0正整数',
+              },
+              {
                 checkLength: true,
               },
             ],
@@ -331,14 +372,14 @@ export default (props: Props) => {
             'x-decorator-props': {
               gridSpan: 2,
             },
-            'x-reactions': {
-              dependencies: ['.accessModes'],
-              fulfill: {
-                state: {
-                  visible: '{{($deps[0] || []).includes("subscribe")}}',
-                },
-              },
-            },
+            // 'x-reactions': {
+            //   dependencies: ['.accessModes'],
+            //   fulfill: {
+            //     state: {
+            //       visible: '{{($deps[0] || []).includes("subscribe")}}',
+            //     },
+            //   },
+            // },
             enum: [
               {
                 label: '只推送变化的数据',
@@ -367,10 +408,13 @@ export default (props: Props) => {
 
   const save = async () => {
     const value = await form.submit<PointItem>();
-    console.log(value);
+    const obj = {
+      provider: props?.collector?.provider || 'MODBUS_TCP',
+      collectorId: props?.collector?.id,
+    };
     const response: any = props.data?.id
       ? await service.updatePoint(props.data?.id, { ...props.data, ...value })
-      : await service.savePoint({ ...props.data, ...value });
+      : await service.savePoint({ ...obj, ...props.data, ...value });
     if (response && response?.status === 200) {
       onlyMessage('操作成功');
       props.reload();

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

@@ -126,24 +126,24 @@ export default (props: Props) => {
               },
             ],
           },
-          'configuration.codec.provider': {
-            title: '数据类型',
-            'x-component': 'Select',
-            'x-decorator': 'FormItem',
-            'x-decorator-props': {
-              gridSpan: 2,
-            },
-            'x-component-props': {
-              placeholder: '请选择数据类型',
-            },
-            'x-reactions': '{{useAsyncDataSource(getCodecProvider)}}',
-            'x-validator': [
-              {
-                required: true,
-                message: '请选择数据类型',
-              },
-            ],
-          },
+          // 'configuration.codec.provider': {
+          //   title: '数据类型',
+          //   'x-component': 'Select',
+          //   'x-decorator': 'FormItem',
+          //   'x-decorator-props': {
+          //     gridSpan: 2,
+          //   },
+          //   'x-component-props': {
+          //     placeholder: '请选择数据类型',
+          //   },
+          //   'x-reactions': '{{useAsyncDataSource(getCodecProvider)}}',
+          //   'x-validator': [
+          //     {
+          //       required: true,
+          //       message: '请选择数据类型',
+          //     },
+          //   ],
+          // },
           accessModes: {
             title: '访问类型',
             type: 'array',

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

@@ -1,4 +1,4 @@
-import { Button, Empty, Modal, Spin, Transfer, Tree } from 'antd';
+import { Button, Empty, Modal, Popconfirm, Spin, Transfer, Tree } from 'antd';
 import type { TransferDirection } from 'antd/es/transfer';
 import { useEffect, useState } from 'react';
 import service from '@/pages/link/DataCollect/service';
@@ -152,13 +152,16 @@ const TreeTransfer = ({
                         <Ellipsis title={item?.title || item.key} />
                       </div>
                       <div style={{ width: 20, marginLeft: 10 }}>
-                        <CloseOutlined
-                          onClick={() => {
+                        <Popconfirm
+                          title={'确认删除?'}
+                          onConfirm={() => {
                             if (onItemRemove) {
                               onItemRemove([item.key]);
                             }
                           }}
-                        />
+                        >
+                          <CloseOutlined />
+                        </Popconfirm>
                       </div>
                     </div>
                   );
@@ -224,6 +227,10 @@ export default (props: Props) => {
           key={2}
           loading={spinning}
           onClick={async () => {
+            if (!arr.length) {
+              onlyMessage('请选择目标数据', 'error');
+              return;
+            }
             const list = arr.map((item) => {
               return {
                 id: item.key,

+ 12 - 5
src/pages/link/DataCollect/components/Point/index.tsx

@@ -34,7 +34,7 @@ export default observer((props: Props) => {
   const { minHeight } = useDomFullHeight(`.data-collect-point`, 24);
   const [param, setParam] = useState({ pageSize: 12, terms: [] });
   const [loading, setLoading] = useState<boolean>(true);
-  const { permission } = PermissionButton.usePermission('device/Instance');
+  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
   const [propertyValue, setPropertyValue] = useState<any>({});
   const [dataSource, setDataSource] = useState<any>({
     data: [],
@@ -78,13 +78,19 @@ export default observer((props: Props) => {
         },
       },
     },
+    {
+      title: '说明',
+      dataIndex: 'description',
+    },
   ];
 
   const subRef = useRef<any>(null);
 
   const subscribeProperty = (list: any) => {
-    const id = `collector-${props.data?.channelId}-${props.data?.id}-data-${list.join('-')}`;
-    const topic = `/collector/${props.data?.channelId}/${props.data?.id}/data`;
+    const id = `collector-${props.data?.channelId || 'channel'}-${
+      props.data?.id || 'point'
+    }-data-${list.join('-')}`;
+    const topic = `/collector/${props.data?.channelId || '*'}/${props.data?.id || '*'}/data`;
     subRef.current = subscribeTopic!(id, topic, {
       pointId: list.join(','),
     })
@@ -111,6 +117,7 @@ export default observer((props: Props) => {
       .then((resp) => {
         if (resp.status === 200) {
           setDataSource(resp.result);
+          console.log(resp.result);
           subscribeProperty((resp.result?.data || []).map((item: any) => item.id));
         }
         setLoading(false);
@@ -135,7 +142,7 @@ export default observer((props: Props) => {
         target="data-collect-point"
         onSearch={(data) => {
           const dt = {
-            pageSize: 10,
+            pageSize: 12,
             terms: [...data?.terms],
           };
           handleSearch(dt);
@@ -221,7 +228,7 @@ export default observer((props: Props) => {
       {PointModel.m_visible && (
         <ModbusSave
           data={PointModel.current}
-          // channelId={props.id}
+          collector={props?.data || {}}
           close={() => {
             PointModel.m_visible = false;
           }}

+ 20 - 12
src/pages/link/DataCollect/components/Tree/index.tsx

@@ -1,8 +1,8 @@
 import { DownOutlined, PlusOutlined, FormOutlined, DeleteOutlined } from '@ant-design/icons';
-import { Button, Input, Tree, Space, Popconfirm, Badge } from 'antd';
+import { Button, Input, Tree, Space, Popconfirm, Badge, Tooltip } from 'antd';
 import { observer } from '@formily/react';
 import { model } from '@formily/reactive';
-import { Empty } from '@/components';
+import { Empty, PermissionButton } from '@/components';
 import styles from './index.less';
 import service from '@/pages/link/DataCollect/service';
 import { useEffect } from 'react';
@@ -31,11 +31,13 @@ interface Props {
     provider: 'OPC_UA' | 'MODBUS_TCP',
     data?: any,
   ) => void;
+  reload?: boolean;
 }
 
 export default observer((props: Props) => {
   const channelImg = require('/public/images/DataCollect/tree-channel.png');
   const deviceImg = require('/public/images/DataCollect/tree-device.png');
+  const { permission } = PermissionButton.usePermission('link/DataCollect/DataGathering');
 
   const handleSearch = (params: any) => {
     TreeModel.loading = true;
@@ -56,13 +58,13 @@ export default observer((props: Props) => {
 
   useEffect(() => {
     handleSearch(TreeModel.param);
-  }, [TreeModel.param]);
+  }, [TreeModel.param, props.reload]);
 
   return (
     <div>
       <div>
         <Input.Search
-          placeholder="搜索"
+          placeholder="请输入名称"
           allowClear
           onSearch={(val) => {
             TreeModel.param = {
@@ -109,14 +111,18 @@ export default observer((props: Props) => {
                       </div>
                       <div>
                         <Space className={styles.iconColor}>
-                          <FormOutlined
-                            onClick={() => {
-                              TreeModel.current = item;
-                              TreeModel.visible = true;
-                            }}
-                          />
+                          <Tooltip title={!permission.edit ? '暂无权限,请联系管理员' : ''}>
+                            <FormOutlined
+                              onClick={() => {
+                                if (permission.edit) {
+                                  TreeModel.current = item;
+                                  TreeModel.visible = true;
+                                }
+                              }}
+                            />
+                          </Tooltip>
                           <Popconfirm
-                            title={'确认删除?'}
+                            title={'该操作将会删除下属采集器与点位,确定删除?'}
                             onConfirm={async () => {
                               const resp = await service.removeChannel(item.id);
                               if (resp.status === 200) {
@@ -126,7 +132,9 @@ export default observer((props: Props) => {
                               }
                             }}
                           >
-                            <DeleteOutlined />
+                            <Tooltip title={!permission.delete ? '暂无权限,请联系管理员' : ''}>
+                              <DeleteOutlined />
+                            </Tooltip>
                           </Popconfirm>
                         </Space>
                       </div>

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

@@ -1402,7 +1402,48 @@ export default [
                   'things-collector',
                 ],
                 permissions: [],
-                buttons: [],
+                buttons: [
+                  {
+                    id: 'add',
+                    name: '新增',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['save'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'update',
+                    name: '编辑',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['add', 'query'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'action',
+                    name: '禁用/启用',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['save', 'query'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'delete',
+                    name: '删除',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['delete'],
+                      },
+                    ],
+                  },
+                ],
               },
               {
                 code: 'link/DataCollect/IntegratedQuery',
@@ -1418,7 +1459,48 @@ export default [
                   'things-collector',
                 ],
                 permissions: [],
-                buttons: [],
+                buttons: [
+                  {
+                    id: 'add',
+                    name: '新增',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['save'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'update',
+                    name: '编辑',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['add', 'query'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'action',
+                    name: '禁用/启用',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['save', 'query'],
+                      },
+                    ],
+                  },
+                  {
+                    id: 'delete',
+                    name: '删除',
+                    permissions: [
+                      {
+                        permission: 'data-collect-channel',
+                        actions: ['delete'],
+                      },
+                    ],
+                  },
+                ],
               },
             ],
           },
@@ -1680,6 +1762,20 @@ export default [
                 ],
               },
               {
+                id: 'view',
+                name: '查看',
+                permissions: [
+                  {
+                    permission: 'dueros-product',
+                    actions: ['query'],
+                  },
+                  {
+                    permission: 'device-product',
+                    actions: ['query'],
+                  },
+                ],
+              },
+              {
                 id: 'delete',
                 name: '删除',
                 permissions: [