Browse Source

(*)用户 资源目录关联机构

master
peng.peng 1 year ago
parent
commit
2fab3b1c0a
  1. 7
      api/app/lib/controllers/auth/index.js
  2. 14
      api/app/lib/controllers/organization/index.js
  3. 6
      api/app/lib/index.js
  4. 121
      api/app/lib/models/resource_catalog.js
  5. 139
      api/app/lib/models/user.js
  6. 11
      web/client/src/sections/memberManagement/components/memberModal.js
  7. 14
      web/client/src/sections/memberManagement/containers/member.js
  8. 18
      web/client/src/sections/metadataManagement/components/resourceCatalogModal.js
  9. 12
      web/client/src/sections/metadataManagement/containers/latestMetadata.js

7
api/app/lib/controllers/auth/index.js

@ -6,7 +6,7 @@ const CryptoJS = require('crypto-js');
const moment = require('moment'); const moment = require('moment');
const uuid = require('uuid'); const uuid = require('uuid');
async function login (ctx, next) { async function login(ctx, next) {
// const transaction = await ctx.fs.dc.orm.transaction(); // const transaction = await ctx.fs.dc.orm.transaction();
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
@ -23,6 +23,9 @@ async function login (ctx, next) {
username: params.username, username: params.username,
password: password, password: password,
}, },
include: [{
model: models.Organization
}]
}); });
} }
if (userRes) { if (userRes) {
@ -60,7 +63,7 @@ async function login (ctx, next) {
} }
} }
async function logout (ctx) { async function logout(ctx) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const params = ctx.request.body; const params = ctx.request.body;

14
api/app/lib/controllers/organization/index.js

@ -51,10 +51,11 @@ function addOrganization(opts) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
try { try {
const { name, code } = ctx.request.body const { name, code } = ctx.request.body
const checkName = await models.Organization.findOne({ where: { name, code } }); const checkName = await models.Organization.findOne({ where: { name } });
if (checkName) { const checkCode = await models.Organization.findOne({ where: { code } });
if (checkName || checkCode) {
ctx.status = 400; ctx.status = 400;
ctx.body = { message: "该机构名称&代码组合已存在" } ctx.body = { message: "机构名称或代码不能重复" }
} else { } else {
let rslt = ctx.request.body; let rslt = ctx.request.body;
await models.Organization.create(Object.assign({}, rslt)) await models.Organization.create(Object.assign({}, rslt))
@ -79,10 +80,11 @@ function editOrganization(opts) {
const { id } = ctx.params; const { id } = ctx.params;
const body = ctx.request.body; const body = ctx.request.body;
const { name, code } = ctx.request.body const { name, code } = ctx.request.body
const checkName = await models.Organization.findOne({ where: { id: { $not: id }, name, code } }); const checkName = await models.Organization.findOne({ where: { id: { $not: id }, name } });
if (checkName) { const checkCode = await models.Organization.findOne({ where: { id: { $not: id }, code } });
if (checkName || checkCode) {
ctx.status = 400; ctx.status = 400;
ctx.body = { message: '该机构名称&代码组合已存在' } ctx.body = { message: '机构名称或代码不能重复' }
} else { } else {
await models.Organization.update( await models.Organization.update(
body, body,

6
api/app/lib/index.js

@ -57,7 +57,7 @@ module.exports.models = function (dc) {
const { const {
DataSource, AcquisitionTask, Adapter, User, MetadataDatabase, MetadataFile, MetadataRestapi, AcquisitionLog, ResourceCatalog, DataSource, AcquisitionTask, Adapter, User, MetadataDatabase, MetadataFile, MetadataRestapi, AcquisitionLog, ResourceCatalog,
BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi, ResourceConsumption, BusinessRule, StandardDoc, DbStatistics BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi, ResourceConsumption, BusinessRule, StandardDoc, DbStatistics
, RestfulApi, RestfulApiRecord , RestfulApi, RestfulApiRecord, Organization
} = dc.models; } = dc.models;
AcquisitionTask.belongsTo(DataSource, { foreignKey: 'dataSourceId', targetKey: 'id' }); AcquisitionTask.belongsTo(DataSource, { foreignKey: 'dataSourceId', targetKey: 'id' });
@ -91,7 +91,7 @@ module.exports.models = function (dc) {
ResourceConsumption.belongsTo(User, { foreignKey: 'applyBy', targetKey: 'id', as: "applyUser" }); ResourceConsumption.belongsTo(User, { foreignKey: 'applyBy', targetKey: 'id', as: "applyUser" });
RestfulApi.hasMany(ResourceConsumption, { foreignKey: 'restServiceId', targetKey: 'id',}); RestfulApi.hasMany(ResourceConsumption, { foreignKey: 'restServiceId', targetKey: 'id', });
ResourceConsumption.belongsTo(User, { foreignKey: 'approveBy', targetKey: 'id', as: 'approveUser' }); ResourceConsumption.belongsTo(User, { foreignKey: 'approveBy', targetKey: 'id', as: 'approveUser' });
@ -102,4 +102,6 @@ module.exports.models = function (dc) {
DataSource.hasMany(DbStatistics, { foreignKey: 'sourceId', sourceKey: 'id' }) DataSource.hasMany(DbStatistics, { foreignKey: 'sourceId', sourceKey: 'id' })
RestfulApiRecord.belongsTo(RestfulApi, { foreignKey: 'restServiceId', targetKey: 'id' }); RestfulApiRecord.belongsTo(RestfulApi, { foreignKey: 'restServiceId', targetKey: 'id' });
User.belongsTo(Organization, { foreignKey: 'orgId', targetKey: 'id' });
}; };

121
api/app/lib/models/resource_catalog.js

@ -3,60 +3,69 @@
'use strict'; 'use strict';
module.exports = dc => { module.exports = dc => {
const DataTypes = dc.ORM; const DataTypes = dc.ORM;
const sequelize = dc.orm; const sequelize = dc.orm;
const ResourceCatalog = sequelize.define("resourceCatalog", { const ResourceCatalog = sequelize.define("resourceCatalog", {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "唯一标识", comment: "唯一标识",
primaryKey: true, primaryKey: true,
field: "id", field: "id",
autoIncrement: true, autoIncrement: true,
unique: "t_resource_catalog_id_uindex" unique: "t_resource_catalog_id_uindex"
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "名称", comment: "名称",
primaryKey: false, primaryKey: false,
field: "name", field: "name",
autoIncrement: false autoIncrement: false
}, },
code: { code: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "代码", comment: "代码",
primaryKey: false, primaryKey: false,
field: "code", field: "code",
autoIncrement: false autoIncrement: false
}, },
description: { description: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "描述", comment: "描述",
primaryKey: false, primaryKey: false,
field: "description", field: "description",
autoIncrement: false autoIncrement: false
}, },
parent: { parent: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "父级目录", comment: "父级目录",
primaryKey: false, primaryKey: false,
field: "parent", field: "parent",
autoIncrement: false autoIncrement: false
} },
}, { orgId: {
tableName: "t_resource_catalog", type: DataTypes.INTEGER,
comment: "", allowNull: true,
indexes: [] defaultValue: null,
}); comment: null,
dc.models.ResourceCatalog = ResourceCatalog; primaryKey: false,
return ResourceCatalog; field: "orgId",
autoIncrement: false
}
}, {
tableName: "t_resource_catalog",
comment: "",
indexes: []
});
dc.models.ResourceCatalog = ResourceCatalog;
return ResourceCatalog;
}; };

139
api/app/lib/models/user.js

@ -3,70 +3,79 @@
'use strict'; 'use strict';
module.exports = dc => { module.exports = dc => {
const DataTypes = dc.ORM; const DataTypes = dc.ORM;
const sequelize = dc.orm; const sequelize = dc.orm;
const User = sequelize.define("user", { const User = sequelize.define("user", {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "唯一标识", comment: "唯一标识",
primaryKey: true, primaryKey: true,
field: "id", field: "id",
autoIncrement: true, autoIncrement: true,
unique: "t_user_id_uindex" unique: "t_user_id_uindex"
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: true, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "姓名", comment: "姓名",
primaryKey: false, primaryKey: false,
field: "name", field: "name",
autoIncrement: false autoIncrement: false
}, },
username: { username: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "用户名", comment: "用户名",
primaryKey: false, primaryKey: false,
field: "username", field: "username",
autoIncrement: false autoIncrement: false
}, },
password: { password: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "密码", comment: "密码",
primaryKey: false, primaryKey: false,
field: "password", field: "password",
autoIncrement: false autoIncrement: false
}, },
role: { role: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: "角色", comment: "角色",
primaryKey: false, primaryKey: false,
field: "role", field: "role",
autoIncrement: false autoIncrement: false
}, },
enabled: { enabled: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
allowNull: true, allowNull: true,
defaultValue: true, defaultValue: true,
comment: "是否启用", comment: "是否启用",
primaryKey: false, primaryKey: false,
field: "enabled", field: "enabled",
autoIncrement: false autoIncrement: false
} },
orgId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "orgId",
autoIncrement: false
}
}, { }, {
tableName: "t_user", tableName: "t_user",
comment: "", comment: "",
indexes: [] indexes: []
}); });
dc.models.User = User; dc.models.User = User;
return User; return User;
}; };

