Преглед изворни кода

feat(firmware): save firmware

Lind пре 4 година
родитељ
комит
72116e27f2

+ 3 - 0
src/components/Upload/index.less

@@ -0,0 +1,3 @@
+.ant-upload.ant-upload-select {
+  display: block;
+}

+ 62 - 17
src/components/Upload/index.tsx

@@ -1,40 +1,85 @@
-import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
+import { LoadingOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
 import SystemConst from '@/utils/const';
 import Token from '@/utils/token';
+import type { ReactNode } from 'react';
 import { useState } from 'react';
 import { connect } from '@formily/react';
-import { Upload } from 'antd';
+import { Input, Upload } from 'antd';
 import type { UploadChangeParam } from 'antd/lib/upload/interface';
+import type { UploadListType } from 'antd/es/upload/interface';
+import './index.less';
 
 interface Props {
   value: string;
-  onChange: (value: string) => void;
+  onChange: (value: string | FileProperty) => void;
+  type?: 'file' | 'image';
 }
 
-const FUploadImage = connect((props: Props) => {
-  const [url, setUrl] = useState<string>(props?.value);
+type FileProperty = {
+  url: string;
+  size: number;
+};
+
+const FUpload = connect((props: Props) => {
+  const [url, setUrl] = useState<string | FileProperty>(props?.value);
   const [loading, setLoading] = useState<boolean>(false);
-  const uploadButton = (
-    <div>
-      {loading ? <LoadingOutlined /> : <PlusOutlined />}
-      <div style={{ marginTop: 8 }}>选择图片</div>
-    </div>
-  );
+
   const handleChange = (info: UploadChangeParam) => {
-    console.log(info);
     if (info.file.status === 'uploading') {
       setLoading(false);
     }
     if (info.file.status === 'done') {
       info.file.url = info.file.response?.result;
       setLoading(false);
-      setUrl(info.file.response?.result);
-      props.onChange(info.file.response?.result);
+      const f = {
+        size: info.file.size || 0,
+        url: info.file.response?.result,
+      };
+      setUrl(f);
+      props.onChange(f);
     }
   };
+
+  const map = new Map<
+    string,
+    {
+      node: ReactNode;
+      type: UploadListType;
+    }
+  >();
+  map.set('image', {
+    node: (
+      <>
+        {url ? (
+          <img src={url as string} alt="avatar" style={{ width: '100%' }} />
+        ) : (
+          <div>
+            {loading ? <LoadingOutlined /> : <PlusOutlined />}
+            <div style={{ marginTop: 8 }}>选择图片</div>
+          </div>
+        )}
+      </>
+    ),
+    type: 'picture-card',
+  });
+  map.set('file', {
+    node: (
+      <>
+        <Input
+          value={(url as FileProperty).url}
+          onClick={(e) => {
+            e.preventDefault();
+            e.stopPropagation();
+          }}
+          addonAfter={<UploadOutlined />}
+        />
+      </>
+    ),
+    type: 'text',
+  });
   return (
     <Upload
-      listType="picture-card"
+      listType={map.get(props.type || 'image')?.type}
       action={`/${SystemConst.API_BASE}/file/static`}
       headers={{
         'X-Access-Token': Token.get(),
@@ -42,8 +87,8 @@ const FUploadImage = connect((props: Props) => {
       onChange={handleChange}
       showUploadList={false}
     >
-      {url ? <img src={url} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
+      {map.get(props.type || 'image')?.node}
     </Upload>
   );
 });
-export default FUploadImage;
+export default FUpload;

+ 94 - 49
src/pages/device/Firmware/Save/index.tsx

@@ -1,9 +1,16 @@
-import { Modal } from 'antd';
+import { message, Modal } from 'antd';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
-import { Form, FormItem, Input, Select, Upload } from '@formily/antd';
+import { Form, FormGrid, FormItem, Input, Select } from '@formily/antd';
+import type { Field } from '@formily/core';
 import { createForm } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
+import FUpload from '@/components/Upload';
+import { action } from '@formily/reactive';
+import { service } from '@/pages/device/Firmware';
+import type { Response } from '@/utils/typings';
+import { useRef } from 'react';
+import type { ProductItem } from '@/pages/device/Product/typings';
 
 interface Props {
   data?: FirmwareItem;
@@ -18,71 +25,109 @@ const Save = (props: Props) => {
     validateFirst: true,
     initialValues: data,
   });
+
+  const products = useRef<ProductItem[]>([]);
+  const useAsyncDataSource = (services: (arg0: Field) => Promise<any>) => (field: Field) => {
+    field.loading = true;
+    services(field).then(
+      action.bound!((list: any) => {
+        field.dataSource = list.result.map((item: any) => ({ label: item.name, value: item.id }));
+        products.current = list.result;
+        field.loading = false;
+      }),
+    );
+  };
+  const loadData = async () => service.queryProduct();
   const SchemaField = createSchemaField({
     components: {
       FormItem,
+      FormGrid,
       Input,
-      Upload,
+      FUpload,
       Select,
     },
   });
 
+  const save = async () => {
+    const values: FirmwareItem = await form.submit();
+    const product = products.current?.find((item) => item.id === values.productId);
+    values.productName = product?.name || '';
+    const resp = (await service.save(values)) as Response<FirmwareItem>;
+    if (resp.status === 200) {
+      message.success('保存成功!');
+    } else {
+      message.error('保存失败!');
+    }
+  };
   const schema: ISchema = {
     type: 'object',
     properties: {
-      productId: {
-        title: '产品',
-        'x-decorator': 'FormItem',
-        'x-component': 'Select',
-      },
-      name: {
-        title: '名称',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input',
-      },
-      version: {
-        title: '版本号',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input',
-      },
-      versionOrder: {
-        title: '版本序号',
-        'x-decorator': 'FormItem',
-        'x-component': 'Select',
-      },
-      signMethod: {
-        title: '签名方式',
-        'x-decorator': 'FormItem',
-        'x-component': 'Select',
-        enum: [
-          { label: 'MD5', value: 'MD5' },
-          { label: 'SHA256', value: 'SHA256' },
-        ],
-      },
-      sign: {
-        title: '签名',
-        'x-decorator': 'FormItem',
-        'x-component': 'Select',
-      },
-      file: {
-        title: '文件上传',
-        'x-decorator': 'FormItem',
-        'x-component': 'Upload',
-      },
-      describe: {
-        title: '描述信息',
-        'x-decorator': 'FormItem',
-        'x-component': 'Input.TextArea',
+      grid: {
+        type: 'void',
+        'x-component': 'FormGrid',
         'x-component-props': {
-          rows: 3,
+          minColumns: 2,
+          maxColumns: 2,
+        },
+        properties: {
+          productId: {
+            title: '产品',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            'x-reactions': ['{{useAsyncDataSource(loadData)}}'],
+          },
+          name: {
+            title: '名称',
+            'x-decorator': 'FormItem',
+            'x-component': 'Input',
+          },
+          version: {
+            title: '版本号',
+            'x-decorator': 'FormItem',
+            'x-component': 'Input',
+          },
+          versionOrder: {
+            title: '版本序号',
+            'x-decorator': 'FormItem',
+            'x-component': 'Input',
+          },
+          signMethod: {
+            title: '签名方式',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            enum: [
+              { label: 'MD5', value: 'MD5' },
+              { label: 'SHA256', value: 'SHA256' },
+            ],
+          },
+          sign: {
+            title: '签名',
+            'x-decorator': 'FormItem',
+            'x-component': 'Input',
+          },
+          '{url,size}': {
+            title: '文件上传',
+            'x-decorator': 'FormItem',
+            'x-component': 'FUpload',
+            'x-component-props': {
+              type: 'file',
+            },
+          },
         },
       },
     },
   };
+
   return (
-    <Modal title="新增固件版本" onCancel={() => close()} onOk={console.log} visible={visible}>
+    <Modal
+      width="50vw"
+      title="新增固件版本"
+      onCancel={() => close()}
+      onOk={() => save()}
+      visible={visible}
+    >
       <Form form={form} labelCol={5} wrapperCol={16}>
-        <SchemaField schema={schema} />
+        <SchemaField schema={schema} scope={{ useAsyncDataSource, loadData }} />
       </Form>
     </Modal>
   );

+ 1 - 1
src/pages/device/Firmware/index.tsx

@@ -19,7 +19,7 @@ export const state = model<{
   current?: FirmwareItem;
   visible: boolean;
 }>({
-  visible: false,
+  visible: true,
 });
 const Firmware = observer(() => {
   const actionRef = useRef<ActionType>();

+ 3 - 0
src/pages/device/Firmware/service.ts

@@ -15,6 +15,9 @@ class Service extends BaseService<FirmwareItem> {
       method: 'GET',
       params,
     });
+
+  queryProduct = () =>
+    request(`/${SystemConst.API_BASE}/device/product/_query/no-paging?paging=false`);
 }
 
 export default Service;

+ 3 - 3
src/pages/device/Product/Save/index.tsx

@@ -4,7 +4,7 @@ import { createForm, onFieldValueChange } from '@formily/core';
 import { TreeSelect, Form, FormItem, FormLayout, Input, Radio, Select } from '@formily/antd';
 import { createSchemaField } from '@formily/react';
 import type { ISchema } from '@formily/json-schema';
-import FUploadImage from '@/components/Upload';
+import FUpload from '@/components/Upload';
 import { service } from '@/pages/device/Product';
 import { action } from '@formily/reactive';
 import 'antd/lib/tree-select/style/index.less';
@@ -69,7 +69,7 @@ const Save = (props: Props) => {
       Input,
       Select,
       Radio,
-      FUploadImage,
+      FUpload,
       FormLayout,
       TreeSelect,
     },
@@ -135,7 +135,7 @@ const Save = (props: Props) => {
         properties: {
           photoUrl: {
             title: '图标',
-            'x-component': 'FUploadImage',
+            'x-component': 'FUpload',
             'x-decorator': 'FormItem',
           },
           id: {