|
|
@@ -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>
|
|
|
);
|
|
|
});
|