11
web/client/src/sections/memberManagement/components/memberModal.js

@ -11,7 +11,7 @@ import {
} from '@ant-design/pro-form'; } from '@ant-design/pro-form';
export default (props) => { export default (props) => {
const { title, triggerRender, editData = null, onFinish, paramsName } = props; const { title, triggerRender, editData = null, onFinish, paramsName, organization } = props;
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }; const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } };
const initialValues = editData ? { const initialValues = editData ? {
...editData, ...editData,
@ -68,6 +68,15 @@ export default (props) => {
label="角色" label="角色"
/> />
<ProFormSelect
disabled={editData}
rules={[{ required: true, message: '请选择机构' }]}
options={organization?.map(s => ({ label: s.name, value: s.id }))}
name="orgId"
label="机构"
/>
<ProFormSwitch name="enabled" label="是否启用" <ProFormSwitch name="enabled" label="是否启用"
fieldProps={ fieldProps={
{ defaultChecked: true } { defaultChecked: true }

14
web/client/src/sections/memberManagement/containers/member.js

@ -8,7 +8,7 @@ import ResetPasswordModal from '../components/resetPassword';
import { useFsRequest, ApiTable } from '$utils'; import { useFsRequest, ApiTable } from '$utils';
import './style.less'; import './style.less';
function Member(props) { function Member(props) {
const { loading, clientHeight, actions, dispatch, member, user } = props; const { loading, clientHeight, actions, dispatch, member, user, organization } = props;
const [pageSize, setPageSize] = useState(10); const [pageSize, setPageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [searchValue, setSearchValue] = useState('') const [searchValue, setSearchValue] = useState('')
@ -26,13 +26,10 @@ function Member(props) {
dispatch(actions.memberManagement.getUserList(query)); dispatch(actions.memberManagement.getUserList(query));
} }
const { data: treeData = [] } = useFsRequest({
url: ApiTable.getResourceCatalog,
refreshDeps: [refreshTree]
});
useEffect(() => { useEffect(() => {
queryData(); queryData();
dispatch(actions.organization.getOrganizationList());
}, [pageSize, currentPage]); }, [pageSize, currentPage]);
const columns = [ const columns = [
@ -73,6 +70,7 @@ function Member(props) {
title="编辑用户" title="编辑用户"
onFinish={onFinish} onFinish={onFinish}
key="editUser" key="editUser"
organization={organization}
/>) />)
options.push( options.push(
<Popconfirm <Popconfirm
@ -149,6 +147,7 @@ function Member(props) {
title="新建用户" title="新建用户"
onFinish={onFinish} onFinish={onFinish}
key="addModel" key="addModel"
organization={organization}
/> />
</Col> </Col>
<Col span={12} style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}> <Col span={12} style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
@ -213,14 +212,15 @@ function Member(props) {
function mapStateToProps(state) { function mapStateToProps(state) {
const { const {
auth, global, datasources, member auth, global, datasources, member, organization
} = state; } = state;
return { return {
loading: datasources.isRequesting, loading: datasources.isRequesting,
clientHeight: global.clientHeight, clientHeight: global.clientHeight,
actions: global.actions, actions: global.actions,
member: member?.data || {}, member: member?.data || {},
user: auth.user user: auth.user,
organization: organization?.data?.rows || [],
}; };
} }

18
web/client/src/sections/metadataManagement/components/resourceCatalogModal.js

@ -1,8 +1,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Modal, Input, Form, message } from 'antd'; import { Modal, Input, Form, message, Select } from 'antd';
const { TextArea } = Input; const { TextArea } = Input;
const ResourceCatalogModal = (props) => { const ResourceCatalogModal = (props) => {
const { resourceCatalog, onConfirm, onCancel, editData } = props; const { resourceCatalog, onConfirm, onCancel, editData, organization } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
useEffect(() => { useEffect(() => {
}, []); }, []);
@ -73,6 +73,20 @@ const ResourceCatalogModal = (props) => {
})]}> })]}>
<Input style={{ width: '90%' }} placeholder={`请输入代码`} /> <Input style={{ width: '90%' }} placeholder={`请输入代码`} />
</Form.Item> </Form.Item>
<Form.Item
label='机构'
name='orgId'
disabled={editData?.orgId}
rules={[{ required: true, message: '' }]}
>
<Select style={{ width: '90%' }} placeholder={`请输入代码`} >
{
organization?.map(s => (<Select.Option value={s.id}>{s.name}</Select.Option>))
}
</Select>
</Form.Item>
<Form.Item <Form.Item
label='描述' label='描述'
name='description' name='description'

12
web/client/src/sections/metadataManagement/containers/latestMetadata.js

@ -10,7 +10,7 @@ let expandedKeysData = [];
let allTreeNodeKeys = []; let allTreeNodeKeys = [];
const LatestMetadata = (props) => { const LatestMetadata = (props) => {
const { user, dispatch, actions, history, clientHeight, resourceCatalog, isRequesting, location, match } = props; const { user, dispatch, actions, history, clientHeight, resourceCatalog, isRequesting, location, match, organization } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const [resourceCatalogData, setResourceCatalogData] = useState([]); const [resourceCatalogData, setResourceCatalogData] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]); const [selectedKeys, setSelectedKeys] = useState([]);
@ -30,6 +30,7 @@ const LatestMetadata = (props) => {
useEffect(() => { useEffect(() => {
const jumpSelectedKey = sessionStorage.getItem('jumpSelectedKey') || null; const jumpSelectedKey = sessionStorage.getItem('jumpSelectedKey') || null;
initData(true, jumpSelectedKey); initData(true, jumpSelectedKey);
dispatch(actions.organization.getOrganizationList());
}, []) }, [])
const initData = (configRefresh, jumpSelectedKey) => { const initData = (configRefresh, jumpSelectedKey) => {
dispatch(metadataManagement.getResourceCatalog()).then(res => { dispatch(metadataManagement.getResourceCatalog()).then(res => {
@ -241,18 +242,21 @@ const LatestMetadata = (props) => {
resourceCatalog={resourceCatalog} resourceCatalog={resourceCatalog}
editData={editData} editData={editData}
onCancel={() => setModalVisible(false)} onCancel={() => setModalVisible(false)}
onConfirm={onConfirm} /> : '' onConfirm={onConfirm}
organization={organization}
/> : ''
} }
</Spin> </Spin>
} }
function mapStateToProps(state) { function mapStateToProps(state) {
const { global, auth, resourceCatalog } = state; const { global, auth, resourceCatalog, organization } = state;
return { return {
user: auth.user, user: auth.user,
actions: global.actions, actions: global.actions,
clientHeight: global.clientHeight, clientHeight: global.clientHeight,
resourceCatalog: resourceCatalog?.data || [], resourceCatalog: resourceCatalog?.data || [],
isRequesting: resourceCatalog.isRequesting isRequesting: resourceCatalog.isRequesting,
organization: organization?.data?.rows || [],
}; };
} }
export default connect(mapStateToProps)(LatestMetadata) export default connect(mapStateToProps)(LatestMetadata)

Loading…
Cancel
Save