Bladeren bron

feat(command): add command

Lind 4 jaren geleden
bovenliggende
commit
c4330f98bf

+ 36 - 0
src/pages/device/Command/cat/index.tsx

@@ -0,0 +1,36 @@
+import { Input, Modal } from 'antd';
+import type { CommandItem } from '@/pages/device/Command/typings';
+import MonacoEditor from 'react-monaco-editor';
+
+interface Props {
+  close: () => void;
+  data: CommandItem | undefined;
+  visible: boolean;
+}
+
+const Cat = (props: Props) => {
+  const { close, data, visible } = props;
+  return (
+    <Modal width="40vw" visible={visible} onCancel={() => close()} footer={null} title="查看指令">
+      下发指令:
+      <MonacoEditor
+        height={300}
+        language={'json'}
+        editorDidMount={(editor) => {
+          editor.onDidScrollChange?.(() => {
+            editor
+              .getAction('editor.action.formatDocument')
+              .run()
+              .finally(() => {
+                editor.updateOptions({ readOnly: true });
+              });
+          });
+        }}
+        value={JSON.stringify(data?.downstream)}
+      />
+      回复结果:
+      <Input.TextArea rows={3} />
+    </Modal>
+  );
+};
+export default Cat;

+ 80 - 39
src/pages/device/Command/create/index.tsx

@@ -5,12 +5,18 @@ import { Form, Input, FormItem, Select, Space, ArrayTable } from '@formily/antd'
 import { action } from '@formily/reactive';
 import type { ISchema } from '@formily/json-schema';
 import { service } from '@/pages/device/Command';
-import { Modal } from 'antd';
+import { message, Modal } from 'antd';
 import FSelectDevices from '@/components/FSelectDevices';
 import { useRef } from 'react';
 import type { DeviceMetadata, ProductItem } from '@/pages/device/Product/typings';
 
