فهرست منبع

fix: 修改bug

100011797 3 سال پیش
والد
کامیت
c27a0e260a

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

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

+ 52 - 0
src/components/FUpload/index.tsx

@@ -0,0 +1,52 @@
+import { UploadOutlined } from '@ant-design/icons';
+import SystemConst from '@/utils/const';
+import Token from '@/utils/token';
+import { useState } from 'react';
+import { connect } from '@formily/react';
+import { Input, Upload } from 'antd';
+import type { UploadChangeParam } from 'antd/lib/upload/interface';
+import './index.less';
+
+interface Props {
+  value: any;
+  onChange: (value: any) => void;
+  placeholder: string;
+  beforeUpload: any;
+}
+
+const FUpload = connect((props: Props) => {
+  const [url, setUrl] = useState<any>(props?.value?.url);
+
+  const handleChange = (info: UploadChangeParam) => {
+    if (info.file.status === 'done') {
+      const result = info.file.response?.result;
+      const f = {
+        ...result,
+        url: `${location.protocol}://${SystemConst.API_BASE}/file/${result?.id}?accessKey=${result?.others?.accessKey}`,
+      };
+      setUrl(f.url);
+      props.onChange(f);
+    }
+  };
+
+  return (
+    <Upload
+      beforeUpload={props.beforeUpload}
+      action={`/${SystemConst.API_BASE}/file/upload`}
+      headers={{
+        'X-Access-Token': Token.get(),
+      }}
+      multiple={false}
+      onChange={handleChange}
+      progress={{}}
+    >
+      <Input
+        placeholder={props.placeholder}
+        value={url || ''}
+        readOnly
+        addonAfter={<UploadOutlined />}
+      />
+    </Upload>
+  );
+});
+export default FUpload;

+ 0 - 66
src/pages/device/Firmware/Detail copy/History/index.tsx

@@ -1,66 +0,0 @@
-import type { ProColumns } from '@jetlinks/pro-table';
-import ProTable from '@jetlinks/pro-table';
-import { service, state } from '@/pages/device/Firmware';
-import type { HistoryItem } from '@/pages/device/Firmware/typings';
-import { useParams } from 'umi';
-import { useEffect, useState } from 'react';
-
-const History = () => {
-  const param = useParams<{ id: string }>();
-
-  const [defaultParams, setParams] = useState<Record<string, unknown>>();
-  useEffect(() => {
-    if (state.historyParams) {
-      setParams({ ...state.historyParams });
-    }
-    return () => {
-      state.historyParams = undefined;
-      state.taskItem = undefined;
-    };
-  }, []);
-  const columns: ProColumns<HistoryItem>[] = [
-    {
-      dataIndex: 'index',
-      valueType: 'indexBorder',
-      width: 48,
-    },
-    {
-      title: '设备名称',
-      dataIndex: 'deviceName',
-    },
-    {
-      title: '任务名称',
-      dataIndex: 'taskName',
-    },
-    {
-      title: '版本',
-      dataIndex: 'version',
-    },
-    {
-      title: '状态',
-      dataIndex: 'state',
-      renderText: (text) => text.text,
-    },
-    {
-      title: '进度(%)',
-      dataIndex: 'progress',
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'createTime',
-      valueType: 'dateTime',
-    },
-  ];
-  return (
-    <ProTable
-      columns={columns}
-      defaultParams={{
-        ...defaultParams,
-        firmwareId: param.id,
-      }}
-      request={(params) => service.history(params)}
-      rowKey="id"
-    />
-  );
-};
-export default History;

+ 0 - 114
src/pages/device/Firmware/Detail copy/Task/Detail/index.tsx

