peng.peng 1 year ago
parent
commit
ace6c7830e
  1. 6
      api/app/lib/controllers/resourceConsumption/index.js
  2. 2
      api/app/lib/index.js
  3. 4
      api/app/lib/routes/latestMetadata/index.js
  4. BIN
      web/client/assets/files/common/1698915773497_5.jpg
  5. 5
      web/client/src/sections/metadataManagement/components/businessDatabaseModal.js
  6. 11
      web/client/src/sections/metadataManagement/containers/businessDatabaseTable.js
  7. 11
      web/client/src/sections/metadataManagement/containers/businessFilesTable.js
  8. 11
      web/client/src/sections/metadataManagement/containers/businessMetadata.js
  9. 11
      web/client/src/sections/metadataManagement/containers/businessRestapisTable.js
  10. 8
      web/client/src/sections/metadataManagement/containers/businessTab.js
  11. 11
      web/client/src/sections/metadataManagement/containers/databasesTable.js
  12. 8
      web/client/src/sections/metadataManagement/containers/filesTable.js
  13. 20
      web/client/src/sections/metadataManagement/containers/latestMetadata.js
  14. 4
      web/client/src/sections/metadataManagement/containers/metadataDetails.js
  15. 8
      web/client/src/sections/metadataManagement/containers/metadataTab.js
  16. 8
      web/client/src/sections/metadataManagement/containers/restapisTable.js
  17. 13
      web/client/src/sections/resourceConsumption/actions/approve.js
  18. 152
      web/client/src/sections/resourceConsumption/containers/myApplication.js

6
api/app/lib/controllers/resourceConsumption/index.js

@ -23,6 +23,10 @@ function getApproveList(opts) {
model: models.User, model: models.User,
as: 'approveUser', as: 'approveUser',
attributes: ['id', 'name'] attributes: ['id', 'name']
}, {
model: models.MetadataFile,
as: 'metadataFile',
attributes: ['id', 'fileName']
}, },
{ {
model: models.MetadataDatabase, model: models.MetadataDatabase,
@ -38,7 +42,7 @@ function getApproveList(opts) {
}, },
{ {
model: models.RestfulApi, model: models.RestfulApi,
attributes: ['id', 'name'], // attributes: ['id', 'name'],
include: [{ include: [{
model: models.ResourceCatalog, model: models.ResourceCatalog,
attributes: ['id', 'name'], attributes: ['id', 'name'],

2
api/app/lib/index.js

@ -113,4 +113,6 @@ module.exports.models = function (dc) {
MetadataFile.belongsTo(ResourceCatalog, { foreignKey: 'catalog', targetKey: 'id' }); MetadataFile.belongsTo(ResourceCatalog, { foreignKey: 'catalog', targetKey: 'id' });
ResourceCatalog.belongsTo(Organization, { foreignKey: 'orgId', targetKey: 'id' }); ResourceCatalog.belongsTo(Organization, { foreignKey: 'orgId', targetKey: 'id' });
ResourceConsumption.belongsTo(MetadataFile, { foreignKey: 'resourceId', targetKey: 'id' });
}; };

4
api/app/lib/routes/latestMetadata/index.js

@ -107,7 +107,7 @@ module.exports = function (app, router, opts) {
tokens = s.token tokens = s.token
} }
}) })
if (tokens && tokens == token) { if (tokens && (tokens == token || tokens == token[1] || tokens == token[0])) {
if (findOne.enabled) { if (findOne.enabled) {
const pool = new Pool({ const pool = new Pool({
user: ctx.fs.dc.orm.config.username, user: ctx.fs.dc.orm.config.username,
@ -208,7 +208,7 @@ module.exports = function (app, router, opts) {
} }
}) })
if (tokens && tokens == token) { if (tokens && (tokens == token || tokens == token[1] || tokens == token[0])) {
if (findOne.enabled) { if (findOne.enabled) {
const pool = new Pool({ const pool = new Pool({
user: ctx.fs.dc.orm.config.username, user: ctx.fs.dc.orm.config.username,

BIN
web/client/assets/files/common/1698915773497_5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

5
web/client/src/sections/metadataManagement/components/businessDatabaseModal.js

@ -6,7 +6,7 @@ const basicInfo = [{ name: '元数据名称:', key: 'name' },
{ name: '上下文路径:', key: 'path' }, { name: '上下文路径:', key: 'path' },
{ name: '元数据详情:', key: 'description' }]; { name: '元数据详情:', key: 'description' }];
const BusinessDatabaseModal = (props) => { const BusinessDatabaseModal = (props) => {
const { onConfirm, onCancel, editData, metadataModels, resourceCatalogPath, businessType } = props; const { onConfirm, onCancel, editData, metadataModels, resourceCatalogPath, businessType, isAdmin } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
useEffect(() => { useEffect(() => {
}, []); }, []);
@ -66,6 +66,7 @@ const BusinessDatabaseModal = (props) => {
return ( return (
<Modal title={editData.title} open={true} destroyOnClose <Modal title={editData.title} open={true} destroyOnClose
okText='确定' width={800} okText='确定' width={800}
footer={!isAdmin ? null : undefined}
onOk={() => handleOk(null)} onOk={() => handleOk(null)}
onCancel={onCancel}> onCancel={onCancel}>
{editData.record && editData.record.businessMetadata.length ? {editData.record && editData.record.businessMetadata.length ?
@ -87,7 +88,7 @@ const BusinessDatabaseModal = (props) => {
({ getFieldValue, validateFields }) => ({ ({ getFieldValue, validateFields }) => ({
validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, item.name) } validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, item.name) }
})]}> })]}>
<Input style={{ width: '90%' }} placeholder={`请输入${item.name}`} /> <Input style={{ width: '90%' }} placeholder={`请输入${item.name}`} disabled={!isAdmin} />
</Form.Item> </Form.Item>
)} )}
</Form> </Form>

11
web/client/src/sections/metadataManagement/containers/businessDatabaseTable.js

@ -6,7 +6,7 @@ import FileSaver from 'file-saver';
import BusinessDatabaseModal from '../components/businessDatabaseModal'; import BusinessDatabaseModal from '../components/businessDatabaseModal';
const BusinessDatabaseTable = (props) => { const BusinessDatabaseTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, const { user, dispatch, actions, clientHeight, resourceCatalogId,
resourceCatalogPath, isRequesting, metadataModels } = props; resourceCatalogPath, isRequesting, metadataModels, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
@ -201,13 +201,13 @@ const BusinessDatabaseTable = (props) => {
if (record.businessMetadataDatabases.length) { if (record.businessMetadataDatabases.length) {
return <div> return <div>
<a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a> <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a>
<Popconfirm {isAdmin && <Popconfirm
title="是否确认删除该业务元数据?" title="是否确认删除该业务元数据?"
onConfirm={() => confirmDelete(record.businessMetadataDatabases[0].id)} onConfirm={() => confirmDelete(record.businessMetadataDatabases[0].id)}
> <a style={{ marginLeft: 10 }}>删除</a></Popconfirm> > <a style={{ marginLeft: 10 }}>删除</a></Popconfirm>}
</div> </div>
} else } else
return <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a> return isAdmin && <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a>
} }
}]; }];
@ -329,7 +329,8 @@ const BusinessDatabaseTable = (props) => {
editData={editData} editData={editData}
onCancel={() => setModalVisible(false)} onCancel={() => setModalVisible(false)}
onConfirm={onConfirm} onConfirm={onConfirm}
resourceCatalogPath={resourceCatalogPath} /> : '' resourceCatalogPath={resourceCatalogPath}
isAdmin={isAdmin} /> : ''
} }
</Spin > </Spin >
} }