-const Create = () => {
+interface Props {
+  close: () => void;
+  visible: boolean;
+}
+
+const Create = (props: Props) => {
+  const { close, visible } = props;
   const products = useRef<ProductItem[]>([]);
 
   const metadataRef = useRef<DeviceMetadata>();
@@ -28,7 +34,7 @@ const Create = () => {
 
         const metadata = JSON.parse(product?.metadata as string) as DeviceMetadata;
         metadataRef.current = metadata;
-        f.setFieldState(field.query('message.properties'), (state) => {
+        f.setFieldState(field.query('message.properties.key'), (state) => {
           state.dataSource = metadata?.properties.map((item) => ({
             label: item.name,
             value: item.id,
@@ -48,6 +54,7 @@ const Create = () => {
           state.value = func?.map((item) => ({
             key: `${item.name}(${item.id})`,
             value: null,
+            name: item.id,
           }));
         });
       });
@@ -65,17 +72,16 @@ const Create = () => {
     },
   });
 
-  const useAsyncDataSource =
-    (services: (arg0: Field<any, any, any, any>) => Promise<any>) => (field: Field) => {
-      field.loading = true;
-      services(field).then(
-        action.bound!((data: any) => {
-          products.current = data.result;
-          field.dataSource = data.result.map((item: any) => ({ label: item.name, value: item.id }));
-          field.loading = false;
-        }),
-      );
-    };
+  const useAsyncDataSource = (services: (arg0: Field) => Promise<any>) => (field: Field) => {
+    field.loading = true;
+    services(field).then(
+      action.bound!((data: any) => {
+        products.current = data.result;
+        field.dataSource = data.result.map((item: any) => ({ label: item.name, value: item.id }));
+        field.loading = false;
+      }),
+    );
+  };
 
   const loadData = async () => service.queryProduct();
 
@@ -110,36 +116,41 @@ const Create = () => {
             ],
           },
           properties: {
-            title: '属性',
-            'x-decorator': 'FormItem',
-            'x-component': 'Select',
-            enum: [],
-            'x-reactions': {
-              dependencies: ['.messageType'],
-              fulfill: {
-                state: {
-                  visible: "{{['READ_PROPERTY','WRITE_PROPERTY'].includes($deps[0])}}",
-                  componentProps: {
-                    mode: "{{$deps[0]==='READ_PROPERTY'&&'multiple'}}",
+            type: 'object',
+            properties: {
+              key: {
+                title: '属性',
+                'x-decorator': 'FormItem',
+                'x-component': 'Select',
+                enum: [],
+                'x-reactions': {
+                  dependencies: ['..messageType'],
+                  fulfill: {
+                    state: {
+                      visible: "{{['READ_PROPERTY','WRITE_PROPERTY'].includes($deps[0])}}",
+                      componentProps: {
+                        mode: "{{$deps[0]==='READ_PROPERTY'&&'multiple'}}",
+                      },
+                    },
                   },
                 },
+                'x-visible': false,
               },
-            },
-            'x-visible': false,
-          },
-          value: {
-            title: '设置值',
-            'x-component': 'Input',
-            'x-decorator': 'FormItem',
-            'x-reactions': {
-              dependencies: ['.messageType'],
-              fulfill: {
-                state: {
-                  visible: "{{['WRITE_PROPERTY'].includes($deps[0])}}",
+              value: {
+                title: '设置值',
+                'x-component': 'Input',
+                'x-decorator': 'FormItem',
+                'x-reactions': {
+                  dependencies: ['..messageType'],
+                  fulfill: {
+                    state: {
+                      visible: "{{['WRITE_PROPERTY'].includes($deps[0])}}",
+                    },
+                  },
                 },
+                'x-visible': false,
               },
             },
-            'x-visible': false,
           },
           functionId: {
             title: '功能',
@@ -206,8 +217,38 @@ const Create = () => {
     },
   };
 
+  const sendCommand = async () => {
+    const values: Record<string, any> = await form.submit();
+    const type = values.message?.messageType;
+    switch (type) {
+      case 'READ_PROPERTY':
+        const property = values.message.properties.key;
+        values.message.properties = property;
+        break;
+      case 'WRITE_PROPERTY':
+        const key = values.message.properties.key;
+        const value = values.message.properties.value;
+        values.message.properties = { [key]: value };
+        break;
+      default:
+        break;
+    }
+    const resp = await service.task(values);
+    if (resp.status === 200) {
+      message.success('操作成功');
+    } else {
+      message.error('操作失败');
+    }
+    close();
+  };
   return (
-    <Modal width="50vw" visible={true} title="下发指令">
+    <Modal
+      onOk={sendCommand}
+      onCancel={() => close()}
+      width="50vw"
+      visible={visible}
+      title="下发指令"
+    >
       <Form form={form} labelCol={5} wrapperCol={16}>
         <SchemaField schema={schema} scope={{ useAsyncDataSource, loadData }} />
       </Form>

+ 63 - 35
src/pages/device/Command/index.tsx

@@ -2,16 +2,29 @@ import { PageContainer } from '@ant-design/pro-layout';
 import { useRef } from 'react';
 import type { ProColumns, ActionType } from '@jetlinks/pro-table';
 import type { CommandItem } from '@/pages/device/Command/typings';
-import { Button, Tooltip } from 'antd';
+import { Button, message, Tooltip } from 'antd';
 import moment from 'moment';
 import { EyeOutlined, PlusOutlined, SyncOutlined } from '@ant-design/icons';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import Service from '@/pages/device/Command/service';
 import ProTable from '@jetlinks/pro-table';
 import Create from '@/pages/device/Command/create';
+import encodeQuery from '@/utils/encodeQuery';
+import { model } from '@formily/reactive';
+import { observer } from '@formily/react';
+import Cat from '@/pages/device/Command/cat';
 
 export const service = new Service('device/message/task');
-const Command = () => {
+
+export const state = model<{
+  visible: boolean;
+  cat: boolean;
+  data?: CommandItem;
+}>({
+  visible: false,
+  cat: false,
+});
+const Command = observer(() => {
   const actionRef = useRef<ActionType>();
   const intl = useIntl();
 
@@ -123,9 +136,10 @@ const Command = () => {
       width: 200,
       render: (text, record) => [
         <a
+          key="cat"
           onClick={() => {
-            // setVisible(true);
-            // setCurrent(record);
+            state.cat = true;
+            state.data = record;
           }}
         >
           <Tooltip
@@ -133,35 +147,33 @@ const Command = () => {
               id: 'pages.data.option.detail',
               defaultMessage: '查看',
             })}
-            key={'detail'}
+            key="detail"
           >
             <EyeOutlined />
           </Tooltip>
         </a>,
-        <a>
-          {record.state.value !== 'wait' && (
-            <a
-              onClick={() => {
-                // service.resend(encodeQueryParam({ terms: { id: record.id } })).subscribe(
-                //   data => {
-                //     message.success('操作成功');
-                //   },
-                //   () => {},
-                //   () => handleSearch(searchParam),
-                // );
-              }}
+        record.state.value !== 'wait' && (
+          <a
+            key="action"
+            onClick={async () => {
+              const resp = await service.resend(encodeQuery({ terms: { id: record.id } }));
+              if (resp.status === 200) {
+                message.success('操作成功!');
+              } else {
+                message.error('操作失败!');
+              }
+            }}
+          >
+            <Tooltip
+              title={intl.formatMessage({
+                id: 'pages.device.command.option.send',
+                defaultMessage: '重新发送',
+              })}
             >
-              <Tooltip
-                title={intl.formatMessage({
-                  id: 'pages.device.command.option.send',
-                  defaultMessage: '重新发送',
-                })}
-              >
-                <SyncOutlined />
-              </Tooltip>
-            </a>
-          )}
-        </a>,
+              <SyncOutlined />
+            </Tooltip>
+          </a>
+        ),
       ],
     },
   ];
@@ -170,11 +182,15 @@ const Command = () => {
     <PageContainer>
       <ProTable<CommandItem>
         toolBarRender={() => [
-          <Button onClick={() => {}} key="button" icon={<PlusOutlined />} type="primary">
-            {intl.formatMessage({
-              id: 'pages.data.option.add',
-              defaultMessage: '新增',
-            })}
+          <Button
+            onClick={() => {
+              state.visible = true;
+            }}
+            key="button"
+            icon={<PlusOutlined />}
+            type="primary"
+          >
+            下发指令
           </Button>,
         ]}
         request={async (params) => service.query(params)}
@@ -182,8 +198,20 @@ const Command = () => {
         actionRef={actionRef}
         rowKey="id"
       />
-      <Create />
+      <Create
+        visible={state.visible}
+        close={() => {
+          state.visible = false;
+        }}
+      />
+      <Cat
+        close={() => {
+          state.cat = false;
+        }}
+        data={state.data}
+        visible={state.cat}
+      />
     </PageContainer>
   );
-};
+});
 export default Command;

+ 12 - 0
src/pages/device/Command/service.ts

@@ -6,6 +6,18 @@ import SystemConst from '@/utils/const';
 class Service extends BaseService<CommandItem> {
   queryProduct = () =>
     request(`/${SystemConst.API_BASE}/device/product/_query/no-paging?paging=false`);
+
+  task = (data: Record<string, unknown>) =>
+    request(`/${SystemConst.API_BASE}/device/message/task`, {
+      method: 'POST',
+      data,
+    });
+
+  resend = (data: Record<string, unknown>) =>
+    request(`/${SystemConst.API_BASE}/device/message/task/state/wait`, {
+      method: 'PUT',
+      data,
+    });
 }
 
 export default Service;