Prechádzať zdrojové kódy

feat(设备详情): 新增设备详情,以及跳转

xieyonghong 3 rokov pred
rodič
commit
5016e1d168

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

@@ -268,6 +268,10 @@ export default {
   'pages.device.instanceDetail.alarm': '告警设置',
   'pages.device.instanceDetail.visualization': '可视化',
   'pages.device.instanceDetail.shadow': '设备影子',
+  'pages.device.instanceDetail.IPAddress': 'IP地址',
+  'pages.device.instanceDetail.info': '设备信息',
+  // 设备管理-设备功能
+  'pages.device.instance.function.result': '执行结果',
   // 设备管理-指令下发
   'pages.device.command': '指令下发',
   'pages.device.command.type': '指令类型',

+ 119 - 116
src/pages/device/Instance/Detail/Config/index.tsx

@@ -1,124 +1,127 @@
-import { Card, Divider, Empty } from 'antd';
+import { Descriptions, Card, Button } from 'antd';
 import { InstanceModel, service } from '@/pages/device/Instance';
-import { useEffect, useState } from 'react';
-import { createSchemaField } from '@formily/react';
-import type { ConfigMetadata, ConfigProperty } from '@/pages/device/Product/typings';
-import type { ISchema } from '@formily/json-schema';
-import { Form, FormGrid, FormItem, FormLayout, Input, Password, PreviewText } from '@formily/antd';
-import { createForm } from '@formily/core';
-import { history, useParams } from 'umi';
-import Tags from '@/pages/device/Instance/Detail/Config/Tags';
+import moment from 'moment';
+import { observer } from '@formily/react';
+import { useIntl } from '@@/plugin-locale/localeExports';
+import { EditOutlined } from '@ant-design/icons';
+import { useState } from 'react';
+import { useParams } from 'umi';
+import Save from '@/pages/device/Instance/Save';
 
-const componentMap = {
-  string: 'Input',
-  password: 'Password',
-};
+const Info = observer(() => {
+  const intl = useIntl();
+  const [visible, setVisible] = useState(false);
+  const param = useParams<{ id: string }>();
 
-const Config = () => {
-  const params = useParams<{ id: string }>();
-  useEffect(() => {
-    const id = InstanceModel.current?.id || params.id;
-    if (id) {
-      service.getConfigMetadata(id).then((response) => {
-        InstanceModel.config = response?.result;
-      });
-    } else {
-      history.goBack();
+  const getDetailInfo = async () => {
+    const res = await service.detail(param.id);
+    if (res.status === 200) {
+      InstanceModel.detail = res.result;
     }
-  }, []);
-
-  const [metadata, setMetadata] = useState<ConfigMetadata[]>([]);
-  const [state, setState] = useState<boolean>(false);
-
-  const form = createForm({
-    validateFirst: true,
-    readPretty: state,
-    initialValues: InstanceModel.detail?.configuration,
-  });
-
-  const id = InstanceModel.current?.id;
-
-  useEffect(() => {
-    if (id) {
-      service.getConfigMetadata(id).then((config) => {
-        setMetadata(config?.result);
-      });
-    }
-
-    return () => {};
-  }, [id]);
-
-  const SchemaField = createSchemaField({
-    components: {
-      FormItem,
-      Input,
-      Password,
-      FormGrid,
-      PreviewText,
-    },
-  });
-
-  const configToSchema = (data: ConfigProperty[]) => {
-    const config = {};
-    data.forEach((item) => {
-      config[item.property] = {
-        type: 'string',
-        title: item.name,
-        'x-decorator': 'FormItem',
-        'x-component': componentMap[item.type.type],
-        'x-decorator-props': {
-          tooltip: item.description,
-        },
-      };
-    });
-    return config;
-  };
-
-  const renderConfigCard = () => {
-    return metadata ? (
-      metadata?.map((item) => {
-        const itemSchema: ISchema = {
-          type: 'object',
-          properties: {
-            grid: {
-              type: 'void',
-              'x-component': 'FormGrid',
-              'x-component-props': {
-                minColumns: [2],
-                maxColumns: [2],
-              },
-              properties: configToSchema(item.properties),
-            },
-          },
-        };
-
-        return (
-          <Card
-            title={item.name}
-            extra={<a onClick={() => setState(!state)}>{state ? '编辑' : '保存'}</a>}
-          >
-            <PreviewText.Placeholder value="-">
-              <Form form={form}>
-                <FormLayout labelCol={6} wrapperCol={16}>
-                  <SchemaField schema={itemSchema} />
-                </FormLayout>
-              </Form>
-            </PreviewText.Placeholder>
-          </Card>
-        );
-      })
-    ) : (
-      <Empty />
-    );
   };
 
   return (
-    <>
-      {renderConfigCard()}
-      <Divider />
-      <Tags />
-    </>
+    <Card>
+      <Descriptions
+        size="small"
+        column={3}
+        bordered
+        title={[
+          <span key={1}>
+            {intl.formatMessage({
+              id: 'pages.device.instanceDetail.info',
+              defaultMessage: '设备信息',
+            })}
+          </span>,
+          <Button
+            key={2}
+            type={'link'}
+            onClick={() => {
+              setVisible(true);
+            }}
+          >
+            <EditOutlined />
+          </Button>,
+        ]}
+      >
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.deviceType',
+            defaultMessage: '设备类型',
+          })}
+        >
+          {InstanceModel.detail?.deviceType?.text}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.transportProtocol',
+            defaultMessage: '链接协议',
+          })}
+        >
+          {InstanceModel.detail?.protocolName}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.protocolName',
+            defaultMessage: '消息协议',
+          })}
+        >
+          {InstanceModel.detail?.transport}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.IPAddress',
+            defaultMessage: 'IP地址',
+          })}
+        >
+          {InstanceModel.detail?.address}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.createTime',
+            defaultMessage: '创建时间',
+          })}
+        >
+          {moment(InstanceModel.detail?.createTime).format('YYYY-MM-DD HH:mm:ss')}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.registerTime',
+            defaultMessage: '注册时间',
+          })}
+        >
+          {InstanceModel.detail?.createTime}
+        </Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.device.instanceDetail.lastTimeOnline',
+            defaultMessage: '最后上线时间',
+          })}
+        >
+          {InstanceModel.detail?.createTime}
+        </Descriptions.Item>
+        <Descriptions.Item label={''}>{}</Descriptions.Item>
+        <Descriptions.Item label={''}>{}</Descriptions.Item>
+        <Descriptions.Item
+          label={intl.formatMessage({
+            id: 'pages.table.description',
+            defaultMessage: '说明',
+          })}
+          span={3}
+        >
+          {InstanceModel.detail?.description}
+        </Descriptions.Item>
+      </Descriptions>
+      <Save
+        data={InstanceModel.detail}
+        model={'edit'}
+        close={() => {
+          setVisible(false);
+        }}
+        reload={getDetailInfo}
+        visible={visible}
+      />
+    </Card>
   );
