Prechádzať zdrojové kódy

fix: 产品设备接入配置修改

sun-chaochao 3 rokov pred
rodič
commit
99aa8d2374

+ 74 - 0
src/pages/device/Product/Detail/Access/index.less

@@ -0,0 +1,74 @@
+.box {
+  display: flex;
+  justify-content: space-between;
+}
+
+.images {
+  width: 64px;
+  height: 64px;
+  color: white;
+  font-size: 18px;
+  line-height: 64px;
+  text-align: center;
+  background: linear-gradient(
+    128.453709216706deg,
+    rgba(255, 255, 255, 1) 4%,
+    rgba(113, 187, 255, 1) 43%,
+    rgba(24, 144, 255, 1) 100%
+  );
+  border: 1px solid rgba(242, 242, 242, 1);
+  border-radius: 50%;
+}
+
+.content {
+  display: flex;
+  flex-direction: column;
+  width: calc(100% - 80px);
+}
+
+.top {
+  display: flex;
+}
+
+.desc {
+  width: 100%;
+  margin-top: 10px;
+  overflow: hidden;
+  color: rgba(0, 0, 0, 0.55);
+  font-weight: 400;
+  font-size: 13px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+.title {
+  font-weight: 600;
+  font-size: 14px;
+}
+
+.container {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  height: 90px;
+  margin-top: 10px;
+}
+
+.server {
+  width: 50%;
+  margin-right: 20px;
+}
+.procotol {
+  display: -webkit-box;
+  width: 50%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 4;
+}
+
+:global {
+  .ant-pagination-item {
+    display: none;
+  }
+}

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

@@ -0,0 +1,386 @@
+import {
+  Alert,
+  Badge,
+  Button,
+  Card,
+  Col,
+  Descriptions,
+  message,
+  Pagination,
+  Row,
+  Table,
+  Tooltip,
+} from 'antd';
+import { service } from '@/pages/link/AccessConfig';
+import styles from './index.less';
+import { useEffect, useState } from 'react';
+import Service from '@/pages/device/Product/service';
+import { productModel } from '@/pages/device/Product';
+import type { ProColumns } from '@jetlinks/pro-table';
+import SearchComponent from '@/components/SearchComponent';
+
+const Access = () => {
+  const service1 = new Service('device-product');
+  const [currrent, setCurrrent] = useState<any>({
+    id: productModel.current?.accessId,
+    name: productModel.current?.accessName,
+    protocol: productModel.current?.messageProtocol,
+    transport: productModel.current?.transportProtocol,
+    protocolDetail: {
+      name: productModel.current?.protocolName,
+    },
+  });
+  const [visible, setVisible] = useState<boolean>(true);
+  const [config, setConfig] = useState<any>();
+
+  // const [networkList, setNetworkList] = useState<any[]>([]);
+  // const [procotolList, setProcotolList] = useState<any[]>([]);
+
+  const [param, setParam] = useState<any>({ pageSize: 10 });
+
+  // const queryNetworkList = () => {
+  //     service1.getNetwork({ paging: false }).then((resp) => {
+  //         if (resp.status === 200) {
+  //             setNetworkList(resp.result);
+  //         }
+  //     });
+  // };
+
+  // const queryProcotolList = () => {
+  //     service1.getProtocol().then((resp) => {
+  //         if (resp.status === 200) {
+  //             setProcotolList(resp.result);
+  //         }
+  //     });
+  // };
+
+  const columns: ProColumns<any>[] = [
+    {
+      title: '名称',
+      dataIndex: 'name',
+    },
+  ];
+
+  const [dataSource, setDataSource] = useState<any>({
+    data: [],
+    pageSize: 10,
+    pageIndex: 0,
+    total: 0,
+  });
+
+  const handleSearch = (params: any) => {
+    setParam(params);
+    service
+      .queryList({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+      .then((resp) => {
+        setDataSource(resp.result);
+      });
+  };
+  const columnsMQTT: any[] = [
+    {
+      title: '分组',
+      dataIndex: 'group',
+      key: 'group',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: 'qos',
+      dataIndex: 'qos',
+      key: 'qos',
+      ellipsis: true,
+      align: 'center',
+    },
+    {
+      title: '地址',
+      dataIndex: 'address',
+      key: 'address',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: 'topic',
+      dataIndex: 'topic',
+      key: 'topic',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '说明',
+      dataIndex: 'description',
+      key: 'description',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+  ];
+
+  const columnsHTTP: any[] = [
+    {
+      title: '地址',
+      dataIndex: 'address',
+      key: 'address',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '分组',
+      dataIndex: 'group',
+      key: 'group',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '示例',
+      dataIndex: 'example',
+      key: 'example',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '说明',
+      dataIndex: 'description',
+      key: 'description',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+  ];
+
+  const getDetail = () => {
+    service
+      .getConfigView(
+        productModel.current?.messageProtocol || '',
+        productModel.current?.transportProtocol || '',
+      )
+      .then((resp) => {
+        if (resp.status === 200) {
+          setConfig(resp.result);
+        }
+      });
+  };
+
+  useEffect(() => {
+    setVisible(!!productModel.current?.accessId);
+    if (productModel.current?.accessId) {
+      getDetail();
+    } else {
+      handleSearch(param);
+    }
+  }, [productModel.current?.accessId]);
+
+  return (
+    <div>
+      {!visible ? (
+        <div style={{ padding: '20px 0' }}>
+          <Alert message="选择与设备通信的网络组件" type="warning" showIcon />
+          <SearchComponent
+            field={columns}
+            pattern={'simple'}
+            onSearch={(data: any) => {
+              const dt = {
+                pageSize: 10,
+                terms: [...data.terms],
+              };
+              handleSearch(dt);
+            }}
+            onReset={() => {
+              handleSearch({ pageSize: 10 });
+            }}
+          />
+          <Row gutter={[16, 16]} style={{ marginTop: 10 }}>
+            {dataSource.data.map((item: any) => (
+              <Col key={item.name} span={12}>
+                <Card
+                  style={{
+                    width: '100%',
+                    border: currrent?.id === item.id ? '1px solid #1d39c4' : '',
+                  }}
+                  hoverable
+                  onClick={() => {
+                    setCurrrent(item);
+                  }}
+                >
+                  <div className={styles.box}>
+                    <div className={styles.images}>{item.name}</div>
+                    <div className={styles.content}>
+                      <div className={styles.header}>
+                        <div className={styles.top}>
+                          <div className={styles.title}>{item.name}</div>
+                          <div className={styles.status}>
+                            <Badge
+                              color={item.state.value === 'disabled' ? 'red' : 'green'}
+                              text={item.state.text}
+                              style={{ marginLeft: '20px' }}
+                            />
+                          </div>
+                        </div>
+                        <div className={styles.desc}>这里是接入方式的解释说明</div>
+                      </div>
+                      <div className={styles.container}>
+                        <div className={styles.server}>
+                          <div className={styles.title}>{item?.channelInfo?.name}</div>
+                          <p>
+                            {item.channelInfo?.addresses.map((i: any) => (
+                              <div key={i.address}>
+                                <Badge color={i.health === -1 ? 'red' : 'green'} text={i.address} />
+                              </div>
+                            ))}
+                          </p>
+                        </div>
+                        <div className={styles.procotol}>
+                          <div className={styles.title}>{item?.protocolDetail?.name}</div>
+                          <p style={{ color: 'rgba(0, 0, 0, .55)' }}>{item.description}</p>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </Card>
+              </Col>
+            ))}
+          </Row>
+          <div style={{ display: 'flex', marginTop: 20, justifyContent: 'flex-end' }}>
+            <Pagination
+              showSizeChanger
+              size="small"
+              className={'pro-table-card-pagination'}
+              total={dataSource?.total || 0}
+              current={dataSource?.pageIndex + 1}
+              onChange={(page, size) => {
+                handleSearch({
+                  ...param,
+                  pageIndex: page - 1,
+                  pageSize: size,
+                });
+              }}
+              pageSizeOptions={[10, 20, 50, 100]}
+              pageSize={dataSource?.pageSize}
+              showTotal={(num) => {
+                const minSize = dataSource?.pageIndex * dataSource?.pageSize + 1;
+                const MaxSize = (dataSource?.pageIndex + 1) * dataSource?.pageSize;
+                return `第 ${minSize} - ${MaxSize > num ? num : MaxSize} 条/总共 ${num} 条`;
+              }}
+            />
+          </div>
+          <div style={{ marginTop: '20px' }}>
+            <Button
+              type="primary"
+              onClick={() => {
+                if (!!currrent) {
+                  service1
+                    .update({
+                      ...productModel.current,
+                      transportProtocol: currrent.transport,
+                      protocolName: currrent.protocolDetail.name,
+                      accessId: currrent.id,
+                      accessName: currrent.name,
+                      messageProtocol: currrent.protocol,
+                    })
+                    .then((resp) => {
+                      if (resp.status === 200) {
+                        message.success('操作成功!');
+                        setVisible(true);
+                        getDetail();
+                      }
+                    });
+                } else {
+                  message.success('请选择接入方式');
+                }
+              }}
+            >
+              保存
+            </Button>
+          </div>
+        </div>
+      ) : (
+        <div className={styles.config}>
+          <div className={styles.title}>配置概览</div>
+          <Descriptions column={1}>
+            {/* <Descriptions.Item label="接入方式">{config?.id || ''}</Descriptions.Item> */}
+            {/* <Descriptions.Item>{props.data?.description || ''}</Descriptions.Item> */}
+            <Descriptions.Item label="消息协议">
+              {productModel.current?.messageProtocol}
+            </Descriptions.Item>
+            {/* <Descriptions.Item>----缺少描述呀----</Descriptions.Item>
+                        <Descriptions.Item label="网络组件">
+                             {(networkList.find((i) => i.id === productModel.current.)?.addresses || []).map(
+                                (item: any) => (
+                                    <div key={item.address}>
+                                        <Badge
+                                            color={item.health === -1 ? 'red' : 'green'}
+                                            text={item.address}
+                                            style={{ marginLeft: '20px' }}
+                                        />
+                                    </div>
+                                ),
+                            )} 
+                        </Descriptions.Item> */}
+          </Descriptions>
+          {config?.routes && config?.routes?.length > 0 && (
+            <div>
+              <div>路由信息:</div>
+              <Table
+                dataSource={config?.routes || []}
+                columns={config.id === 'MQTT' ? columnsMQTT : columnsHTTP}
+                pagination={false}
+                scroll={{ x: 500 }}
+              />
+            </div>
+          )}
+
+          <div style={{ marginTop: '20px' }}>
+            <Button
+              type="primary"
+              onClick={() => {
+                setVisible(false);
+                handleSearch({ pageSize: 10 });
+              }}
+            >
+              编辑
+            </Button>
+          </div>
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default Access;

+ 7 - 3
src/pages/device/Product/Detail/index.tsx

@@ -18,7 +18,8 @@ import { productModel, service } from '@/pages/device/Product';
 import { useCallback, useEffect, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import Metadata from '@/pages/device/components/Metadata';
-import Alarm from '@/pages/device/components/Alarm';
+// import Alarm from '@/pages/device/components/Alarm';
+import Access from '@/pages/device/Product/Detail/Access';
 import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import { Store } from 'jetlinks-store';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
@@ -220,7 +221,10 @@ const ProductDetail = observer(() => {
           >
             <Metadata type="product" />
           </Tabs.TabPane>
-          <Tabs.TabPane
+          <Tabs.TabPane tab={'设备接入'} key="access">
+            <Access />
+          </Tabs.TabPane>
+          {/* <Tabs.TabPane
             tab={intl.formatMessage({
               id: 'pages.device.productDetail.alarm',
               defaultMessage: '告警设置',
@@ -228,7 +232,7 @@ const ProductDetail = observer(() => {
             key="alarm"
           >
             <Alarm type="product" />
-          </Tabs.TabPane>
+          </Tabs.TabPane> */}
         </Tabs>
       </Card>
     </PageContainer>

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

@@ -134,6 +134,12 @@ class Service extends BaseService<ProductItem> {
       method: 'GET',
     });
 
+  public getNetwork = (params: any) =>
+    request(`/${SystemConst.API_BASE}/network/config/_query/`, {
+      method: 'GET',
+      params,
+    });
+
   //上传物模型属性
   public importProductProperty = (productId: string, fileUrl: string) =>
     request(

+ 2 - 0
src/pages/device/Product/typings.d.ts

@@ -23,6 +23,8 @@ export type ProductItem = {
   state: number;
   transportProtocol: string;
   describe?: string;
+  accessId?: string;
+  accessName?: string;
 };
 
 export type ConfigProperty = {

+ 55 - 45
src/pages/link/AccessConfig/Detail/Access/index.less

@@ -1,24 +1,40 @@
 .box {
   display: flex;
-  flex-direction: column;
-  align-items: center;
-  margin: 20px 30px;
-  .steps {
-    width: 100%;
-  }
+  justify-content: space-between;
+}
 
-  .content {
-    width: 100%;
-    margin: 20px 0;
-  }
+.images {
+  width: 64px;
+  height: 64px;
+  color: white;
+  font-size: 18px;
+  line-height: 64px;
+  text-align: center;
+  background: linear-gradient(
+    128.453709216706deg,
+    rgba(255, 255, 255, 1) 4%,
+    rgba(113, 187, 255, 1) 43%,
+    rgba(24, 144, 255, 1) 100%
+  );
+  border: 1px solid rgba(242, 242, 242, 1);
+  border-radius: 50%;
+}
 
-  .action {
-    width: 100%;
-  }
+.content {
+  display: flex;
+  flex-direction: column;
+  width: calc(100% - 80px);
 }
 
-.title {
-  font-weight: 600;
+.top {
+  display: flex;
+  justify-content: space-between;
+  .left {
+    display: flex;
+  }
+  .action a {
+    margin: 0 5px;
+  }
 }
 
 .desc {
@@ -32,40 +48,34 @@
   text-overflow: ellipsis;
 }
 
-.cardContent {
-  display: flex;
-  margin-top: 10px;
-  color: rgba(0, 0, 0, 0.55);
-  .item {
-    width: 100%;
-    margin: 5px 0;
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-  }
+.title {
+  font-weight: 600;
+  font-size: 14px;
 }
 
-.view {
+.container {
   display: flex;
-  justify-content: space-between;
-  .info,
-  .config {
-    width: 48%;
-    .title {
-      width: 100%;
-      margin-bottom: 10px;
-      font-weight: 600;
-    }
-    .title::before {
-      margin-right: 10px;
-      background-color: #2810ff;
-      content: '|';
-    }
-  }
+  width: 100%;
+  height: 90px;
+  margin-top: 10px;
 }
 
-.search {
-  display: flex;
+.server {
   align-items: center;
-  justify-content: space-between;
+  width: 50%;
+  margin-right: 20px;
+}
+.procotol {
+  display: -webkit-box;
+  width: 50%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 4;
+}
+
+:global {
+  .ant-pagination-item {
+    display: none;
+  }
 }

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

@@ -11,6 +11,8 @@ import {
   message,
   Row,
   Steps,
+  Table,
+  Tooltip,
 } from 'antd';
 import { useEffect, useState } from 'react';
 import styles from './index.less';
@@ -33,7 +35,7 @@ const Access = (props: Props) => {
   const [procotolList, setProcotolList] = useState<any[]>([]);
   const [procotolCurrent, setProcotolCurrent] = useState<string>('');
   const [networkCurrent, setNetworkCurrent] = useState<string>('');
-  // const [config, setConfig] = useState<any>();
+  const [config, setConfig] = useState<any>();
 
   const MetworkTypeMapping = new Map();
   MetworkTypeMapping.set('websocket-server', 'WEB_SOCKET_SERVER');
@@ -93,7 +95,7 @@ const Access = (props: Props) => {
           .getConfigView(procotolCurrent, ProcotoleMapping.get(props.data?.id))
           .then((resp) => {
             if (resp.status === 200) {
-              // setConfig(resp.result)
+              setConfig(resp.result);
             }
           });
         setCurrent(current + 1);
@@ -117,53 +119,114 @@ const Access = (props: Props) => {
     },
   ];
 
-  // const columns = [
-  //     {
-  //         title: '姓名',
-  //         dataIndex: 'name',
-  //         key: 'name',
-  //     },
-  //     {
-  //         title: '年龄',
-  //         dataIndex: 'age',
-  //         key: 'age',
-  //     },
-  //     {
-  //         title: '住址',
-  //         dataIndex: 'address',
-  //         key: 'address',
-  //     },
-  //     {
-  //         title: '姓名',
-  //         dataIndex: 'name',
-  //         key: 'name',
-  //     },
-  //     {
-  //         title: '年龄',
-  //         dataIndex: 'age',
-  //         key: 'age',
-  //     },
-  //     {
-  //         title: '住址',
-  //         dataIndex: 'address',
-  //         key: 'address',
-  //     },
-  // ];
+  const columnsMQTT: any[] = [
+    {
+      title: '分组',
+      dataIndex: 'group',
+      key: 'group',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: 'qos',
+      dataIndex: 'qos',
+      key: 'qos',
+      ellipsis: true,
+      align: 'center',
+    },
+    {
+      title: '地址',
+      dataIndex: 'address',
+      key: 'address',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: 'topic',
+      dataIndex: 'topic',
+      key: 'topic',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '说明',
+      dataIndex: 'description',
+      key: 'description',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+  ];
 
-  // const dataSource = [
-  //     {
-  //         key: '1',
-  //         name: '胡彦斌',
-  //         age: 32,
-  //         address: '西湖区湖底公园1号',
-  //     },
-  //     {
-  //         key: '2',
-  //         name: '胡彦祖',
-  //         age: 42,
-  //         address: '西湖区湖底公园1号',
-  //     },
-  // ];
+  const columnsHTTP: any[] = [
+    {
+      title: '地址',
+      dataIndex: 'address',
+      key: 'address',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '分组',
+      dataIndex: 'group',
+      key: 'group',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '示例',
+      dataIndex: 'example',
+      key: 'example',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+    {
+      title: '说明',
+      dataIndex: 'description',
+      key: 'description',
+      ellipsis: true,
+      align: 'center',
+      render: (text: any) => (
+        <Tooltip placement="top" title={text}>
+          {text}
+        </Tooltip>
+      ),
+    },
+  ];
 
   const renderSteps = (cur: number) => {
     switch (cur) {
@@ -210,16 +273,10 @@ const Access = (props: Props) => {
                     >
                       <div className={styles.title}>{item.name}</div>
                       <div className={styles.cardContent}>
-                        <div style={{ width: '40%' }}>
-                          <div className={styles.item}>
-                            {MetworkTypeMapping.get(props.data?.id)}
-                          </div>
-                          <div className={styles.item}>共享配置</div>
-                        </div>
-                        <div style={{ width: '60%' }}>
+                        <div style={{ width: '100%', height: '50px' }}>
                           {item.addresses.slice(0, 2).map((i: any) => (
                             <div className={styles.item} key={i.address}>
-                              公网: {i.address}
+                              <Badge color={i.health === -1 ? 'red' : 'green'} text={i.address} />
                             </div>
                           ))}
                         </div>
@@ -296,7 +353,7 @@ const Access = (props: Props) => {
                       }}
                     >
                       <div className={styles.title}>{item.name}</div>
-                      <div className={styles.desc}>这里是协议包中的协议说明</div>
+                      <div className={styles.desc}>缺少描述呀</div>
                     </Card>
                   </Col>
                 ))}
@@ -356,20 +413,28 @@ const Access = (props: Props) => {
                 <Descriptions.Item label="网络组件">
                   {(networkList.find((i) => i.id === networkCurrent)?.addresses || []).map(
                     (item: any) => (
-                      <Badge
-                        key={item.address}
-                        color={item.health === -1 ? 'red' : 'green'}
-                        text={item.address}
-                        style={{ marginLeft: '20px' }}
-                      />
+                      <div key={item.address}>
+                        <Badge
+                          color={item.health === -1 ? 'red' : 'green'}
+                          text={item.address}
+                          style={{ marginLeft: '20px' }}
+                        />
+                      </div>
                     ),
                   )}
                 </Descriptions.Item>
               </Descriptions>
-              {/* <div>
-                            <div>路由信息</div>
-                            <Table dataSource={dataSource} columns={columns} pagination={false} />
-                        </div> */}
+              {config?.routes && config?.routes?.length > 0 && (
+                <div>
+                  <div>路由信息:</div>
+                  <Table
+                    dataSource={config?.routes || []}
+                    columns={config.id === 'MQTT' ? columnsMQTT : columnsHTTP}
+                    pagination={false}
+                    scroll={{ x: 500 }}
+                  />
+                </div>
+              )}
             </div>
           </div>
         );

+ 155 - 151
src/pages/link/AccessConfig/index.tsx

@@ -2,10 +2,9 @@ import SearchComponent from '@/components/SearchComponent';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import { CheckCircleOutlined, DeleteOutlined, EditOutlined, StopOutlined } from '@ant-design/icons';
 import { PageContainer } from '@ant-design/pro-layout';
-import ProList from '@jetlinks/pro-list';
 import type { ProColumns } from '@jetlinks/pro-table';
-import { Badge, Button, Card, message, Popconfirm } from 'antd';
-import { useState } from 'react';
+import { Badge, Button, Card, Col, message, Pagination, Popconfirm, Row } from 'antd';
+import { useEffect, useState } from 'react';
 import { useHistory } from 'umi';
 import styles from './index.less';
 import Service from './service';
@@ -14,41 +13,35 @@ export const service = new Service('gateway/device');
 
 const AccessConfig = () => {
   const history = useHistory();
-  const [param, setParam] = useState({});
-  // const actionRef = useRef<ActionType>();
+  const [param, setParam] = useState<any>({ pageSize: 10 });
 
   const columns: ProColumns<any>[] = [
     {
       title: '名称',
       dataIndex: 'name',
     },
-    // {
-    //   title: '状态',
-    //   dataIndex: 'state',
-    //   align: 'center',
-    //   valueType: 'select',
-    //   valueEnum: {
-    //     // 1: {
-    //     //   text: intl.formatMessage({
-    //     //     id: 'pages.searchTable.titleStatus.normal',
-    //     //     defaultMessage: '正常',
-    //     //   }),
-    //     //   status: 1,
-    //     // },
-    //     // 0: {
-    //     //   text: intl.formatMessage({
-    //     //     id: 'pages.searchTable.titleStatus.disable',
-    //     //     defaultMessage: '禁用',
-    //     //   }),
-    //     //   status: 0,
-    //     // },
-    //   },
-    //   render: (text, record) => (
-    //     <Badge status={record.status === 1 ? 'success' : 'error'} text={text} />
-    //   ),
-    // },
   ];
 
+  const [dataSource, setDataSource] = useState<any>({
+    data: [],
+    pageSize: 10,
+    pageIndex: 0,
+    total: 0,
+  });
+
+  const handleSearch = (params: any) => {
+    setParam(params);
+    service
+      .queryList({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+      .then((resp) => {
+        setDataSource(resp.result);
+      });
+  };
+
+  useEffect(() => {
+    handleSearch(param);
+  }, []);
+
   return (
     <PageContainer>
       <Card>
@@ -56,12 +49,14 @@ const AccessConfig = () => {
           field={columns}
           pattern={'simple'}
           onSearch={(data: any) => {
-            setParam(data);
-            // actionRef.current?.reset?.();
+            const dt = {
+              pageSize: 10,
+              terms: [...data.terms],
+            };
+            handleSearch(dt);
           }}
           onReset={() => {
-            setParam({});
-            // actionRef.current?.reset?.();
+            handleSearch({ pageSize: 10 });
           }}
         />
         <div style={{ width: '100%', display: 'flex', justifyContent: 'flex-end' }}>
@@ -74,126 +69,135 @@ const AccessConfig = () => {
             新增
           </Button>
         </div>
-        <ProList<any>
-          pagination={{
-            defaultPageSize: 8,
-            showSizeChanger: false,
-          }}
-          showActions="always"
-          rowKey="id"
-          // actionRef={actionRef}
-          request={async (data) =>
-            service.queryList({ ...param, ...data, sorts: [{ name: 'createTime', order: 'desc' }] })
-          }
-          grid={{ gutter: 16, column: 2 }}
-          showExtra="always"
-          metas={{
-            title: {
-              dataIndex: 'name',
-              render: (text, row) => (
-                <div style={{ fontSize: 16, width: '70%' }}>
-                  <div>
-                    {text}
-                    <Badge
-                      color={row.state.value === 'disabled' ? 'red' : 'green'}
-                      text={row.state.text}
-                      style={{ marginLeft: '20px' }}
-                    />
-                  </div>
-                  <div className={styles.desc}>{row.describe}</div>
-                </div>
-              ),
-            },
-            avatar: {
-              render: (text, reocrd) => <div className={styles.images}>{reocrd.name}</div>,
-            },
-            subTitle: {
-              render: () => <div></div>,
-            },
-            content: {
-              render: (text, row) => (
-                <div className={styles.content}>
-                  <div className={styles.server}>
-                    <div className={styles.title}>{row?.channelInfo?.name}</div>
-                    <p>
-                      {row.channelInfo?.addresses.map((item: any) => (
-                        <div key={item.address}>
-                          <Badge color={'green'} text={item.address} />
+        <Row gutter={[16, 16]} style={{ marginTop: 10 }}>
+          {dataSource.data.map((item: any) => (
+            <Col key={item.name} span={12}>
+              <Card hoverable>
+                <div className={styles.box}>
+                  <div className={styles.images}>{item.name}</div>
+                  <div className={styles.content}>
+                    <div className={styles.header}>
+                      <div className={styles.top}>
+                        <div className={styles.left}>
+                          <div className={styles.title}>{item.name}</div>
+                          <div className={styles.status}>
+                            <Badge
+                              color={item.state.value === 'disabled' ? 'red' : 'green'}
+                              text={item.state.text}
+                              style={{ marginLeft: '20px' }}
+                            />
+                          </div>
                         </div>
-                      ))}
-                    </p>
-                  </div>
-                  <div className={styles.procotol}>
-                    <div className={styles.title}>{row?.protocolDetail?.name}</div>
-                    <p style={{ color: 'rgba(0, 0, 0, .55)' }}>{row.description}</p>
+                        <div className={styles.action}>
+                          <a
+                            key="edit"
+                            onClick={() => {
+                              history.push(
+                                `${getMenuPathByCode(MENUS_CODE['link/AccessConfig/Detail'])}?id=${
+                                  item.id
+                                }`,
+                              );
+                            }}
+                          >
+                            <EditOutlined />
+                            编辑
+                          </a>
+                          <a key="warning">
+                            <Popconfirm
+                              title={`确认${item.state.value !== 'disabled' ? '禁用' : '启用'}`}
+                              onConfirm={() => {
+                                if (item.state.value !== 'disabled') {
+                                  service.shutDown(item.id).then((resp) => {
+                                    if (resp.status === 200) {
+                                      message.success('操作成功!');
+                                    }
+                                  });
+                                } else {
+                                  service.startUp(item.id).then((resp) => {
+                                    if (resp.status === 200) {
+                                      message.success('操作成功!');
+                                    }
+                                  });
+                                }
+                              }}
+                            >
+                              {item.state.value !== 'disabled' ? (
+                                <span>
+                                  <StopOutlined />
+                                  禁用
+                                </span>
+                              ) : (
+                                <span>
+                                  <CheckCircleOutlined />
+                                  启用
+                                </span>
+                              )}
+                            </Popconfirm>
+                          </a>
+                          <a key="remove">
+                            <Popconfirm
+                              title={'确认删除?'}
+                              onConfirm={() => {
+                                service.remove(item.id).then((resp: any) => {
+                                  if (resp.status === 200) {
+                                    message.success('操作成功!');
+                                  }
+                                });
+                              }}
+                            >
+                              <DeleteOutlined />
+                              删除
+                            </Popconfirm>
+                          </a>
+                        </div>
+                      </div>
+                      <div className={styles.desc}>这里是接入方式的解释说明</div>
+                    </div>
+                    <div className={styles.container}>
+                      <div className={styles.server}>
+                        <div className={styles.title}>{item?.channelInfo?.name}</div>
+                        <p>
+                          {item.channelInfo?.addresses.map((i: any) => (
+                            <div key={i.address}>
+                              <Badge color={i.health === -1 ? 'red' : 'green'} text={i.address} />
+                            </div>
+                          ))}
+                        </p>
+                      </div>
+                      <div className={styles.procotol}>
+                        <div className={styles.title}>{item?.protocolDetail?.name}</div>
+                        <p style={{ color: 'rgba(0, 0, 0, .55)' }}>{item.description}</p>
+                      </div>
+                    </div>
                   </div>
                 </div>
-              ),
-            },
-            actions: {
-              render: (text, row) => [
-                <a
-                  key="edit"
-                  onClick={() => {
-                    history.push(
-                      `${getMenuPathByCode(MENUS_CODE['link/AccessConfig/Detail'])}?id=${row.id}`,
-                    );
-                  }}
-                >
-                  <EditOutlined />
-                  编辑
-                </a>,
-                <a key="warning">
-                  <Popconfirm
-                    title={`确认${row.state.value !== 'disabled' ? '禁用' : '启用'}`}
-                    onConfirm={() => {
-                      if (row.state.value !== 'disabled') {
-                        service.shutDown(row.id).then((resp) => {
-                          if (resp.status === 200) {
-                            message.success('操作成功!');
-                          }
-                        });
-                      } else {
-                        service.startUp(row.id).then((resp) => {
-                          if (resp.status === 200) {
-                            message.success('操作成功!');
-                          }
-                        });
-                      }
-                    }}
-                  >
-                    {row.state.value !== 'disabled' ? (
-                      <span>
-                        <StopOutlined />
-                        禁用
-                      </span>
-                    ) : (
-                      <span>
-                        <CheckCircleOutlined />
-                        启用
-                      </span>
-                    )}
-                  </Popconfirm>
-                </a>,
-                <a key="remove">
-                  <Popconfirm
-                    title={'确认删除?'}
-                    onConfirm={() => {
-                      service.remove(row.id).then((resp: any) => {
-                        if (resp.status === 200) {
-                          message.success('操作成功!');
-                        }
-                      });
-                    }}
-                  >
-                    <DeleteOutlined />
-                    删除
-                  </Popconfirm>
-                </a>,
-              ],
-            },
-          }}
-        />
+              </Card>
+            </Col>
+          ))}
+        </Row>
+        <div style={{ display: 'flex', marginTop: 20, justifyContent: 'flex-end' }}>
+          <Pagination
+            showSizeChanger
+            size="small"
+            className={'pro-table-card-pagination'}
+            total={dataSource?.total || 0}
+            current={dataSource?.pageIndex + 1}
+            onChange={(page, size) => {
+              handleSearch({
+                ...param,
+                pageIndex: page - 1,
+                pageSize: size,
+              });
+            }}
+            pageSizeOptions={[10, 20, 50, 100]}
+            pageSize={dataSource?.pageSize}
+            showTotal={(num) => {
+              const minSize = dataSource?.pageIndex * dataSource?.pageSize + 1;
+              const MaxSize = (dataSource?.pageIndex + 1) * dataSource?.pageSize;
+              return `第 ${minSize} - ${MaxSize > num ? num : MaxSize} 条/总共 ${num} 条`;
+            }}
+          />
+        </div>
       </Card>
     </PageContainer>
   );