11
web/client/src/sections/metadataManagement/containers/businessFilesTable.js

@ -6,7 +6,7 @@ import FileSaver from 'file-saver';
import BusinessDatabaseModal from '../components/businessDatabaseModal'; import BusinessDatabaseModal from '../components/businessDatabaseModal';
const BusinessFilesTable = (props) => { const BusinessFilesTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, const { user, dispatch, actions, clientHeight, resourceCatalogId,
resourceCatalogPath, isRequesting, metadataModels } = props; resourceCatalogPath, isRequesting, metadataModels, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
@ -190,13 +190,13 @@ const BusinessFilesTable = (props) => {
if (record.businessMetadataFiles.length) { if (record.businessMetadataFiles.length) {
return <div> return <div>
<a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a> <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a>
<Popconfirm {isAdmin && <Popconfirm
title="是否确认删除该业务元数据?" title="是否确认删除该业务元数据?"
onConfirm={() => confirmDelete(record.businessMetadataFiles[0].id)} onConfirm={() => confirmDelete(record.businessMetadataFiles[0].id)}
> <a style={{ marginLeft: 10 }}>删除</a></Popconfirm> > <a style={{ marginLeft: 10 }}>删除</a></Popconfirm>}
</div> </div>
} else } else
return <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a> return isAdmin && <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a>
} }
}]; }];
@ -317,7 +317,8 @@ const BusinessFilesTable = (props) => {
onCancel={() => setModalVisible(false)} onCancel={() => setModalVisible(false)}
onConfirm={onConfirm} onConfirm={onConfirm}
resourceCatalogPath={resourceCatalogPath} resourceCatalogPath={resourceCatalogPath}
businessType='文件' /> : '' businessType='文件'
isAdmin={isAdmin} /> : ''
} }
</Spin > </Spin >
} }

11
web/client/src/sections/metadataManagement/containers/businessMetadata.js