-};
-
-export default Config;
+});
+export default Info;

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

@@ -130,7 +130,13 @@ export default (props: FunctionProps) => {
         </div>
       </div>
       <div className="right">
-        <p>执行结果:</p>
+        <p>
+          {intl.formatMessage({
+            id: 'pages.device.instance.function.result',
+            defaultMessage: '执行结果',
+          })}
+          :
+        </p>
         <Input.TextArea value={result} rows={6} />
       </div>
     </div>

+ 18 - 68
src/pages/device/Instance/Detail/Info/index.tsx

@@ -1,85 +1,35 @@
 import { Descriptions } from 'antd';
 import { InstanceModel } from '@/pages/device/Instance';
-import moment from 'moment';
 import { observer } from '@formily/react';
 import { useIntl } from '@@/plugin-locale/localeExports';
+import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
+import { useHistory } from 'umi';
 
 const Info = observer(() => {
   const intl = useIntl();
+  const history = useHistory();
   return (
     <>
-      <Descriptions size="small" column={3}>
+      <Descriptions size="small" column={5}>
+        <Descriptions.Item label={'ID'}>{InstanceModel.detail?.id}</Descriptions.Item>
         <Descriptions.Item
           label={intl.formatMessage({
-            id: 'pages.table.deviceId',
-            defaultMessage: '设备ID',
-          })}
-        >
-          {InstanceModel.detail?.id}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.table.productName',
-            defaultMessage: '产品名称',
-          })}
-        >
-          {InstanceModel.detail?.name}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.deviceType',
-            defaultMessage: '设备类型',
-          })}
-        >
-          {InstanceModel.detail?.deviceType?.text}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.transportProtocol',
+            id: 'pages.device.firmware.productName',
             defaultMessage: '链接协议',
           })}
         >
