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='用户管理'>
+ //
+ // 用户权限
+ //
+ // SubMenu >
+ )
+
+}
\ 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",