@@ -1,114 +0,0 @@
-import { Badge, Col, Modal, Row, Statistic } from 'antd';
-import { useEffect, useState } from 'react';
-import { service, state } from '@/pages/device/Firmware';
-import encodeQuery from '@/utils/encodeQuery';
-
-interface Props {
-  visible: boolean;
-  close: () => void;
-}
-
-type TaskState = 'waiting' | 'processing' | 'success' | 'failed';
-const map = {
-  waiting: {
-    status: 'warning',
-    text: '等待升级',
-  },
-  processing: {
-    status: 'processing',
-    text: '升级中',
-  },
-  success: {
-    status: 'success',
-    text: '完成',
-  },
-  failed: {
-    status: 'error',
-    text: '失败',
-  },
-};
-const Detail = (props: Props) => {
-  const [count, setCount] = useState<{
-    waiting: number;
-    processing: number;
-    success: number;
-    failed: number;
-  }>({
-    waiting: 0,
-    processing: 0,
-    success: 0,
-    failed: 0,
-  });
-
-  const getStateCount = (status: TaskState) =>
-    service
-      .historyCount(
-        encodeQuery({
-          terms: {
-            taskId: state.taskItem?.id,
-            state: status,
-          },
-        }),
-      )
-      .then((resp) => {
-        count[`${status}`] = resp.result;
-        setCount({ ...count });
-      });
-
-  useEffect(() => {
-    (['waiting', 'processing', 'success', 'failed'] as TaskState[]).forEach((s) => {
-      if (state.taskItem?.id) {
-        getStateCount(s);
-      }
-    });
-  }, [state.taskItem]);
-
-  return (
-    <Modal
-      maskClosable={false}
-      width="30vw"
-      visible={props.visible}
-      onCancel={() => props.close()}
-      title="任务详情"
-    >
-      <Row gutter={16}>
-        {Object.keys(count)
-          .reduce((previousValue: any[], currentValue) => {
-            previousValue.push({
-              key: currentValue,
-              value: count[currentValue],
-              ...map[currentValue],
-            });
-            return previousValue;
-          }, [])
-          .map((item) => (
-            <Col span={6} key={item.key}>
-              <Statistic
-                title={
-                  <Badge
-                    status={item.status}
-                    text={
-                      <a
-                        onClick={() => {
-                          state.taskDetail = false;
-                          state.tab = 'history';
-                          state.historyParams = {
-                            taskId: state.taskItem?.id,
-                            state: item.key,
-                          };
-                        }}
-                      >
-                        {item.text}
-                      </a>
-                    }
-                  />
-                }
-                value={item.value}
-              />
-            </Col>
-          ))}
-      </Row>
-    </Modal>
-  );
-};
-export default Detail;

+ 0 - 92
src/pages/device/Firmware/Detail copy/Task/Release/index.tsx

@@ -1,92 +0,0 @@
-import { Modal } from 'antd';
-import { createForm } from '@formily/core';
-import { createSchemaField } from '@formily/react';
-import { Form, FormItem, Select } from '@formily/antd';
-import type { ISchema } from '@formily/json-schema';
-import FSelectDevices from '@/components/FSelectDevices';
-import { service, state } from '@/pages/device/Firmware';
-import type { DeviceInstance } from '@/pages/device/Instance/typings';
-import { onlyMessage } from '@/utils/util';
-
-interface Props {
-  close: () => void;
-  visible: boolean;
-}
-
-const Release = (props: Props) => {
-  const form = createForm({
-    validateFirst: true,
-  });
-
-  const SchemaField = createSchemaField({
-    components: {
-      FormItem,
-      Select,
-      FSelectDevices,
-    },
-  });
-
-  const save = async () => {
-    const values: { releaseType: 'all' | 'part'; part: DeviceInstance[] } = await form.submit();
-    if (!(values.part?.length && values.part?.length <= 0)) {
-      values.releaseType = 'all';
-    }
-    const resp = await service.deploy(
-      state.taskItem!.id,
-      values?.releaseType,
-      values?.part?.map((i) => i.id),
-    );
-    if (resp.status === 200) {
-      onlyMessage('操作成功');
-    } else {
-      onlyMessage('操作失败', 'error');
-    }
-    props.close();
-  };
-
-  const schema: ISchema = {
-    type: 'object',
-    properties: {
-      releaseType: {
-        title: '发布方式',
-        'x-component': 'Select',
-        'x-decorator': 'FormItem',
-        default: 'all',
-        enum: [
-          { label: '所有设备', value: 'all' },
-          { label: '选择设备', value: 'part' },
-        ],
-      },
-      part: {
-        title: '选择设备',
-        'x-decorator': 'FormItem',
-        'x-component': 'FSelectDevices',
-        'x-visible': false,
-        'x-reactions': {
-          dependencies: ['.releaseType'],
-          fulfill: {
-            state: {
-              visible: '{{$deps[0]==="part"}}',
-            },
-          },
-        },
-      },
-    },
-  };
-  return (
-    <Modal
-      maskClosable={false}
-      title="发布任务"
-      onOk={save}
-      visible={props.visible}
-      onCancel={() => {
-        props.close();
-      }}
-    >
-      <Form form={form}>
-        <SchemaField schema={schema} />
-      </Form>
-    </Modal>
-  );
-};
-export default Release;

