From 1aa4564f983d8ef3d31ad5ebd038ba43cfbd61ae Mon Sep 17 00:00:00 2001 From: "peng.peng" Date: Tue, 20 Jun 2023 10:16:30 +0800 Subject: [PATCH] =?UTF-8?q?(*)=E6=95=B0=E6=8D=AE=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/backups/index.js | 41 ++++++- api/app/lib/routes/backups/index.js | 4 +- .../src/sections/backups/actions/backups.js | 12 ++ .../backups/components/backupsModal.js | 7 +- .../sections/backups/components/taskModal.js | 26 ----- .../sections/backups/containers/backupTask.js | 103 ++++++++++++------ web/client/src/sections/homePage/nav-item.js | 2 +- web/client/src/sections/homePage/routes.js | 2 +- .../resourceRetrieval/containers/retrieval.js | 2 +- 9 files changed, 129 insertions(+), 70 deletions(-) delete mode 100644 web/client/src/sections/backups/components/taskModal.js diff --git a/api/app/lib/controllers/backups/index.js b/api/app/lib/controllers/backups/index.js index f148301..f8a4e6a 100644 --- a/api/app/lib/controllers/backups/index.js +++ b/api/app/lib/controllers/backups/index.js @@ -33,6 +33,7 @@ function getBackupsList(opts) { } const res = await models.Backups.findAndCount(option); + res.time = moment() ctx.status = 200; ctx.body = res; } catch (error) { @@ -56,11 +57,13 @@ function addBackups(opts) { //调用后端备份接口 // const url = '10.8.30.160:8085/dumpDB?dbHost=10.8.30.75&dbPort=5432&user=postgres&password=1234&dbName=Anxinyun0916'//测试使用 const url = backupsUrl + `/dumpDB?dbHost=${host}&dbPort=${port}&user=${user}&password=${password}&dbName=${database}`; - const res = await request.post(url) - const { fileInfo: { name, size }, message } = res.body - await models.Backups.update({ - size, source: name, state: message, completeTime: moment() - }, { where: { id: backup.id } }) + request.post(url).then(res => { + const { fileInfo: { name, size }, message } = res.body + models.Backups.update({ + size, source: name, state: message, completeTime: moment() + }, { where: { id: backup.id } }) + }) + ctx.status = 204; ctx.body = { message: '新建数据备份成功' } } catch (error) { @@ -119,12 +122,38 @@ function deleteBackups(opts) { } } +// 新增数据备份 +function restore(opts) { + return async function (ctx, next) { + const { backupsUrl } = opts; + const models = ctx.fs.dc.models; + try { + let rslt = ctx.request.body; + const { id, source, databases: { database, host, password, port, user } } = ctx.request.body + //调用后端备份接口 + const url = backupsUrl + `/restoreDB?dbHost=${host}&dbPort=${port}&user=${user}&password=${password}&dbName=${database}&backFileName=${source}`; + request.post(url).then(res => { + const { fileInfo: { name, size }, message } = res.body + models.Backups.update({ + size, source: name, state: message, completeTime: moment() + }, { where: { id: id } }) + }) + + ctx.status = 204; + ctx.body = { message: '备份还原成功' } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '备份还原失败' } + } + } +} module.exports = { getBackupsList, addBackups, editBackups, deleteBackups, - + restore } \ No newline at end of file diff --git a/api/app/lib/routes/backups/index.js b/api/app/lib/routes/backups/index.js index a13b4e1..56edfbf 100644 --- a/api/app/lib/routes/backups/index.js +++ b/api/app/lib/routes/backups/index.js @@ -19,5 +19,7 @@ module.exports = function (app, router, opts, AuthCode) { app.fs.api.logAttr['GET/meta/backups'] = { content: '获取数据备份信息列表', visible: true }; router.get('/meta/backups', backups.getBackupsList(opts)); - + //恢复备份 + app.fs.api.logAttr['POST/backups/restore'] = { content: '恢复备份', visible: true }; + router.post('/backups/restore', backups.restore(opts)) }; diff --git a/web/client/src/sections/backups/actions/backups.js b/web/client/src/sections/backups/actions/backups.js index ad8fdbd..5d9a594 100644 --- a/web/client/src/sections/backups/actions/backups.js +++ b/web/client/src/sections/backups/actions/backups.js @@ -54,3 +54,15 @@ export function modifyBackups(id, params, msg) { }); } +export function restoreBackups(params) { + return (dispatch) => basicAction({ + type: 'post', + data: params, + dispatch, + actionType: 'RESTORE_BACKUPS_REPORT', + url: ApiTable.restoreBackups, + msg: { + option: '备份恢复', + }, + }); +} \ No newline at end of file diff --git a/web/client/src/sections/backups/components/backupsModal.js b/web/client/src/sections/backups/components/backupsModal.js index ce33fab..b7fa5c5 100644 --- a/web/client/src/sections/backups/components/backupsModal.js +++ b/web/client/src/sections/backups/components/backupsModal.js @@ -36,18 +36,19 @@ export default (props) => { values.databases = dataSources?.rows?.find(s => s.id == values?.databases?.value)?.config; values.createTime = moment(); values.state = '备份中'; + values.title = title; return onFinish && await onFinish(values, editData, form) // return true; }} width={500} > - + />} { title: 'postgre', disabled: true, value: '0-0', - children: dataSources?.rows?.filter(s => s?.type != '备份数据库')?.map(s => { + children: dataSources?.rows?.filter(s => (title != '恢复数据备份' && s?.type != '备份数据库') || (title == '恢复数据备份' && s?.type == '备份数据库'))?.map(s => { return { title: s.name, value: s.id, diff --git a/web/client/src/sections/backups/components/taskModal.js b/web/client/src/sections/backups/components/taskModal.js deleted file mode 100644 index 0278fa8..0000000 --- a/web/client/src/sections/backups/components/taskModal.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { Tabs, Card, Modal } from 'antd' -import AdapterStep from './adapterStep'; -import { STEP_CONFIG } from './steps/index' -function DataSourceModal(props) { - const { visible, editData, onFinish, onCancel, - type = 'postgre',//当前卡片的key (目前只有postgre,支持后续扩展) - dataSourceFilter, - } = props; - const { StepThree } = STEP_CONFIG[type]; - // const onFinish = () => { } - return <> - { onCancel() }} - open={visible} - footer={null} - width={1200} - destroyOnClose={true} - > - - - -} - -export default DataSourceModal \ No newline at end of file diff --git a/web/client/src/sections/backups/containers/backupTask.js b/web/client/src/sections/backups/containers/backupTask.js index 93a1392..73b4537 100644 --- a/web/client/src/sections/backups/containers/backupTask.js +++ b/web/client/src/sections/backups/containers/backupTask.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useMemo } from 'react' import { Spin, Popconfirm, Select, Row, Col, Button, Input, Table } from 'antd'; import { connect } from 'react-redux'; import ProTable from '@ant-design/pro-table'; @@ -6,12 +6,15 @@ import moment from 'moment'; import BackupsModal from '../components/backupsModal'; import './style.less'; +import { ApiTable, useFsRequest } from '$utils'; + function Member(props) { - const { loading, clientHeight, actions, dispatch, backups, user, dataSources } = props; + const { loading, clientHeight, actions, dispatch, backups, backupsIsRequesting, dataSources } = props; const [pageSize, setPageSize] = useState(10); const [currentPage, setCurrentPage] = useState(1); const [searchValue, setSearchValue] = useState(''); const [addLoading, setAddLoading] = useState(false) + const [autoSearchValue, setAutoSearchValue] = useState(''); const queryData = (search) => { const query = { limit: search ? 10 : pageSize || 10, @@ -22,6 +25,18 @@ function Member(props) { dispatch(actions.backups.getBackupsList(query)); } + const { data: tableData = {} } = useFsRequest({ + url: ApiTable.getBackupsList, + query: { + limit: pageSize || 10, + page: currentPage || 1, + name: autoSearchValue, + }, + ready: !backupsIsRequesting, + refreshDeps: [pageSize, currentPage, autoSearchValue], + pollingInterval: 1000 + }); + useEffect(() => { dispatch(actions.metadataAcquisition.getDataSources()); }, []) @@ -66,20 +81,17 @@ function Member(props) { render: (text, record) => { const options = []; options.push( -
是否确认重置该数据备份密码?
- } - onConfirm={() => { - dispatch(actions.backups.modifyBackups(record.id, { password: 'e10adc3949ba59abbe56e057f20f883e' }, '重置密码')) - }} - okText="是" - cancelText="否" - > - 恢复 -
) - options.push( { window.open('/assets/files/backups/1.sql') }}>下载) + record?.source ? 恢复} + title="恢复数据备份" + onFinish={onFinish} + key="addModel" + /> : 恢复) + options.push( + record?.source ? + { window.open(record?.source) }}> 下载 : 下载 + ) options.push( { - setAddLoading(true) - return dispatch(actions.backups.addBackups({ - ...values, - })).then(res => { - setAddLoading(false) - if (res.success) { - queryData(); - return true; - } else { - return false; - } - }); + if (values?.title == '恢复数据备份') { + return dispatch(actions.backups.restoreBackups({ + id: editData.id, + source: editData.source, + databases: values.databases + })).then(res => { + setAddLoading(false) + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + + } else { + setAddLoading(true) + return dispatch(actions.backups.addBackups({ + ...values, + })).then(res => { + setAddLoading(false) + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + } + }; + const tableDataFilter = useMemo(() => { + if (tableData?.count && backups?.count) { + return tableData.time > backups.time ? tableData : backups; + } else { + return backups; + } + }, [tableData, backups]) + return @@ -137,10 +175,12 @@ function Member(props) { style={{ width: 220, marginRight: 15 }} placeholder="请输入" /> + }} type='primary'>查询 + @@ -194,6 +234,7 @@ function mapStateToProps(state) { backups: backups?.data || {}, user: auth.user, dataSources: datasources?.data || {}, + backupsIsRequesting: backups.isRequesting }; } diff --git a/web/client/src/sections/homePage/nav-item.js b/web/client/src/sections/homePage/nav-item.js index e541a1e..7ca5bfb 100644 --- a/web/client/src/sections/homePage/nav-item.js +++ b/web/client/src/sections/homePage/nav-item.js @@ -5,7 +5,7 @@ import { HomeOutlined } from '@ant-design/icons'; export function getNavItem() { return ( }> - 首页 + 数据监控平台 ); } \ No newline at end of file diff --git a/web/client/src/sections/homePage/routes.js b/web/client/src/sections/homePage/routes.js index 127cc57..b1331e4 100644 --- a/web/client/src/sections/homePage/routes.js +++ b/web/client/src/sections/homePage/routes.js @@ -6,7 +6,7 @@ export default [{ route: { path: '/homePage', key: 'homePage', - breadcrumb: '首页', + breadcrumb: '数据监控平台', // 不设置 component 则面包屑禁止跳转 component: homePage } diff --git a/web/client/src/sections/resourceRetrieval/containers/retrieval.js b/web/client/src/sections/resourceRetrieval/containers/retrieval.js index f2a23c6..f9b8bf5 100644 --- a/web/client/src/sections/resourceRetrieval/containers/retrieval.js +++ b/web/client/src/sections/resourceRetrieval/containers/retrieval.js @@ -64,7 +64,7 @@ function Retrieval(props) { id: searchDataId }, refreshDeps: [searchDataId], - ready: !!searchDataId + ready: !!searchDataId, }); useEffect(() => {