Browse Source

feat: merge

xieyonghong 3 years ago
parent
commit
4186b4e4f6

BIN
public/images/bind/Rectangle.png


BIN
public/images/bind/Vector.png


BIN
public/images/bind/bindPage.png


BIN
public/images/bind/jetlinksLogo.png


+ 18 - 3
src/components/ProTableCard/CardItems/AlarmConfig.tsx

@@ -1,10 +1,12 @@
 import React from 'react';
-import { TableCard } from '@/components';
+import { PermissionButton, TableCard } from '@/components';
 import '@/style/common.less';
 import '../index.less';
 import { StatusColorEnum } from '@/components/BadgeStatus';
 import { Tooltip } from 'antd';
 import { Store } from 'jetlinks-store';
+import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { useHistory } from 'umi';
 
 export interface AlarmConfigProps extends ConfigurationItem {
   detail?: React.ReactNode;
@@ -15,6 +17,7 @@ export interface AlarmConfigProps extends ConfigurationItem {
 export const aliyunSms = require('/public/images/alarm/alarm-config.png');
 
 export default (props: AlarmConfigProps) => {
+  const history = useHistory();
   return (
     <TableCard
       actions={props.actions}
@@ -38,8 +41,20 @@ export default (props: AlarmConfigProps) => {
           <div className={'card-item-content'}>
             <div>
               <label>关联场景联动</label>
-              <div className={'ellipsis'}>
-                <Tooltip title={props?.sceneName || ''}>{props?.sceneName || ''}</Tooltip>
+              <div>
+                <PermissionButton
+                  type={'link'}
+                  isPermission={!!getMenuPathByCode(MENUS_CODE['rule-engine/Scene'])}
+                  style={{ padding: 0, height: 'auto' }}
+                  onClick={() => {
+                    const url = getMenuPathByCode('rule-engine/Scene/Save');
+                    history.push(`${url}?id=${props.sceneId}`);
+                  }}
+                >
+                  <div className={'ellipsis'}>
+                    <Tooltip title={props?.sceneName || ''}>{props?.sceneName || ''}</Tooltip>
+                  </div>
+                </PermissionButton>
               </div>
             </div>
             <div>

+ 2 - 0
src/components/Upload/index.tsx

@@ -15,6 +15,7 @@ interface Props {
   type?: 'file' | 'image';
   placeholder: string;
   display?: string;
+  beforeUpload: any;
 }
 
 type FileProperty = {
@@ -91,6 +92,7 @@ const FUpload = connect((props: Props) => {
   });
   return (
     <Upload
+      beforeUpload={props.beforeUpload}
       listType={map.get(props.type || 'image')?.type}
       action={`/${SystemConst.API_BASE}/file/static`}
       headers={{

+ 1 - 0
src/pages/Northbound/AliCloud/Detail/index.tsx

@@ -271,6 +271,7 @@ const Detail = observer(() => {
         required: true,
         'x-component': 'ArrayCollapse',
         'x-decorator': 'FormItem',
+        title: '产品映射',
         items: {
           type: 'object',
           'x-component': 'ArrayCollapse.CollapsePanel',

+ 55 - 8
src/pages/account/Center/bind/index.less

@@ -1,12 +1,59 @@
-.col {
-  display: flex;
-  justify-content: center;
+.cards {
+  position: absolute;
+  top: 150px;
+  left: 17%;
+  box-sizing: border-box;
+  width: 66%;
+  background: #fff;
+  border: 1px solid #e0e4e8;
+  border-radius: 2px;
 
-  .item {
+  .title {
+    margin: 50px 0;
+    color: #0f1222;
+    font-weight: 400;
+    font-size: 24px;
+    font-family: 'PingFang SC';
+    font-style: normal;
+    line-height: 25px;
+    text-align: center;
+  }
+
+  .info {
+    display: flex;
+    justify-content: center;
+
+    .infotitle {
+      width: 64px;
+      height: 24px;
+      margin-left: 10px;
+      color: rgba(0, 0, 0, 0.85);
+      font-weight: 400;
+      font-size: 16px;
+      font-family: 'PingFang SC';
+      font-style: normal;
+      line-height: 24px;
+    }
+
+    .item {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      width: 300px;
+
+      .fonts {
+        font-weight: 400;
+        font-size: 16px;
+        font-family: 'PingFang SC';
+        font-style: normal;
+        line-height: 16px;
+        opacity: 0.75;
+        mix-blend-mode: normal;
+      }
+    }
+  }
+  .btn {
     display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: space-around;
-    width: 300px;
+    justify-content: center;
   }
 }

+ 74 - 49
src/pages/account/Center/bind/index.tsx

@@ -1,4 +1,4 @@
-import { Avatar, Button, Card, Col, message, Row } from 'antd';
+import { Button, Card, message } from 'antd';
 import { useEffect, useState } from 'react';
 import Service from '@/pages/account/Center/service';
 import styles from './index.less';
@@ -10,14 +10,15 @@ const Bind = () => {
   const [user, setUser] = useState<any>();
   const [code, setCode] = useState<string>('');
 
+  const bindPage = require('/public/images/bind/bindPage.png');
+  const Vector = require('/public/images/bind/Vector.png');
+  const Rectangle = require('/public/images/bind/Rectangle.png');
+  const logo = require('/public/images/bind/jetlinksLogo.png');
+
   const iconMap = new Map();
   iconMap.set('dingtalk', require('/public/images/notice/dingtalk.png'));
   iconMap.set('wechat-webapp', require('/public/images/notice/wechat.png'));
 
-  const bGroundMap = new Map();
-  bGroundMap.set('dingtalk', require('/public/images/notice/dingtalk-background.png'));
-  bGroundMap.set('wechat-webapp', require('/public/images/notice/wechat-background.png'));
-
   const bindUserInfo = (params: string) => {
     service.bindUserInfo(params).then((res) => {
       if (res.status === 200) {
@@ -40,55 +41,79 @@ const Bind = () => {
   }, []);
   return (
     <>
-      <Card>
-        <div style={{ margin: '0 auto', width: 800 }}>
-          <Row>
-            <Col span={12} className={styles.col}>
-              <Card title="个人信息">
-                <div className={styles.item}>
-                  <div style={{ height: 100 }}>
-                    <Avatar size={90} src={user?.avatar} />
+      <div
+        style={{
+          width: '100%',
+          height: '100%',
+          background: `url(${bindPage}) no-repeat`,
+          backgroundSize: '100% 100%',
+        }}
+      >
+        <div className={styles.cards}>
+          <div className={styles.title}>第三方账户绑定</div>
+          <div className={styles.info}>
+            <Card
+              title={
+                <div style={{ display: 'flex', alignItems: 'center' }}>
+                  <div>
+                    <img src={Rectangle} />
                   </div>
-                  <p>登录账号:{user?.username}</p>
-                  <p>姓名:{user?.name}</p>
+                  <div className={styles.infotitle}>个人信息</div>
                 </div>
-              </Card>
-            </Col>
-            <Col span={12} className={styles.col}>
-              <Card title="三方账号信息">
-                <div className={styles.item}>
-                  <div style={{ height: 100 }}>
-                    <img style={{ height: 80 }} src={iconMap.get(bindUser?.type)} />
+              }
+            >
+              <div className={styles.item}>
+                <div style={{ height: 100, marginTop: 10, marginBottom: 10 }}>
+                  <img src={logo} style={{ width: 90, height: 90 }} />
+                </div>
+                <p className={styles.fonts}>账号:{user?.username}</p>
+                <p className={styles.fonts}>用户名:{user?.name}</p>
+              </div>
+            </Card>
+            <div style={{ position: 'relative', top: '135px', margin: '0 20px' }}>
+              <img src={Vector} />
+            </div>
+            <Card
+              title={
+                <div style={{ display: 'flex', alignItems: 'center' }}>
+                  <div>
+                    <img src={Rectangle} />
                   </div>
-                  <p>组织:{bindUser?.providerName}</p>
-                  <p>名字:{bindUser?.result.others.name}</p>
+                  <div className={styles.infotitle}>三方账户信息</div>
+                </div>
+              }
+            >
+              <div className={styles.item}>
+                <div style={{ height: 100, marginTop: 10, marginBottom: 10 }}>
+                  <img style={{ height: 80 }} src={iconMap.get(bindUser?.type)} />
                 </div>
-              </Card>
-            </Col>
-          </Row>
-          <Row>
-            <Col span={24} style={{ textAlign: 'center', marginTop: 20 }}>
-              <Button
-                type="primary"
-                onClick={() => {
-                  // window.close()
-                  service.bind(code).then((res) => {
-                    if (res.status === 200) {
-                      message.success('绑定成功');
-                      localStorage.setItem('onBind', 'true');
-                      setTimeout(() => window.close(), 300);
-                    } else {
-                      message.error('绑定失败');
-                    }
-                  });
-                }}
-              >
-                立即绑定
-              </Button>
-            </Col>
-          </Row>
+                <p className={styles.fonts}>账户:{bindUser?.providerName}</p>
+                <p className={styles.fonts}>用户名:{bindUser?.result.others.name}</p>
+              </div>
+            </Card>
+          </div>
+          <div className={styles.btn}>
+            <Button
+              style={{ marginTop: 30, marginBottom: 30 }}
+              type="primary"
+              onClick={() => {
+                // window.close()
+                service.bind(code).then((res) => {
+                  if (res.status === 200) {
+                    message.success('绑定成功');
+                    localStorage.setItem('onBind', 'true');
+                    setTimeout(() => window.close(), 1000);
+                  } else {
+                    message.error('绑定失败');
+                  }
+                });
+              }}
+            >
+              立即绑定
+            </Button>
+          </div>
         </div>
-      </Card>
+      </div>
     </>
   );
 };

+ 5 - 4
src/pages/device/Instance/Detail/MetadataLog/Property/index.tsx

@@ -56,7 +56,7 @@ const PropertyLog = (props: Props) => {
       render: (text: any) => <span>{text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : ''}</span>,
     },
     {
-      title: <span>{data.valueType?.type !== 'file' ? '自定义属性' : '文件内容'}</span>,
+      title: <span>{data.name}</span>,
       dataIndex: 'value',
       key: 'value',
       ellipsis: true,
@@ -110,7 +110,7 @@ const PropertyLog = (props: Props) => {
       render: (text: any) => <span>{text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : ''}</span>,
     },
     {
-      title: '位置',
+      title: <span>{data.name}</span>,
       dataIndex: 'value',
       key: 'value',
       render: (text: any, record: any) => (
@@ -252,6 +252,7 @@ const PropertyLog = (props: Props) => {
               pageSize: dataSource?.pageSize || 10,
               showSizeChanger: true,
               total: dataSource?.total || 0,
+              pageSizeOptions: [5, 10, 20, 50],
             }}
           />
         );
@@ -344,7 +345,7 @@ const PropertyLog = (props: Props) => {
     if (tab === 'table') {
       handleSearch(
         {
-          pageSize: 10,
+          pageSize: data.valueType?.type === 'file' ? 5 : 10,
           pageIndex: 0,
         },
         start,
@@ -496,7 +497,7 @@ const PropertyLog = (props: Props) => {
             if (key === 'table') {
               handleSearch(
                 {
-                  pageSize: 10,
+                  pageSize: data.valueType?.type === 'file' ? 5 : 10,
                   pageIndex: 0,
                 },
                 start,

+ 15 - 10
src/pages/device/Instance/Detail/Opcua/index.tsx

@@ -1,6 +1,6 @@
 import PermissionButton from '@/components/PermissionButton';
 import { Badge, Card, Empty, message, Tabs, Tooltip } from 'antd';
-import { useEffect, useRef, useState } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
 import { useIntl } from 'umi';
 import styles from '@/pages/link/Channel/Opcua/Access/index.less';
 import ProTable, { ActionType, ProColumns } from '@jetlinks/pro-table';
@@ -181,6 +181,19 @@ const Opcua = () => {
       });
   };
 
+  const edit = useMemo(
+    () => (
+      <Save
+        data={channel}
+        close={() => {
+          setVisible(false);
+        }}
+        device={InstanceModel.detail}
+      />
+    ),
+    [channel.id],
+  );
+
   useEffect(() => {
     const { id } = InstanceModel.detail;
     setDeviceId(id);
@@ -342,15 +355,7 @@ const Opcua = () => {
       ) : (
         <Empty />
       )}
-      {visible && (
-        <Save
-          data={channel}
-          close={() => {
-            setVisible(false);
-          }}
-          device={InstanceModel.detail}
-        />
-      )}
+      {visible && edit}
       {pointVisiable && (
         <AddPoint
           deviceId={deviceId}

+ 1 - 1
src/pages/device/Instance/Detail/Running/Property/FileComponent/index.less

@@ -2,7 +2,7 @@
   display: flex;
   align-items: center;
   width: 100%;
-  height: 60px;
+  max-height: 60px;
 
   .other {
     width: 100%;

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

@@ -6,7 +6,7 @@ import {
 } from '@ant-design/icons';
 import { Card, message, Space, Spin, Tooltip } from 'antd';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
 import { service } from '@/pages/device/Instance';
 import { useParams } from 'umi';
 import PropertyLog from '@/pages/device/Instance/Detail/MetadataLog/Property';
@@ -40,6 +40,7 @@ const Property = (props: Props) => {
   const [visible, setVisible] = useState<boolean>(false);
   const [editVisible, setEditVisible] = useState<boolean>(false);
   const [indicatorVisible, setIndicatorVisible] = useState<boolean>(false);
+  const [dataValue, setDataValue] = useState<any>(null);
 
   const renderTitle = (title: string) => {
     return (
@@ -84,12 +85,20 @@ const Property = (props: Props) => {
     );
   };
 
+  useEffect(() => {
+    if (!dataValue?.timestamp) {
+      setDataValue(value);
+    } else if (dataValue?.timestamp && dataValue?.timestamp < value?.timestamp) {
+      setDataValue(value);
+    }
+  }, [value]);
+
   return (
     <Card bordered hoverable style={{ backgroundColor: 'rgba(0, 0, 0, .02)' }}>
       <Spin spinning={loading}>
         <div>
           <div>{renderTitle(data?.name || '')}</div>
-          <FileComponent type="card" value={value} data={data} />
+          <FileComponent type="card" value={dataValue} data={data} />
           <div style={{ marginTop: 10 }}>
             <div style={{ color: 'rgba(0, 0, 0, .65)', fontSize: 12 }}>更新时间</div>
             <div style={{ marginTop: 5, fontSize: 16, color: 'black' }} className="value">

+ 33 - 0
src/pages/device/Instance/Detail/Running/Property/PropertyTable.tsx

@@ -0,0 +1,33 @@
+import moment from 'moment';
+import { useEffect, useState } from 'react';
+import FileComponent from './FileComponent';
+
+interface Props {
+  type: 'time' | 'value';
+  data: any;
+  value: any;
+}
+const PropertyTable = (props: Props) => {
+  const { type, data, value } = props;
+  const [dataValue, setDataValue] = useState<any>(null);
+
+  useEffect(() => {
+    if (!dataValue?.timestamp) {
+      setDataValue(value);
+    } else if (dataValue?.timestamp && dataValue?.timestamp < value?.timestamp) {
+      setDataValue(value);
+    }
+  }, [value]);
+
+  return (
+    <div>
+      {type === 'time' ? (
+        <span>{moment(dataValue?.timestamp).format('YYYY-MM-DD HH:mm:ss')}</span>
+      ) : (
+        <FileComponent type="table" value={dataValue} data={data} />
+      )}
+    </div>
+  );
+};
+
+export default PropertyTable;

+ 42 - 17
src/pages/device/Instance/Detail/Running/Property/index.tsx

@@ -1,6 +1,6 @@
 import { Col, Input, message, Pagination, Row, Space, Table } from 'antd';
 import CheckButton from '@/components/CheckButton';
-import { useEffect, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
 import type { PropertyMetadata } from '@/pages/device/Product/typings';
 import PropertyCard from './PropertyCard';
 import { EditOutlined, SyncOutlined, UnorderedListOutlined } from '@ant-design/icons';
@@ -10,9 +10,9 @@ import { map } from 'rxjs/operators';
 import EditProperty from './EditProperty';
 import { useParams } from 'umi';
 import PropertyLog from '../../MetadataLog/Property';
-import moment from 'moment';
 import styles from './index.less';
-import FileComponent from './FileComponent';
+import { throttle } from 'lodash';
+import PropertyTable from './PropertyTable';
 
 interface Props {
   data: Partial<PropertyMetadata>[];
@@ -64,17 +64,17 @@ const Property = (props: Props) => {
       title: '值',
       dataIndex: 'value',
       key: 'value',
-      render: (text: any, record: any) => (
-        <FileComponent type="table" value={propertyValue[record.id]} data={record} />
-      ),
+      render: (text: any, record: any) => {
+        return <PropertyTable type="value" value={propertyValue[record.id]} data={record} />;
+      },
     },
     {
       title: '更新时间',
       dataIndex: 'time',
       key: 'time',
-      render: (text: any, record: any) => (
-        <span>{moment(propertyValue[record.id]?.timestamp).format('YYYY-MM-DD HH:mm:ss')}</span>
-      ),
+      render: (text: any, record: any) => {
+        return <PropertyTable type="time" value={propertyValue[record.id]} data={record} />;
+      },
     },
     {
       title: '操作',
@@ -110,6 +110,24 @@ const Property = (props: Props) => {
     },
   ];
 
+  const list = useRef<any[]>([]);
+
+  const subRef = useRef<any>(null);
+
+  const valueChange = (payload: any) => {
+    (payload || [])
+      .sort((a: any, b: any) => a.timestamp - b.timestamp)
+      .forEach((item: any) => {
+        const { value } = item;
+        propertyValue[value?.property] = { ...item, ...value };
+      });
+    setPropertyValue({ ...propertyValue });
+    list.current = [];
+  };
+
+  // eslint-disable-next-line react-hooks/exhaustive-deps
+  const throttleFn = useCallback(throttle(valueChange, 500), []);
+
   /**
    * 订阅属性数据
    */
@@ -118,16 +136,15 @@ const Property = (props: Props) => {
       .map((i: PropertyMetadata) => i.id)
       .join('-')}`;
     const topic = `/dashboard/device/${device.productId}/properties/realTime`;
-    subscribeTopic!(id, topic, {
+    subRef.current = subscribeTopic!(id, topic, {
       deviceId: device.id,
       properties: dataSource.data.map((i: PropertyMetadata) => i.id),
       history: 1,
     })
       ?.pipe(map((res) => res.payload))
       .subscribe((payload: any) => {
-        const { value } = payload;
-        propertyValue[value.property] = { ...payload, ...value };
-        setPropertyValue({ ...propertyValue });
+        list.current = [...list.current, payload];
+        throttleFn(list.current);
       });
   };
 
@@ -161,6 +178,13 @@ const Property = (props: Props) => {
     }
   }, [dataSource]);
 
+  useEffect(() => {
+    return () => {
+      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
+      subRef.current && subRef.current?.unsubscribe();
+    };
+  }, []);
+
   return (
     <div>
       <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
@@ -170,15 +194,15 @@ const Property = (props: Props) => {
             placeholder="请输入名称"
             onSearch={(value: string) => {
               if (!!value) {
-                const list = data.filter((item) => {
+                const li = data.filter((item) => {
                   return (
                     item.name && item.name.toLowerCase().indexOf(value.toLocaleLowerCase()) !== -1
                   );
                 });
-                setPropertyList(list);
+                setPropertyList(li);
                 setDataSource({
-                  total: list.length,
-                  data: (list || []).slice(0, 8),
+                  total: li.length,
+                  data: (li || []).slice(0, 8),
                   pageSize: 8,
                   currentPage: 0,
                 });
@@ -229,6 +253,7 @@ const Property = (props: Props) => {
               total={dataSource.total}
               showSizeChanger
               pageSize={dataSource.pageSize}
+              pageSizeOptions={[8, 16, 32, 48]}
               onChange={(page: number, size: number) => {
                 setDataSource({
                   total: propertyList.length,

+ 15 - 10
src/pages/device/Instance/Detail/index.tsx

@@ -149,24 +149,29 @@ const InstanceDetail = observer(() => {
       tab: '物模型映射',
       component: <MetadataMap type="device" />,
     },
-    {
-      key: 'opcua',
-      tab: 'OPC UA',
-      component: <Opcua />,
-    },
-    {
-      key: 'modbus',
-      tab: 'Modbus',
-      component: <Modbus />,
-    },
   ];
   const [list, setList] =
     useState<{ key: string; tab: string | ReactNode; component: ReactNode }[]>(baseList);
 
   const getDetail = (id: string) => {
     service.detail(id).then((response) => {
+      console.log(response.result);
       InstanceModel.detail = response?.result;
       const datalist = [...baseList];
+      if (response.result.protocol === 'modbus-tcp') {
+        datalist.push({
+          key: 'modbus',
+          tab: 'Modbus',
+          component: <Modbus />,
+        });
+      }
+      if (response.result.protocol === 'opc-ua') {
+        datalist.push({
+          key: 'opcua',
+          tab: 'OPC UA',
+          component: <Opcua />,
+        });
+      }
       if (response.result.deviceType?.value === 'gateway') {
         // 产品类型为网关的情况下才显示此模块
         datalist.push({

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

@@ -137,6 +137,7 @@ const Import = (props: Props) => {
               formatOnPaste: true,
               type: 'file',
               beforeUpload: (file: any) => {
+                console.log(file, 'fff');
                 const reader = new FileReader();
                 reader.readAsText(file);
                 reader.onload = (json) => {
@@ -182,6 +183,7 @@ const Import = (props: Props) => {
     if (data.metadata === 'alink') {
       service.convertMetadata('to', 'alink', data.import).subscribe({
         next: async (meta) => {
+          message.success('导入成功');
           await service.modify(param.id, { metadata: JSON.stringify(meta) });
         },
         error: () => {
@@ -189,10 +191,12 @@ const Import = (props: Props) => {
         },
       });
     } else {
-      await service.modify(param.id, { metadata: data[data.type] });
+      const resp = await service.modify(param.id, { metadata: data[data.type] });
+      if (resp.status === '200') {
+        message.success('导入成功');
+      }
     }
     Store.set(SystemConst.GET_METADATA, true);
-    message.success('导入成功');
     props.close();
   };
   return (

+ 10 - 17
src/pages/link/Channel/Modbus/Access/addPoint/index.tsx

@@ -57,8 +57,10 @@ const AddPoint = (props: Props) => {
         initialValues={{
           ...props.data,
           codecConfig: {
+            ...props.data?.codecConfig,
             readIndex: props.data?.codecConfig?.readIndex || 0,
             scaleFactor: props.data?.codecConfig?.scaleFactor || 1,
+            revertBytes: props.data?.codecConfig?.revertBytes || false,
           },
         }}
       >
@@ -138,23 +140,14 @@ const AddPoint = (props: Props) => {
             </Form.Item>
           </Col>
           <Col span={12}>
-            <Form.Item
-              label="读取长度"
-              name={['codecConfig', 'readLength']}
-              required
-              rules={[
-                { required: true, message: '请输入读取长度' },
-                ({}) => ({
-                  validator(_, value) {
-                    if (value !== 0 || /(^[1-9]\d*$)/.test(value)) {
-                      return Promise.resolve();
-                    }
-                    return Promise.reject(new Error('请输入正整数'));
-                  },
-                }),
-              ]}
-            >
-              <InputNumber style={{ width: '100%' }} placeholder="请输入" min={1} />
+            <Form.Item label="读取长度" name={['codecConfig', 'readLength']} required>
+              <Select placeholder="请选择">
+                <Select.Option value={1}>1</Select.Option>
+                <Select.Option value={2}>2</Select.Option>
+                <Select.Option value={3}>3</Select.Option>
+                <Select.Option value={4}>4</Select.Option>
+                <Select.Option value={8}>8</Select.Option>
+              </Select>
             </Form.Item>
           </Col>
         </Row>

+ 2 - 2
src/pages/link/Channel/Modbus/index.tsx

@@ -93,12 +93,12 @@ const Modbus = () => {
             onConfirm: async () => {
               if (record.state.value === 'disabled') {
                 await service.edit({
-                  id: record.id,
+                  ...record,
                   state: 'enabled',
                 });
               } else {
                 await service.edit({
-                  id: record.id,
+                  ...record,
                   state: 'disabled',
                 });
               }

+ 12 - 8
src/pages/link/Channel/Opcua/Save/index.tsx

@@ -6,7 +6,7 @@ import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/link/Channel/Opcua';
 import { Modal } from '@/components';
 import { message } from 'antd';
-import { useEffect, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 
 interface Props {
   data: Partial<OpaUa>;
@@ -19,13 +19,17 @@ const Save = (props: Props) => {
   const [policies, setPolicies] = useState<any>([]);
   const [modes, setModes] = useState<any>([]);
 
-  const form = createForm({
-    validateFirst: true,
-    initialValues: {
-      ...props.data,
-      clientConfigs: props.data?.clientConfigs?.[0],
-    },
-  });
+  const form = useMemo(
+    () =>
+      createForm({
+        validateFirst: true,
+        initialValues: {
+          ...props.data,
+          clientConfigs: props.data?.clientConfigs?.[0],
+        },
+      }),
+    [props.data.id],
+  );
 
   const SchemaField = createSchemaField({
     components: {

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

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

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

@@ -203,10 +203,10 @@ const Config = () => {
       createForm({
         validateFirst: true,
         effects() {
-          onFormInit(async () => {
+          onFormInit(async (f) => {
             const resp = await service.getDataExchange('consume');
             if (resp.status === 200) {
-              console.log(resp, 'resp');
+              f.setInitialValues(resp.result?.config.config);
             }
           });
         },
@@ -218,10 +218,10 @@ const Config = () => {
       createForm({
         validateFirst: true,
         effects() {
-          onFormInit(async () => {
+          onFormInit(async (f) => {
             const resp = await service.getDataExchange('producer');
             if (resp.status === 200) {
-              console.log(resp, 'producer');
+              f.setInitialValues(resp.result?.config.config);
             }
           });
         },

+ 25 - 0
src/pages/rule-engine/Alarm/Configuration/index.tsx

@@ -18,11 +18,14 @@ import Save from './Save';
 import Service from '@/pages/rule-engine/Alarm/Configuration/service';
 import AlarmConfig from '@/components/ProTableCard/CardItems/AlarmConfig';
 import { Store } from 'jetlinks-store';
+import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { useHistory } from 'umi';
 
 const service = new Service('alarm/config');
 
 const Configuration = () => {
   const intl = useIntl();
+  const history = useHistory();
   const [visible, setVisible] = useState<boolean>(false);
   const actionRef = useRef<ActionType>();
   const { permission } = PermissionButton.usePermission('rule-engine/Alarm/Configuration');
@@ -36,6 +39,15 @@ const Configuration = () => {
     {
       title: '类型',
       dataIndex: 'targetType',
+      renderText: (text: string) => {
+        const map = {
+          product: '产品',
+          device: '设备',
+          org: '部门',
+          other: '其他',
+        };
+        return map[text];
+      },
     },
     {
       title: '告警级别',
@@ -50,6 +62,19 @@ const Configuration = () => {
     {
       title: '关联场景联动',
       dataIndex: 'sceneName',
+      render: (text: any, record: any) => (
+        <PermissionButton
+          type={'link'}
+          isPermission={!!getMenuPathByCode(MENUS_CODE['rule-engine/Scene'])}
+          style={{ padding: 0, height: 'auto' }}
+          onClick={() => {
+            const url = getMenuPathByCode('rule-engine/Scene/Save');
+            history.push(`${url}?id=${record.sceneId}`);
+          }}
+        >
+          {text}
+        </PermissionButton>
+      ),
     },
     {
       title: '状态',

+ 0 - 21
src/pages/rule-engine/Scene/TriggerTerm/index.tsx

@@ -29,8 +29,6 @@ import { useAsyncDataSource } from '@/utils/util';
 import { Store } from 'jetlinks-store';
 import { treeFilter } from '@/utils/tree';
 import FInputGroup from '@/components/FInputGroup';
-import { Button } from 'antd';
-import _ from 'lodash';
 
 const service = new Service('scene');
 
@@ -490,25 +488,6 @@ const TriggerTerm = (props: Props, ref: any) => {
   return (
     <Form form={form} layout="vertical" className={styles.form}>
       <SchemaField schema={schema} scope={{ useAsyncDataSource, getParseTerm }} />
-      <Button
-        onClick={async () => {
-          const data: any = await form.submit();
-          data.trigger?.map((item: { terms: any[] }) =>
-            item.terms.map((j) => {
-              if (j.value.value.length === 1) {
-                j.value.value = j.value.value[0];
-              }
-              return j;
-            }),
-          );
-          const value = _.get(data, 'trigger[*].terms[*].value.value');
-          console.log(value, 'vvvv');
-          _.set(value, 'x[*].xxx', 'test');
-          console.log(data);
-        }}
-      >
-        保存数据
-      </Button>
     </Form>
   );
 };

+ 0 - 12
src/utils/menu/index.ts

@@ -85,12 +85,6 @@ export const extraRouteArr = [
         url: '/account/center',
       },
       {
-        code: 'account/Center/bind',
-        name: '第三方页面',
-        url: '/account/center/bind',
-        hideInMenu: true,
-      },
-      {
         code: 'account/NotificationSubscription',
         name: '通知订阅',
         url: '/account/NotificationSubscription',
@@ -100,12 +94,6 @@ export const extraRouteArr = [
         name: '通知记录',
         url: '/account/NotificationRecord',
       },
-      // {
-      //   code: 'account/Center/bind',
-      //   name: '第三方页面',
-      //   url: '/account/center/bind',
-      //   hideInMenu: true,
-      // },
     ],
   },
 ];