+ 0 - 86
src/pages/device/Firmware/Detail copy/Task/Save/index.tsx

@@ -1,86 +0,0 @@
-import { Modal } from 'antd';
-import { service, state } from '../../..';
-import { createForm } from '@formily/core';
-import { createSchemaField } from '@formily/react';
-import { Form, FormItem, Input, NumberPicker, Select } from '@formily/antd';
-import type { ISchema } from '@formily/json-schema';
-import { onlyMessage } from '@/utils/util';
-
-interface Props {
-  visible: boolean;
-  close: () => void;
-}
-
-const Save = (props: Props) => {
-  const form = createForm({
-    validateFirst: true,
-  });
-
-  const SchemaField = createSchemaField({
-    components: {
-      FormItem,
-      Input,
-      Select,
-      NumberPicker,
-    },
-  });
-
-  const schema: ISchema = {
-    type: 'object',
-    properties: {
-      name: {
-        title: '名称',
-        'x-component': 'Input',
-        'x-decorator': 'FormItem',
-      },
-      timeoutSeconds: {
-        title: '超时时间',
-        'x-component': 'NumberPicker',
-        'x-decorator': 'FormItem',
-      },
-      mode: {
-        title: '推送方式',
-        'x-component': 'Select',
-        'x-decorator': 'FormItem',
-        enum: [
-          { label: '平台推送', value: 'push' },
-          { label: '设备拉取', value: 'pull' },
-        ],
-      },
-      description: {
-        title: '名称',
-        'x-component': 'Input.TextArea',
-        'x-decorator': 'FormItem',
-      },
-    },
-  };
-
-  const save = async () => {
-    const values: Record<string, unknown> = await form.submit();
-    // 判断current 没有数据应该回退上一页
-    values.productId = state.current?.productId;
-    values.firmwareId = state.current?.id;
-    const resp = await service.saveTask(values);
-    if (resp.status === 200) {
-      onlyMessage('操作成功');
-    } else {
-      onlyMessage('操作失败', 'error');
-    }
-    props.close();
-  };
-  return (
-    <Modal
-      maskClosable={false}
-      onOk={save}
-      width="40vw"
-      visible={props.visible}
-      onCancel={() => props.close()}
-      title="新建任务"
-    >
-      <Form form={form} labelCol={5} wrapperCol={16}>
-        <SchemaField schema={schema} />
-      </Form>
-    </Modal>
-  );
-};
-export default Save;

+ 0 - 136
src/pages/device/Firmware/Detail copy/Task/index.tsx