-          {InstanceModel.detail?.protocolName}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.protocolName',
-            defaultMessage: '消息协议',
-          })}
-        >
-          {InstanceModel.detail?.transport}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.createTime',
-            defaultMessage: '创建时间',
-          })}
-        >
-          {moment(InstanceModel.detail?.createTime).format('YYYY-MM-DD HH:mm:ss')}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.registerTime',
-            defaultMessage: '注册时间',
-          })}
-        >
-          {InstanceModel.detail?.createTime}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.device.instanceDetail.lastTimeOnline',
-            defaultMessage: '最后上线时间',
-          })}
-        >
-          {InstanceModel.detail?.createTime}
-        </Descriptions.Item>
-        <Descriptions.Item
-          label={intl.formatMessage({
-            id: 'pages.table.description',
-            defaultMessage: '说明',
-          })}
-        >
-          {InstanceModel.detail?.description}
+          <a
+            onClick={() => {
+              history.push({
+                pathname: `${getMenuPathByCode(MENUS_CODE['device/Product'])}`,
+                state: {
+                  id: InstanceModel.detail?.productId,
+                },
+              });
+            }}
+          >
+            {InstanceModel.detail?.productName}
+          </a>
         </Descriptions.Item>
       </Descriptions>
     </>

+ 28 - 4
src/pages/device/Instance/Save/index.tsx

@@ -8,21 +8,37 @@ import { service } from '@/pages/device/Instance';
 import 'antd/lib/tree-select/style/index.less';
 import type { DeviceInstance } from '../typings';
 import { useEffect, useState } from 'react';
