diff --git a/api/app/lib/controllers/organization/index.js b/api/app/lib/controllers/organization/index.js new file mode 100644 index 0000000..26c40c4 --- /dev/null +++ b/api/app/lib/controllers/organization/index.js @@ -0,0 +1,146 @@ +'use strict'; +const Hex = require('crypto-js/enc-hex'); +const MD5 = require('crypto-js/md5'); +const CryptoJS = require('crypto-js'); + +function getOrganizationList(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.name = { $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.Organization.findAndCount(option); + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + +// 新增机构 +function addOrganization(opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + try { + const { name, code } = ctx.request.body + const checkName = await models.Organization.findOne({ where: { name, code } }); + if (checkName) { + ctx.status = 400; + ctx.body = { message: "该机构名称&代码组合已存在" } + } else { + let rslt = ctx.request.body; + await models.Organization.create(Object.assign({}, rslt)) + ctx.status = 204; + ctx.body = { message: '新建机构成功' } + } + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '新建机构失败' } + } + } +} + +// 修改机构 +function editOrganization(opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + const { id } = ctx.params; + const body = ctx.request.body; + const { name, code } = ctx.request.body + const checkName = await models.Organization.findOne({ where: { id: { $not: id }, name, code } }); + if (checkName) { + ctx.status = 400; + ctx.body = { message: '该机构名称&代码组合已存在' } + } else { + await models.Organization.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 deleteOrganization(opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + const { id } = ctx.params; + + // const checkName1 = await models.MetadataDatabase.findOne({ where: { createBy: id } }); + // const checkName2 = await models.MetadataFile.findOne({ where: { createBy: id } }); + // const checkName3 = await models.MetadataRestapi.findOne({ where: { createBy: id } }); + // if (checkName1 || checkName2 || checkName3) { + // ctx.status = 400; + // ctx.body = { message: '该机构下存在依赖资源无法删除!' } + // } else { + await models.Organization.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: '删除机构失败' } + } + } +} + + + +module.exports = { + getOrganizationList, + addOrganization, + editOrganization, + deleteOrganization, + +} \ No newline at end of file diff --git a/api/app/lib/models/organization.js b/api/app/lib/models/organization.js new file mode 100644 index 0000000..3ac5568 --- /dev/null +++ b/api/app/lib/models/organization.js @@ -0,0 +1,53 @@ +/* eslint-disable*/ + +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const Organization = sequelize.define("organization", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "organization_id_uindex" + }, + name: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "name", + autoIncrement: false + }, + code: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "code", + autoIncrement: false + }, + ability: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "职能", + primaryKey: false, + field: "ability", + autoIncrement: false + } + }, { + tableName: "organization", + comment: "", + indexes: [] + }); + dc.models.Organization = Organization; + return Organization; +}; \ No newline at end of file diff --git a/api/app/lib/routes/organization/index.js b/api/app/lib/routes/organization/index.js new file mode 100644 index 0000000..59b0005 --- /dev/null +++ b/api/app/lib/routes/organization/index.js @@ -0,0 +1,23 @@ +'use strict'; + +const organization = require('../../controllers/organization/index'); + +module.exports = function (app, router, opts, AuthCode) { + + app.fs.api.logAttr['POST/organization'] = { content: '增加机构', visible: true }; + router.post('/organization', organization.addOrganization(opts)) + + // 修改机构信息 + app.fs.api.logAttr['PUT/organization/:id'] = { content: '修改机构信息', visible: true }; + router.put('/organization/:id', organization.editOrganization(opts)) + + // 删除机构信息 + app.fs.api.logAttr['DEL/organization/:id'] = { content: '删除机构信息', visible: true }; + router.del('/organization/:id', organization.deleteOrganization(opts)) + + //获取机构信息列表 + app.fs.api.logAttr['GET/organization'] = { content: '获取机构信息列表', visible: true }; + router.get('/organization', organization.getOrganizationList(opts)); + + +}; diff --git a/web/client/src/app.js b/web/client/src/app.js index 29ed713..690698f 100644 --- a/web/client/src/app.js +++ b/web/client/src/app.js @@ -13,6 +13,7 @@ import dataQuality from './sections/dataQuality'; import safetySpecification from './sections/safetySpecification'; import backups from './sections/backups'; import dataService from './sections/dataService'; +import organization from './sections/organization' const App = props => { const { projectName } = props @@ -34,7 +35,8 @@ const App = props => { safetySpecification, dataService, memberManagement, - backups + backups, + organization ]} /> ) diff --git a/web/client/src/sections/organization/actions/index.js b/web/client/src/sections/organization/actions/index.js new file mode 100644 index 0000000..d5ff79e --- /dev/null +++ b/web/client/src/sections/organization/actions/index.js @@ -0,0 +1,6 @@ +'use strict'; + +import * as member from './organization'; +export default { + ...member +} \ No newline at end of file diff --git a/web/client/src/sections/organization/actions/organization.js b/web/client/src/sections/organization/actions/organization.js new file mode 100644 index 0000000..3f0195b --- /dev/null +++ b/web/client/src/sections/organization/actions/organization.js @@ -0,0 +1,56 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function getOrganizationList(query) { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + query: query || {}, + actionType: 'GET_ORGANIZATION_REPORT', + url: `${ApiTable.getOrganizationList}`, + msg: { error: '获取机构列表失败' }, + reducer: { name: 'organization' } + }); +} + + +export function addOrganization(params) { + return (dispatch) => basicAction({ + type: 'post', + data: params, + dispatch, + actionType: 'ADD_ORGANIZATION_REPORT', + url: ApiTable.addOrganization, + msg: { + option: '机构新增', + }, + }); +} + +export function deleteOrganization(id) { + return (dispatch) => basicAction({ + type: 'del', + dispatch, + actionType: 'DELETE_ORGANIZATION_REPORT', + url: ApiTable.modifyOrganization.replace('{id}', id), + msg: { + option: '机构删除', + }, + }); +} + +export function modifyOrganization(id, params, msg) { + return (dispatch) => basicAction({ + type: 'put', + data: params, + dispatch, + actionType: 'MODIFY_ORGANIZATION_REPORT', + url: ApiTable.modifyOrganization.replace('{id}', id), + msg: { + option: msg || '机构编辑', + }, + }); +} + diff --git a/web/client/src/sections/organization/components/organizationModal.js b/web/client/src/sections/organization/components/organizationModal.js new file mode 100644 index 0000000..abd21ef --- /dev/null +++ b/web/client/src/sections/organization/components/organizationModal.js @@ -0,0 +1,68 @@ +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, 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/organization/containers/index.js b/web/client/src/sections/organization/containers/index.js new file mode 100644 index 0000000..ac6d772 --- /dev/null +++ b/web/client/src/sections/organization/containers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +import Organization from './organization'; + +export { Organization }; diff --git a/web/client/src/sections/organization/containers/organization.js b/web/client/src/sections/organization/containers/organization.js new file mode 100644 index 0000000..62b814b --- /dev/null +++ b/web/client/src/sections/organization/containers/organization.js @@ -0,0 +1,195 @@ +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 OrganizationModal from '../components/organizationModal'; + +import { useFsRequest, ApiTable } from '$utils'; +import './style.less'; +function organization(props) { + const { loading, clientHeight, actions, dispatch, organization, Organization } = 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.organization.getOrganizationList(query)); + } + + useEffect(() => { + queryData(); + }, [pageSize, currentPage]); + + const columns = [ + { + title: '序号', + dataIndex: 'index', + render: (text, record, index) => { return index + 1 } + }, + { + title: '机构名称', + dataIndex: 'name', + }, + { + title: '机构代码', + dataIndex: 'code', + }, + { + title: '机构职能', + dataIndex: 'ability', + }, + { + title: '操作', + width: 160, + key: 'option', + valueType: 'option', + render: (text, record) => { + const options = []; + options.push(编辑} + title="编辑机构" + onFinish={onFinish} + key="editOrganization" + />) + options.push( +
是否确认删除该机构?
+ } + onConfirm={() => handleDelete(record.id)} + okText="是" + cancelText="否" + > + 删除 +
) + + + return options; + + }, + }, + ]; + + const handleDelete = (id) => { + dispatch(actions.organization.deleteOrganization(id)).then(() => { + queryData(); + }); + }; + + const onFinish = async (values, editData) => { + if (editData) { + const dataToSave = { ...values } + return dispatch( + actions.organization.modifyOrganization(editData.id, dataToSave, values?.msg || ''), + ).then((res) => { + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + } + + return dispatch(actions.organization.addOrganization({ + ...values, + })).then(res => { + if (res.success) { + queryData(); + return true; + } else { + return false; + } + }); + }; + + return + + + 新建} + title="新建机构" + onFinish={onFinish} + key="addOrganization" + /> + + + 机构名称: { 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={organization?.rows || []} + options={false} + /> + + +} + +function mapStateToProps(state) { + const { + auth, global, datasources, organization + } = state; + return { + loading: datasources.isRequesting, + clientHeight: global.clientHeight, + actions: global.actions, + organization: organization?.data || {}, + }; +} + +export default connect(mapStateToProps)(organization); + + + diff --git a/web/client/src/sections/organization/containers/style.less b/web/client/src/sections/organization/containers/style.less new file mode 100644 index 0000000..8219c4f --- /dev/null +++ b/web/client/src/sections/organization/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/organization/index.js b/web/client/src/sections/organization/index.js new file mode 100644 index 0000000..535f432 --- /dev/null +++ b/web/client/src/sections/organization/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: 'organization', + name: '机构管理', + reducers: reducers, + routes: routes, + actions: actions, + getNavItem: getNavItem +}; \ No newline at end of file diff --git a/web/client/src/sections/organization/nav-item.js b/web/client/src/sections/organization/nav-item.js new file mode 100644 index 0000000..8bebc92 --- /dev/null +++ b/web/client/src/sections/organization/nav-item.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Menu } from 'antd'; +import { UserOutlined } from '@ant-design/icons'; +const SubMenu = Menu.SubMenu; + +export function getNavItem(user) { + + return ( + user?.role == '系统管理员' && } key="organization"> + 机构管理 + + // user?.role == '系统管理员' && } title='用户管理'> + // + // 用户权限 + // + // + ) + +} \ No newline at end of file diff --git a/web/client/src/sections/organization/reducers/index.js b/web/client/src/sections/organization/reducers/index.js new file mode 100644 index 0000000..7ed1088 --- /dev/null +++ b/web/client/src/sections/organization/reducers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + +} \ No newline at end of file diff --git a/web/client/src/sections/organization/routes.js b/web/client/src/sections/organization/routes.js new file mode 100644 index 0000000..6d19150 --- /dev/null +++ b/web/client/src/sections/organization/routes.js @@ -0,0 +1,12 @@ +'use strict'; +import { Organization } from './containers'; +export default [{ + type: 'inner', + route: { + path: '/organization', + key: 'organization', + breadcrumb: '机构管理', + component: Organization, + + } +}]; \ No newline at end of file diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index 0245b23..dd295dc 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -80,11 +80,17 @@ export const ApiTable = { //资源消费 approveList: 'resource/approve', + //用户管理 getUserList: 'meta/members', addUser: 'meta/member', modifyUser: 'meta/member/{id}', + //机构管理 + getOrganizationList: 'organization', + addOrganization: 'organization', + modifyOrganization: 'organization/{id}', + //元数据检索 searchMetadata: "meta/data/search",