@@ -1,136 +0,0 @@
-import type { ProColumns } from '@jetlinks/pro-table';
-import ProTable from '@jetlinks/pro-table';
-import type { TaskItem } from '@/pages/device/Firmware/typings';
-import { service, state } from '@/pages/device/Firmware';
-import { Button, Tooltip } from 'antd';
-import {
-  CloudDownloadOutlined,
-  DeleteOutlined,
-  EyeOutlined,
-  PieChartOutlined,
-  PlusOutlined,
-} from '@ant-design/icons';
-import { useIntl, useParams } from 'umi';
-import Save from './Save';
-import { observer } from '@formily/react';
-import Release from './Release';
-import Detail from './Detail';
-
-const Task = observer(() => {
-  const intl = useIntl();
-  const param = useParams<{ id: string }>();
-  const columns: ProColumns<TaskItem>[] = [
-    {
-      dataIndex: 'index',
-      valueType: 'indexBorder',
-      width: 48,
-    },
-    {
-      dataIndex: 'id',
-      title: 'id',
-      width: 200,
-    },
-    {
-      dataIndex: 'name',
-      title: '任务名称',
-    },
-    {
-      dataIndex: 'mode',
-      title: '升级方式',
-      renderText: (text) => text.text,
-    },
-    {
-      dataIndex: 'timeoutSeconds',
-      title: '超时时间(秒)',
-    },
-    {
-      dataIndex: 'createTime',
-      valueType: 'dateTime',
-      title: '创建时间',
-    },
-    {
-      title: '操作',
-      valueType: 'option',
-      align: 'center',
-      render: (text, record) => [
-        <a
-          key="cat"
-          onClick={() => {
-            state.task = true;
-          }}
-        >
-          <Tooltip title="查看">
-            <EyeOutlined />
-          </Tooltip>
-        </a>,
-        <a
-          key="task"
-          onClick={() => {
-            state.release = true;
-            state.taskItem = record;
-          }}
-        >
-          <Tooltip title="下发任务">
-            <CloudDownloadOutlined />
-          </Tooltip>
-        </a>,
-        <a
-          key="detail"
-          onClick={() => {
-            state.taskDetail = true;
-            state.taskItem = record;
-          }}
-        >
-          <Tooltip title="任务详情">
-            <PieChartOutlined />
-          </Tooltip>
-        </a>,
-        <a key="remove">
-          <Tooltip title="删除">
-            <DeleteOutlined />
-          </Tooltip>
-        </a>,
-      ],
-    },
-  ];
-  return (
-    <>
-      <ProTable
-        columns={columns}
-        rowKey="id"
-        defaultParams={{
-          firmwareId: param.id,
-        }}
-        toolBarRender={() => [
-          <Button onClick={() => {}} key="button" icon={<PlusOutlined />} type="primary">
-            {intl.formatMessage({
-              id: 'pages.data.option.add',
-              defaultMessage: '新增',
-            })}
-          </Button>,
-        ]}
-        request={async (params) => service.task(params)}
-      />
-      <Save
-        close={() => {
-          state.task = false;
-        }}
-        visible={state.task}
-      />
-      <Release
-        close={() => {
-          state.release = false;
-        }}
-        visible={state.release}
-      />
-      <Detail
-        visible={state.taskDetail}
-        close={() => {
-          state.taskDetail = false;
-          state.taskItem = undefined;
-        }}
-      />
-    </>
-  );
-});
-export default Task;

+ 0 - 68
src/pages/device/Firmware/Detail copy/index.tsx

