wenlele
2 years ago
28 changed files with 905 additions and 94 deletions
@ -0,0 +1,163 @@ |
|||
'use strict'; |
|||
const request = require('superagent') |
|||
const moment = require('moment'); |
|||
function getBackupsList(opts) { |
|||
return async function (ctx, next) { |
|||
|
|||
const models = ctx.fs.dc.models; |
|||
const { page, limit, name } = ctx.query; |
|||
const Op = ctx.fs.dc.ORM.Op; |
|||
let errMsg = { message: '获取数据备份失败' } |
|||
try { |
|||
let searchWhere = { |
|||
|
|||
} |
|||
let option = { |
|||
where: searchWhere, |
|||
order: [["id", "desc"]], |
|||
attributes: { exclude: ['password'] }, |
|||
} |
|||
|
|||
if (name) { |
|||
searchWhere.note = { $like: '%' + name + '%' }; |
|||
} |
|||
|
|||
|
|||
option.where = searchWhere |
|||
let limit_ = limit || 10; |
|||
let page_ = page || 1; |
|||
let offset = (page_ - 1) * limit_; |
|||
if (limit && page) { |
|||
option.limit = limit_ |
|||
option.offset = offset |
|||
} |
|||
|
|||
const res = await models.Backups.findAndCount(option); |
|||
res.time = moment() |
|||
ctx.status = 200; |
|||
ctx.body = res; |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|||
ctx.status = 400; |
|||
ctx.body = errMsg |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 新增数据备份
|
|||
function addBackups(opts) { |
|||
return async function (ctx, next) { |
|||
const { backupsUrl } = opts; |
|||
const models = ctx.fs.dc.models; |
|||
try { |
|||
let rslt = ctx.request.body; |
|||
const { database, host, password, port, user } = ctx.request.body.databases |
|||
let backup = await models.Backups.create(Object.assign({}, rslt)) |
|||
|
|||
//调用后端备份接口
|
|||
// 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}`; |
|||
request.post(url).then(res => { |
|||
const { fileInfo: { name, size }, code } = res.body |
|||
models.Backups.update({ |
|||
size, source: name, state: code == 200 ? '备份成功' : '备份失败', completeTime: moment() |
|||
}, { where: { id: backup.id } }) |
|||
if (code != 200) ctx.fs.logger.error(`path: ${ctx.path}, error: ${message}`); |
|||
}) |
|||
|
|||
ctx.status = 204; |
|||
ctx.body = { message: '新建数据备份成功' } |
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|||
ctx.status = 400; |
|||
ctx.body = { message: '新建数据备份失败' } |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 修改数据备份
|
|||
function editBackups(opts) { |
|||
return async function (ctx, next) { |
|||
|
|||
try { |
|||
const models = ctx.fs.dc.models; |
|||
const { id } = ctx.params; |
|||
const body = ctx.request.body; |
|||
|
|||
|
|||
await models.Backups.update( |
|||
body, |
|||
{ 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: '修改数据备份失败' } |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 删除数据备份
|
|||
function deleteBackups(opts) { |
|||
return async function (ctx, next) { |
|||
|
|||
try { |
|||
const models = ctx.fs.dc.models; |
|||
const { id } = ctx.params; |
|||
|
|||
await models.Backups.destroy({ |
|||
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: '删除数据备份失败' } |
|||
} |
|||
} |
|||
} |
|||
|
|||
//备份恢复
|
|||
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 |
|||
await models.Backups.update({ |
|||
state: '恢复中', |
|||
}, { where: { id: id } }) |
|||
//调用后端备份接口
|
|||
const url = backupsUrl + `/restoreDB?dbHost=${host}&dbPort=${port}&user=${user}&password=${password}&dbName=${database}&backFileName=${source}`; |
|||
request.post(url).then(res => { |
|||
const { code, message } = res.body |
|||
models.Backups.update({ |
|||
state: code == 200 ? '恢复成功' : '恢复失败', |
|||
}, { where: { id: id } }) |
|||
if (code != 200) ctx.fs.logger.error(`path: ${ctx.path}, error: ${message}`); |
|||
}) |
|||
|
|||
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 |
|||
} |
@ -0,0 +1,89 @@ |
|||
/* eslint-disable*/ |
|||
|
|||
'use strict'; |
|||
|
|||
module.exports = dc => { |
|||
const DataTypes = dc.ORM; |
|||
const sequelize = dc.orm; |
|||
const Backups = sequelize.define("backups", { |
|||
id: { |
|||
type: DataTypes.INTEGER, |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: true, |
|||
field: "id", |
|||
autoIncrement: true, |
|||
unique: "backups_id_uindex" |
|||
}, |
|||
note: { |
|||
type: DataTypes.STRING, |
|||
allowNull: false, |
|||
defaultValue: null, |
|||
comment: "备注信息", |
|||
primaryKey: false, |
|||
field: "note", |
|||
autoIncrement: false |
|||
}, |
|||
databases: { |
|||
type: DataTypes.JSONB, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "databases", |
|||
autoIncrement: false |
|||
}, |
|||
size: { |
|||
type: DataTypes.STRING, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "size", |
|||
autoIncrement: false |
|||
}, |
|||
createTime: { |
|||
type: DataTypes.DATE, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "create_time", |
|||
autoIncrement: false |
|||
}, |
|||
completeTime: { |
|||
type: DataTypes.DATE, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: "备份完成时间", |
|||
primaryKey: false, |
|||
field: "complete_time", |
|||
autoIncrement: false |
|||
}, |
|||
state: { |
|||
type: DataTypes.STRING, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: null, |
|||
primaryKey: false, |
|||
field: "state", |
|||
autoIncrement: false |
|||
}, |
|||
source: { |
|||
type: DataTypes.TEXT, |
|||
allowNull: true, |
|||
defaultValue: null, |
|||
comment: "备份文件路径", |
|||
primaryKey: false, |
|||
field: "source", |
|||
autoIncrement: false |
|||
} |
|||
}, { |
|||
tableName: "backups", |
|||
comment: "", |
|||
indexes: [] |
|||
}); |
|||
dc.models.Backups = Backups; |
|||
return Backups; |
|||
}; |
@ -0,0 +1,25 @@ |
|||
'use strict'; |
|||
|
|||
const backups = require('../../controllers/backups/index'); |
|||
|
|||
module.exports = function (app, router, opts, AuthCode) { |
|||
|
|||
app.fs.api.logAttr['POST/meta/backups'] = { content: '增加数据备份', visible: true }; |
|||
router.post('/meta/backups', backups.addBackups(opts)) |
|||
|
|||
// 修改数据备份信息
|
|||
app.fs.api.logAttr['PUT/meta/backups/:id'] = { content: '修改数据备份信息', visible: true }; |
|||
router.put('/meta/backups/:id', backups.editBackups(opts)) |
|||
|
|||
// 删除数据备份信息
|
|||
app.fs.api.logAttr['DEL/meta/backups/:id'] = { content: '删除数据备份信息', visible: true }; |
|||
router.del('/meta/backups/:id', backups.deleteBackups(opts)) |
|||
|
|||
//获取数据备份信息列表
|
|||
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)) |
|||
}; |
@ -0,0 +1,25 @@ |
|||
create table backups |
|||
( |
|||
id serial |
|||
constraint backups_pk |
|||
primary key, |
|||
note varchar(255) not null, |
|||
databases jsonb, |
|||
size varchar(255), |
|||
create_time timestamp with time zone, |
|||
complete_time timestamp with time zone, |
|||
state enum_task_state, |
|||
source text |
|||
); |
|||
|
|||
comment on table backups is '备份任务表'; |
|||
|
|||
comment on column backups.note is '备注信息'; |
|||
|
|||
comment on column backups.complete_time is '备份完成时间'; |
|||
|
|||
comment on column backups.source is '备份文件路径'; |
|||
|
|||
create unique index backups_id_uindex |
|||
on backups (id); |
|||
|
@ -0,0 +1,4 @@ |
|||
alter table t_resource_consumption |
|||
add resource_id int; |
|||
|
|||
comment on column t_resource_consumption.resource_id is '元数据id'; |
@ -0,0 +1,68 @@ |
|||
'use strict'; |
|||
|
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
export function getBackupsList(query) { |
|||
return dispatch => basicAction({ |
|||
type: 'get', |
|||
dispatch: dispatch, |
|||
query: query || {}, |
|||
actionType: 'GET_BACKUPS_REPORT', |
|||
url: `${ApiTable.getBackupsList}`, |
|||
msg: { error: '获取数据备份列表失败' }, |
|||
reducer: { name: 'backups' } |
|||
}); |
|||
} |
|||
|
|||
|
|||
export function addBackups(params) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'post', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'ADD_BACKUPS_REPORT', |
|||
url: ApiTable.addBackups, |
|||
msg: { |
|||
option: '新增数据备份下发', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function deleteBackups(id) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'del', |
|||
dispatch, |
|||
actionType: 'DELETE_BACKUPS_REPORT', |
|||
url: ApiTable.modifyBackups.replace('{id}', id), |
|||
msg: { |
|||
option: '数据备份删除', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function modifyBackups(id, params, msg) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'put', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'MODIFY_BACKUPS_REPORT', |
|||
url: ApiTable.modifyBackups.replace('{id}', id), |
|||
msg: { |
|||
option: msg || '数据备份编辑', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function restoreBackups(params) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'post', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'RESTORE_BACKUPS_REPORT', |
|||
url: ApiTable.restoreBackups, |
|||
msg: { |
|||
option: '备份恢复下发', |
|||
}, |
|||
}); |
|||
} |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
|
|||
import * as backups from './backups'; |
|||
export default { |
|||
...backups |
|||
} |
@ -0,0 +1,95 @@ |
|||
import React, { useRef } from 'react'; |
|||
import { Button, Form } from 'antd'; |
|||
import { InfoCircleOutlined } from '@ant-design/icons'; |
|||
import { |
|||
ModalForm, |
|||
ProFormTreeSelect, |
|||
ProFormText, |
|||
} from '@ant-design/pro-form'; |
|||
import moment from 'moment'; |
|||
export default (props) => { |
|||
const { title, triggerRender, editData = null, onFinish, dataSources } = props; |
|||
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }; |
|||
const initialValues = editData ? { |
|||
...editData, |
|||
} : {}; |
|||
const [form] = Form.useForm(); |
|||
const formRef = useRef(); |
|||
return ( |
|||
<ModalForm |
|||
formRef={formRef} |
|||
title={title || ''} |
|||
initialValues={initialValues} |
|||
trigger={ |
|||
triggerRender ? triggerRender : <Button type="primary" > |
|||
{title || ''} |
|||
</Button> |
|||
} |
|||
layout="horizontal" |
|||
grid={true} |
|||
{...formItemLayout} |
|||
modalProps={{ |
|||
destroyOnClose: true, |
|||
onCancel: () => { }, |
|||
}} |
|||
onFinish={async (values) => { |
|||
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 != '恢复数据备份' && <ProFormText |
|||
rules={[{ required: true, message: '请输入姓名' }, |
|||
{ max: 255, message: '姓名长度不能大于255个字符' }, |
|||
]} |
|||
name="note" |
|||
label="备份信息" |
|||
/>} |
|||
|
|||
<ProFormTreeSelect |
|||
name="databases" |
|||
label='数据源' |
|||
placeholder="请选择数据源" |
|||
tooltip={title == '恢复数据备份' ? '恢复前请确保恢复数据源数据库为空数据库' : ''} |
|||
allowClear |
|||
secondary |
|||
request={async () => { |
|||
return [ |
|||
{ |
|||
title: 'postgre', |
|||
disabled: true, |
|||
value: '0-0', |
|||
children: dataSources?.rows?.filter(s => (title != '恢复数据备份' && s?.type != '备份数据库') || (title == '恢复数据备份' && s?.type == '备份数据库'))?.map(s => { |
|||
return { |
|||
title: s.name, |
|||
value: s.id, |
|||
} |
|||
}) |
|||
}, |
|||
]; |
|||
}} |
|||
rules={[{ required: true, message: '请选择数据源' }]} |
|||
// tree-select args
|
|||
fieldProps={{ |
|||
showArrow: false, |
|||
filterTreeNode: true, |
|||
showSearch: true, |
|||
popupMatchSelectWidth: false, |
|||
labelInValue: true, |
|||
autoClearSearchValue: true, |
|||
multiple: false, |
|||
treeDefaultExpandAll: true, |
|||
treeNodeFilterProp: 'title', |
|||
fieldNames: { |
|||
label: 'title', |
|||
}, |
|||
}} |
|||
/> |
|||
|
|||
</ModalForm> |
|||
); |
|||
}; |
@ -0,0 +1,6 @@ |
|||
.step-footer { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
margin-top: 20px; |
|||
width: 100%; |
|||
} |
@ -0,0 +1,248 @@ |
|||
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'; |
|||
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, 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, |
|||
page: search ? 1 : currentPage || 1, |
|||
name: searchValue, |
|||
} |
|||
|
|||
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()); |
|||
}, []) |
|||
|
|||
useEffect(() => { |
|||
queryData(); |
|||
}, [pageSize, currentPage]); |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '序号', |
|||
dataIndex: 'index', |
|||
render: (text, record, index) => { return index + 1 } |
|||
}, |
|||
{ |
|||
title: '备份信息', |
|||
dataIndex: 'note', |
|||
}, |
|||
{ |
|||
title: '备份大小', |
|||
dataIndex: 'size', |
|||
}, |
|||
{ |
|||
title: '备份时间', |
|||
dataIndex: 'createTime', |
|||
render: (text, record) => { return moment(record?.createTime).format('YYYY-MM-DD HH:mm:ss') } |
|||
}, |
|||
{ |
|||
title: '备份完成时间', |
|||
dataIndex: 'completeTime', |
|||
render: (text, record) => { return record?.completeTime ? moment(record?.completeTime).format('YYYY-MM-DD HH:mm:ss') : '-' } |
|||
}, |
|||
{ |
|||
title: '状态', |
|||
dataIndex: 'state', |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
width: 160, |
|||
key: 'option', |
|||
valueType: 'option', |
|||
render: (text, record) => { |
|||
const options = []; |
|||
options.push( |
|||
(record?.state != '恢复中' && record?.source) ? <BackupsModal |
|||
editData={record} |
|||
dataSources={dataSources} |
|||
triggerRender={<a type='primary'>恢复</a>} |
|||
title="恢复数据备份" |
|||
onFinish={onFinish} |
|||
key="addModel" |
|||
/> : <a style={{ color: 'gray' }}>恢复</a>) |
|||
options.push( |
|||
record?.source ? |
|||
<a a onClick={() => { window.open(record?.source) }}> 下载</a> : <a style={{ color: 'gray' }}>下载</a> |
|||
) |
|||
|
|||
if (record?.state != '备份中' && record?.state != '恢复中') { |
|||
options.push( |
|||
<Popconfirm |
|||
key="del" |
|||
placement="top" |
|||
title={<><div>是否确认删除该数据备份?</div> |
|||
</>} |
|||
onConfirm={() => handleDelete(record.id)} |
|||
okText="是" |
|||
cancelText="否" |
|||
> |
|||
<a>删除</a> |
|||
</Popconfirm>) |
|||
} |
|||
|
|||
return options; |
|||
|
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
const handleDelete = (id) => { |
|||
dispatch(actions.backups.deleteBackups(id)).then(() => { |
|||
queryData(); |
|||
}); |
|||
}; |
|||
|
|||
const onFinish = async (values, editData) => { |
|||
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 <Spin spinning={loading || addLoading}> |
|||
<Row className='protable-title'> |
|||
<Col span={12}> |
|||
<BackupsModal |
|||
dataSources={dataSources} |
|||
triggerRender={<Button type='primary'>新建</Button>} |
|||
title="新建数据备份" |
|||
onFinish={onFinish} |
|||
key="addModel" |
|||
/> |
|||
</Col> |
|||
<Col span={12} style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}> |
|||
<span>备份信息: </span> <Input |
|||
value={searchValue} onChange={e => { setSearchValue(e.target.value) }} |
|||
style={{ width: 220, marginRight: 15 }} placeholder="请输入" /> |
|||
|
|||
<Button onClick={() => { |
|||
setAutoSearchValue(searchValue) |
|||
setCurrentPage(1) |
|||
setPageSize(10) |
|||
queryData(true) |
|||
}} type='primary'>查询</Button> |
|||
</Col> |
|||
|
|||
</Row> |
|||
<ProTable |
|||
columns={columns} |
|||
dateFormatter="string" |
|||
search={false} |
|||
scroll={ |
|||
{ |
|||
scrollToFirstRowOnChange: true, |
|||
y: clientHeight - 260 |
|||
} |
|||
} |
|||
pagination={{ |
|||
size: 'large', |
|||
total: tableDataFilter?.count, |
|||
showSizeChanger: true, |
|||
showQuickJumper: true, |
|||
current: currentPage, |
|||
pageSize: pageSize || 10, |
|||
defaultPageSize: 10, |
|||
pageSizeOptions: [10, 20, 50], |
|||
showTotal: (total) => { |
|||
return <span style={{ fontSize: 15 }}>{`共${Math.ceil(total / pageSize)}页,${total}项`}</span> |
|||
}, |
|||
onShowSizeChange: (currentPage, pageSize) => { |
|||
setCurrentPage(currentPage); |
|||
setPageSize(pageSize); |
|||
|
|||
}, |
|||
onChange: (page, pageSize) => { |
|||
setCurrentPage(page); |
|||
setPageSize(pageSize); |
|||
|
|||
} |
|||
}} |
|||
dataSource={tableDataFilter?.rows || []} |
|||
options={false} |
|||
/> |
|||
</Spin> |
|||
|
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { |
|||
auth, global, datasources, backups |
|||
} = state; |
|||
return { |
|||
loading: backups.isRequesting || datasources.isRequesting, |
|||
clientHeight: global.clientHeight, |
|||
actions: global.actions, |
|||
backups: backups?.data || {}, |
|||
user: auth.user, |
|||
dataSources: datasources?.data || {}, |
|||
backupsIsRequesting: backups.isRequesting |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(Member); |
|||
|
|||
|
|||
|
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
import Restore from './backupTask'; |
|||
|
|||
export { Restore }; |
@ -0,0 +1,5 @@ |
|||
.protable-title { |
|||
margin-bottom: 16px; |
|||
padding-left: 24px; |
|||
padding-right: 24px; |
|||
} |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
|
|||
import reducers from './reducers'; |
|||
import routes from './routes'; |
|||
import actions from './actions'; |
|||
import { getNavItem } from './nav-item'; |
|||
|
|||
export default { |
|||
key: 'backups', |
|||
name: '数据备份恢复', |
|||
reducers: reducers, |
|||
routes: routes, |
|||
actions: actions, |
|||
getNavItem: getNavItem |
|||
}; |
@ -0,0 +1,17 @@ |
|||
import React from 'react'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { Menu } from 'antd'; |
|||
import { ControlOutlined } from '@ant-design/icons'; |
|||
const SubMenu = Menu.SubMenu; |
|||
|
|||
export function getNavItem(user) { |
|||
|
|||
return ( |
|||
user?.role == '系统管理员' && <SubMenu key="数据备份恢复" icon={<ControlOutlined />} title='数据备份恢复'> |
|||
<Menu.Item key="backups"> |
|||
<Link to="/backups/restore">备份恢复</Link> |
|||
</Menu.Item> |
|||
</ SubMenu > |
|||
) |
|||
|
|||
} |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
export default { |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
'use strict'; |
|||
import { Restore } from './containers'; |
|||
export default [{ |
|||
type: 'inner', |
|||
route: { |
|||
path: '/backups', |
|||
key: 'backups', |
|||
breadcrumb: '数据备份恢复', |
|||
// 不设置 component 则面包屑禁止跳转
|
|||
childRoutes: [{ |
|||
path: '/restore', |
|||
key: 'restore', |
|||
component: Restore, |
|||
breadcrumb: '备份恢复' |
|||
}] |
|||
} |
|||
}]; |
|||
|
@ -1,69 +0,0 @@ |
|||
'use strict'; |
|||
|
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
export function addTask(params, msg) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'post', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'ADD_ACQ_TASK', |
|||
url: ApiTable.addTask, |
|||
msg: { |
|||
option: msg || '新增采集任务', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function getTasks(query) { |
|||
return dispatch => basicAction({ |
|||
type: 'get', |
|||
dispatch: dispatch, |
|||
query: query || {}, |
|||
actionType: 'GET_ACQ_TASKS', |
|||
url: `${ApiTable.getTasks}`, |
|||
msg: { error: '获取采集任务列表失败' }, |
|||
reducer: { name: 'tasks' } |
|||
}); |
|||
} |
|||
|
|||
export function deleteTask(id) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'del', |
|||
dispatch, |
|||
actionType: 'DELETE_ACQ_TASK', |
|||
url: ApiTable.modifyTask.replace('{id}', id), |
|||
msg: { |
|||
option: '采集任务删除', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function modifyTask(id, params, msg) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'put', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'MODIFY_ACQ_TASK', |
|||
url: ApiTable.modifyTask.replace('{id}', id), |
|||
msg: { |
|||
option: msg || '采集任务编辑', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function runTask(params, msg) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'post', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'RUN_ACQ_TASK', |
|||
url: ApiTable.runTask, |
|||
msg: { |
|||
option: msg || '任务执行', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
|
@ -1,5 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
import DataSourceManagement from './member'; |
|||
import MemberManagement from './member'; |
|||
|
|||
export { DataSourceManagement }; |
|||
export { MemberManagement }; |
|||
|
Loading…
Reference in new issue