100011797 3 лет назад
Родитель
Сommit
e43842856d
30 измененных файлов с 576 добавлено и 285 удалено
  1. BIN
      public/images/firmware/button.png
  2. 5 1
      src/components/Ellipsis/index.tsx
  3. 3 3
      src/components/ProTableCard/CardItems/Stream/index.tsx
  4. 4 4
      src/components/ProTableCard/index.tsx
  5. 103 104
      src/components/SearchComponent/index.tsx
  6. 22 0
      src/pages/device/Firmware/Task/Detail/Details/index.tsx
  7. 22 3
      src/pages/device/Firmware/Task/Detail/index.less
  8. 233 30
      src/pages/device/Firmware/Task/Detail/index.tsx
  9. 3 1
      src/pages/device/Firmware/Task/Save/index.tsx
  10. 25 18
      src/pages/device/Firmware/Task/index.tsx
  11. 1 0
      src/pages/device/Firmware/index.tsx
  12. 20 12
      src/pages/device/Firmware/service.ts
  13. 1 1
      src/pages/device/Instance/Detail/ChildDevice/index.tsx
  14. 77 4
      src/pages/init-home/components/data/index.tsx
  15. 6 51
      src/pages/init-home/components/data/save/index.tsx
  16. 4 2
      src/pages/init-home/index.tsx
  17. 1 1
      src/pages/init-home/service.ts
  18. 2 1
      src/pages/media/Home/service.tsx
  19. 2 2
      src/pages/notice/Config/Debug/index.tsx
  20. 18 18
      src/pages/notice/Template/Debug/index.tsx
  21. 1 1
      src/pages/notice/Template/index.tsx
  22. 3 8
      src/pages/rule-engine/Alarm/Log/TabComponent/index.tsx
  23. 6 6
      src/pages/rule-engine/Scene/Save/action/VariableItems/builtIn.tsx
  24. 2 2
      src/pages/rule-engine/Scene/Save/action/action.tsx
  25. 1 1
      src/pages/rule-engine/Scene/Save/action/device/ConditionalFiltering.tsx
  26. 6 6
      src/pages/rule-engine/Scene/Save/action/device/WriteProperty/index.tsx
  27. 1 1
      src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx
  28. 2 2
      src/pages/rule-engine/Scene/Save/action/device/index.tsx
  29. 1 1
      src/pages/system/Department/Assets/deivce/index.tsx
  30. 1 1
      src/pages/system/Relationship/index.tsx

BIN
public/images/firmware/button.png


+ 5 - 1
src/components/Ellipsis/index.tsx

@@ -93,7 +93,11 @@ export default (props: EllipsisProps) => {
       )}
       <div
         className={classnames(props.titleClassName?.replace('ellipsis', ''), Style['ellipsis-max'])}
-        style={props.titleStyle ? { ...props.titleStyle, width: 'max-content !important' } : {width: 'max-content !important'}}
+        style={
+          props.titleStyle
+            ? { ...props.titleStyle, width: 'max-content !important' }
+            : { width: 'max-content !important' }
+        }
         ref={extraNode}
       >
         {props.title}

+ 3 - 3
src/components/ProTableCard/CardItems/Stream/index.tsx