@ -4,10 +4,12 @@ import { Spin, Row, Col, Tree, Tooltip, Input } from 'antd';
import BusinessTab from './businessTab'; import BusinessTab from './businessTab';
let expandedKeysData = []; let expandedKeysData = [];
let allTreeNodeKeys = []; let allTreeNodeKeys = [];
let resourceCatalogRawData = [];
const BusinessMetadata = (props) => { const BusinessMetadata = (props) => {
const { user, dispatch, actions, clientHeight, isRequesting, resourceCatalog } = props; const { user, dispatch, actions, clientHeight, isRequesting, resourceCatalog } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const [isAdmin, setIsAdmin] = useState(false);
const [resourceCatalogData, setResourceCatalogData] = useState([]); const [resourceCatalogData, setResourceCatalogData] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]); const [selectedKeys, setSelectedKeys] = useState([]);
const [expandedKeys, setExpandedKeys] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]);
@ -23,6 +25,7 @@ const BusinessMetadata = (props) => {
dispatch(metadataManagement.getResourceCatalog()).then(res => { dispatch(metadataManagement.getResourceCatalog()).then(res => {
const { data } = res.payload; const { data } = res.payload;
if (res.success) { if (res.success) {
resourceCatalogRawData = data;
allTreeNodeKeys = [] allTreeNodeKeys = []
const resourceCatalogData = getTreeNodeData(data, null, 'rc', [], null); const resourceCatalogData = getTreeNodeData(data, null, 'rc', [], null);
setResourceCatalogData(resourceCatalogData); setResourceCatalogData(resourceCatalogData);
@ -44,7 +47,10 @@ const BusinessMetadata = (props) => {
const keyArr = selectedData[0].split('-'); const keyArr = selectedData[0].split('-');
keyArr.shift();//['rc-2-5']->返回'rc';keyArr:['2','5'] keyArr.shift();//['rc-2-5']->返回'rc';keyArr:['2','5']
const allExpandedKeys = allTreeNodeKeys.filter(k => keyArr.includes(k.id.toString())); const allExpandedKeys = allTreeNodeKeys.filter(k => keyArr.includes(k.id.toString()));
setResourceCatalogId(keyArr.pop()); const resourceCatalogId = keyArr.pop();
setResourceCatalogId(resourceCatalogId);
setIsAdmin(user?.username === 'SuperAdmin'
|| (user?.role === '系统管理员' && user?.orgId == resourceCatalogRawData.find(a => a.id == resourceCatalogId)?.orgId));
setResourceCatalogKey(selectedData[0]); setResourceCatalogKey(selectedData[0]);
const resourceCatalogPath = allExpandedKeys.map(a => a.name); const resourceCatalogPath = allExpandedKeys.map(a => a.name);
setResourceCatalogPath(resourceCatalogPath); setResourceCatalogPath(resourceCatalogPath);
@ -161,7 +167,8 @@ const BusinessMetadata = (props) => {
<Col style={{ width: 'calc(100% - 240px)' }}> <Col style={{ width: 'calc(100% - 240px)' }}>
<BusinessTab resourceCatalogId={resourceCatalogId} <BusinessTab resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogKey={resourceCatalogKey}
resourceCatalogPath={resourceCatalogPath} /> resourceCatalogPath={resourceCatalogPath}
isAdmin={isAdmin} />
</Col> </Col>
</Row> </Row>
</Spin> </Spin>

11
web/client/src/sections/metadataManagement/containers/businessRestapisTable.js

@ -6,7 +6,7 @@ import FileSaver from 'file-saver';
import BusinessDatabaseModal from '../components/businessDatabaseModal'; import BusinessDatabaseModal from '../components/businessDatabaseModal';
const BusinessFilesTable = (props) => { const BusinessFilesTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, const { user, dispatch, actions, clientHeight, resourceCatalogId,
resourceCatalogPath, isRequesting, metadataModels } = props; resourceCatalogPath, isRequesting, metadataModels, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
@ -190,13 +190,13 @@ const BusinessFilesTable = (props) => {
if (record.businessMetadataRestapis.length) { if (record.businessMetadataRestapis.length) {
return <div> return <div>
<a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a> <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, false)}>查看</a>
<Popconfirm {isAdmin && <Popconfirm
title="是否确认删除该业务元数据?" title="是否确认删除该业务元数据?"
onConfirm={() => confirmDelete(record.businessMetadataRestapis[0].id)} onConfirm={() => confirmDelete(record.businessMetadataRestapis[0].id)}
> <a style={{ marginLeft: 10 }}>删除</a></Popconfirm> > <a style={{ marginLeft: 10 }}>删除</a></Popconfirm>}
</div> </div>
} else } else
return <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a> return isAdmin && <a style={{ marginLeft: 10 }} onClick={() => onAdd(record, true)}>新建</a>
} }
}]; }];
@ -317,7 +317,8 @@ const BusinessFilesTable = (props) => {
onCancel={() => setModalVisible(false)} onCancel={() => setModalVisible(false)}
onConfirm={onConfirm} onConfirm={onConfirm}
resourceCatalogPath={resourceCatalogPath} resourceCatalogPath={resourceCatalogPath}
businessType='接口' /> : '' businessType='接口'
isAdmin={isAdmin} /> : ''
} }
</Spin > </Spin >
} }

8
web/client/src/sections/metadataManagement/containers/businessTab.js