+import { useIntl } from '@@/plugin-locale/localeExports';
 
 interface Props {
   visible: boolean;
   close: () => void;
-  data?: DeviceInstance;
+  reload: () => void;
+  model?: 'add' | 'edit';
+  data?: Partial<DeviceInstance>;
 }
 
 const Save = (props: Props) => {
   const { visible, close, data } = props;
   const [productList, setProductList] = useState<any[]>([]);
   const form = createForm({
-    initialValues: data,
+    initialValues: {},
   });
 
   useEffect(() => {
+    if (visible && data) {
+      form.setValues({
+        id: data.id,
+        name: data.name,
+        productId: data.productId,
+        describe: data.describe,
+      });
+    }
+  }, [visible]);
+
+  const intl = useIntl();
+
+  useEffect(() => {
     service.getProductList({ paging: false }).then((resp) => {
       if (resp.status === 200) {
         const list = resp.result.map((item: { name: any; id: any }) => ({
@@ -46,6 +62,7 @@ const Save = (props: Props) => {
 
   const handleSave = async () => {
     const values = (await form.submit()) as any;
+    console.log(values);
     const productId = values.productId;
     if (productId) {
       const product = productList.find((i) => i.value === productId);
@@ -54,9 +71,13 @@ const Save = (props: Props) => {
     const resp = (await service.update(values)) as any;
     if (resp.status === 200) {
       message.success('保存成功');
+      if (props.reload) {
+        props.reload();
+      }
       props.close();
     }
   };
+
   const schema: ISchema = {
     type: 'object',
     properties: {
@@ -111,7 +132,7 @@ const Save = (props: Props) => {
             enum: [...productList],
           },
           describe: {
-            title: '描述',
+            title: '说明',
             'x-component': 'Input.TextArea',
             'x-decorator': 'FormItem',
             'x-component-props': {
@@ -128,7 +149,10 @@ const Save = (props: Props) => {
       visible={visible}
       onCancel={() => close()}
       width="30vw"
-      title={data?.id ? '编辑' : '新增'}
+      title={intl.formatMessage({
+        id: `pages.data.option.${props.model || 'add'}`,
+        defaultMessage: '新增',
+      })}
       onOk={handleSave}
     >
       <Form form={form}>

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

@@ -140,7 +140,7 @@ const Instance = () => {
         id: 'pages.table.description',
         defaultMessage: '说明',
       }),
-      dataIndex: 'description',
+      dataIndex: 'describe',
       width: '15%',
       ellipsis: true,
     },
@@ -395,8 +395,11 @@ const Instance = () => {
       />
       <Save
         data={current}
+        model={!current ? 'add' : 'edit'}
         close={() => {
           setVisible(false);
+        }}
+        reload={() => {
           actionRef.current?.reload();
         }}
         visible={visible}

+ 4 - 2
src/pages/device/Product/Save/index.tsx

@@ -124,7 +124,9 @@ const Save = (props: Props) => {
     const resp = (await service.update(values)) as any;
     if (resp.status === 200) {
       message.success('保存成功');
-      props.reload();
+      if (props.reload) {
+        props.reload();
+      }
       props.close();
     }
   };
@@ -237,7 +239,7 @@ const Save = (props: Props) => {
       onCancel={() => close()}
       width="30vw"
       title={intl.formatMessage({
-        id: `pages.data.option.${props.model}`,
+        id: `pages.data.option.${props.model || 'add'}`,
         defaultMessage: '新增',
       })}
       onOk={handleSave}

+ 17 - 4
src/pages/device/Product/index.tsx

@@ -16,12 +16,13 @@ import { model } from '@formily/reactive';
 import { Link } from 'umi';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
-import { useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import ProTable from '@jetlinks/pro-table';
 import encodeQuery from '@/utils/encodeQuery';
 import Save from '@/pages/device/Product/Save';
 import SearchComponent from '@/components/SearchComponent';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import { useHistory } from 'umi';
 
 export const service = new Service('device-product');
 export const statusMap = {
@@ -39,7 +40,19 @@ const Product = observer(() => {
   const [current, setCurrent] = useState<ProductItem>();
   const actionRef = useRef<ActionType>();
   const intl = useIntl();
-  const [param, setParam] = useState({});
+  const [queryParam, setQueryParam] = useState({});
+  const history = useHistory<Record<string, string>>();
+
+  useEffect(() => {
+    if (history) {
+      const state = history.location.state;
+      if (state) {
+        setQueryParam({
+          terms: history.location.state,
+        });
+      }
+    }
+  }, [history]);
 
   const status = {
     1: (
@@ -80,7 +93,7 @@ const Product = observer(() => {
    * @param data
    */
   const searchFn = (data: any) => {
-    setParam({
+    setQueryParam({
       terms: data,
     });
   };
@@ -230,7 +243,7 @@ const Product = observer(() => {
         //     service.queryZipCount(encodeQuery({ ...params, sorts: { id: 'ascend' } })),
         //   );
         // }}
-        params={param}
+        params={queryParam}
         request={(params = {}) =>
           service.query(encodeQuery({ ...params, sorts: { createTime: 'ascend' } }))
         }