From 42721f8b38be11e0d50a094622a3d10150f8122a Mon Sep 17 00:00:00 2001 From: "peng.peng" Date: Fri, 16 Jun 2023 10:00:12 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BC=88*=EF=BC=89=E5=A4=87=E4=BB=BD=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E5=88=9D=E5=A7=8B=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/client/src/app.js | 2 + .../src/sections/backups/actions/index.js | 6 + .../src/sections/backups/actions/member.js | 56 +++++ .../src/sections/backups/actions/task.js | 69 ++++++ .../backups/components/memberModal.js | 78 ++++++ .../backups/components/resetPassword.js | 61 +++++ .../sections/backups/components/style.less | 6 + .../sections/backups/components/taskModal.js | 26 ++ .../src/sections/backups/containers/index.js | 5 + .../sections/backups/containers/restore.js | 229 ++++++++++++++++++ .../sections/backups/containers/style.less | 5 + web/client/src/sections/backups/index.js | 15 ++ web/client/src/sections/backups/nav-item.js | 17 ++ .../src/sections/backups/reducers/index.js | 5 + web/client/src/sections/backups/routes.js | 18 ++ .../memberManagement/containers/index.js | 4 +- .../src/sections/memberManagement/routes.js | 4 +- 17 files changed, 602 insertions(+), 4 deletions(-) create mode 100644 web/client/src/sections/backups/actions/index.js create mode 100644 web/client/src/sections/backups/actions/member.js create mode 100644 web/client/src/sections/backups/actions/task.js create mode 100644 web/client/src/sections/backups/components/memberModal.js create mode 100644 web/client/src/sections/backups/components/resetPassword.js create mode 100644 web/client/src/sections/backups/components/style.less create mode 100644 web/client/src/sections/backups/components/taskModal.js create mode 100644 web/client/src/sections/backups/containers/index.js create mode 100644 web/client/src/sections/backups/containers/restore.js create mode 100644 web/client/src/sections/backups/containers/style.less create mode 100644 web/client/src/sections/backups/index.js create mode 100644 web/client/src/sections/backups/nav-item.js create mode 100644 web/client/src/sections/backups/reducers/index.js create mode 100644 web/client/src/sections/backups/routes.js diff --git a/web/client/src/app.js b/web/client/src/app.js index f45bedc..60017ea 100644 --- a/web/client/src/app.js +++ b/web/client/src/app.js @@ -11,6 +11,7 @@ import resourceRetrieval from './sections/resourceRetrieval'; import memberManagement from './sections/memberManagement'; import dataQuality from './sections/dataQuality'; import safetySpecification from './sections/safetySpecification'; +import backups from './sections/backups'; const App = props => { const { projectName } = props @@ -31,6 +32,7 @@ const App = props => { dataQuality, safetySpecification, memberManagement, + backups ]} /> ) diff --git a/web/client/src/sections/backups/actions/index.js b/web/client/src/sections/backups/actions/index.js new file mode 100644 index 0000000..5abd7d2 --- /dev/null +++ b/web/client/src/sections/backups/actions/index.js @@ -0,0 +1,6 @@ +'use strict'; + +import * as member from './member'; +export default { + ...member +} \ No newline at end of file diff --git a/web/client/src/sections/backups/actions/member.js b/web/client/src/sections/backups/actions/member.js new file mode 100644 index 0000000..ec6ab27 --- /dev/null +++ b/web/client/src/sections/backups/actions/member.js @@ -0,0 +1,56 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function getUserList(query) { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + query: query || {}, + actionType: 'GET_MEMBER_REPORT', + url: `${ApiTable.getUserList}`, + msg: { error: '获取用户列表失败' }, + reducer: { name: 'member' } + }); +} + + +export function addUser(params) { + return (dispatch) => basicAction({ + type: 'post', + data: params, + dispatch, + actionType: 'ADD_MEMBER_REPORT', + url: ApiTable.addUser, + msg: { + option: '用户新增', + }, + }); +} + +export function deleteUser(id) { + return (dispatch) => basicAction({ + type: 'del', + dispatch, + actionType: 'DELETE_MEMBER_REPORT', + url: ApiTable.modifyUser.replace('{id}', id), + msg: { + option: '用户删除', + }, + }); +} + +export function modifyUser(id, params, msg) { + return (dispatch) => basicAction({ + type: 'put', + data: params, + dispatch, + actionType: 'MODIFY_MEMBER_REPORT', + url: ApiTable.modifyUser.replace('{id}', id), + msg: { + option: msg || '用户编辑', + }, + }); +} + diff --git a/web/client/src/sections/backups/actions/task.js b/web/client/src/sections/backups/actions/task.js new file mode 100644 index 0000000..11d8ce3 --- /dev/null +++ b/web/client/src/sections/backups/actions/task.js @@ -0,0 +1,69 @@ +'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 || '任务执行', + }, + }); +} + + diff --git a/web/client/src/sections/backups/components/memberModal.js b/web/client/src/sections/backups/components/memberModal.js new file mode 100644 index 0000000..e2e7a26 --- /dev/null +++ b/web/client/src/sections/backups/components/memberModal.js @@ -0,0 +1,78 @@ +import React, { useRef } from 'react'; +import { Button, Form } from 'antd'; +import { InfoCircleOutlined } from '@ant-design/icons'; +import { + ModalForm, + ProFormSelect, + ProFormTextArea, + ProFormDigit, + ProFormText, + ProFormSwitch +} from '@ant-design/pro-form'; + +export default (props) => { + const { title, triggerRender, editData = null, onFinish, paramsName } = props; + const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }; + const initialValues = editData ? { + ...editData, + } : {}; + const [form] = Form.useForm(); + const formRef = useRef(); + return ( + + {title || ''} + + } + layout="horizontal" + grid={true} + {...formItemLayout} + modalProps={{ + destroyOnClose: true, + onCancel: () => { }, + }} + onFinish={async (values) => { + return onFinish && await onFinish(values, editData, form) + // return true; + }} + width={500} + > + + + + + + + + + ); +}; \ No newline at end of file diff --git a/web/client/src/sections/backups/components/resetPassword.js b/web/client/src/sections/backups/components/resetPassword.js new file mode 100644 index 0000000..f633c36 --- /dev/null +++ b/web/client/src/sections/backups/components/resetPassword.js @@ -0,0 +1,61 @@ +import React, { useRef } from 'react'; +import { Button, Form } from 'antd'; +import { + ModalForm, + ProFormText, +} from '@ant-design/pro-form'; + +export default (props) => { + const { title, triggerRender, editData = null, onFinish } = props; + const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }; + const initialValues = {}; + const [form] = Form.useForm(); + const formRef = useRef(); + return ( + + {title || ''} + + } + layout="horizontal" + grid={true} + {...formItemLayout} + modalProps={{ + destroyOnClose: true, + onCancel: () => { }, + }} + onFinish={async (values) => { + return onFinish && await onFinish({ ...values, msg: '重置密码' }, editData, '重置密码') + }} + width={500} + > + + + + + + + ); +}; \ No newline at end of file diff --git a/web/client/src/sections/backups/components/style.less b/web/client/src/sections/backups/components/style.less new file mode 100644 index 0000000..cf451f1 --- /dev/null +++ b/web/client/src/sections/backups/components/style.less @@ -0,0 +1,6 @@ +.step-footer { + display: flex; + justify-content: flex-end; + margin-top: 20px; + width: 100%; +} \ No newline at end of file diff --git a/web/client/src/sections/backups/components/taskModal.js b/web/client/src/sections/backups/components/taskModal.js new file mode 100644 index 0000000..0278fa8 --- /dev/null +++ b/web/client/src/sections/backups/components/taskModal.js @@ -0,0 +1,26 @@ +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/index.js b/web/client/src/sections/backups/containers/index.js new file mode 100644 index 0000000..779d542 --- /dev/null +++ b/web/client/src/sections/backups/containers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +import Restore from './restore'; + +export { Restore }; diff --git a/web/client/src/sections/backups/containers/restore.js b/web/client/src/sections/backups/containers/restore.js new file mode 100644 index 0000000..821ea7e --- /dev/null +++ b/web/client/src/sections/backups/containers/restore.js @@ -0,0 +1,229 @@ +import React, { useEffect, useState } 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 MemberModal from '../components/memberModal'; +import ResetPasswordModal from '../components/resetPassword'; +import { useFsRequest, ApiTable } from '$utils'; +import './style.less'; +function Member(props) { + const { loading, clientHeight, actions, dispatch, member, user } = props; + const [pageSize, setPageSize] = useState(10); + const [currentPage, setCurrentPage] = useState(1); + const [searchValue, setSearchValue] = useState('') + const [visible, setVisible] = useState(false);//是否展示新增编辑模态框 + const [editData, setEditData] = useState(null);//模态框编辑数据 + const [refreshTree, setRefreshTree] = useState(1); + const [searchRole, setSearchRole] = useState() + const queryData = (search) => { + const query = { + limit: search ? 10 : pageSize || 10, + page: search ? 1 : currentPage || 1, + name: searchValue, + role: searchRole + } + + dispatch(actions.memberManagement.getUserList(query)); + } + const { data: treeData = [] } = useFsRequest({ + url: ApiTable.getResourceCatalog, + refreshDeps: [refreshTree] + }); + + useEffect(() => { + queryData(); + }, [pageSize, currentPage]); + + const columns = [ + { + title: '序号', + dataIndex: 'index', + render: (text, record, index) => { return index + 1 } + }, + { + title: '姓名', + dataIndex: 'name', + }, + { + title: '用户名', + dataIndex: 'username', + }, + { + title: '角色', + dataIndex: 'role', + }, + { + title: '状态', + dataIndex: 'enabled', + render: (text, record) => { + return ● {record?.enabled ? '正常' : '禁用'} + } + }, + { + title: '操作', + width: 160, + key: 'option', + valueType: 'option', + render: (text, record) => { + const options = []; + options.push(编辑} + title="编辑用户" + onFinish={onFinish} + key="editUser" + />) + options.push( +
是否确认删除该用户?
+ } + onConfirm={() => handleDelete(record.id)} + okText="是" + cancelText="否" + > + 删除 +
) + user?.username == 'SuperAdmin' && options.push( +
是否确认重置该用户密码?
+ } + onConfirm={() => { + dispatch(actions.memberManagement.modifyUser(record.id, { password: 'e10adc3949ba59abbe56e057f20f883e' }, '重置密码')) + }} + okText="是" + cancelText="否" + > + 重置密码 +
) + + + return options; + + }, + }, + ]; + + const handleDelete = (id) => { + dispatch(actions.memberManagement.deleteUser(id)).then(() => { + queryData(); + }); + }; + + const onFinish = async (values, editData) => { + if (editData) { + const dataToSave = { ...values } + return dispatch( + actions.memberManagement.modifyUser(editData.id, dataToSave, values?.msg || ''), + ).then((res) => { + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + } + + return dispatch(actions.memberManagement.addUser({ + ...values, + })).then(res => { + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + }; + + return + + + 新建} + title="新建用户" + onFinish={onFinish} + key="addModel" + /> + + + 用户姓名: { setSearchValue(e.target.value) }} + style={{ width: 220, marginRight: 15 }} placeholder="请输入" /> + + 角色: + + + + + { + return {`共${Math.ceil(total / pageSize)}页,${total}项`} + }, + onShowSizeChange: (currentPage, pageSize) => { + setCurrentPage(currentPage); + setPageSize(pageSize); + + }, + onChange: (page, pageSize) => { + setCurrentPage(page); + setPageSize(pageSize); + } + }} + dataSource={member?.rows || []} + options={false} + /> + + +} + +function mapStateToProps(state) { + const { + auth, global, datasources, member + } = state; + return { + loading: datasources.isRequesting, + clientHeight: global.clientHeight, + actions: global.actions, + member: member?.data || {}, + user: auth.user + }; +} + +export default connect(mapStateToProps)(Member); + + + diff --git a/web/client/src/sections/backups/containers/style.less b/web/client/src/sections/backups/containers/style.less new file mode 100644 index 0000000..8219c4f --- /dev/null +++ b/web/client/src/sections/backups/containers/style.less @@ -0,0 +1,5 @@ +.protable-title { + margin-bottom: 16px; + padding-left: 24px; + padding-right: 24px; +} \ No newline at end of file diff --git a/web/client/src/sections/backups/index.js b/web/client/src/sections/backups/index.js new file mode 100644 index 0000000..0854c67 --- /dev/null +++ b/web/client/src/sections/backups/index.js @@ -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 +}; \ No newline at end of file diff --git a/web/client/src/sections/backups/nav-item.js b/web/client/src/sections/backups/nav-item.js new file mode 100644 index 0000000..752f8dc --- /dev/null +++ b/web/client/src/sections/backups/nav-item.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Menu } from 'antd'; +import { BarChartOutlined } from '@ant-design/icons'; +const SubMenu = Menu.SubMenu; + +export function getNavItem(user) { + + return ( + user?.role == '系统管理员' && } title='数据备份恢复'> + + 备份恢复 + + + ) + +} \ No newline at end of file diff --git a/web/client/src/sections/backups/reducers/index.js b/web/client/src/sections/backups/reducers/index.js new file mode 100644 index 0000000..7ed1088 --- /dev/null +++ b/web/client/src/sections/backups/reducers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + +} \ No newline at end of file diff --git a/web/client/src/sections/backups/routes.js b/web/client/src/sections/backups/routes.js new file mode 100644 index 0000000..935dda3 --- /dev/null +++ b/web/client/src/sections/backups/routes.js @@ -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: '备份恢复' + }] + } +}]; + diff --git a/web/client/src/sections/memberManagement/containers/index.js b/web/client/src/sections/memberManagement/containers/index.js index 8b9e540..b322ad1 100644 --- a/web/client/src/sections/memberManagement/containers/index.js +++ b/web/client/src/sections/memberManagement/containers/index.js @@ -1,5 +1,5 @@ 'use strict'; -import DataSourceManagement from './member'; +import MemberManagement from './member'; -export { DataSourceManagement }; +export { MemberManagement }; diff --git a/web/client/src/sections/memberManagement/routes.js b/web/client/src/sections/memberManagement/routes.js index 0888966..91e3250 100644 --- a/web/client/src/sections/memberManagement/routes.js +++ b/web/client/src/sections/memberManagement/routes.js @@ -1,5 +1,5 @@ 'use strict'; -import { Adapter, DataSourceManagement, AcquisitionTask, AcquisitionLog, AdapterDetail } from './containers'; +import { MemberManagement } from './containers'; export default [{ type: 'inner', route: { @@ -10,7 +10,7 @@ export default [{ childRoutes: [{ path: '/auth', key: 'auth', - component: DataSourceManagement, + component: MemberManagement, breadcrumb: '权限管理' }] }