@@ -1,68 +0,0 @@
-import { PageContainer } from '@ant-design/pro-layout';
-import { history, useParams } from 'umi';
-import { Descriptions } from 'antd';
-import { service, state } from '@/pages/device/Firmware';
-import History from './History';
-import { useEffect, useState } from 'react';
-import type { FirmwareItem } from '@/pages/device/Firmware/typings';
-import Task from './Task';
-import { observer } from '@formily/react';
-
-const Detail = observer(() => {
-  const [data, setData] = useState<FirmwareItem | undefined>(state.current);
-  const param = useParams<{ id: string }>();
-  useEffect(() => {
-    if (!state.current) {
-      service.detail(param.id).then((resp) => {
-        if (resp.status === 200) {
-          setData(resp.result);
-        }
-      });
-    }
-  }, [param.id]);
-
-  const list = [
-    {
-      key: 'task',
-      tab: '升级任务',
-      component: <Task />,
-    },
-    {
-      key: 'history',
-      tab: '升级记录',
-      component: <History />,
-    },
-  ];
-  return (
-    <PageContainer
-      tabActiveKey={state.tab}
-      onBack={history.goBack}
-      onTabChange={(key) => {
-        state.tab = key as 'task' | 'history';
-      }}
-      content={
-        <>
-          <Descriptions size="small" column={3}>
-            {[
-              { key: 'ID', value: data?.id },
-              { key: '所属产品', value: data?.productName },
-              { key: '版本号', value: data?.version },
-              { key: '版本序号', value: data?.versionOrder },
-              { key: '签名方式', value: data?.signMethod },
-              { key: '签名', value: data?.sign },
-            ].map((item) => (
-              <Descriptions.Item key={item.key} label={item.key}>
-                {item.value}
-              </Descriptions.Item>
-            ))}
-          </Descriptions>
-        </>
-      }
-      title={<>固件: {state.current?.name}</>}
-      tabList={list}
-    >
-      {list.find((k) => k.key === state.tab)?.component}
-    </PageContainer>
-  );
-});
-export default Detail;

+ 72 - 23
src/pages/device/Firmware/Save/index.tsx

@@ -3,12 +3,12 @@ import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import { createSchemaField } from '@formily/react';
 import { Form, FormGrid, FormItem, Input, Select, ArrayTable } from '@formily/antd';
 import type { Field } from '@formily/core';
+import { onFieldValueChange, onFormInit } from '@formily/core';
 import { createForm } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
-import FUpload from '@/components/Upload';
+import FUpload from '@/components/FUpload';
 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';
 import { onlyMessage } from '@/utils/util';