@@ -37,13 +37,13 @@ export default (props: StreamCardProps) => {
               {/*<div className={'ellipsis'}>*/}
               {/*  <Tooltip title={props?.provider}>{props?.provider}</Tooltip>*/}
               {/*</div>*/}
-              <div style={{width: '100%'}}>
+              <div style={{ width: '100%' }}>
                 <Ellipsis title={props?.provider} titleClassName={'stream-title'} />
               </div>
             </div>
             <div>
               <label>RTP IP</label>
-              <div style={{width: '100%'}}>
+              <div style={{ width: '100%' }}>
                 <Ellipsis title={props?.configuration?.rtpIp} />
               </div>
               {/*<div className={'ellipsis'}>*/}
@@ -52,7 +52,7 @@ export default (props: StreamCardProps) => {
             </div>
             <div>
               <label>API HOST</label>
-              <div style={{width: '100%'}}>
+              <div style={{ width: '100%' }}>
                 <Ellipsis title={props?.configuration?.apiHost} />
               </div>
               {/*<div className={'ellipsis'}>*/}

+ 4 - 4
src/components/ProTableCard/index.tsx

@@ -28,7 +28,7 @@ interface ProTableCardProps<T> {
    * gridColumns[1] 1440 ~  1600 分辨率;
    * gridColumns[2] > 1600 分辨率;
    */
-  gridColumns?: [number, number, number]
+  gridColumns?: [number, number, number];
   height?: 'none';
 }
 
@@ -130,13 +130,13 @@ const ProTableCard = <
 
   const windowChange = () => {
     if (window.innerWidth <= 1440) {
-      const _column = props.gridColumn && props.gridColumn < 2 ? props.gridColumn : 2
+      const _column = props.gridColumn && props.gridColumn < 2 ? props.gridColumn : 2;
       setColumn(props.gridColumns ? props.gridColumns[0] : _column);
     } else if (window.innerWidth > 1440 && window.innerWidth <= 1600) {
-      const _column = props.gridColumn && props.gridColumn < 3 ? props.gridColumn : 3
+      const _column = props.gridColumn && props.gridColumn < 3 ? props.gridColumn : 3;
       setColumn(props.gridColumns ? props.gridColumns[1] : _column);
     } else if (window.innerWidth > 1600) {
-      const _column = props.gridColumn && props.gridColumn < 4 ? props.gridColumn : 4
+      const _column = props.gridColumn && props.gridColumn < 4 ? props.gridColumn : 4;
       setColumn(props.gridColumns ? props.gridColumns[2] : _column);
     }
   };

+ 103 - 104
src/components/SearchComponent/index.tsx

@@ -201,117 +201,116 @@ const SearchComponent = <T extends Record<string, any>>(props: Props<T>) => {
         effects() {
           onFieldReact('*.*.column', async (typeFiled, f) => {
             // if ((typeFiled as Field).modified) {
-              const isModified = (typeFiled as Field).modified
-              const _column = (typeFiled as Field).value;
-              const _field = field.find((item) => item.dataIndex === _column);
-              if (_column === 'id') {
-                if (isModified) {
-                  f.setFieldState(typeFiled.query('.termType'), async (state) => {
-                    state.value = 'eq';
-                  });
-
-                }
-                f.setFieldState(typeFiled.query('.value'), async (state) => {
-                  state.componentType = 'Input';
-                  state.componentProps = { allowClear: true };
+            const isModified = (typeFiled as Field).modified;
+            const _column = (typeFiled as Field).value;
+            const _field = field.find((item) => item.dataIndex === _column);
+            if (_column === 'id') {
+              if (isModified) {
+                f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                  state.value = 'eq';
                 });
-              } else {
-                switch (_field?.valueType) {
-                  case 'select':
-                    let __option: { label: any; value: any }[] | FieldDataSource | undefined = [];
-                    if (_field?.valueEnum) {
-                      __option = Object.values(_field?.valueEnum || {}).map((item) => ({
-                        label: item.text,
-                        value: item.status,
-                      }));
-                    } else if (_field?.request) {
-                      __option = await _field.request();
-                    }
-                    if (isModified) {
-                      f.setFieldState(typeFiled.query('.termType'), async (state) => {
-                        state.value = 'eq';
-                      });
-                    }
-
-                    f.setFieldState(typeFiled.query('.value'), async (state) => {
-                      console.log(state.value);
-                      state.componentType = 'Select';
-                      state.dataSource = __option;
-                      state.componentProps = {
-                        allowClear: true,
-                        showSearch: true,
-                        filterOption: (input: string, option: any) =>
-                          option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
-                      };
+              }
+              f.setFieldState(typeFiled.query('.value'), async (state) => {
+                state.componentType = 'Input';
+                state.componentProps = { allowClear: true };
+              });
+            } else {
+              switch (_field?.valueType) {
+                case 'select':
+                  let __option: { label: any; value: any }[] | FieldDataSource | undefined = [];
+                  if (_field?.valueEnum) {
+                    __option = Object.values(_field?.valueEnum || {}).map((item) => ({
+                      label: item.text,
+                      value: item.status,
+                    }));
+                  } else if (_field?.request) {
+                    __option = await _field.request();
+                  }
+                  if (isModified) {
+                    f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                      state.value = 'eq';
                     });
-                    break;
-                  case 'treeSelect':
-                    let _option: { label: any; value: any }[] | FieldDataSource | undefined = [];
-                    if (_field?.valueEnum) {
-                      _option = Object.values(_field?.valueEnum || {}).map((item) => ({
-                        label: item.text,
-                        value: item.status,
-                      }));
-                    } else if (_field?.request) {
-                      _option = await _field.request();
-                    }
-                    if (isModified) {
-                      f.setFieldState(typeFiled.query('.termType'), (_state) => {
-                        _state.value = 'eq';
-                      });
-                    }
-
-                    f.setFieldState(typeFiled.query('.value'), (state) => {
-                      state.componentType = 'TreeSelect';
-                      state.dataSource = _option;
-                      state.componentProps = {
-                        ..._field.fieldProps,
-                        allowClear: true,
-                        showSearch: true,
-                        treeNodeFilterProp: 'name',
-                        filterOption: (input: string, option: any) =>
-                          option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
-                      };
+                  }
+
+                  f.setFieldState(typeFiled.query('.value'), async (state) => {
+                    console.log(state.value);
+                    state.componentType = 'Select';
+                    state.dataSource = __option;
+                    state.componentProps = {
+                      allowClear: true,
+                      showSearch: true,
+                      filterOption: (input: string, option: any) =>
+                        option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
+                    };
+                  });
+                  break;
+                case 'treeSelect':
+                  let _option: { label: any; value: any }[] | FieldDataSource | undefined = [];
+                  if (_field?.valueEnum) {
+                    _option = Object.values(_field?.valueEnum || {}).map((item) => ({
+                      label: item.text,
+                      value: item.status,
+                    }));
+                  } else if (_field?.request) {
+                    _option = await _field.request();
+                  }
+                  if (isModified) {
+                    f.setFieldState(typeFiled.query('.termType'), (_state) => {
+                      _state.value = 'eq';
                     });
-                    break;
-                  case 'digit':
-                    f.setFieldState(typeFiled.query('.value'), async (state) => {
-                      state.componentType = 'NumberPicker';
-                      state.componentProps = { allowClear: true };
+                  }
+
+                  f.setFieldState(typeFiled.query('.value'), (state) => {
+                    state.componentType = 'TreeSelect';
+                    state.dataSource = _option;
+                    state.componentProps = {
+                      ..._field.fieldProps,
+                      allowClear: true,
+                      showSearch: true,
+                      treeNodeFilterProp: 'name',
+                      filterOption: (input: string, option: any) =>
+                        option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
+                    };
+                  });
+                  break;
+                case 'digit':
+                  f.setFieldState(typeFiled.query('.value'), async (state) => {
+                    state.componentType = 'NumberPicker';
+                    state.componentProps = { allowClear: true };
+                  });
+                  if (isModified) {
+                    f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                      state.value = 'eq';
                     });
-                    if (isModified) {
-                      f.setFieldState(typeFiled.query('.termType'), async (state) => {
-                        state.value = 'eq';
-                      });
-                    }
-
-                    break;
-                  case 'dateTime':
-                    f.setFieldState(typeFiled.query('.value'), async (state) => {
-                      state.componentType = 'DatePicker';
-                      state.componentProps = { showTime: true, allowClear: true };
+                  }
+
+                  break;
+                case 'dateTime':
+                  f.setFieldState(typeFiled.query('.value'), async (state) => {
+                    state.componentType = 'DatePicker';
+                    state.componentProps = { showTime: true, allowClear: true };
+                  });
+                  if (isModified) {
+                    f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                      state.value = 'gte';
                     });
-                    if (isModified) {
-                      f.setFieldState(typeFiled.query('.termType'), async (state) => {
-                        state.value = 'gte';
-                      });
-                    }
-
-                    break;
-                  default:
-                    if (isModified) {
-                      f.setFieldState(typeFiled.query('.termType'), async (state) => {
-                        state.value = 'like';
-                      });
-                    }
-
-                    f.setFieldState(typeFiled.query('.value'), async (state) => {
-                      state.componentType = 'Input';
-                      state.componentProps = { allowClear: true };
+                  }
+
+                  break;
+                default:
+                  if (isModified) {
+                    f.setFieldState(typeFiled.query('.termType'), async (state) => {
+                      state.value = 'like';
                     });
-                    break;
-                }
+                  }
+
+                  f.setFieldState(typeFiled.query('.value'), async (state) => {
+                    state.componentType = 'Input';
+                    state.componentProps = { allowClear: true };
+                  });
+                  break;
               }
+            }
             // }
           });
           onFieldValueChange('*.*.column', (field1, form1) => {

+ 22 - 0
src/pages/device/Firmware/Task/Detail/Details/index.tsx

@@ -0,0 +1,22 @@
+import { Modal } from 'antd';
+import { useEffect, useState } from 'react';
+
+interface Props {
+  data: string;
+  close: () => void;
+}
+
+const Details = (props: Props) => {
+  const [data, setDada] = useState<string>(props.data || '');
+
+  useEffect(() => {
+    setDada(props.data);
+  }, [props.data]);
+
+  return (
+    <Modal title={'详情'} visible onCancel={props.close} onOk={props.close} width={500}>
+      <p>失败原因: {String(data)}</p>
+    </Modal>
+  );
+};
+export default Details;

+ 22 - 3
src/pages/device/Firmware/Task/Detail/index.less

@@ -7,9 +7,28 @@
   border-radius: 2px;
   box-shadow: 0 4px 18px #efefef;
 
-  .firmwareDetailCardTitle {
-    color: rgba(0, 0, 0, 0.64);
-    font-size: 14px;
+  .firmwareDetailCardHeader {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    width: 100%;
+
+    .firmwareDetailCardTitle {
+      color: rgba(0, 0, 0, 0.64);
+      font-size: 14px;
+    }
+
+    .firmwareDetailCardRight {
+      z-index: 2;
+      display: flex;
+      align-items: center;
+      margin-right: 10px;
+      .firmwareDetailCardRefresh {
+        width: 25px;
+        margin-left: 5px;
+        cursor: pointer;
+      }
+    }
   }
 
   .firmwareDetailCardNum {

+ 233 - 30
src/pages/device/Firmware/Task/Detail/index.tsx

@@ -1,20 +1,21 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { observer } from '@formily/react';
-import { Badge, Card, Col, Row } from 'antd';
+import { Badge, Card, Col, message, Popconfirm, Row } from 'antd';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { Tooltip } from 'antd';
-import { useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { EyeOutlined } from '@ant-design/icons';
-// import { useHistory } from 'umi';
+import { RedoOutlined, SearchOutlined } from '@ant-design/icons';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
 import useDomFullHeight from '@/hooks/document/useDomFullHeight';
-// import usePermissions from '@/hooks/permission';
 import SearchComponent from '@/components/SearchComponent';
 import { service } from '@/pages/device/Firmware';
 import styles from './index.less';
 import { model } from '@formily/reactive';
+import { useParams } from 'umi';
+import moment from 'moment';
+import Details from './Details/index';
 
 const colorMap = new Map();
 colorMap.set('waiting', '#FF9000');
@@ -38,8 +39,12 @@ const Detail = observer(() => {
   const actionRef = useRef<ActionType>();
   const intl = useIntl();
   const { minHeight } = useDomFullHeight(`.firmware-task-detail`, 24);
-  // const { permission } = usePermissions('device/Firmware');
   const [param, setParam] = useState({});
+  const params = useParams<any>();
+  const [visible, setVisible] = useState<boolean>(false);
+  const [reason, setReason] = useState<string>('');
+
+  const buttonImg = require('/public/images/firmware/button.png');
 
   const arr = [
     {
@@ -64,36 +69,160 @@ const Detail = observer(() => {
     },
   ];
 
+  const statusMap = new Map();
+  statusMap.set('waiting', 'warning');
+  statusMap.set('processing', 'processing');
+  statusMap.set('failed', 'error');
+  statusMap.set('success', 'success');
+  statusMap.set('canceled', 'default');
+
+  // 等待升级
+  const queryWaiting = async () => {
+    const resp = await service.historyCount({
+      terms: [
+        {
+          terms: [
+            { column: 'taskId', value: params.id },
+            { column: 'state', value: 'waiting' },
+          ],
+        },
+      ],
+    });
+    if (resp.status === 200) {
+      state.waiting = resp?.result || 0;
+    }
+  };
+  // 升级中
+  const queryProcessing = async () => {
+    const resp = await service.historyCount({
+      terms: [
+        {
+          terms: [
+            { column: 'taskId', value: params.id },
+            { column: 'state', value: 'processing' },
+          ],
+        },
+      ],
+    });
+    if (resp.status === 200) {
+      state.loading = resp?.result || 0;
+    }
+  };
+  // 升级失败
+  const queryFailed = async () => {
+    const resp = await service.historyCount({
+      terms: [
+        {
+          terms: [
+            { column: 'taskId', value: params.id },
+            { column: 'state', value: 'failed' },
+          ],
+        },
+      ],
+    });
+    if (resp.status === 200) {
+      state.error = resp?.result || 0;
+    }
+  };
+  // 升级完成
+  const querySuccess = async () => {
+    const resp = await service.historyCount({
+      terms: [
+        {
+          terms: [
+            { column: 'taskId', value: params.id },
+            { column: 'state', value: 'success' },
+          ],
+        },
+      ],
+    });
+    if (resp.status === 200) {
+      state.finish = resp?.result || 0;
+    }
+  };
+
+  const handleSearch = () => {
+    queryWaiting();
+    queryProcessing();
+    querySuccess();
+    queryFailed();
+  };
+
+  useEffect(() => {
+    handleSearch();
+  }, [params.id]);
+
   const columns: ProColumns<FirmwareItem>[] = [
     {
       title: '设备名称',
       ellipsis: true,
-      dataIndex: 'name',
+      dataIndex: 'deviceName',
     },
     {
       title: '所属产品',
       ellipsis: true,
-      dataIndex: 'version',
+      dataIndex: 'productName',
+      valueType: 'select',
+      request: async () => {
+        const res: any = await service.queryProduct();
+        if (res.status === 200) {
+          return res.result.map((pItem: any) => ({ label: pItem.name, value: pItem.name }));
+        }
+        return [];
+      },
     },
     {
       title: '创建时间',
       ellipsis: true,
-      dataIndex: 'signMethod',
+      dataIndex: 'createTime',
+      valueType: 'dateTime',
+      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
     },
     {
       title: '完成时间',
       ellipsis: true,
-      dataIndex: 'signMethod',
+      dataIndex: 'completeTime',
+      valueType: 'dateTime',
+      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
     },
     {
       title: '进度',
       ellipsis: true,
-      dataIndex: 'signMethod',
+      dataIndex: 'progress',
     },
     {
       title: '状态',
       ellipsis: true,
-      dataIndex: 'signMethod',
+      dataIndex: 'state',
+      render: (text: any, record: any) =>
+        record?.state ? (
+          <Badge status={statusMap.get(record?.state?.value)} text={record?.state?.text} />
+        ) : (
+          ''
+        ),
+      valueType: 'select',
+      valueEnum: {
+        waiting: {
+          text: '等待升级',
+          status: 'waiting',
+        },
+        processing: {
+          text: '升级中',
+          status: 'processing',
+        },
+        failed: {
+          text: '升级失败',
+          status: 'failed',
+        },
+        success: {
+          text: '升级成功',
+          status: 'success',
+        },
+        canceled: {
+          text: '已取消',
+          status: 'canceled',
+        },
+      },
     },
     {
       title: intl.formatMessage({
@@ -102,22 +231,51 @@ const Detail = observer(() => {
       }),
       valueType: 'option',
       align: 'center',
+      fixed: 'right',
       width: 200,
-      render: () => [
-        <a onClick={() => {}} key="link">
-          <Tooltip
-            title={intl.formatMessage({
-              id: 'pages.data.option.detail',
-              defaultMessage: '查看',
-            })}
-            key={'detail'}
-          >
-            <EyeOutlined />
-          </Tooltip>
-        </a>,
-      ],
+      render: (text: any, record: any) =>
+        record?.state?.value === 'failed'
+          ? [
+              <a
+                onClick={() => {
+                  setVisible(true);
+                  setReason(record?.errorReason || '');
+                }}
+                key="link"
+              >
+                <Tooltip
+                  title={intl.formatMessage({
+                    id: 'pages.data.option.detail',
+                    defaultMessage: '查看',
+                  })}
+                  key={'detail'}
+                >
+                  <SearchOutlined />
+                </Tooltip>
+              </a>,
+              <Popconfirm
+                key="refresh"
+                onConfirm={async () => {
+                  const resp = await service.startOneTask([record.id]);
+                  if (resp.status === 200) {
+                    message.success('操作成功!');
+                    handleSearch();
+                    actionRef.current?.reload?.();
+                  }
+                }}
+                title={'确认重试'}
+              >
+                <a>
+                  <Tooltip title={'重试'} key={'refresh'}>
+                    <RedoOutlined />
+                  </Tooltip>
+                </a>
+              </Popconfirm>,
+            ]
+          : [],
     },
   ];
+
   return (
     <PageContainer>
       <Card style={{ marginBottom: 20 }}>
@@ -125,9 +283,45 @@ const Detail = observer(() => {
           {arr.map((item) => (
             <Col span={6} key={item.key}>
               <div className={styles.firmwareDetailCard}>
-                <div className={styles.firmwareDetailCardTitle}>
-                  <Badge color={colorMap.get(item.key)} />
-                  {item.name}
+                <div className={styles.firmwareDetailCardHeader}>
+                  <div className={styles.firmwareDetailCardTitle}>
+                    <Badge color={colorMap.get(item.key)} />
+                    {item.name}
+                  </div>
+                  <div className={styles.firmwareDetailCardRight}>
+                    {item.key === 'error' && (
+                      <Popconfirm
+                        title="确认批量重试"
+                        onConfirm={async () => {
+                          const resp = await service.startTask(params.id, ['failed']);
+                          if (resp.status === 200) {
+                            message.success('操作成功!');
+                            queryFailed();
+                            actionRef.current?.reload?.();
+                          }
+                        }}
+                      >
+                        <a>批量重试</a>
+                      </Popconfirm>
+                    )}
+                    <div className={styles.firmwareDetailCardRefresh}>
+                      <img
+                        style={{ width: '100%' }}
+                        src={buttonImg}
+                        onClick={() => {
+                          if (item.key === 'waiting') {
+                            queryWaiting();
+                          } else if (item.key === 'finish') {
+                            querySuccess();
+                          } else if (item.key === 'loading') {
+                            queryProcessing();
+                          } else {
+                            queryFailed();
+                          }
+                        }}
+                      />
+                    </div>
+                  </div>
                 </div>
                 <div
                   className={styles.firmwareDetailCardNum}
@@ -146,6 +340,7 @@ const Detail = observer(() => {
       <SearchComponent<FirmwareItem>
         field={columns}
         target="firmware-task-detail"
+        defaultParam={[{ column: 'taskId', value: params?.id }]}
         onSearch={(data) => {
           // 重置分页数据
           actionRef.current?.reset?.();
@@ -159,12 +354,20 @@ const Detail = observer(() => {
         search={false}
         columnEmptyText={''}
         params={param}
-        request={async (params) =>
-          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        request={async (params1) =>
+          service.history({ ...params1, sorts: [{ name: 'createTime', order: 'desc' }] })
         }
         columns={columns}
         actionRef={actionRef}
       />
+      {visible && (
+        <Details
+          data={reason}
+          close={() => {
+            setVisible(false);
+          }}
+        />
+      )}
     </PageContainer>
   );
 });

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

@@ -77,8 +77,10 @@ const Save = (props: Props) => {
 
   const save = async () => {
     const values: any = await form.submit();
-    if (values?.releaseType === 'all') {
+    if (values?.releaseType !== 'all') {
       values.deviceId = devices.current.map((item) => item.id);
+    } else {
+      values.deviceId = undefined;
     }
     const resp = await service.saveTask({
       ...values,

+ 25 - 18
src/pages/device/Firmware/Task/index.tsx

@@ -4,8 +4,8 @@ import ProTable from '@jetlinks/pro-table';
 import { Popconfirm, Tooltip } from 'antd';
 import { useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons';
-import { Link, useHistory, useLocation } from 'umi';
+import { DeleteOutlined, EyeOutlined, PlusOutlined, StopOutlined } from '@ant-design/icons';
+import { useHistory, useLocation } from 'umi';
 import { model } from '@formily/reactive';
 import { observer } from '@formily/react';
 import type { FirmwareItem } from '@/pages/device/Firmware/typings';
@@ -44,7 +44,19 @@ const Task = observer(() => {
     {
       title: '推送方式',
       ellipsis: true,
-      dataIndex: 'version',
+      dataIndex: 'mode',
+      render: (text: any, record: any) => record?.mode?.text || '',
+      valueType: 'select',
+      valueEnum: {
+        pull: {
+          text: '设备拉取',
+          status: 'pull',
+        },
+        push: {
+          text: '平台推送',
+          status: 'push',
+        },
+      },
     },
     {
       title: intl.formatMessage({
@@ -58,6 +70,7 @@ const Task = observer(() => {
     {
       title: '完成比例',
       ellipsis: true,
+      hideInSearch: true,
       dataIndex: 'signMethod',
     },
     {
@@ -68,14 +81,13 @@ const Task = observer(() => {
       valueType: 'option',
       align: 'center',
       width: 200,
-
+      fixed: 'right',
       render: (text, record) => [
-        <Link
+        <a
           onClick={() => {
-            const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task/Detail'], '123');
+            const url = getMenuPathByParams(MENUS_CODE['device/Firmware/Task/Detail'], record?.id);
             history.push(url);
           }}
-          to={`/device/firmware/detail/${record.id}`}
           key="link"
         >
           <Tooltip
@@ -87,21 +99,16 @@ const Task = observer(() => {
           >
             <EyeOutlined />
           </Tooltip>
-        </Link>,
+        </a>,
         <a
           key="editable"
           onClick={() => {
-            state.visible = true;
-            state.current = record;
+            // state.visible = true;
+            // state.current = record;
           }}
         >
-          <Tooltip
-            title={intl.formatMessage({
-              id: 'pages.data.option.edit',
-              defaultMessage: '编辑',
-            })}
-          >
-            <EditOutlined />
+          <Tooltip title={'停止'}>
+            <StopOutlined />
           </Tooltip>
         </a>,
         <a key="delete">
@@ -111,7 +118,7 @@ const Task = observer(() => {
               defaultMessage: '确认删除?',
             })}
             onConfirm={async () => {
-              await service.remove(record.id);
+              await service.deleteTask(record.id);
               onlyMessage(
                 intl.formatMessage({
                   id: 'pages.data.option.success',

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

@@ -117,6 +117,7 @@ const Firmware = observer(() => {
       valueType: 'option',
       align: 'center',
       width: 200,
+      fixed: 'right',
       render: (text, record) => [
         <PermissionButton
           style={{ padding: 0 }}

+ 20 - 12
src/pages/device/Firmware/service.ts

@@ -16,25 +16,33 @@ class Service extends BaseService<FirmwareItem> {
       data,
     });
 
-  deploy = (id: string, type?: 'all' | 'part', deviceId?: string[]) =>
-    request(
-      `/${SystemConst.API_BASE}/firmware/upgrade/task/${id}${type === 'all' ? '/all' : ''}/_deploy`,
-      {
-        method: 'POST',
-        data: deviceId,
-      },
-    );
+  deleteTask = (id: string) =>
+    request(`/${SystemConst.API_BASE}/firmware/upgrade/task/${id}`, {
+      method: 'DELETE',
+    });
 
   history = (params: Record<string, unknown>) =>
     request(`/${SystemConst.API_BASE}/firmware/upgrade/history/_query`, {
-      method: 'GET',
-      params,
+      method: 'POST',
+      data: params,
     });
 
   historyCount = (params: Record<string, unknown>) =>
     request(`/${SystemConst.API_BASE}/firmware/upgrade/history/_count`, {
-      method: 'GET',
-      params,
+      method: 'POST',
+      data: params,
+    });
+
+  startTask = (id: string, params: string[]) =>
+    request(`/${SystemConst.API_BASE}/firmware/upgrade/task/${id}/_start`, {
+      method: 'POST',
+      data: params,
+    });
+
+  startOneTask = (params: string[]) =>
+    request(`/${SystemConst.API_BASE}/firmware/upgrade/task/_start`, {
+      method: 'POST',
+      data: params,
     });
 
   queryProduct = () =>

+ 1 - 1
src/pages/device/Instance/Detail/ChildDevice/index.tsx

@@ -128,7 +128,7 @@ const ChildDevice = () => {
             title={'确认解绑吗?'}
           >
             <Tooltip title={'解绑'}>
-            <DisconnectOutlined />
+              <DisconnectOutlined />
             </Tooltip>
           </Popconfirm>
         </a>,

+ 77 - 4
src/pages/init-home/components/data/index.tsx

@@ -1,10 +1,81 @@
-import { useState } from 'react';
-// import { service } from '../index';
+import { useEffect, useState } from 'react';
+import { service } from '../../index';
 import Save from './save';
+interface Props {
+  isTrigger: boolean;
+  onChange: (state: boolean) => void;
+}
 
-const Data = () => {
+const Data = (props: Props) => {
   const [flag, setFlag] = useState<boolean>(false);
   const [visible, setVisible] = useState<boolean>(false);
+  const [values, setValues] = useState<any>({});
+
+  const handleChange = async () => {
+    if (Object.keys(values).length === 0) {
+      props.onChange(true);
+      return;
+    }
+    // 新增网络组件
+    const network = await service.saveNetwork({
+      type: 'MQTT_SERVER',
+      shareCluster: true,
+      name: 'MQTT网络组件',
+      configuration: {
+        host: '0.0.0.0',
+        secure: false,
+        port: values.port,
+        publicHost: values.publicHost,
+        publicPort: values.publicPort,
+      },
+    });
+    // 保存协议
+    const protocol = await service.saveProtocol();
+    let protocolItem: any = undefined;
+    if (protocol.status === 200) {
+      const proid = await service.getProtocol();
+      if (proid.status === 200) {
+        protocolItem = (proid?.result || []).find((it: any) => it.name === 'JetLinks官方协议');
+      }
+    }
+    // 新增设备接入网关
+    const accessConfig = await service.saveAccessConfig({
+      name: 'MQTT类型设备接入网关',
+      provider: 'mqtt-server-gateway',
+      protocol: protocolItem?.id,
+      transport: 'MQTT',
+      channel: 'network',
+      channelId: network?.result?.id,
+    });
+    // 新增产品
+    const product = await service.saveProduct({
+      name: 'MQTT产品',
+      messageProtocol: protocolItem?.id,
+      protocolName: protocolItem?.name,
+      transportProtocol: 'MQTT',
+      deviceType: 'device',
+      accessId: accessConfig.result?.id,
+      accessName: accessConfig.result?.name,
+      accessProvider: 'mqtt-server-gateway',
+    });
+    // 新增设备
+    const device = await service.saveDevice({
+      name: 'MQTT设备',
+      productId: product?.result?.id,
+      productName: product?.result?.name,
+    });
+    if (device.status === 200) {
+      props.onChange(true);
+    } else {
+      props.onChange(false);
+    }
+  };
+
+  useEffect(() => {
+    if (props.isTrigger) {
+      handleChange();
+    }
+  }, [props.isTrigger]);
 
   return (
     <div>
@@ -24,9 +95,11 @@ const Data = () => {
           close={() => {
             setVisible(false);
           }}
-          save={() => {
+          data={values}
+          save={(data: any) => {
             setVisible(false);
             setFlag(true);
+            setValues(data);
           }}
         />
       )}

+ 6 - 51
src/pages/init-home/components/data/save/index.tsx

@@ -6,18 +6,20 @@ import { createForm } from '@formily/core';
 import type { ISchema } from '@formily/json-schema';
 import { service } from '../../../index';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
+import { onlyMessage } from '@/utils/util';
 
 interface Props {
   data?: any;
   close: () => void;
-  save: () => void;
+  save: (values: any) => void;
 }
 
 const Save = (props: Props) => {
-  const { close } = props;
+  const { close, data } = props;
 
   const form = createForm({
     validateFirst: true,
+    initialValues: data,
     effects: () => {
       onFormInit(async (form1) => {
         const resp = await service.getResourcesCurrent();
@@ -42,55 +44,8 @@ const Save = (props: Props) => {
 
   const save = async () => {
     const values: any = await form.submit();
-    // 新增网络组件
-    const network = await service.saveNetwork({
-      type: 'MQTT_SERVER',
-      shareCluster: true,
-      name: 'MQTT网络组件',
-      configuration: {
-        host: '0.0.0.0',
-        secure: false,
-        port: values.port,
-        publicHost: values.publicHost,
-        publicPort: values.publicPort,
-      },
-    });
-    // 保存协议
-    const protocol = await service.saveProtocol();
-    let protocolItem: any = undefined;
-    if (protocol.status === 200) {
-      const proid = await service.getProtocol();
-      if (proid.status === 200) {
-        protocolItem = (proid?.result || []).find((it: any) => it.name === 'Jetlinks官方协议');
-      }
-    }
-    // 新增设备接入网关
-    const accessConfig = await service.saveAccessConfig({
-      name: 'MQTT类型设备接入网关',
-      provider: 'mqtt-server-gateway',
-      protocol: protocolItem?.id,
-      transport: 'MQTT',
-      channel: 'network',
-      channelId: network?.result?.id,
-    });
-    if (accessConfig) {
-    }
-    // 新增产品
-
-    // 新增设备
-
-    // values.productName = product?.name || '';
-    // 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('保存成功!');
-    //   close();
-    // }
+    onlyMessage('保存成功!');
+    props.save(values);
   };
   const schema: ISchema = {
     type: 'object',

+ 4 - 2
src/pages/init-home/index.tsx

@@ -66,10 +66,12 @@ const InitHome = () => {
                 }
                 key="4"
               >
-                <Data />
+                <Data isTrigger={false} onChange={() => {}} />
               </Collapse.Panel>
             </Collapse>
-            <Button type="primary">确认</Button>
+            <Button type="primary" style={{ marginTop: 20 }}>
+              确认
+            </Button>
           </div>
         </div>
       </div>

+ 1 - 1
src/pages/init-home/service.ts

@@ -27,7 +27,7 @@ class Service extends BaseService<any> {
       method: 'POST',
     });
   getProtocol = () =>
-    request(`${SystemConst.API_BASE}/protocol/default-protocol/_query/no-paging?paging=false`, {
+    request(`${SystemConst.API_BASE}/protocol/_query/no-paging?paging=false`, {
       method: 'GET',
     });
   saveAccessConfig = (data: any) =>

+ 2 - 1
src/pages/media/Home/service.tsx

@@ -3,7 +3,8 @@ import { request } from 'umi';
 import type { DeviceItem } from '@/pages/media/Device/typings';
 
 class Service extends BaseService<DeviceItem> {
-  deviceCount = (data?: any) => request(`${this.uri}/device/_count`, { methods: 'GET', params: data });
+  deviceCount = (data?: any) =>
+    request(`${this.uri}/device/_count`, { methods: 'GET', params: data });
 
   channelCount = (data: any = {}) =>
     request(`${this.uri}/channel/_count`, { method: 'POST', data: data });

+ 2 - 2
src/pages/notice/Config/Debug/index.tsx

@@ -1,5 +1,5 @@
 import { Modal } from 'antd';
-import {useMemo, useRef} from 'react';
+import { useMemo, useRef } from 'react';
 import { createForm, Field, onFieldReact, onFieldValueChange } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import {
@@ -76,7 +76,7 @@ const Debug = observer(() => {
                 format.setComponent(Input);
                 break;
             }
-            console.log(variableRef.current)
+            console.log(variableRef.current);
             if (variableRef.current) {
               const a = variableRef.current?.find((i: any) => i.id === _id.value);
               const businessType = a?.expands?.businessType;

+ 18 - 18
src/pages/notice/Template/Debug/index.tsx

@@ -1,7 +1,7 @@
-import {Modal, Spin} from 'antd';
-import {useEffect, useMemo, useRef, useState} from 'react';
-import {createForm, Field, onFieldReact, onFieldValueChange} from '@formily/core';
-import {createSchemaField, observer} from '@formily/react';
+import { Modal, Spin } from 'antd';
+import { useEffect, useMemo, useRef, useState } from 'react';
+import { createForm, Field, onFieldReact, onFieldValueChange } from '@formily/core';
+import { createSchemaField, observer } from '@formily/react';
 import {
   ArrayTable,
   DatePicker,
@@ -12,11 +12,11 @@ import {
   PreviewText,
   Select,
 } from '@formily/antd';
-import {ISchema} from '@formily/json-schema';
-import {configService, service, state} from '@/pages/notice/Template';
-import {useLocation} from 'umi';
-import {onlyMessage, useAsyncDataSource} from '@/utils/util';
-import {Store} from 'jetlinks-store';
+import { ISchema } from '@formily/json-schema';
+import { configService, service, state } from '@/pages/notice/Template';
+import { useLocation } from 'umi';
+import { onlyMessage, useAsyncDataSource } from '@/utils/util';
+import { Store } from 'jetlinks-store';
 import FUpload from '@/components/Upload';
 
 const Debug = observer(() => {
@@ -142,8 +142,8 @@ const Debug = observer(() => {
     configService
       .queryNoPagingPost({
         terms: [
-          {column: 'type$IN', value: id},
-          {column: 'provider', value: state.current?.provider},
+          { column: 'type$IN', value: id },
+          { column: 'provider', value: state.current?.provider },
         ],
       })
       .then((resp: any) => {
@@ -174,8 +174,8 @@ const Debug = observer(() => {
         'x-decorator': 'FormItem',
         'x-component': 'ArrayTable',
         'x-component-props': {
-          pagination: {pageSize: 9999},
-          scroll: {x: '100%'},
+          pagination: { pageSize: 9999 },
+          scroll: { x: '100%' },
         },
         'x-visible': false,
         items: {
@@ -184,7 +184,7 @@ const Debug = observer(() => {
             column0: {
               type: 'void',
               'x-component': 'ArrayTable.Column',
-              'x-component-props': {title: '类型', width: '120px'},
+              'x-component-props': { title: '类型', width: '120px' },
               'x-hidden': true,
               properties: {
                 type: {
@@ -198,7 +198,7 @@ const Debug = observer(() => {
             column1: {
               type: 'void',
               'x-component': 'ArrayTable.Column',
-              'x-component-props': {title: '变量', width: '120px'},
+              'x-component-props': { title: '变量', width: '120px' },
               properties: {
                 id: {
                   type: 'string',
@@ -211,7 +211,7 @@ const Debug = observer(() => {
             column2: {
               type: 'void',
               'x-component': 'ArrayTable.Column',
-              'x-component-props': {title: '名称', width: '120px'},
+              'x-component-props': { title: '名称', width: '120px' },
               properties: {
                 name: {
                   type: 'string',
@@ -224,7 +224,7 @@ const Debug = observer(() => {
             column3: {
               type: 'void',
               'x-component': 'ArrayTable.Column',
-              'x-component-props': {title: '值', width: '120px'},
+              'x-component-props': { title: '值', width: '120px' },
               properties: {
                 value: {
                   required: true,
@@ -292,7 +292,7 @@ const Debug = observer(() => {
     >
       <Spin spinning={spinning}>
         <Form form={form} layout={'vertical'}>
-          <SchemaField schema={schema} scope={{getConfig, useAsyncDataSource}}/>
+          <SchemaField schema={schema} scope={{ getConfig, useAsyncDataSource }} />
         </Form>
       </Spin>
     </Modal>

+ 1 - 1
src/pages/notice/Template/index.tsx

@@ -230,7 +230,7 @@ const Template = observer(() => {
         params={param}
         columns={columns}
         columnEmptyText={''}
-        gridColumns={[2,2,3]}
+        gridColumns={[2, 2, 3]}
         headerTitle={
           <Space>
             <PermissionButton

+ 3 - 8
src/pages/rule-engine/Alarm/Log/TabComponent/index.tsx

@@ -15,7 +15,7 @@ import { useHistory } from 'umi';
 import classNames from 'classnames';
 import { useDomFullHeight } from '@/hooks';
 import PermissionButton from '@/components/PermissionButton';
-import {Ellipsis} from "@/components";
+import { Ellipsis } from '@/components';
 
 interface Props {
   type: string;
@@ -203,13 +203,8 @@ const TabComponent = observer((props: Props) => {
                     <div className={classNames('iot-card')}>
                       <div className={'card-warp'}>
                         <div className={classNames('card-content')}>
-                          <div
-                            style={{ width: 'calc(100% - 90px)' }}
-                          >
-                            <Ellipsis
-                              title={item.alarmName}
-                              titleStyle={{color: '#2F54EB'}}
-                            />
+                          <div style={{ width: 'calc(100% - 90px)' }}>
+                            <Ellipsis title={item.alarmName} titleStyle={{ color: '#2F54EB' }} />
                             {/*<Tooltip title={item.alarmName}>*/}
                             {/*  <a style={{ cursor: 'default' }}>{item.alarmName}</a>*/}
                             {/*</Tooltip>*/}

+ 6 - 6
src/pages/rule-engine/Scene/Save/action/VariableItems/builtIn.tsx

@@ -23,7 +23,7 @@ interface BuiltInProps {
   parallel?: boolean;
   form: FormInstance;
   name: number;
-  isEdit?: boolean
+  isEdit?: boolean;
 }
 
 export default (props: BuiltInProps) => {
@@ -33,7 +33,7 @@ export default (props: BuiltInProps) => {
 
   const [builtInList, setBuiltInList] = useState<any[]>([]);
 
-  const [isEdit, setIsEdit] = useState(false)
+  const [isEdit, setIsEdit] = useState(false);
 
   const onChange = (_source: string = 'fixed', _value?: any, _upperKey?: string) => {
     const obj: ChangeType = {
@@ -65,7 +65,7 @@ export default (props: BuiltInProps) => {
 
   useEffect(() => {
     if (props.isEdit) {
-      setIsEdit(false)
+      setIsEdit(false);
       const data = props.form.getFieldsValue();
       const params = props.name - 1 >= 0 ? { action: props.name - 1 } : undefined;
       queryBuiltInParams(data, params).then((res: any) => {
@@ -77,9 +77,9 @@ export default (props: BuiltInProps) => {
       });
     }
     setTimeout(() => {
-      setIsEdit(true)
-    }, 300)
-  }, [ props.isEdit ])
+      setIsEdit(true);
+    }, 300);
+  }, [props.isEdit]);
 
   useEffect(() => {
     if (source === 'upper' && isEdit) {

+ 2 - 2
src/pages/rule-engine/Scene/Save/action/action.tsx

@@ -240,7 +240,7 @@ export default observer((props: ActionProps) => {
             setIsFiltering(e.target.checked);
             if (!e.target.checked) {
               const actions = props.form?.getFieldValue('actions');
-              delete actions[name].terms
+              delete actions[name].terms;
               props.form?.setFieldsValue({
                 actions,
               });
@@ -301,7 +301,7 @@ export default observer((props: ActionProps) => {
             restField={props.restField}
             parallel={props.parallel}
             onProductIdChange={(_id) => {
-              setProductId(_id)
+              setProductId(_id);
               const actions = props.form.getFieldValue('actions');
               if (actions[name].device?.message?.properties) {
                 actions[name].device.message.properties = undefined;

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/device/ConditionalFiltering.tsx

@@ -261,7 +261,7 @@ export default (props: ConditionalFilteringProps) => {
         </Form.Item>
       </Col>
       <Col>
-        <div style={{ height: '100%', display: 'flex', alignItems: 'center', paddingBottom: 24}}>
+        <div style={{ height: '100%', display: 'flex', alignItems: 'center', paddingBottom: 24 }}>
           执行后续动作
         </div>
       </Col>

+ 6 - 6
src/pages/rule-engine/Scene/Save/action/device/WriteProperty/index.tsx

@@ -26,7 +26,7 @@ export default (props: WritePropertyProps) => {
   const [propertiesKey, setPropertiesKey] = useState<string | undefined>(undefined);
   const [propertiesValue, setPropertiesValue] = useState(undefined);
   const [propertiesType, setPropertiesType] = useState('');
-  const [isEdit, setIsEdit] = useState(false)
+  const [isEdit, setIsEdit] = useState(false);
   const paramsListRef = useRef<any[]>();
 
   const handleName = (data: any) => {
@@ -114,7 +114,7 @@ export default (props: WritePropertyProps) => {
 
   useEffect(() => {
     if (props.isEdit) {
-      setIsEdit(false)
+      setIsEdit(false);
       const params = props.name - 1 >= 0 ? { action: props.name - 1 } : undefined;
       const data = props.form.getFieldsValue();
       queryBuiltInParams(data, params).then((res: any) => {
@@ -139,9 +139,9 @@ export default (props: WritePropertyProps) => {
       });
     }
     setTimeout(() => {
-      setIsEdit(true)
-    }, 300)
-  }, [props.isEdit])
+      setIsEdit(true);
+    }, 300);
+  }, [props.isEdit]);
 
   useEffect(() => {
     if (props.trigger?.trigger?.device?.productId && source === 'upper' && isEdit) {
@@ -157,7 +157,7 @@ export default (props: WritePropertyProps) => {
   // }, [props.productId]);
 
   useEffect(() => {
-    console.log(props.value)
+    console.log(props.value);
     if (props.value) {
       if (props.properties && props.properties.length) {
         if (0 in props.value) {

+ 1 - 1
src/pages/rule-engine/Scene/Save/action/device/deviceModal.tsx

@@ -43,7 +43,7 @@ export default (props: DeviceModelProps) => {
   useEffect(() => {
     setValue(props.value || []);
     setSelectKeys(props.value || []);
-    console.log(props.value)
+    console.log(props.value);
   }, [props.value]);
 
   const columns: ProColumns<DeviceItem>[] = [

+ 2 - 2
src/pages/rule-engine/Scene/Save/action/device/index.tsx

@@ -18,7 +18,7 @@ interface DeviceProps {
   onFunctionChange: (functionItem: any) => void;
   parallel?: boolean;
   onProductIdChange: (id: string) => void;
-  isEdit?: boolean
+  isEdit?: boolean;
 }
 
 enum SourceEnum {
@@ -96,7 +96,7 @@ export default (props: DeviceProps) => {
         actions[name].device.selector = SourceEnum.fixed;
       }
       if (actions[name].device.selectorValues) {
-        console.log('useEffect')
+        console.log('useEffect');
         actions[name].device.selectorValues = undefined;
       }
     }

+ 1 - 1
src/pages/system/Department/Assets/deivce/index.tsx

@@ -28,7 +28,7 @@ export const DeviceBadge = (props: DeviceBadgeProps) => {
     offline: 'error',
     online: 'processing',
   };
-  console.log(STATUS[props.type], props)
+  console.log(STATUS[props.type], props);
   return <Badge status={STATUS[props.type]} text={props.text} />;
 };
 

+ 1 - 1
src/pages/system/Relationship/index.tsx

@@ -75,7 +75,7 @@ const Relationship = () => {
           isPermission={permission.delete}
           style={{ padding: 0 }}
           tooltip={{
-            title: '删除'
+            title: '删除',
           }}
           popConfirm={{
             title: '确认删除',