xieyonghong 3 vuotta sitten
vanhempi
commit
83bc54e729

+ 4 - 0
src/locales/zh-CN/pages.ts

@@ -18,6 +18,10 @@ export default {
   'pages.data.option.disabled.tips': '确认禁用?',
   'pages.data.option.enabled': '启用',
   'pages.data.option.enabled.tips': '确认启用?',
+  'pages.data.option.disable': '禁用',
+  'pages.data.option.disable.tips': '确认禁用?',
+  'pages.data.option.enable': '启用',
+  'pages.data.option.enable.tips': '确认启用?',
   'pages.data.option.noPermission': '暂无权限,请联系管理员',
   'pages.data.option.add': '新增',
   'pages.data.option.edit': '编辑',

+ 2 - 1
src/pages/account/NotificationSubscription/index.tsx

@@ -96,6 +96,7 @@ const NotificationSubscription = observer(() => {
         type={'link'}
         isPermission={true}
         style={{ padding: 0 }}
+        disabled={record?.state?.value !== 'disabled'}
         popConfirm={{
           title: '确认删除?',
           onConfirm: async () => {
@@ -109,7 +110,7 @@ const NotificationSubscription = observer(() => {
           },
         }}
         tooltip={{
-          title: '删除',
+          title: record?.state?.value !== 'disabled' ? '请先禁用,再删除' : '删除',
         }}
       >
         <DeleteOutlined />

+ 12 - 34
src/pages/device/Instance/Detail/MetadataLog/Property/index.tsx

@@ -5,12 +5,11 @@ import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import encodeQuery from '@/utils/encodeQuery';
 import { useEffect, useState } from 'react';
 import moment from 'moment';
-import { Axis, Chart, Geom, Legend, Slider, Tooltip } from 'bizcharts';
+import { Axis, Chart, LineAdvance, Legend, Slider, Tooltip, Point } from 'bizcharts';
 import FileComponent from '../../Running/Property/FileComponent';
 import { DownloadOutlined, SearchOutlined } from '@ant-design/icons';
 import Detail from './Detail';
 import AMap from './AMap';
-
 interface Props {
   close: () => void;
   data: Partial<PropertyMetadata>;
@@ -170,6 +169,7 @@ const PropertyLog = (props: Props) => {
       const dataList: any[] = [];
       resp.result.forEach((i: any) => {
         dataList.push({
+          ...i,
           year: moment(i.time).format('YYYY-MM-DD HH:mm:ss'),
           value: Number(i[data.id || '']),
           type: data?.name || '',
@@ -189,9 +189,10 @@ const PropertyLog = (props: Props) => {
   const scale = {
     value: { min: 0 },
     year: {
-      range: [0, 1],
-      type: 'timeCat',
+      type: 'time',
       mask: 'YYYY-MM-DD HH:mm:ss',
+      max: end,
+      min: start,
     },
   };
 
@@ -215,7 +216,7 @@ const PropertyLog = (props: Props) => {
             dataSource={dataSource?.data || []}
             columns={data?.valueType?.type === 'geoPoint' ? geoColumns : columns}
             pagination={{
-              current: dataSource?.pageIndex + 1,
+              current: (dataSource?.pageIndex || 0) + 1,
               pageSize: dataSource?.pageSize || 10,
               showSizeChanger: true,
               total: dataSource?.total || 0,
@@ -297,8 +298,8 @@ const PropertyLog = (props: Props) => {
                 </div>
               )}
             </div>
-            <div style={{ paddingTop: 15 }}>
-              <Chart height={400} data={chartsList} scale={scale} autoFit>
+            <div style={{ marginTop: 10 }}>
+              <Chart height={400} data={chartsList} scale={scale} padding="auto" autoFit>
                 <Legend />
                 <Axis name="year" />
                 <Axis
@@ -307,33 +308,9 @@ const PropertyLog = (props: Props) => {
                     formatter: (val) => parseFloat(val).toLocaleString(),
                   }}
                 />
-                <Tooltip showCrosshairs shared />
-                <Geom
-                  type="line"
-                  tooltip={[
-                    'value*type',
-                    (value, name) => {
-                      return {
-                        value: value,
-                        name,
-                      };
-                    },
-                  ]}
-                  position="year*value"
-                  size={2}
-                />
-                <Geom
-                  type="point"
-                  tooltip={false}
-                  position="year*value"
-                  size={4}
-                  shape={'circle'}
-                  style={{
-                    stroke: '#fff',
-                    lineWidth: 1,
-                  }}
-                />
-                <Geom type="area" position="year*value" shape={'circle'} tooltip={false} />
+                <Tooltip shared />
+                <Point position="year*value" />
+                <LineAdvance position="year*value" shape="smooth" area />
                 <Slider />
               </Chart>
             </div>
@@ -390,6 +367,7 @@ const PropertyLog = (props: Props) => {
           }
         });
     }
+    setDateValue([moment(start), moment(end)]);
   }, [start, end]);
 
   // @ts-ignore

+ 137 - 119
src/pages/device/Instance/Detail/Modbus/index.tsx

@@ -1,5 +1,5 @@
 import PermissionButton from '@/components/PermissionButton';
-import { Badge, Card, Empty, message, Tabs } from 'antd';
+import { Badge, Card, Empty, message, Tabs, Tooltip } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 import { useIntl } from 'umi';
 import styles from '@/pages/link/Channel/Opcua/Access/index.less';
@@ -14,7 +14,9 @@ import {
 import { service } from '@/pages/link/Channel/Modbus';
 import Save from '@/pages/link/Channel/Modbus/Save';
 import { InstanceModel } from '@/pages/device/Instance';
-import AddPoint from '@/pages/link/Channel/Opcua/Access/addPoint';
+import AddPoint from '@/pages/link/Channel/Modbus/Access/addPoint';
+import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
+import { map } from 'rxjs/operators';
 
 const Modbus = () => {
   const intl = useIntl();
@@ -28,6 +30,10 @@ const Modbus = () => {
   const [pointVisiable, setPointVisiable] = useState<boolean>(false);
   const [current, setCurrent] = useState<any>({});
   const [deviceId, setDeviceId] = useState<any>('');
+  const [data, setData] = useState<any>([]);
+  const [subscribeTopic] = useSendWebsocketMessage();
+  const [propertyValue, setPropertyValue] = useState<any>({});
+  const wsRef = useRef<any>();
 
   const columns: ProColumns<any>[] = [
     {
@@ -48,8 +54,7 @@ const Modbus = () => {
     },
     {
       title: '值',
-      // dataIndex: '4',
-      //   render: (record: any) => <>{propertyValue[record.property]}</>,
+      render: (record: any) => <>{propertyValue[record?.property] || '-'}</>,
     },
     {
       title: '状态',
@@ -133,6 +138,7 @@ const Modbus = () => {
           }}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enabled',
             onConfirm: async () => {
               const resp: any = await service.removeMetadataConfig(record.id);
               if (resp.status === 200) {
@@ -162,10 +168,7 @@ const Modbus = () => {
       })
       .then((res) => {
         setBindList(res.result.data);
-        setOpcId(res.result?.[0]?.id);
-        // setParam({
-        //     sorts: [{ name: 'createTime', order: 'desc' }],
-        // })
+        setOpcId(res.result?.data?.[0].id);
       });
   };
 
@@ -177,14 +180,27 @@ const Modbus = () => {
     }
   }, [visible]);
 
-  // useEffect(() => {
-  //     if(opcId){
-  //         setLoading(false)
-  //     }
-  //  }, [opcId])
+  useEffect(() => {
+    const { id, productId } = InstanceModel.detail;
+    const point = data.map((item: any) => item.metadataId);
+    const wsId = `instance-info-property-${id}-${productId}-${point.join('-')}`;
+    const topic = `/dashboard/device/${productId}/properties/realTime`;
+    wsRef.current = subscribeTopic?.(wsId, topic, {
+      deviceId: deviceId,
+      properties: data.map((item: any) => item.metadataId),
+      history: 1,
+    })
+      ?.pipe(map((res: any) => res.payload))
+      .subscribe((payload: any) => {
+        const { value } = payload;
+        propertyValue[value.property] = value.formatValue;
+        setPropertyValue({ ...propertyValue });
+        // console.log(propertyValue)
+      });
+  }, [data]);
 
   return (
-    <Card>
+    <Card className={styles.list}>
       <PermissionButton
         onClick={() => {
           setVisible(true);
@@ -199,117 +215,119 @@ const Modbus = () => {
         新增通道
       </PermissionButton>
       {bindList.length > 0 ? (
-        <Tabs
-          tabPosition={'left'}
-          defaultActiveKey={opcId}
-          onChange={(e) => {
-            setOpcId(e);
-            setParam({
-              terms: [{ column: 'opcUaId', value: e }],
-            });
-          }}
-        >
-          {bindList.map((item: any) => (
-            <Tabs.TabPane
-              key={item.id}
-              tab={
-                <div className={styles.left}>
-                  <div style={{ width: '100px', textAlign: 'left' }}>{item.name}</div>
+        <div style={{ display: 'flex' }}>
+          <div>
+            <Tabs
+              tabPosition={'left'}
+              defaultActiveKey={opcId}
+              onChange={(e) => {
+                setOpcId(e);
+                console.log(e);
+                actionRef.current?.reload();
+                setParam({});
+              }}
+            >
+              {bindList.map((item: any) => (
+                <Tabs.TabPane
+                  key={item.id}
+                  tab={
+                    <div className={styles.left}>
+                      <Tooltip title={item.name}>
+                        <div className={styles.text}>{item.name}</div>
+                      </Tooltip>
+                      <PermissionButton
+                        isPermission={permission.update}
+                        key="edit"
+                        onClick={() => {
+                          setVisible(true);
+                          setChannel(item);
+                        }}
+                        type={'link'}
+                        style={{ padding: 0 }}
+                        tooltip={{
+                          title: intl.formatMessage({
+                            id: 'pages.data.option.edit',
+                            defaultMessage: '编辑',
+                          }),
+                        }}
+                      >
+                        <EditOutlined />
+                      </PermissionButton>
+                      <PermissionButton
+                        isPermission={permission.delete}
+                        style={{ padding: 0 }}
+                        popConfirm={{
+                          title: '确认删除',
+                          onConfirm: async () => {
+                            const resp: any = await service.remove(item.id);
+                            if (resp.status === 200) {
+                              getModbus();
+                              message.success(
+                                intl.formatMessage({
+                                  id: 'pages.data.option.success',
+                                  defaultMessage: '操作成功!',
+                                }),
+                              );
+                            }
+                          },
+                        }}
+                        key="delete"
+                        type="link"
+                      >
+                        <DeleteOutlined />
+                      </PermissionButton>
+                    </div>
+                  }
+                ></Tabs.TabPane>
+              ))}
+            </Tabs>
+          </div>
+          <div style={{ width: '100%' }}>
+            <ProTable
+              actionRef={actionRef}
+              params={param}
+              columns={columns}
+              rowKey="id"
+              search={false}
+              headerTitle={
+                <>
                   <PermissionButton
-                    isPermission={permission.update}
-                    key="edit"
                     onClick={() => {
-                      setVisible(true);
-                      setChannel(item);
+                      setPointVisiable(true);
+                      setCurrent({});
                     }}
-                    type={'link'}
-                    style={{ padding: 0 }}
-                    tooltip={{
-                      title: intl.formatMessage({
-                        id: 'pages.data.option.edit',
-                        defaultMessage: '编辑',
-                      }),
-                    }}
-                  >
-                    <EditOutlined />
-                  </PermissionButton>
-                  <PermissionButton
-                    isPermission={permission.delete}
-                    style={{ padding: 0 }}
-                    popConfirm={{
-                      title: '确认删除',
-                      onConfirm: async () => {
-                        const resp: any = await service.remove(item.id);
-                        if (resp.status === 200) {
-                          getModbus();
-                          message.success(
-                            intl.formatMessage({
-                              id: 'pages.data.option.success',
-                              defaultMessage: '操作成功!',
-                            }),
-                          );
-                        }
-                      },
-                    }}
-                    key="delete"
-                    type="link"
+                    isPermission={permission.add}
+                    key="add"
+                    icon={<PlusOutlined />}
+                    type="primary"
                   >
-                    <DeleteOutlined />
+                    {intl.formatMessage({
+                      id: 'pages.data.option.add',
+                      defaultMessage: '新增',
+                    })}
                   </PermissionButton>
-                </div>
+                </>
               }
-            >
-              <ProTable
-                actionRef={actionRef}
-                // loading={loading}
-                params={param}
-                columns={columns}
-                rowKey="id"
-                search={false}
-                headerTitle={
-                  <>
-                    <PermissionButton
-                      onClick={() => {
-                        setPointVisiable(true);
-                        setCurrent({});
-                      }}
-                      isPermission={permission.add}
-                      key="add"
-                      icon={<PlusOutlined />}
-                      type="primary"
-                    >
-                      {intl.formatMessage({
-                        id: 'pages.data.option.add',
-                        defaultMessage: '新增',
-                      })}
-                    </PermissionButton>
-                  </>
-                }
-                request={async (params) => {
-                  console.log(opcId);
-                  // setTimeout(() => {
-                  //     const master =
-                  // }, 10);
-                  const res = await service.queryMetadataConfig(opcId, deviceId, {
-                    ...params,
-                    sorts: [{ name: 'createTime', order: 'desc' }],
-                  });
-                  // setData(res.result.data);
-                  return {
-                    code: res.message,
-                    result: {
-                      data: res.result.data,
-                      pageIndex: 0,
-                      pageSize: 0,
-                      total: 0,
-                    },
-                    status: res.status,
-                  };
-                }}
-              />
-            </Tabs.TabPane>
-          ))}
-        </Tabs>
+              request={async (params) => {
+                const res = await service.queryMetadataConfig(opcId, deviceId, {
+                  ...params,
+                  sorts: [{ name: 'createTime', order: 'desc' }],
+                });
+                setData(res.result.data);
+                return {
+                  code: res.message,
+                  result: {
+                    data: res.result.data,
+                    pageIndex: 0,
+                    pageSize: 0,
+                    total: 0,
+                  },
+                  status: res.status,
+                };
+              }}
+            />
+          </div>
+        </div>
       ) : (
         <Empty />
       )}

+ 150 - 114
src/pages/device/Instance/Detail/Opcua/index.tsx

@@ -1,5 +1,5 @@
 import PermissionButton from '@/components/PermissionButton';
-import { Badge, Card, Empty, message, Tabs } from 'antd';
+import { Badge, Card, Empty, message, Tabs, Tooltip } from 'antd';
 import { useEffect, useRef, useState } from 'react';
 import { useIntl } from 'umi';
 import styles from '@/pages/link/Channel/Opcua/Access/index.less';
@@ -15,6 +15,8 @@ import { service } from '@/pages/link/Channel/Opcua';
 import Save from '@/pages/link/Channel/Opcua/Save';
 import { InstanceModel } from '@/pages/device/Instance';
 import AddPoint from '@/pages/link/Channel/Opcua/Access/addPoint';
+import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
+import { map } from 'rxjs/operators';
 
 const Opcua = () => {
   const intl = useIntl();
@@ -28,6 +30,10 @@ const Opcua = () => {
   const [pointVisiable, setPointVisiable] = useState<boolean>(false);
   const [current, setCurrent] = useState<any>({});
   const [deviceId, setDeviceId] = useState<any>('');
+  const [data, setData] = useState<any>([]);
+  const [subscribeTopic] = useSendWebsocketMessage();
+  const [propertyValue, setPropertyValue] = useState<any>({});
+  const wsRef = useRef<any>();
 
   const columns: ProColumns<any>[] = [
     {
@@ -48,8 +54,7 @@ const Opcua = () => {
     },
     {
       title: '值',
-      // dataIndex: '4',
-      //   render: (record: any) => <>{propertyValue[record.property]}</>,
+      render: (record: any) => <>{propertyValue[record?.property] || '-'}</>,
     },
     {
       title: '状态',
@@ -88,11 +93,13 @@ const Opcua = () => {
           style={{ padding: 0 }}
           popConfirm={{
             title: intl.formatMessage({
-              id: `pages.data.option.${record.state.value !== 'disable' ? 'disable' : 'good'}.tips`,
+              id: `pages.data.option.${
+                record.state?.value !== 'disable' ? 'disable' : 'enable'
+              }.tips`,
               defaultMessage: '确认禁用?',
             }),
             onConfirm: async () => {
-              if (record.state.value === 'disable') {
+              if (record.state?.value === 'disable') {
                 await service.enablePoint(record.deviceId, [record.id]);
               } else {
                 await service.stopPoint(record.deviceId, [record.id]);
@@ -109,28 +116,29 @@ const Opcua = () => {
           isPermission={permission.action}
           tooltip={{
             title: intl.formatMessage({
-              id: `pages.data.option.${record.state.value !== 'disable' ? 'disable' : 'good'}`,
-              defaultMessage: record.state.value !== 'disable' ? '禁用' : '启用',
+              id: `pages.data.option.${record.state?.value !== 'disable' ? 'disable' : 'enable'}`,
+              defaultMessage: record.state?.value !== 'disable' ? '禁用' : '启用',
             }),
           }}
         >
-          {record.state.value !== 'disable' ? <StopOutlined /> : <PlayCircleOutlined />}
+          {record.state?.value !== 'disable' ? <StopOutlined /> : <PlayCircleOutlined />}
         </PermissionButton>,
         <PermissionButton
           isPermission={permission.delete}
           style={{ padding: 0 }}
-          disabled={record.state.value === 'good'}
+          disabled={record.state?.value === 'enable'}
           tooltip={{
             title:
-              record.state.value === 'disable'
+              record.state?.value === 'disable'
                 ? intl.formatMessage({
                     id: 'pages.data.option.remove',
                     defaultMessage: '删除',
                   })
-                : '请先禁用该组件,再删除。',
+                : '请先禁用该点位,再删除。',
           }}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enable',
             onConfirm: async () => {
               const resp: any = await service.deletePoint(record.id);
               if (resp.status === 200) {
@@ -164,7 +172,7 @@ const Opcua = () => {
           },
         ],
       })
-      .then((res) => {
+      .then((res: any) => {
         setBindList(res.result);
         setOpcId(res.result?.[0]?.id);
         setParam({
@@ -181,8 +189,27 @@ const Opcua = () => {
     }
   }, [visible]);
 
+  useEffect(() => {
+    const { id, productId } = InstanceModel.detail;
+    const point = data.map((item: any) => item.property);
+    const wsId = `instance-info-property-${id}-${productId}-${point.join('-')}`;
+    const topic = `/dashboard/device/${productId}/properties/realTime`;
+    wsRef.current = subscribeTopic?.(wsId, topic, {
+      deviceId: deviceId,
+      properties: data.map((item: any) => item.property),
+      history: 1,
+    })
+      ?.pipe(map((res: any) => res.payload))
+      .subscribe((payload: any) => {
+        const { value } = payload;
+        propertyValue[value.property] = value.formatValue;
+        setPropertyValue({ ...propertyValue });
+        // console.log(propertyValue)
+      });
+  }, [data]);
+
   return (
-    <Card>
+    <Card className={styles.list}>
       <PermissionButton
         onClick={() => {
           setVisible(true);
@@ -192,117 +219,126 @@ const Opcua = () => {
         key="add"
         icon={<PlusOutlined />}
         type="dashed"
-        style={{ width: '200px', marginLeft: 20, marginBottom: 5 }}
+        style={{ width: '200px', margin: '16px 0 18px 20px' }}
       >
         新增通道
       </PermissionButton>
       {bindList.length > 0 ? (
-        <Tabs
-          tabPosition={'left'}
-          defaultActiveKey={opcId}
-          onChange={(e) => {
-            setOpcId(e);
-            setParam({
-              terms: [{ column: 'opcUaId', value: e }],
-            });
-          }}
-        >
-          {bindList.map((item: any) => (
-            <Tabs.TabPane
-              key={item.id}
-              tab={
-                <div className={styles.left}>
-                  <div style={{ width: '100px', textAlign: 'left' }}>{item.name}</div>
+        <div style={{ display: 'flex' }}>
+          <div>
+            <Tabs
+              tabPosition={'left'}
+              defaultActiveKey={opcId}
+              onChange={(e) => {
+                setOpcId(e);
+                setParam({
+                  terms: [{ column: 'opcUaId', value: e }],
+                });
+              }}
+            >
+              {bindList.map((item: any) => (
+                <Tabs.TabPane
+                  key={item.id}
+                  tab={
+                    <div className={styles.left}>
+                      <Tooltip title={item.name}>
+                        <div className={styles.text}>{item.name}</div>
+                      </Tooltip>
+                      <div>
+                        <PermissionButton
+                          isPermission={permission.update}
+                          key="edit"
+                          onClick={() => {
+                            setVisible(true);
+                            setChannel(item);
+                          }}
+                          type={'link'}
+                          style={{ padding: 0 }}
+                          tooltip={{
+                            title: intl.formatMessage({
+                              id: 'pages.data.option.edit',
+                              defaultMessage: '编辑',
+                            }),
+                          }}
+                        >
+                          <EditOutlined />
+                        </PermissionButton>
+                        <PermissionButton
+                          isPermission={permission.delete}
+                          style={{ padding: 0 }}
+                          popConfirm={{
+                            title: '确认删除',
+                            onConfirm: async () => {
+                              const resp: any = await service.remove(item.id);
+                              if (resp.status === 200) {
+                                getOpc(deviceId);
+                                message.success(
+                                  intl.formatMessage({
+                                    id: 'pages.data.option.success',
+                                    defaultMessage: '操作成功!',
+                                  }),
+                                );
+                              }
+                            },
+                          }}
+                          key="delete"
+                          type="link"
+                        >
+                          <DeleteOutlined />
+                        </PermissionButton>
+                      </div>
+                    </div>
+                  }
+                ></Tabs.TabPane>
+              ))}
+            </Tabs>
+          </div>
+          <div style={{ width: '100%' }}>
+            <ProTable
+              actionRef={actionRef}
+              params={param}
+              columns={columns}
+              rowKey="id"
+              search={false}
+              headerTitle={
+                <>
                   <PermissionButton
-                    isPermission={permission.update}
-                    key="edit"
                     onClick={() => {
-                      setVisible(true);
-                      setChannel(item);
-                    }}
-                    type={'link'}
-                    style={{ padding: 0 }}
-                    tooltip={{
-                      title: intl.formatMessage({
-                        id: 'pages.data.option.edit',
-                        defaultMessage: '编辑',
-                      }),
+                      setPointVisiable(true);
+                      setCurrent({});
                     }}
+                    isPermission={permission.add}
+                    key="add"
+                    icon={<PlusOutlined />}
+                    type="primary"
                   >
-                    <EditOutlined />
+                    {intl.formatMessage({
+                      id: 'pages.data.option.add',
+                      defaultMessage: '新增',
+                    })}
                   </PermissionButton>
-                  <PermissionButton
-                    isPermission={permission.delete}
-                    style={{ padding: 0 }}
-                    popConfirm={{
-                      title: '确认删除',
-                      onConfirm: async () => {
-                        const resp: any = await service.remove(item.id);
-                        if (resp.status === 200) {
-                          getOpc(deviceId);
-                          message.success(
-                            intl.formatMessage({
-                              id: 'pages.data.option.success',
-                              defaultMessage: '操作成功!',
-                            }),
-                          );
-                        }
-                      },
-                    }}
-                    key="delete"
-                    type="link"
-                  >
-                    <DeleteOutlined />
-                  </PermissionButton>
-                </div>
+                </>
               }
-            >
-              <ProTable
-                actionRef={actionRef}
-                params={param}
-                columns={columns}
-                rowKey="id"
-                search={false}
-                headerTitle={
-                  <>
-                    <PermissionButton
-                      onClick={() => {
-                        setPointVisiable(true);
-                        setCurrent({});
-                      }}
-                      isPermission={permission.add}
-                      key="add"
-                      icon={<PlusOutlined />}
-                      type="primary"
-                    >
-                      {intl.formatMessage({
-                        id: 'pages.data.option.add',
-                        defaultMessage: '新增',
-                      })}
-                    </PermissionButton>
-                  </>
-                }
-                request={async (params) => {
-                  const res = await service.PointList({
-                    ...params,
-                    sorts: [{ name: 'createTime', order: 'desc' }],
-                  });
-                  // setData(res.result.data);
-                  return {
-                    code: res.message,
-                    result: {
-                      data: res.result.data,
-                      pageIndex: 0,
-                      pageSize: 0,
-                      total: 0,
-                    },
-                    status: res.status,
-                  };
-                }}
-              />
-            </Tabs.TabPane>
-          ))}
-        </Tabs>
+              request={async (params) => {
+                const res = await service.PointList({
+                  ...params,
+                  sorts: [{ name: 'createTime', order: 'desc' }],
+                });
+                setData(res.result.data);
+                return {
+                  code: res.message,
+                  result: {
+                    data: res.result.data,
+                    pageIndex: 0,
+                    pageSize: 0,
+                    total: 0,
+                  },
+                  status: res.status,
+                };
+              }}
+            />
+          </div>
+        </div>
       ) : (
         <Empty />
       )}

+ 4 - 5
src/pages/link/Channel/Modbus/Access/addPoint/index.tsx

@@ -23,7 +23,7 @@ const AddPoint = (props: Props) => {
         metadataType: 'property',
         codec: 'number',
       })
-      .then((res) => {
+      .then((res: any) => {
         if (res.status === 200) {
           message.success('操作成功!');
           props.close();
@@ -33,7 +33,7 @@ const AddPoint = (props: Props) => {
   };
 
   useEffect(() => {
-    service.deviceDetail(props.deviceId).then((res) => {
+    service.deviceDetail(props.deviceId).then((res: any) => {
       if (res.result.metadata) {
         const item = JSON.parse(res.result?.metadata);
         setProperty(item.properties);
@@ -56,8 +56,7 @@ const AddPoint = (props: Props) => {
         layout="vertical"
         initialValues={{
           ...props.data,
-          initialValue: props.data?.configuration?.initialValue,
-          multiple: props.data?.configuration?.multiple,
+          // readIndex:props.data?.readIndex || 0,
         }}
       >
         <Row gutter={[24, 24]}>
@@ -124,7 +123,7 @@ const AddPoint = (props: Props) => {
                 { required: true, message: '请输入读取起始位置' },
                 ({}) => ({
                   validator(_, value) {
-                    if (/(^[1-9]\d*$)/.test(value)) {
+                    if (/(^[0-9]\d*$)/.test(value)) {
                       return Promise.resolve();
                     }
                     return Promise.reject(new Error('请输入正整数'));

+ 15 - 3
src/pages/link/Channel/Modbus/Access/index.less

@@ -1,7 +1,12 @@
 .list {
   :global {
-    .ant-tabs-tab .ant-tabs-tab-active .ant-tabs-tab-btn {
-      text-shadow: 0 0 0 currentColor;
+    .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
+      color: #1d39c4;
+      text-shadow: none;
+    }
+
+    .ant-tabs-content-holder {
+      width: 1px;
     }
   }
 }
@@ -11,7 +16,14 @@
   align-items: center;
   justify-content: space-between;
   width: 200px;
-
+  .text {
+    width: 130px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-align: left;
+    text-overflow: ellipsis;
+    word-break: break-all;
+  }
   .icon {
     display: none;
   }

+ 134 - 132
src/pages/link/Channel/Modbus/Access/index.tsx

@@ -1,7 +1,7 @@
 import PermissionButton from '@/components/PermissionButton';
 import { PageContainer } from '@ant-design/pro-layout';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
-import { Badge, Card, Empty, Input, message, Popconfirm, Tabs } from 'antd';
+import { Badge, Card, Empty, Input, message, Popconfirm, Tabs, Tooltip } from 'antd';
 import { useIntl, useLocation } from 'umi';
 import { useEffect, useRef, useState } from 'react';
 import {
@@ -26,7 +26,7 @@ const Access = () => {
   const location = useLocation<string>();
   const [param, setParam] = useState({});
   const [opcUaId, setOpcUaId] = useState<any>('');
-  const { permission } = PermissionButton.usePermission('link/Channel/Opcua');
+  const { permission } = PermissionButton.usePermission('link/Channel/Modbus');
   const [deviceVisiable, setDeviceVisiable] = useState<boolean>(false);
   const [pointVisiable, setPointVisiable] = useState<boolean>(false);
   const [bindList, setBindList] = useState<any>([]);
@@ -36,6 +36,7 @@ const Access = () => {
   const [data, setData] = useState<any>([]);
   const [subscribeTopic] = useSendWebsocketMessage();
   const [propertyValue, setPropertyValue] = useState<any>({});
+  const wsRef = useRef<any>();
 
   const columns: ProColumns<any>[] = [
     {
@@ -56,8 +57,7 @@ const Access = () => {
     },
     {
       title: '值',
-      // dataIndex: '4',
-      render: (record: any) => <>{propertyValue[record.property]}</>,
+      render: (record: any) => <>{propertyValue[record?.property] || '-'}</>,
     },
     {
       title: '状态',
@@ -141,6 +141,7 @@ const Access = () => {
           }}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enabled',
             onConfirm: async () => {
               const resp: any = await service.removeMetadataConfig(record.id);
               if (resp.status === 200) {
@@ -163,25 +164,6 @@ const Access = () => {
     },
   ];
 
-  const pointWs = () => {
-    if (productId && deviceId) {
-      const id = `instance-info-property-${deviceId}-${productId}-opc-point`;
-      const topic = `/dashboard/device/${productId}/properties/realTime`;
-      subscribeTopic!(id, topic, {
-        deviceId: deviceId,
-        properties: data.map((item: any) => item.property),
-        history: 0,
-      })
-        ?.pipe(map((res) => res.patload))
-        .subscribe((payload: any) => {
-          const { value } = payload;
-          console.log(value);
-          propertyValue[value.property] = { ...payload, ...value };
-          setPropertyValue({ ...propertyValue });
-        });
-    }
-  };
-
   const getBindList = (masterId: any) => {
     service
       .bindDevice(
@@ -191,7 +173,7 @@ const Access = () => {
           },
         }),
       )
-      .then((res) => {
+      .then((res: any) => {
         console.log(res.result);
         if (res.status === 200) {
           setDeviceId(res.result[0]?.id);
@@ -204,14 +186,6 @@ const Access = () => {
       });
   };
 
-  // useEffect(() => {
-  //   pointWs();
-  // }, [deviceId, productId])
-
-  useEffect(() => {
-    pointWs();
-  }, [data]);
-
   useEffect(() => {
     const item = new URLSearchParams(location.search);
     const id = item.get('id');
@@ -221,6 +195,27 @@ const Access = () => {
     }
   }, []);
 
+  useEffect(() => {
+    if (productId && deviceId) {
+      const point = data.map((item: any) => item.metadataId);
+      const id = `instance-info-property-${deviceId}-${productId}-${point.join('-')}`;
+      const topic = `/dashboard/device/${productId}/properties/realTime`;
+      wsRef.current = subscribeTopic?.(id, topic, {
+        deviceId: deviceId,
+        properties: data.map((item: any) => item.metadataId),
+        history: 1,
+      })
+        ?.pipe(map((res) => res.payload))
+        .subscribe((payload: any) => {
+          const { value } = payload;
+          propertyValue[value.property] = value.formatValue;
+          setPropertyValue({ ...propertyValue });
+          // console.log(propertyValue)
+        });
+    }
+    return () => wsRef.current && wsRef.current?.unsubscribe();
+  }, [data]);
+
   return (
     <PageContainer>
       <Card className={styles.list}>
@@ -232,113 +227,120 @@ const Access = () => {
           key="add"
           icon={<PlusOutlined />}
           type="dashed"
-          style={{ width: '200px', marginLeft: 20, marginBottom: 5 }}
+          style={{ width: '200px', margin: '16px 0 18px 20px' }}
         >
           绑定设备
         </PermissionButton>
         {bindList.length > 0 ? (
-          <Tabs
-            tabPosition={'left'}
-            defaultActiveKey={deviceId}
-            onChange={(e) => {
-              setDeviceId(e);
-              const items = bindList.find((item: any) => item.id === e);
-              setProductId(items[0]?.productId);
-              setParam({
-                terms: [{ column: 'deviceId', value: e }],
-              });
-            }}
-          >
-            {bindList.map((item: any) => (
-              <Tabs.TabPane
-                key={item.id}
-                tab={
-                  <div className={styles.left}>
-                    <div style={{ width: '100px', textAlign: 'left' }}>{item.name}</div>
-                    <Popconfirm
-                      title="确认解绑该设备嘛?"
-                      onConfirm={() => {
-                        service.unbind([item.id], opcUaId).then((res) => {
-                          if (res.status === 200) {
-                            message.success('解绑成功');
-                            getBindList(opcUaId);
-                          }
-                        });
-                      }}
-                      okText="Yes"
-                      cancelText="No"
-                    >
-                      <DisconnectOutlined className={styles.icon} />
-                    </Popconfirm>
-                  </div>
-                }
+          <div style={{ display: 'flex' }}>
+            <div>
+              <Tabs
+                tabPosition={'left'}
+                defaultActiveKey={deviceId}
+                onChange={(e) => {
+                  setDeviceId(e);
+                  const items = bindList.find((item: any) => item.id === e);
+                  setProductId(items?.productId);
+                  setParam({
+                    terms: [{ column: 'deviceId', value: e }],
+                  });
+                }}
               >
-                <ProTable
-                  actionRef={actionRef}
-                  params={param}
-                  columns={columns}
-                  rowKey="id"
-                  search={false}
-                  headerTitle={
-                    <>
-                      <PermissionButton
-                        onClick={() => {
-                          setPointVisiable(true);
-                          setCurrent({});
-                        }}
-                        isPermission={permission.add}
-                        key="add"
-                        icon={<PlusOutlined />}
-                        type="primary"
-                      >
-                        {intl.formatMessage({
-                          id: 'pages.data.option.add',
-                          defaultMessage: '新增',
-                        })}
-                      </PermissionButton>
-                      <div style={{ marginLeft: 10 }}>
-                        <Input.Search
-                          placeholder="请输入属性ID"
-                          allowClear
-                          onSearch={(value) => {
-                            console.log(value);
-                            if (value) {
-                              setParam({
-                                terms: [
-                                  { column: 'metadataId', value: `%${value}%`, termType: 'like' },
-                                ],
-                              });
-                            } else {
-                              setParam({
-                                terms: [{ column: 'deviceId', value: deviceId }],
-                              });
-                            }
+                {bindList.map((item: any) => (
+                  <Tabs.TabPane
+                    key={item.id}
+                    tab={
+                      <div className={styles.left}>
+                        <Tooltip title={item.name}>
+                          <div className={styles.text}>{item.name}</div>
+                        </Tooltip>
+                        <Popconfirm
+                          title="确认解绑该设备嘛?"
+                          onConfirm={() => {
+                            service.unbind([item.id], opcUaId).then((res: any) => {
+                              if (res.status === 200) {
+                                message.success('解绑成功');
+                                getBindList(opcUaId);
+                              }
+                            });
                           }}
-                        />
+                          okText="Yes"
+                          cancelText="No"
+                        >
+                          <DisconnectOutlined className={styles.icon} />
+                        </Popconfirm>
                       </div>
-                    </>
-                  }
-                  request={async (params) => {
-                    const res = await service.queryMetadataConfig(opcUaId, deviceId, {
-                      ...params,
-                      sorts: [{ name: 'createTime', order: 'desc' }],
-                    });
-                    setData(res.result.data);
-                    return {
-                      code: res.message,
-                      result: {
-                        data: res.result.data,
-                        pageIndex: 0,
-                        pageSize: 0,
-                        total: 0,
-                      },
-                      status: res.status,
-                    };
-                  }}
-                />
-              </Tabs.TabPane>
-            ))}
-          </Tabs>
+                    }
+                  ></Tabs.TabPane>
+                ))}
+              </Tabs>
+            </div>
+            <div style={{ width: '100%' }}>
+              <ProTable
+                actionRef={actionRef}
+                params={param}
+                columns={columns}
+                rowKey="id"
+                search={false}
+                headerTitle={
+                  <>
+                    <PermissionButton
+                      onClick={() => {
+                        setPointVisiable(true);
+                        setCurrent({});
+                      }}
+                      isPermission={permission.add}
+                      key="add"
+                      icon={<PlusOutlined />}
+                      type="primary"
+                    >
+                      {intl.formatMessage({
+                        id: 'pages.data.option.add',
+                        defaultMessage: '新增',
+                      })}
+                    </PermissionButton>
+                    <div style={{ marginLeft: 10 }}>
+                      <Input.Search
+                        placeholder="请输入属性ID"
+                        allowClear
+                        onSearch={(value) => {
+                          console.log(value);
+                          if (value) {
+                            setParam({
+                              terms: [
+                                { column: 'metadataId', value: `%${value}%`, termType: 'like' },
+                              ],
+                            });
+                          } else {
+                            setParam({
+                              terms: [{ column: 'deviceId', value: deviceId }],
+                            });
+                          }
+                        }}
+                      />
+                    </div>
+                  </>
+                }
+                request={async (params) => {
+                  const res = await service.queryMetadataConfig(opcUaId, deviceId, {
+                    ...params,
+                    sorts: [{ name: 'createTime', order: 'desc' }],
+                  });
+                  setData(res.result.data);
+                  return {
+                    code: res.message,
+                    result: {
+                      data: res.result.data,
+                      pageIndex: 0,
+                      pageSize: 0,
+                      total: 0,
+                    },
+                    status: res.status,
+                  };
+                }}
+              />
+            </div>
+          </div>
         ) : (
           <Empty />
         )}

+ 23 - 6
src/pages/link/Channel/Modbus/Save/index.tsx

@@ -6,6 +6,7 @@ import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/link/Channel/Modbus';
 import { Modal } from '@/components';
 import { message } from 'antd';
+import { useEffect } from 'react';
 
 interface Props {
   data: any;
@@ -141,15 +142,31 @@ const Save = (props: Props) => {
           }
         });
     } else {
-      service.save(value).then((res: any) => {
-        if (res.status === 200) {
-          message.success('保存成功');
-          props.close();
-        }
-      });
+      if (props.device) {
+        service.save(value).then((res: any) => {
+          if (res.status === 200) {
+            service.bind([props.device.id], res.result.id).then((resp: any) => {
+              if (resp.status === 200) {
+                message.success('保存成功');
+                props.close();
+              }
+            });
+          }
+        });
+      } else {
+        service.save(value).then((res: any) => {
+          if (res.status === 200) {
+            message.success('保存成功');
+            props.close();
+          }
+        });
+      }
     }
   };
 
+  useEffect(() => {
+    console.log(props.data.id);
+  }, []);
   return (
     <Modal
       title={intl.formatMessage({

+ 1 - 0
src/pages/link/Channel/Modbus/index.tsx

@@ -141,6 +141,7 @@ const Modbus = () => {
           disabled={record.state.value === 'enabled'}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enabled',
             onConfirm: async () => {
               const resp: any = await service.remove(record.id);
               if (resp.status === 200) {

+ 3 - 2
src/pages/link/Channel/Opcua/Access/addPoint/index.tsx

@@ -123,6 +123,7 @@ const AddPoint = (props: Props) => {
         layout="vertical"
         initialValues={{
           ...props.data,
+          enableCalculate: props.data.enableCalculate || false,
           initialValue: props.data?.configuration?.initialValue,
           multiple: props.data?.configuration?.multiple,
         }}
@@ -145,7 +146,7 @@ const AddPoint = (props: Props) => {
         <Row gutter={[24, 24]}>
           <Col span={12}>
             <Form.Item
-              label="属性"
+              label="属性ID"
               name="property"
               required
               rules={[{ required: true, message: '属性必选' }]}
@@ -235,7 +236,7 @@ const AddPoint = (props: Props) => {
             </Col>
             <Col span={12}>
               <Form.Item label="倍数" name="multiple" required>
-                <InputNumber style={{ width: '100%' }} min={1} />
+                <InputNumber style={{ width: '100%' }} min={1} placeholder="请输入倍数" />
               </Form.Item>
             </Col>
           </Row>

+ 15 - 3
src/pages/link/Channel/Opcua/Access/index.less

@@ -1,7 +1,12 @@
 .list {
   :global {
-    .ant-tabs-tab .ant-tabs-tab-active .ant-tabs-tab-btn {
-      text-shadow: 0 0 0 currentColor;
+    .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
+      color: #1d39c4;
+      text-shadow: none;
+    }
+
+    .ant-tabs-content-holder {
+      width: 1px;
     }
   }
 }
@@ -11,7 +16,14 @@
   align-items: center;
   justify-content: space-between;
   width: 200px;
-
+  .text {
+    width: 130px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-align: left;
+    text-overflow: ellipsis;
+    word-break: break-all;
+  }
   .icon {
     display: none;
   }

+ 143 - 141
src/pages/link/Channel/Opcua/Access/index.tsx

@@ -1,7 +1,7 @@
 import PermissionButton from '@/components/PermissionButton';
 import { PageContainer } from '@ant-design/pro-layout';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
-import { Badge, Card, Empty, Input, message, Popconfirm, Tabs } from 'antd';
+import { Badge, Card, Empty, Input, message, Popconfirm, Tabs, Tooltip } from 'antd';
 import { useIntl, useLocation } from 'umi';
 import { useEffect, useRef, useState } from 'react';
 import {
@@ -36,6 +36,7 @@ const Access = () => {
   const [data, setData] = useState<any>([]);
   const [subscribeTopic] = useSendWebsocketMessage();
   const [propertyValue, setPropertyValue] = useState<any>({});
+  const wsRef = useRef<any>();
 
   const columns: ProColumns<any>[] = [
     {
@@ -56,8 +57,7 @@ const Access = () => {
     },
     {
       title: '值',
-      // dataIndex: '4',
-      render: (record: any) => <>{propertyValue[record.property]}</>,
+      render: (record: any) => <>{propertyValue[record?.property] || '-'}</>,
     },
     {
       title: '状态',
@@ -96,7 +96,9 @@ const Access = () => {
           style={{ padding: 0 }}
           popConfirm={{
             title: intl.formatMessage({
-              id: `pages.data.option.${record.state.value !== 'disable' ? 'disable' : 'good'}.tips`,
+              id: `pages.data.option.${
+                record.state.value !== 'disable' ? 'disable' : 'enable'
+              }.tips`,
               defaultMessage: '确认禁用?',
             }),
             onConfirm: async () => {
@@ -117,7 +119,7 @@ const Access = () => {
           isPermission={permission.action}
           tooltip={{
             title: intl.formatMessage({
-              id: `pages.data.option.${record.state.value !== 'disable' ? 'disable' : 'good'}`,
+              id: `pages.data.option.${record.state.value !== 'disable' ? 'disable' : 'enable'}`,
               defaultMessage: record.state.value !== 'disable' ? '禁用' : '启用',
             }),
           }}
@@ -127,7 +129,7 @@ const Access = () => {
         <PermissionButton
           isPermission={permission.delete}
           style={{ padding: 0 }}
-          disabled={record.state.value === 'good'}
+          disabled={record.state.value === 'enable'}
           tooltip={{
             title:
               record.state.value === 'disable'
@@ -135,12 +137,12 @@ const Access = () => {
                     id: 'pages.data.option.remove',
                     defaultMessage: '删除',
                   })
-                : '请先禁用该组件,再删除。',
+                : '请先禁用该点位,再删除。',
           }}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enable',
             onConfirm: async () => {
-              console.log(111);
               const resp: any = await service.deletePoint(record.id);
               if (resp.status === 200) {
                 message.success(
@@ -162,28 +164,8 @@ const Access = () => {
     },
   ];
 
-  const pointWs = () => {
-    if (productId && deviceId) {
-      const id = `instance-info-property-${deviceId}-${productId}-opc-point`;
-      const topic = `/dashboard/device/${productId}/properties/realTime`;
-      subscribeTopic!(id, topic, {
-        deviceId: deviceId,
-        properties: data.map((item: any) => item.property),
-        history: 0,
-      })
-        ?.pipe(map((res) => res.patload))
-        .subscribe((payload: any) => {
-          const { value } = payload;
-          console.log(value);
-          propertyValue[value.property] = { ...payload, ...value };
-          setPropertyValue({ ...propertyValue });
-        });
-    }
-  };
-
   const getBindList = (params: any) => {
-    service.getBindList(params).then((res) => {
-      console.log(res.result);
+    service.getBindList(params).then((res: any) => {
       if (res.status === 200) {
         setDeviceId(res.result[0]?.deviceId);
         setProductId(res.result[0]?.productId);
@@ -195,12 +177,25 @@ const Access = () => {
     });
   };
 
-  // useEffect(() => {
-  //   pointWs();
-  // }, [deviceId, productId])
-
   useEffect(() => {
-    pointWs();
+    if (productId && deviceId) {
+      const point = data.map((item: any) => item.property);
+      const id = `instance-info-property-${deviceId}-${productId}-${point.join('-')}`;
+      const topic = `/dashboard/device/${productId}/properties/realTime`;
+      wsRef.current = subscribeTopic?.(id, topic, {
+        deviceId: deviceId,
+        properties: data.map((item: any) => item.property),
+        history: 1,
+      })
+        ?.pipe(map((res) => res.payload))
+        .subscribe((payload: any) => {
+          const { value } = payload;
+          propertyValue[value.property] = value.formatValue;
+          setPropertyValue({ ...propertyValue });
+          // console.log(propertyValue)
+        });
+    }
+    return () => wsRef.current && wsRef.current?.unsubscribe();
   }, [data]);
 
   useEffect(() => {
@@ -229,120 +224,127 @@ const Access = () => {
           key="add"
           icon={<PlusOutlined />}
           type="dashed"
-          style={{ width: '200px', marginLeft: 20, marginBottom: 5 }}
+          style={{ width: '200px', margin: '16px 0 18px 20px' }}
         >
           绑定设备
         </PermissionButton>
         {bindList.length > 0 ? (
-          <Tabs
-            tabPosition={'left'}
-            defaultActiveKey={deviceId}
-            onChange={(e) => {
-              setDeviceId(e);
-              const items = bindList.find((item: any) => item.deviceId === e);
-              setProductId(items[0]?.productId);
-              setParam({
-                terms: [{ column: 'deviceId', value: e }],
-              });
-            }}
-          >
-            {bindList.map((item: any) => (
-              <Tabs.TabPane
-                key={item.deviceId}
-                tab={
-                  <div className={styles.left}>
-                    <div style={{ width: '100px', textAlign: 'left' }}>{item.name}</div>
-                    <Popconfirm
-                      title="确认解绑该设备嘛?"
-                      onConfirm={() => {
-                        service.unbind([item.deviceId], opcUaId).then((res) => {
-                          if (res.status === 200) {
-                            message.success('解绑成功');
-                            getBindList(
-                              encodeQuery({
-                                terms: {
-                                  opcUaId: opcUaId,
-                                },
-                              }),
-                            );
-                          }
-                        });
-                      }}
-                      okText="Yes"
-                      cancelText="No"
-                    >
-                      <DisconnectOutlined className={styles.icon} />
-                    </Popconfirm>
-                  </div>
-                }
+          <div style={{ display: 'flex' }}>
+            <div>
+              <Tabs
+                tabPosition={'left'}
+                defaultActiveKey={deviceId}
+                onChange={(e) => {
+                  setDeviceId(e);
+                  const items = bindList.find((item: any) => item.deviceId === e);
+                  setProductId(items?.productId);
+                  setParam({
+                    terms: [{ column: 'deviceId', value: e }],
+                  });
+                }}
               >
-                <ProTable
-                  actionRef={actionRef}
-                  params={param}
-                  columns={columns}
-                  rowKey="id"
-                  search={false}
-                  headerTitle={
-                    <>
-                      <PermissionButton
-                        onClick={() => {
-                          setPointVisiable(true);
-                          setCurrent({});
-                        }}
-                        isPermission={permission.add}
-                        key="add"
-                        icon={<PlusOutlined />}
-                        type="primary"
-                      >
-                        {intl.formatMessage({
-                          id: 'pages.data.option.add',
-                          defaultMessage: '新增',
-                        })}
-                      </PermissionButton>
-                      <div style={{ marginLeft: 10 }}>
-                        <Input.Search
-                          placeholder="请输入属性"
-                          allowClear
-                          onSearch={(value) => {
-                            console.log(value);
-                            if (value) {
-                              setParam({
-                                terms: [
-                                  { column: 'deviceId', value: deviceId },
-                                  { column: 'property', value: `%${value}%`, termType: 'like' },
-                                ],
-                              });
-                            } else {
-                              setParam({
-                                terms: [{ column: 'deviceId', value: deviceId }],
-                              });
-                            }
+                {bindList.map((item: any) => (
+                  <Tabs.TabPane
+                    key={item.deviceId}
+                    tab={
+                      <div className={styles.left}>
+                        <Tooltip title={item.name}>
+                          <div className={styles.text}>{item.name}</div>
+                        </Tooltip>
+                        <Popconfirm
+                          title="确认解绑该设备嘛?"
+                          onConfirm={() => {
+                            service.unbind([item.deviceId], opcUaId).then((res: any) => {
+                              if (res.status === 200) {
+                                message.success('解绑成功');
+                                getBindList(
+                                  encodeQuery({
+                                    terms: {
+                                      opcUaId: opcUaId,
+                                    },
+                                  }),
+                                );
+                              }
+                            });
                           }}
-                        />
+                          okText="Yes"
+                          cancelText="No"
+                        >
+                          <DisconnectOutlined className={styles.icon} />
+                        </Popconfirm>
                       </div>
-                    </>
-                  }
-                  request={async (params) => {
-                    const res = await service.PointList({
-                      ...params,
-                      sorts: [{ name: 'createTime', order: 'desc' }],
-                    });
-                    setData(res.result.data);
-                    return {
-                      code: res.message,
-                      result: {
-                        data: res.result.data,
-                        pageIndex: 0,
-                        pageSize: 0,
-                        total: 0,
-                      },
-                      status: res.status,
-                    };
-                  }}
-                />
-              </Tabs.TabPane>
-            ))}
-          </Tabs>
+                    }
+                  ></Tabs.TabPane>
+                ))}
+              </Tabs>
+            </div>
+            <div style={{ width: '100%' }}>
+              <ProTable
+                actionRef={actionRef}
+                params={param}
+                columns={columns}
+                rowKey="id"
+                search={false}
+                headerTitle={
+                  <>
+                    <PermissionButton
+                      onClick={() => {
+                        setPointVisiable(true);
+                        setCurrent({});
+                      }}
+                      isPermission={permission.add}
+                      key="add"
+                      icon={<PlusOutlined />}
+                      type="primary"
+                    >
+                      {intl.formatMessage({
+                        id: 'pages.data.option.add',
+                        defaultMessage: '新增',
+                      })}
+                    </PermissionButton>
+                    <div style={{ marginLeft: 10 }}>
+                      <Input.Search
+                        placeholder="请输入属性"
+                        allowClear
+                        onSearch={(value) => {
+                          console.log(value);
+                          if (value) {
+                            setParam({
+                              terms: [
+                                { column: 'deviceId', value: deviceId },
+                                { column: 'property', value: `%${value}%`, termType: 'like' },
+                              ],
+                            });
+                          } else {
+                            setParam({
+                              terms: [{ column: 'deviceId', value: deviceId }],
+                            });
+                          }
+                        }}
+                      />
+                    </div>
+                  </>
+                }
+                request={async (params) => {
+                  const res = await service.PointList({
+                    ...params,
+                    sorts: [{ name: 'createTime', order: 'desc' }],
+                  });
+                  setData(res.result.data);
+                  return {
+                    code: res.message,
+                    result: {
+                      data: res.result.data,
+                      pageIndex: 0,
+                      pageSize: 0,
+                      total: 0,
+                    },
+                    status: res.status,
+                  };
+                }}
+              />
+            </div>
+          </div>
         ) : (
           <Empty />
         )}

+ 1 - 0
src/pages/link/Channel/Opcua/index.tsx

@@ -136,6 +136,7 @@ const Opcua = () => {
           disabled={record.state.value === 'enabled'}
           popConfirm={{
             title: '确认删除',
+            disabled: record.state.value === 'enable',
             onConfirm: async () => {
               const resp: any = await service.remove(record.id);
               if (resp.status === 200) {