@@ -21,13 +21,30 @@ interface Props {
 
 const Save = (props: Props) => {
   const { data, close, visible } = props;
+  const fileInfo = useRef<any>({});
+  const signMethod = useRef<'md5' | 'sha256'>('md5');
 
   const form = createForm({
     validateFirst: true,
     initialValues: data,
+    effects: () => {
+      onFormInit(async (form1) => {
+        if (!data?.id) return;
+        form1.setInitialValues({ ...data, upload: { url: data?.url } });
+      });
+      onFieldValueChange('signMethod', (field) => {
+        const value = (field as Field).value;
+        signMethod.current = value;
+      });
+      onFieldValueChange('upload', (field) => {
+        const value = (field as Field).value;
+        fileInfo.current = value;
+      });
+    },
   });
 
   const products = useRef<ProductItem[]>([]);
+
   const useAsyncDataSource = (services: (arg0: Field) => Promise<any>) => (field: Field) => {
     field.loading = true;
     services(field).then(
@@ -51,14 +68,19 @@ const Save = (props: Props) => {
   });
 
   const save = async () => {
-    const values: FirmwareItem = await form.submit();
+    const values: any = 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>;
+    const { upload, ...extra } = values;
+    const params = {
+      ...extra,
+      url: upload.url || data?.url,
+      size: upload.length || data?.size,
+    };
+    const resp = (await service.update(params)) as any;
     if (resp.status === 200) {
       onlyMessage('保存成功!');
-    } else {
-      onlyMessage('保存失败!', 'error');
+      close();
     }
   };
   const schema: ISchema = {
@@ -162,8 +184,8 @@ const Save = (props: Props) => {
             'x-decorator': 'FormItem',
             'x-component': 'Select',
             enum: [
-              { label: 'MD5', value: 'MD5' },
-              { label: 'SHA256', value: 'SHA256' },
+              { label: 'MD5', value: 'md5' },
+              { label: 'SHA256', value: 'sha256' },
             ],
             'x-component-props': {
               placeholder: '请选择签名方式',
@@ -196,14 +218,38 @@ const Save = (props: Props) => {
                 required: true,
                 message: '请输入签名',
               },
+              // {
+              //   validator: (value: string) => {
+              //     return new Promise((resolve, reject) => {
+              //       if (value !== '' && signMethod.current && fileInfo.current[signMethod.current]) {
+              //         if (value !== fileInfo.current[signMethod.current]) {
+              //           return reject(new Error('签名不一致,请检查文件是否上传正确'));
+              //         }
+              //       }
+              //       return resolve('');
+              //     });
+              //   },
+              // },
+            ],
+            'x-reactions': [
+              {
+                dependencies: ['.upload', 'signMethod'],
+                fulfill: {
+                  state: {
+                    selfErrors:
+                      '{{$deps[0] && $deps[1] && $deps[0][$deps[1]] && $self.value && $self.value !== $deps[0][$deps[1]] ? "签名不一致,请检查文件是否上传正确" : ""}}',
+                  },
+                },
+              },
             ],
           },
-          '{url,size}': {
+          upload: {
             title: '文件上传',
             'x-decorator': 'FormItem',
             'x-component': 'FUpload',
             'x-component-props': {
               type: 'file',
+              placeholder: '请上传文件',
             },
             'x-decorator-props': {
               gridSpan: 2,
@@ -216,7 +262,7 @@ const Save = (props: Props) => {
               },
             ],
           },
-          array: {
+          properties: {
             type: 'array',
             'x-decorator': 'FormItem',
             'x-component': 'ArrayTable',
@@ -236,7 +282,7 @@ const Save = (props: Props) => {
                   'x-component': 'ArrayTable.Column',
                   'x-component-props': { title: 'KEY' },
                   properties: {
-                    a1: {
+                    id: {
                       type: 'string',
                       'x-decorator': 'Editable',
                       'x-component': 'Input',
@@ -248,7 +294,7 @@ const Save = (props: Props) => {
                   'x-component': 'ArrayTable.Column',
                   'x-component-props': { title: 'VALUE' },
                   properties: {
-                    a2: {
+                    value: {
                       type: 'string',
                       'x-decorator': 'FormItem',
                       'x-component': 'Input',
@@ -285,16 +331,19 @@ const Save = (props: Props) => {
               },
             },
           },
-        },
-        description: {
-          title: '说明',
-          'x-decorator': 'FormItem',
-          'x-component': 'Input.TextArea',
-          'x-component-props': {
-            rows: 3,
-            showCount: true,
-            maxLength: 200,
-            placeholder: '请输入说明',
+          description: {
+            title: '说明',
+            'x-decorator': 'FormItem',
+            'x-component': 'Input.TextArea',
+            'x-decorator-props': {
+              gridSpan: 2,
+            },
+            'x-component-props': {
+              rows: 3,
+              showCount: true,
+              maxLength: 200,
+              placeholder: '请输入说明',
+            },
           },
         },
       },
@@ -305,7 +354,7 @@ const Save = (props: Props) => {
     <Modal
       maskClosable={false}
       width="50vw"
-      title="新增"
+      title={data?.id ? '编辑' : '新增'}
       onCancel={() => close()}
       onOk={() => save()}
       visible={visible}

+ 3 - 10
src/pages/device/Firmware/Task/index.tsx

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
-import { Button, Popconfirm, Tooltip } from 'antd';
+import { Popconfirm, Tooltip } from 'antd';
 import { useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { EditOutlined, EyeOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons';
@@ -69,7 +69,8 @@ const Task = observer(() => {
       render: (text, record) => [
         <Link
           onClick={() => {
-            state.current = record;
+            const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task/Detail'], '123');
+            history.push(url);
           }}
           to={`/device/firmware/detail/${record.id}`}
           key="link"
@@ -163,14 +164,6 @@ const Task = observer(() => {
                 defaultMessage: '新增',
               })}
             </PermissionButton>
-            <Button
-              onClick={() => {
-                const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task/Detail'], '123');
-                history.push(url);
-              }}
-            >
-              详情
-            </Button>
           </div>
         }
         request={async (params) =>

+ 40 - 67
src/pages/device/Firmware/index.tsx

@@ -1,18 +1,17 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
-import { Button, Popconfirm, Tooltip } from 'antd';
+import { Popconfirm } from 'antd';
 import moment from 'moment';
 import { useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { EditOutlined, EyeOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons';
-import { Link, useHistory } from 'umi';
+import { DeleteOutlined, EditOutlined, NodeExpandOutlined, PlusOutlined } from '@ant-design/icons';
+import { useHistory } from 'umi';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
-import type { FirmwareItem, TaskItem } from '@/pages/device/Firmware/typings';
+import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import Service from '@/pages/device/Firmware/service';
 import Save from '@/pages/device/Firmware/Save';
-import { onlyMessage } from '@/utils/util';
 import { PermissionButton } from '@/components';
 import useDomFullHeight from '@/hooks/document/useDomFullHeight';
 import usePermissions from '@/hooks/permission';
@@ -24,18 +23,8 @@ export const service = new Service('firmware');
 export const state = model<{
   current?: FirmwareItem;
   visible: boolean;
-  task: boolean;
-  release: boolean;
-  taskItem?: TaskItem;
-  taskDetail: boolean;
-  tab: 'task' | 'history';
-  historyParams?: Record<string, unknown>;
 }>({
   visible: false,
-  task: false,
-  release: false,
-  taskDetail: false,
-  tab: 'task',
 });
 const Firmware = observer(() => {
   const actionRef = useRef<ActionType>();
@@ -109,67 +98,56 @@ const Firmware = observer(() => {
       valueType: 'option',
       align: 'center',
       width: 200,
-
       render: (text, record) => [
-        <Link
+        <PermissionButton
+          style={{ padding: 0 }}
+          type="link"
+          isPermission={permission.action}
+          key="upgrade"
           onClick={() => {
-            state.current = record;
+            const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task'], record?.id);
+            history.push(url);
+          }}
+          tooltip={{
+            title: '升级任务',
           }}
-          to={`/device/firmware/detail/${record.id}`}
-          key="link"
         >
-          <Tooltip
-            title={intl.formatMessage({
-              id: 'pages.data.option.detail',
-              defaultMessage: '查看',
-            })}
-            key={'detail'}
-          >
-            <EyeOutlined />
-          </Tooltip>
-        </Link>,
-        <a
+          <NodeExpandOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          style={{ padding: 0 }}
+          type="link"
+          isPermission={permission.update}
           key="editable"
           onClick={() => {
             state.visible = true;
+            state.current = record;
           }}
-        >
-          <Tooltip
-            title={intl.formatMessage({
+          tooltip={{
+            title: intl.formatMessage({
               id: 'pages.data.option.edit',
               defaultMessage: '编辑',
-            })}
-          >
-            <EditOutlined />
-          </Tooltip>
-        </a>,
-        <a key="delete">
+            }),
+          }}
+        >
+          <EditOutlined />
+        </PermissionButton>,
+        <PermissionButton
+          type="link"
+          key="delete"
+          style={{ padding: 0 }}
+          isPermission={permission.delete}
+        >
           <Popconfirm
-            title={intl.formatMessage({
-              id: 'pages.data.option.remove.tips',
-              defaultMessage: '确认删除?',
-            })}
             onConfirm={async () => {
               await service.remove(record.id);
-              onlyMessage(
-                intl.formatMessage({
-                  id: 'pages.data.option.success',
-                  defaultMessage: '操作成功!',
-                }),
-              );
               actionRef.current?.reload();
             }}
+            title="确认删除?"
           >
-            <Tooltip
-              title={intl.formatMessage({
-                id: 'pages.data.option.remove',
-                defaultMessage: '删除',
-              })}
-            >
-              <MinusOutlined />
-            </Tooltip>
+            <DeleteOutlined />
           </Popconfirm>
-        </a>,
+        </PermissionButton>,
       ],
     },
   ];
@@ -191,11 +169,13 @@ const Firmware = observer(() => {
         tableStyle={{ minHeight }}
         search={false}
         params={param}
+        columnEmptyText={''}
         headerTitle={
           <div>
             <PermissionButton
               onClick={() => {
                 state.visible = true;
+                state.current = undefined;
               }}
               isPermission={permission.add}
               key="button"
@@ -207,14 +187,6 @@ const Firmware = observer(() => {
                 defaultMessage: '新增',
               })}
             </PermissionButton>
-            <Button
-              onClick={() => {
-                const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task'], '123');
-                history.push(url);
-              }}
-            >
-              升级任务
-            </Button>
           </div>
         }
         request={async (params) =>
@@ -228,6 +200,7 @@ const Firmware = observer(() => {
         visible={state.visible}
         close={() => {
           state.visible = false;
+          actionRef.current?.reload();
         }}
       />
     </PageContainer>

+ 28 - 1
src/pages/init-home/index.less

@@ -1,7 +1,7 @@
 .init {
   width: 100%;
   height: 100vh;
-  padding: 64px 128px;
+  padding: 32px 128px 64px 128px;
   overflow: hidden;
   background-image: url('/images/init-home/background.png');
   background-repeat: no-repeat;
@@ -10,6 +10,33 @@
   .box {
     width: 100%;
     height: 100%;
+    padding: 24px;
     background: white;
+
+    .container {
+      display: flex;
+      justify-content: space-between;
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+
+      .left {
+        width: 30px;
+        height: 100%;
+      }
+
+      .right {
+        width: calc(100% - 50px);
+        height: 1200px;
+
+        // .collapseTitle {
+
+        // }
+
+        // .collapseDesc {
+
+        // }
+      }
+    }
   }
 }

+ 34 - 1
src/pages/init-home/index.tsx

@@ -1,11 +1,44 @@
 import { TitleComponent } from '@/components';
+import { Collapse, Steps } from 'antd';
 import styles from './index.less';
 
 const InitHome = () => {
+  const text = `
+        A dog is a type of domesticated animal.
+        Known for its loyalty and faithfulness,
+        it can be found as a welcome guest in many households across the world.
+    `;
   return (
     <div className={styles.init}>
       <TitleComponent data={'系统初始化'} />
-      <div className={styles.box}>123</div>
+      <div className={styles.box}>
+        <div className={styles.container}>
+          <div className={styles.left}>
+            <Steps direction="vertical" current={1} percent={60} style={{ height: '100%' }}>
+              <Steps.Step />
+              <Steps.Step />
+              <Steps.Step />
+              <Steps.Step />
+            </Steps>
+          </div>
+          <div className={styles.right}>
+            <Collapse defaultActiveKey={['1', '2', '3', '4']}>
+              <Collapse.Panel header={<div>基本信息</div>} key="1">
+                <p>{text}</p>
+              </Collapse.Panel>
+              <Collapse.Panel header="This is panel header 2" key="2">
+                <p>{text}</p>
+              </Collapse.Panel>
+              <Collapse.Panel header="This is panel header 3" key="3">
+                <p>{text}</p>
+              </Collapse.Panel>
+              <Collapse.Panel header="This is panel header 3" key="4">
+                <p>{text}</p>
+              </Collapse.Panel>
+            </Collapse>
+          </div>
+        </div>
+      </div>
     </div>
   );
 };