@ -6,7 +6,7 @@ import BusinessFilesTable from './businessFilesTable';
import BusinessRestapisTable from './businessRestapisTable'; import BusinessRestapisTable from './businessRestapisTable';
const BusinessTab = (props) => { const BusinessTab = (props) => {
const { resourceCatalogId, resourceCatalogKey, resourceCatalogPath, actions, dispatch } = props; const { resourceCatalogId, resourceCatalogKey, resourceCatalogPath, actions, dispatch, isAdmin } = props;
const [activeKey, setActiveKey] = useState('databases'); const [activeKey, setActiveKey] = useState('databases');
useEffect(() => { useEffect(() => {
setActiveKey('databases'); setActiveKey('databases');
@ -36,11 +36,11 @@ const BusinessTab = (props) => {
</Tabs> </Tabs>
{ {
activeKey === 'databases' && resourceCatalogId ? <BusinessDatabaseTable resourceCatalogId={resourceCatalogId} activeKey === 'databases' && resourceCatalogId ? <BusinessDatabaseTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} isAdmin={isAdmin} /> :
activeKey === 'files' && resourceCatalogId ? <BusinessFilesTable resourceCatalogId={resourceCatalogId} activeKey === 'files' && resourceCatalogId ? <BusinessFilesTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} isAdmin={isAdmin} /> :
activeKey === 'restapis' && resourceCatalogId ? <BusinessRestapisTable resourceCatalogId={resourceCatalogId} activeKey === 'restapis' && resourceCatalogId ? <BusinessRestapisTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} isAdmin={isAdmin} /> :
null null
} }
</div> </div>

11
web/client/src/sections/metadataManagement/containers/databasesTable.js

@ -11,7 +11,7 @@ import MetadataResourceModal from '../components/metadataResourceModal';
import ReleaseModal from '../components/releaseModal'; import ReleaseModal from '../components/releaseModal';
const DatabaseTable = (props) => { const DatabaseTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey, const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey, isAdmin,
resourceCatalogPath, isRequesting, metadataModels, setView, tagList, metadataResourceApplications, params } = props; resourceCatalogPath, isRequesting, metadataModels, setView, tagList, metadataResourceApplications, params } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
@ -182,7 +182,7 @@ const DatabaseTable = (props) => {
ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id);
return <ButtonGroup> return <ButtonGroup>
<a onClick={() => onView(record)}>查看</a> <a onClick={() => onView(record)}>查看</a>
{user.role == '数据消费者' ? null : {!isAdmin ? null :
<> <>
<a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a> <a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a>
<Popconfirm <Popconfirm
@ -192,11 +192,10 @@ const DatabaseTable = (props) => {
{record.type === '表' ? <a style={{ marginLeft: 10 }} onClick={() => marking(record.id)}>打标</a> : null} {record.type === '表' ? <a style={{ marginLeft: 10 }} onClick={() => marking(record.id)}>打标</a> : null}
</> </>
} }
{isAdmin ? null : record.type === '表' ? resourceApplicationsRecords.length === 0 ?
{user.role !== '数据消费者' ? null : record.type === '表' ? resourceApplicationsRecords.length === 0 ?
<a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> : <a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> :
<span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span> : null} <span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span> : null}
{user.role == '数据消费者' ? null : {!isAdmin ? null :
record.type === '表' ? record.type === '表' ?
<a style={{ marginLeft: 10 }} onClick={() => servicePublication(record)}>REST服务发布</a> : null <a style={{ marginLeft: 10 }} onClick={() => servicePublication(record)}>REST服务发布</a> : null
} }
@ -272,7 +271,7 @@ const DatabaseTable = (props) => {
return <Spin spinning={isRequesting}> return <Spin spinning={isRequesting}>
<Row style={{ marginBottom: 16 }}> <Row style={{ marginBottom: 16 }}>
<Col span={12}> <Col span={12}>
{user.role == '数据消费者' ? null : <> {!isAdmin ? null : <>
<Button type='primary' onClick={() => { <Button type='primary' onClick={() => {
dispatch(metadataManagement.getMetadataModels({ modelTypes: ModelTypes.join(',') })).then(res => { dispatch(metadataManagement.getMetadataModels({ modelTypes: ModelTypes.join(',') })).then(res => {
if (res.success) { if (res.success) {

8
web/client/src/sections/metadataManagement/containers/filesTable.js

@ -12,7 +12,7 @@ import { RouteTable } from '$utils'
const FilesTable = (props) => { const FilesTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey, const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey,
isRequesting, metadataModels, tagList, metadataResourceApplications, params } = props; isRequesting, metadataModels, tagList, metadataResourceApplications, params, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' }; const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
@ -207,7 +207,7 @@ const FilesTable = (props) => {
let resourceApplicationsRecords = metadataResourceApplications.filter(ra => let resourceApplicationsRecords = metadataResourceApplications.filter(ra =>
ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id && !!record.token); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id && !!record.token);
return <ButtonGroup> return <ButtonGroup>
{user.role == '数据消费者' ? null : {!isAdmin ? null :
<> <>
<a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a> <a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a>
<Popconfirm <Popconfirm
@ -218,7 +218,7 @@ const FilesTable = (props) => {
</> </>
} }
{user.role == '系统管理员' ? '' : resourceApplicationsRecords.length === 0 ? {isAdmin ? '' : resourceApplicationsRecords.length === 0 ?
<a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> : <a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> :
<span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span>} <span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span>}
</ButtonGroup> </ButtonGroup>
@ -305,7 +305,7 @@ const FilesTable = (props) => {
return <Spin spinning={isRequesting}> return <Spin spinning={isRequesting}>
<Row style={{ marginBottom: 16 }}> <Row style={{ marginBottom: 16 }}>
<Col span={12}> <Col span={12}>
{user.role == '数据消费者' ? null : <> {!isAdmin ? null : <>
<Button type='primary' onClick={() => { <Button type='primary' onClick={() => {
dispatch(metadataManagement.getMetadataModels({ modelTypes: '文件' })).then(res => { dispatch(metadataManagement.getMetadataModels({ modelTypes: '文件' })).then(res => {
if (res.success) { if (res.success) {

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

@ -8,10 +8,12 @@ import MetadataTab from './metadataTab';
import MetadataDetails from './metadataDetails'; import MetadataDetails from './metadataDetails';
let expandedKeysData = []; let expandedKeysData = [];
let allTreeNodeKeys = []; let allTreeNodeKeys = [];
let resourceCatalogRawData = [];
const LatestMetadata = (props) => { const LatestMetadata = (props) => {
const { user, dispatch, actions, history, clientHeight, resourceCatalog, isRequesting, location, match, organization } = props; const { user, dispatch, actions, history, clientHeight, resourceCatalog, isRequesting, location, match, organization } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const [isAdmin, setIsAdmin] = useState(false);
const [resourceCatalogData, setResourceCatalogData] = useState([]); const [resourceCatalogData, setResourceCatalogData] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]); const [selectedKeys, setSelectedKeys] = useState([]);
const [expandedKeys, setExpandedKeys] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]);
@ -36,6 +38,7 @@ const LatestMetadata = (props) => {
dispatch(metadataManagement.getResourceCatalog()).then(res => { dispatch(metadataManagement.getResourceCatalog()).then(res => {
const { data } = res.payload; const { data } = res.payload;
if (res.success) { if (res.success) {
resourceCatalogRawData = data;
allTreeNodeKeys = [] allTreeNodeKeys = []
const resourceCatalogData = getTreeNodeData(data, null, 'rc', [], null); const resourceCatalogData = getTreeNodeData(data, null, 'rc', [], null);
setResourceCatalogData(resourceCatalogData); setResourceCatalogData(resourceCatalogData);
@ -47,6 +50,8 @@ const LatestMetadata = (props) => {
params?.catalogKey ? setSelectedKeys([params?.catalogKey]) : setSelectedKeys(expandedKeysData); params?.catalogKey ? setSelectedKeys([params?.catalogKey]) : setSelectedKeys(expandedKeysData);
params?.catalogKey ? setExpandedKeys(getExpandKeys([params?.catalogKey])) : setExpandedKeys(expandedKeys); params?.catalogKey ? setExpandedKeys(getExpandKeys([params?.catalogKey])) : setExpandedKeys(expandedKeys);
params?.treeId && setResourceCatalogId(params?.treeId); params?.treeId && setResourceCatalogId(params?.treeId);
params?.treeId && params?.treeId && setIsAdmin(user?.username === 'SuperAdmin'
|| (user?.role === '系统管理员' && user?.orgId == resourceCatalogRawData.find(a => a.id == params?.treeId)?.orgId));
expandedKeysData = []; expandedKeysData = [];
} }
} else { } else {
@ -60,7 +65,10 @@ const LatestMetadata = (props) => {
const keyArr = selectedData[0].split('-'); const keyArr = selectedData[0].split('-');
keyArr.shift();//['rc-2-5']->返回'rc';keyArr:['2','5'] keyArr.shift();//['rc-2-5']->返回'rc';keyArr:['2','5']
const allExpandedKeys = allTreeNodeKeys.filter(k => keyArr.includes(k.id.toString())); const allExpandedKeys = allTreeNodeKeys.filter(k => keyArr.includes(k.id.toString()));
!params?.treeId && setResourceCatalogId(keyArr.pop()); const resourceCatalogId = keyArr.pop();
!params?.treeId && setResourceCatalogId(resourceCatalogId);
!params?.treeId && setIsAdmin(user?.username === 'SuperAdmin'
|| (user?.role === '系统管理员' && user?.orgId == resourceCatalogRawData.find(a => a.id == resourceCatalogId)?.orgId));
setResourceCatalogKey(selectedData[0]); setResourceCatalogKey(selectedData[0]);
const resourceCatalogPath = allExpandedKeys.map(a => a.name); const resourceCatalogPath = allExpandedKeys.map(a => a.name);
setResourceCatalogPath(resourceCatalogPath); setResourceCatalogPath(resourceCatalogPath);
@ -104,6 +112,7 @@ const LatestMetadata = (props) => {
const renderTreeNode = (ds, dataSource) => { const renderTreeNode = (ds, dataSource) => {
return <div className={theStyle.icon} style={{ width: 180 }}> return <div className={theStyle.icon} style={{ width: 180 }}>
{setTreeNodeTitle(ds.name)} {setTreeNodeTitle(ds.name)}
{(user?.username === 'SuperAdmin' || (user?.role === '系统管理员' && user?.orgId == ds?.orgId)) && <>
<EditOutlined title='修改' className={theStyle.tip} onClick={() => { <EditOutlined title='修改' className={theStyle.tip} onClick={() => {
let record = JSON.parse(JSON.stringify(ds)); let record = JSON.parse(JSON.stringify(ds));
let parentData = dataSource.filter(rc => rc.id === record.parent); let parentData = dataSource.filter(rc => rc.id === record.parent);
@ -122,9 +131,10 @@ const LatestMetadata = (props) => {
<MinusCircleOutlined title='删除' className={theStyle.tip} /> <MinusCircleOutlined title='删除' className={theStyle.tip} />
</Popconfirm> </Popconfirm>
<PlusCircleOutlined title='新建' className={theStyle.tip} onClick={() => { <PlusCircleOutlined title='新建' className={theStyle.tip} onClick={() => {
setEditData({ record: { parent: ds.id, parentName: ds.name }, title: '新建子类', child: true, add: true }); setEditData({ record: { parent: ds.id, parentName: ds.name, orgId: ds?.orgId }, title: '新建子类', child: true, add: true });
setModalVisible(true); setModalVisible(true);
}} /> }} />
</>}
</div > </div >
}; };
//新建、修改 //新建、修改
@ -194,7 +204,7 @@ const LatestMetadata = (props) => {
allowClear onChange={onChangeSearch} allowClear onChange={onChangeSearch}
onKeyPress={onChangeSearch} /> onKeyPress={onChangeSearch} />
{user?.role == '系统管理员' && <Button type='primary' style={{ marginBottom: 16 }} onClick={() => { {user?.role == '系统管理员' && <Button type='primary' style={{ marginBottom: 16 }} onClick={() => {
setEditData({ title: '新建资源目录', add: true }); setEditData({ title: '新建资源目录', add: true, record: { orgId: user?.orgId } });
setModalVisible(true); setModalVisible(true);
}}>新建资源目录</Button>} }}>新建资源目录</Button>}
<Tree <Tree
@ -222,11 +232,13 @@ const LatestMetadata = (props) => {
<MetadataDetails resourceCatalogId={resourceCatalogId} <MetadataDetails resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogKey={resourceCatalogKey}
resourceCatalogPath={resourceCatalogPath} resourceCatalogPath={resourceCatalogPath}
match={match} /> : match={match}
isAdmin={isAdmin} /> :
<MetadataTab resourceCatalogId={resourceCatalogId} <MetadataTab resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogKey={resourceCatalogKey}
resourceCatalogPath={resourceCatalogPath} resourceCatalogPath={resourceCatalogPath}
params={params} params={params}
isAdmin={isAdmin}
/> />
// <MetadataTab resourceCatalogId={params?.treeId} // <MetadataTab resourceCatalogId={params?.treeId}
// resourceCatalogKey={params?.catalogKey} // resourceCatalogKey={params?.catalogKey}

4
web/client/src/sections/metadataManagement/containers/metadataDetails.js

@ -7,7 +7,7 @@ import MetadataDatabaseModal from '../components/metadataDatabaseModal';
import { ModelTypes, ConfigurableTypes } from '../constants/index'; import { ModelTypes, ConfigurableTypes } from '../constants/index';
const MetadataDetails = (props) => { const MetadataDetails = (props) => {
const { user, actions, dispatch, clientHeight, metadataModels, isRequesting, resourceCatalogPath, match } = props; const { user, actions, dispatch, clientHeight, metadataModels, isRequesting, resourceCatalogPath, match, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const [activeKey, setActiveKey] = useState('info'); const [activeKey, setActiveKey] = useState('info');
const [databasesRecord, setDatabasesRecord] = useState(null); const [databasesRecord, setDatabasesRecord] = useState(null);
@ -108,7 +108,7 @@ const MetadataDetails = (props) => {
return databasesRecord && (ConfigurableTypes['表'].includes(databasesRecord.type) || databasesRecord.type === '视图') ? null : <Spin spinning={isRequesting}> return databasesRecord && (ConfigurableTypes['表'].includes(databasesRecord.type) || databasesRecord.type === '视图') ? null : <Spin spinning={isRequesting}>
<div style={{ marginBottom: 16 }}> <div style={{ marginBottom: 16 }}>
{user?.role == '系统管理员' && <Button type='primary' onClick={() => { {isAdmin && <Button type='primary' onClick={() => {
setEditData({ add: true, title: '新建库表元数据', record: { path: '/' + resourceCatalogPath.join('/'), type: ConfigurableTypes[databasesRecord.type][0] } }); setEditData({ add: true, title: '新建库表元数据', record: { path: '/' + resourceCatalogPath.join('/'), type: ConfigurableTypes[databasesRecord.type][0] } });
setModalVisible(true); setModalVisible(true);
}}>新建</Button>} }}>新建</Button>}

8
web/client/src/sections/metadataManagement/containers/metadataTab.js

@ -7,7 +7,7 @@ import RestapisTable from './restapisTable';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
const MetadataTab = (props) => { const MetadataTab = (props) => {
const { resourceCatalogId, resourceCatalogKey, resourceCatalogPath, actions, dispatch, params } = props; const { resourceCatalogId, resourceCatalogKey, resourceCatalogPath, actions, dispatch, params, isAdmin } = props;
const [activeKey, setActiveKey] = useState(params?.type || 'databases'); const [activeKey, setActiveKey] = useState(params?.type || 'databases');
useEffect(() => { useEffect(() => {
if (!params?.type) if (!params?.type)
@ -42,11 +42,11 @@ const MetadataTab = (props) => {
</Tabs> </Tabs>
{ {
activeKey === 'databases' && resourceCatalogId ? <DatabaseTable params={params} resourceCatalogId={resourceCatalogId} activeKey === 'databases' && resourceCatalogId ? <DatabaseTable params={params} resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} setView={onView} /> : resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} setView={onView} isAdmin={isAdmin} /> :
activeKey === 'files' && resourceCatalogId ? <FilesTable params={params} resourceCatalogId={resourceCatalogId} activeKey === 'files' && resourceCatalogId ? <FilesTable params={params} resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} isAdmin={isAdmin} /> :
activeKey === 'restapis' && resourceCatalogId ? < RestapisTable params={params} resourceCatalogId={resourceCatalogId} activeKey === 'restapis' && resourceCatalogId ? < RestapisTable params={params} resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : null resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} isAdmin={isAdmin} /> : null
} }
</div> </div>
} }

8
web/client/src/sections/metadataManagement/containers/restapisTable.js

@ -8,7 +8,7 @@ import MetadataResourceModal from '../components/metadataResourceModal';
const RestapisTable = (props) => { const RestapisTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey, const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey,
isRequesting, metadataModels, tagList, metadataResourceApplications, params } = props; isRequesting, metadataModels, tagList, metadataResourceApplications, params, isAdmin } = props;
const { metadataManagement } = actions; const { metadataManagement } = actions;
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
const [tableDataCount, setTableDataCount] = useState(0);//Table数据 const [tableDataCount, setTableDataCount] = useState(0);//Table数据
@ -143,7 +143,7 @@ const RestapisTable = (props) => {
let resourceApplicationsRecords = metadataResourceApplications.filter(ra => let resourceApplicationsRecords = metadataResourceApplications.filter(ra =>
ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id && !!record.token); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id && !!record.token);
return <ButtonGroup> return <ButtonGroup>
{user.role == '数据消费者' ? null : {!isAdmin ? null :
<> <>
<a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a> <a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a>
<Popconfirm <Popconfirm
@ -154,7 +154,7 @@ const RestapisTable = (props) => {
</> </>
} }
{user.role == '系统管理员' ? '' : resourceApplicationsRecords.length === 0 ? {isAdmin ? '' : resourceApplicationsRecords.length === 0 ?
<a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> : <a style={{ marginLeft: 10 }} onClick={() => applyResources(record)}>申请资源</a> :
<span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span>} <span style={{ marginLeft: 10, color: "#c0c0c0" }} title='已存在资源申请'>申请资源</span>}
</ButtonGroup> </ButtonGroup>
@ -187,7 +187,7 @@ const RestapisTable = (props) => {
return <Spin spinning={isRequesting}> return <Spin spinning={isRequesting}>
<Row style={{ marginBottom: 16 }}> <Row style={{ marginBottom: 16 }}>
<Col span={12}> <Col span={12}>
{user.role == '数据消费者' ? null : <> <Button type='primary' onClick={() => { {!isAdmin ? null : <> <Button type='primary' onClick={() => {
dispatch(metadataManagement.getMetadataModels({ modelTypes: '接口' })).then(res => { dispatch(metadataManagement.getMetadataModels({ modelTypes: '接口' })).then(res => {
if (res.success) { if (res.success) {
setEditData({ add: true, title: '新建接口元数据', record: {} }); setEditData({ add: true, title: '新建接口元数据', record: {} });

13
web/client/src/sections/resourceConsumption/actions/approve.js

@ -27,3 +27,16 @@ export function postApprove (data = {}) {
reducer: { name: '' } reducer: { name: '' }
}); });
} }
export function getRestData (query = {}) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_REST_DATA',
url: query?.url,
msg: { error: '获取rest服务请求数据失败' },
reducer: { name: '' }
});
}

152
web/client/src/sections/resourceConsumption/containers/myApplication.js

@ -1,12 +1,13 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import moment from 'moment'; import moment from 'moment';
import { useFsRequest, ApiTable } from '$utils';
import ApproveModal from '../components/approveModal'; import ApproveModal from '../components/approveModal';
import { downloadImg, markRedKeywords } from '../../resourceRetrieval/utils/index'
import { Tabs, Form, Input, DatePicker, Button, Table, Select, message } from 'antd';
import xlsx from 'xlsx';
import { Tabs, Form, Input, DatePicker, Button, Table, Select } from 'antd';
import { v1 } from 'uuid';
function MyApplication ({ loading, clientHeight, actions, dispatch, user }) { function MyApplication ({ loading, clientHeight, actions, dispatch, user }) {
@ -15,6 +16,10 @@ function MyApplication({ loading, clientHeight, actions, dispatch, user }) {
const [query, setQuery] = useState({ page: 0, limit: 10 }); const [query, setQuery] = useState({ page: 0, limit: 10 });
const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); const [proTableList, setProTableList] = useState({ rows: [], count: 0 });
const [formData, setFormData] = useState({}) const [formData, setFormData] = useState({})
const [searchDataId, setSearchDataId] = useState(null)
const [keywords, setKeywords] = useState()
useEffect(() => { useEffect(() => {
resourceData() resourceData()
@ -30,6 +35,71 @@ function MyApplication({ loading, clientHeight, actions, dispatch, user }) {
}) })
} }
//检索元数据
const { data: tableData = {} } = useFsRequest({
url: 'meta/table/data',
query: {
id: searchDataId
},
refreshDeps: [searchDataId],
ready: !!searchDataId,
});
//检索元数据
const { data: result = {} } = useFsRequest({
url: ApiTable.searchMetadata,
query: {
keywords: keywords
},
refreshDeps: [keywords],
ready: !!keywords
});
useEffect(() => {
if (tableData?.rslt && tableData?.metaDataChildren) handleTableExport()
}, [tableData])
const handleTableExport = () => {
const metaData = result?.rows?.find(s => s.id == searchDataId)
if (!metaData) return;
let excelTitle = tableData?.metaDataChildren.map(s => {
return { k: s, v: s }
});
let workBook = {
SheetNames: [], //sheet名称
Sheets: {} //根据SheetNames名称顺序依次添加每个sheet数据
};
if (tableData?.rslt && tableData?.rslt?.length > 0) {
let sheetName = '元数据列表';
let sheetDataMap = new Map();
let sheetData = [excelTitle];
let index = 1;
tableData?.rslt.map(data => {
const arr = []
tableData?.metaDataChildren.map(s => {
arr.push(
{ k: s, v: JSON.stringify(data[s]) },
);
});
sheetData.push(arr)
index = index + 1;
})
sheetDataMap.set(sheetName, sheetData);
sheetDataMap.forEach((values, key) => {
// 写入excel
workBook.Sheets[key] = xlsx.utils.aoa_to_sheet(values);
workBook.Sheets[key]['!cols'] = [{ wpx: 50 }, { wpx: 150 }, { wpx: 180 }, { wpx: 230 }, { wpx: 230 }, { wpx: 230 }]
})
workBook.SheetNames = [sheetName];
// 将workBook写入文件
xlsx.writeFile(workBook, `${metaData?.name}-data.xlsx`);
} else {
message.info('当前资源暂无数据!')
}
}
const columns = [{ const columns = [{
title: '资源名称', title: '资源名称',
@ -80,8 +150,84 @@ function MyApplication({ loading, clientHeight, actions, dispatch, user }) {
compare: (a, b) => moment(b?.approveAt).valueOf() - moment(a?.approveAt).valueOf(), compare: (a, b) => moment(b?.approveAt).valueOf() - moment(a?.approveAt).valueOf(),
// multiple: 2, // multiple: 2,
}, },
}, {
title: '操作',
dataIndex: 'action',
render: (text, record) => {
return record?.token && <Button type="link" onClick={async () => {
console.log(record);
if (record?.resourceType == '文件') {
const suffix = record?.metadataFile?.fileName?.substring(record?.metadataFile?.fileName?.length - 3, record?.metadataFile?.fileName?.length)
if (suffix == 'png' || suffix == 'jpg') {
downloadImg(record?.metadataFile.fileName)
} else {
window.open('/assets/files/common/' + record?.metadataFile.fileName)
}
} else if (record?.resourceType == '库表') {
setKeywords(record?.resourceName)
setSearchDataId(null)
setTimeout(() => {
setSearchDataId(record.metadataDatabase?.id)
}, 10);
} else if (record?.resourceType == '数据服务') {
dispatch(resourceConsumption.getRestData({
url: record?.restfulApi?.url,
token: record?.token
})).then(res => {
if (res.success) {
let restData = res.payload.data?.rows
if (restData.length > 0) {
restTableExport(record?.resourceName, restData)
} else {
message.info('当前资源暂无数据!')
}
}
})
}
}}>下载</Button>
}
}]; }];
const restTableExport = (name, data = []) => {
let dataKey = Object.keys(data[0])||[]
let excelTitle = dataKey.map(s => {
return { k: s, v: s }
});
let workBook = {
SheetNames: [], //sheet名称
Sheets: {} //根据SheetNames名称顺序依次添加每个sheet数据
};
let sheetName = '元数据列表';
let sheetDataMap = new Map();
let sheetData = [excelTitle];
let index = 1;
data.map(data => {
const arr = []
dataKey.map(s => {
arr.push(
{ k: s, v: JSON.stringify(data[s]) },
);
});
sheetData.push(arr)
index = index + 1;
})
sheetDataMap.set(sheetName, sheetData);
sheetDataMap.forEach((values, key) => {
// 写入excel
workBook.Sheets[key] = xlsx.utils.aoa_to_sheet(values);
workBook.Sheets[key]['!cols'] = [{ wpx: 50 }, { wpx: 150 }, { wpx: 180 }, { wpx: 230 }, { wpx: 230 }, { wpx: 230 }]
})
workBook.SheetNames = [sheetName];
// 将workBook写入文件
xlsx.writeFile(workBook, `${name}-data.xlsx`);
}
return <> return <>

Loading…
Cancel
Save