Browse Source

库表元数据查看详情页面操作逻辑

master
zmh 2 years ago
parent
commit
66ab87086e
  1. 23
      api/app/lib/controllers/latestMetadata/index.js
  2. 2
      api/app/lib/routes/latestMetadata/index.js
  3. 8
      scripts/0.0.4/01_alter_t_metadata_database&t_resource_consumption.sql
  4. 2
      web/client/src/layout/components/sider/index.js
  5. 12
      web/client/src/sections/metadataManagement/actions/metadata.js
  6. 125
      web/client/src/sections/metadataManagement/components/metadataDatabModal.js
  7. 2
      web/client/src/sections/metadataManagement/components/resourceCatalogModal.js
  8. 2
      web/client/src/sections/metadataManagement/components/tagSetModal.js
  9. 3
      web/client/src/sections/metadataManagement/constants/index.js
  10. 68
      web/client/src/sections/metadataManagement/containers/databasesTable.js
  11. 4
      web/client/src/sections/metadataManagement/containers/index.js
  12. 49
      web/client/src/sections/metadataManagement/containers/latestMetadata.js
  13. 2
      web/client/src/sections/metadataManagement/containers/metaModelManagement.js
  14. 20
      web/client/src/sections/metadataManagement/containers/metadataTab.js
  15. 4
      web/client/src/sections/metadataManagement/containers/tagManagement.js
  16. 16
      web/client/src/sections/metadataManagement/routes.js
  17. 1
      web/client/src/utils/webapi.js

23
api/app/lib/controllers/latestMetadata/index.js

@ -229,6 +229,26 @@ async function getMetadataRestapis(ctx) {
}
}
}
//获取元数据模型
async function getMetadataModels(ctx) {
try {
const models = ctx.fs.dc.models;
const { modelTypes } = ctx.query;
const rslt = await models.MetaModel.findAll({
where: {
modelType: { $in: modelTypes }
}
});
ctx.status = 200;
ctx.body = rslt;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "获取元数据模型失败"
}
}
}
module.exports = {
getResourceCatalog,
postResourceCatalog,
@ -236,5 +256,6 @@ module.exports = {
delResourceCatalog,
getMetadataDatabases,
getMetadataFiles,
getMetadataRestapis
getMetadataRestapis,
getMetadataModels
}

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

@ -24,4 +24,6 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/metadata/restapis'] = { content: '获取接口元数据列表', visible: false };
router.get('/metadata/restapis', latestMetadata.getMetadataRestapis);
app.fs.api.logAttr['GET/metadata/models'] = { content: '获取元数据模型', visible: false };
router.get('/metadata/models', latestMetadata.getMetadataModels);
};

8
scripts/0.0.4/01_alter_t_metadata_database&t_resource_consumption.sql

@ -1,2 +1,10 @@
alter table t_metadata_database alter column type type varchar(255) using type::varchar(255);
alter table t_resource_consumption alter column approve_state type varchar(20) using approve_state::varchar(20);
DROP TYPE "public"."enum_metadata_type";
DROP TYPE "public"."enum_approve_state";
alter table t_metadata_database
add "catalogKey" varchar(255) not null;
alter table t_metadata_file
add "catalogKey" varchar(255) not null;
alter table t_metadata_restapi
add "catalogKey" varchar(255) not null;

2
web/client/src/layout/components/sider/index.js

@ -15,6 +15,8 @@ const Sider = (props) => {
localStorage.setItem('governmentDataResourceCenter_selected_sider', JSON.stringify([jumpurlObj.keys]))
setSelectedKeys(jumpurlObj.keys)
}
if (pathname.indexOf('metadataManagement/latestMetadata') < 0)
sessionStorage.removeItem('jumpSelectedKey');
}, [pathname])
useEffect(() => {

12
web/client/src/sections/metadataManagement/actions/metadata.js

@ -87,3 +87,15 @@ export function getMetadataRestapis(params) {
reducer: { name: 'metadataRestapis' }
});
}
export function getMetadataModels(params) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query: params,
actionType: 'GET_METADATA_MODELS_LIST',
url: ApiTable.getMetadataModels,
msg: { error: '获取元数据模型失败' },
reducer: { name: 'metadataModels' }
});
}

125
web/client/src/sections/metadataManagement/components/metadataDatabModal.js

@ -0,0 +1,125 @@
import React, { useEffect, useState } from 'react';
import { Modal, Input, Form, Select, InputNumber } from 'antd';
const { TextArea } = Input;
const MetadataDatabaseModal = (props) => {
const { onConfirm, onCancel, editData, metadataModels, modelTypes, resourceCatalogPath } = props;
const [form] = Form.useForm();
useEffect(() => {
}, []);
const handleOk = () => {
form.validateFields().then(values => {
if (onConfirm) {
onConfirm(values)
}
})
}
const validatorNull = (rule, value, getFieldValue, validateFields, label) => {
if (!value || !value.trim().length) {
return Promise.reject(new Error(`${label}不可空字符串`));
}
return Promise.resolve();
}
const renderModel = () => {
const items = metadataModels.map(m => {
if (m.control === '文本框') {
const rules = [{ required: m.nullable, message: '' },
{ max: m.length, message: `${m.attributeName}不超过${m.length}个字符` }]
if (m.nullable) {
rules.push(({ getFieldValue, validateFields }) => ({
validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, m.attributeName) }
}))
}
return <Form.Item
label={m.attributeName}
name={m.attributeCode}
rules={rules}>
<Input style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} />
</Form.Item>
} else if (m.control === '数字输入框') {
return <Form.Item
label={m.attributeName}
name={m.attributeCode}
rules={[{ required: m.nullable, message: '' }, { max: m.length || 0 }]}>
<InputNumber style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} />
</Form.Item>
} else {
return <Form.Item
label={m.attributeName}
name={m.attributeCode}
rules={[{ required: m.nullable, message: '' }]}>
<Select
placeholder={`请选择${m.attributeName}`}
style={{ width: '90%' }}
showSearch
optionFilterProp='children'
getPopupContainer={triggerNode => triggerNode.parentNode}
filterOption={(input, option) => option.props.children
.toLowerCase().indexOf(input.toLowerCase()) >= 0}
>
<Select.Option value={'是'} key={'是'}></Select.Option>
<Select.Option value={'否'} key={'否'}></Select.Option>
</Select>
</Form.Item >
}
})
return items;
}
return (
<Modal title={editData.title} open={true} destroyOnClose
okText='确定' width={800}
onOk={() => handleOk(null)}
onCancel={onCancel}>
<Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} initialValues={editData.record || {}}>
<Form.Item
label='元数据名称'
name='name'
rules={[{ required: true, message: '' }, { max: 50, message: `元数据名称不超过50个字符` },
({ getFieldValue, validateFields }) => ({
validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '元数据名称') }
})]}>
<Input style={{ width: '90%' }} placeholder={`请输入元数据名称`} />
</Form.Item>
<Form.Item
label='元数据代码'
name='code'
rules={[{ required: true, message: '' }, { max: 50, message: `元数据代码不超过50个字符` },
({ getFieldValue, validateFields }) => ({
validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '元数据代码') }
})]}>
<Input style={{ width: '90%' }} placeholder={`请输入元数据代码`} />
</Form.Item>
<Form.Item
label="元数据类型"
name='type'
rules={[{ required: true, message: '请选择元数据类型' }]}>
<Select
placeholder='请选择元数据类型'
style={{ width: '90%' }}
showSearch
optionFilterProp='children'
getPopupContainer={triggerNode => triggerNode.parentNode}
filterOption={(input, option) => option.props.children
.toLowerCase().indexOf(input.toLowerCase()) >= 0}
>
{modelTypes.map(m => <Select.Option value={m} key={m}>{m}</Select.Option>)}
</Select>
</Form.Item>
<Form.Item
label='上下文路径'
name='path'
rules={[{ required: true }]}
>
<Input disabled style={{ width: '90%' }} />
</Form.Item>
<Form.Item
label='详情'
name='description'
rules={[{ max: 255, message: `描述不超过255个字符` }]}>
<TextArea rows={4} style={{ width: '90%' }} placeholder={`请输入描述`} />
</Form.Item>
{renderModel()}
</Form>
</Modal>
)
}
export default MetadataDatabaseModal;

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

@ -44,7 +44,7 @@ const ResourceCatalogModal = (props) => {
return Promise.resolve();
}
return (
<Modal title={editData.title} visible={true} destroyOnClose
<Modal title={editData.title} open={true} destroyOnClose
okText='确定' width={800}
onOk={() => handleOk(null)}
onCancel={onCancel}>

2
web/client/src/sections/metadataManagement/components/tagSetModal.js

@ -49,7 +49,7 @@ const TagSetModal = (props) => {
return Promise.resolve();
}
return (
<Modal title={editData.title} visible={true} destroyOnClose
<Modal title={editData.title} open={true} destroyOnClose
okText='确定' width={800}
onOk={() => handleOk(null)}
onCancel={onCancel}>

3
web/client/src/sections/metadataManagement/constants/index.js

@ -0,0 +1,3 @@
'use strict';
import React from 'react';
export const ModelTypes = ['目录', '库', '视图', '表', '字段', '索引', '外键', '主键', '唯一约束'];

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

@ -4,9 +4,12 @@ import { Spin, Table, Popconfirm, Button, Input } from 'antd';
import { ButtonGroup } from '$components';
import moment from 'moment';
import FileSaver from 'file-saver';
import MetadataDatabaseModal from '../components/metadataDatabModal';
import { ModelTypes } from '../constants/index';
const DatabaseTable = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalogId, isRequesting } = props;
const { user, dispatch, actions, clientHeight, resourceCatalogId, resourceCatalogKey,
resourceCatalogPath, isRequesting, metadataModels, setView } = props;
const { metadataManagement } = actions;
const SortValues = { 'ascend': 'asc', 'descend': 'desc' };
const [tableData, setTableData] = useState([]);
@ -17,6 +20,8 @@ const DatabaseTable = (props) => {
const [currentPage, setCurrentPage] = useState(1);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [editData, setEditData] = useState({});
useEffect(() => {
setCreateAtSort('descend');
@ -31,8 +36,17 @@ const DatabaseTable = (props) => {
}
})
}
const onView = (id) => { }
const onEdit = (record) => { }
const onView = (id) => {
setView(id);
}
const onEdit = (record) => {
dispatch(metadataManagement.getMetadataModels({ modelTypes: ModelTypes })).then(res => {
if (res.success) {
setEditData({ title: '修改库表元数据', record: { path: '/' + resourceCatalogPath.join('/'), ...record } });
setModalVisible(true);
}
})
}
const confirmDelete = (id) => { }
const marking = (id) => { }
const applyResources = (id) => { }
@ -51,7 +65,8 @@ const DatabaseTable = (props) => {
setSelectedRows([]);
initData(query);
}
const columns = [{
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
@ -103,7 +118,7 @@ const DatabaseTable = (props) => {
width: '8%',
render: (text, record) => {
return <ButtonGroup>
<a onClick={() => onView(id)}>查看</a>
<a onClick={() => onView(record.id)}>查看</a>
<a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a>
<Popconfirm
title="是否确认删除该元数据?若确认删除则关联的数据将一并删除!"
@ -161,13 +176,33 @@ const DatabaseTable = (props) => {
let tempStr = new Blob([exportTable], { type: 'text/plain;charset=utf-8' });
FileSaver.saveAs(tempStr, `库表元数据导出.xls`);
}
//新建、修改
const onConfirm = (values) => {
let obj = { ...values }
// if (editData.add) {
// obj = { ...values, ...editData.record || {} }
// dispatch(metadataManagement.postResourceCatalog(obj)).then(() => {
// onSearch(); setModalVisible(false);
// });
// } else {
// dispatch(metadataManagement.putResourceCatalog(editData.record.id, obj)).then(() => {
// onSearch(); setModalVisible(false);
// });
// }
}
return <Spin spinning={isRequesting}>
<div style={{ marginBottom: 16 }}>
< div style={{ marginBottom: 16 }
}>
<Button type='primary' onClick={() => {
setEditData({ title: '新建库表元数据' });
dispatch(metadataManagement.getMetadataModels({ modelTypes: ModelTypes })).then(res => {
if (res.success) {
setEditData({ title: '新建库表元数据', record: { path: '/' + resourceCatalogPath.join('/') } });
setModalVisible(true);
}
})
}}>新建</Button>
{tableDataCount == 0 ? <Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }} onClick={() => handleExport()}>导出</Button> :
{
tableDataCount == 0 ? <Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }} onClick={() => handleExport()}>导出</Button> :
selectedRowKeys && selectedRowKeys.length ?
<Button disabled={tableDataCount == 0} style={{ marginLeft: 16 }} onClick={() => handleExport()}>导出</Button>
: <Popconfirm title={'是否导出全部?'} onConfirm={() => handleExport(true)} okText="确定" cancelText="取消">
@ -217,16 +252,27 @@ const DatabaseTable = (props) => {
}}
>
</Table>
{
modalVisible ?
<MetadataDatabaseModal
resourceCatalogPath={resourceCatalogPath}
modelTypes={ModelTypes.filter(m => m === '目录')}
metadataModels={metadataModels.filter(m => m.modelType === '目录')}
editData={editData}
onCancel={() => setModalVisible(false)}
onConfirm={onConfirm} /> : ''
}
</Spin >
}
function mapStateToProps(state) {
const { global, auth, metadataDatabases } = state;
const { global, auth, metadataDatabases, metadataModels } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
isRequesting: metadataDatabases.isRequesting,
isRequesting: metadataDatabases.isRequesting || metadataModels.isRequesting,
metadataModels: metadataModels.data,
};
}
export default connect(mapStateToProps)(DatabaseTable)

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

@ -4,6 +4,8 @@ import LatestMetadata from './latestMetadata';
import BusinessMetadata from './businessMetadata';
import MetaModelManagement from './metaModelManagement';
import TagManagement from './tagManagement';
import MetadataTab from './metadataTab';
import MetadataDetails from './metadataDetails';
export { LatestMetadata, BusinessMetadata, MetaModelManagement, TagManagement, MetadataDetails };
export { LatestMetadata, MetadataTab, BusinessMetadata, MetaModelManagement, TagManagement, MetadataDetails };

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

@ -5,10 +5,12 @@ import { PlusCircleOutlined, EditOutlined, MinusCircleOutlined } from '@ant-desi
import theStyle from './style.css';
import ResourceCatalogModal from '../components/resourceCatalogModal';
import MetadataTab from './metadataTab';
import MetadataDetails from './metadataDetails';
let expandedKeysData = [];
let allTreeNodeKeys = [];
const LatestMetadata = (props) => {
const { user, dispatch, actions, clientHeight, resourceCatalog, isRequesting } = props;
const { user, dispatch, actions, history, clientHeight, resourceCatalog, isRequesting, location } = props;
const { metadataManagement } = actions;
const [resourceCatalogData, setResourceCatalogData] = useState([]);
const [selectedKeys, setSelectedKeys] = useState([]);
@ -16,11 +18,14 @@ const LatestMetadata = (props) => {
const [modalVisible, setModalVisible] = useState(false);
const [editData, setEditData] = useState({});
const [resourceCatalogId, setResourceCatalogId] = useState('');
const [resourceCatalogKey, setResourceCatalogKey] = useState('');
const [resourceCatalogPath, setResourceCatalogPath] = useState([]);
useEffect(() => {
initData(true);
const jumpSelectedKey = sessionStorage.getItem('jumpSelectedKey') || null;
initData(true, jumpSelectedKey);
}, [])
const initData = (configRefresh) => {
const initData = (configRefresh, jumpSelectedKey) => {
dispatch(metadataManagement.getResourceCatalog()).then(res => {
const { data } = res.payload;
if (res.success) {
@ -28,10 +33,13 @@ const LatestMetadata = (props) => {
setResourceCatalogData(resourceCatalogData);
if (data.length) {
if (configRefresh) {
setExpandedKeys(expandedKeysData);
if (jumpSelectedKey || selectedKeys.length)
expandedKeysData = [jumpSelectedKey] || selectedKeys;
let expandedKeys = getExpandKeys(expandedKeysData);
setSelectedKeys(expandedKeysData);
let id = expandedKeysData[0].split('-').pop();
setResourceCatalogId(id);
setExpandedKeys(expandedKeys);
expandedKeysData = [];
allTreeNodeKeys = [];
}
} else {
setExpandedKeys([]);
@ -40,6 +48,16 @@ const LatestMetadata = (props) => {
}
})
}
const getExpandKeys = (selectedData) => {
const keyArr = selectedData[0].split('-');
keyArr.shift();//['rc-2-5']->返回'rc';keyArr:['2','5']
const allExpandedKeys = allTreeNodeKeys.filter(k => keyArr.includes(k.id.toString()));
setResourceCatalogId(keyArr.pop());
setResourceCatalogKey(selectedData[0]);
const resourceCatalogPath = allExpandedKeys.map(a => a.name);
setResourceCatalogPath(resourceCatalogPath);
return allExpandedKeys.map(a => a.key);
}
const getTreeNodeData = (dataSource, parent, key) => {
let treeData = [];
let data = [];
@ -52,6 +70,7 @@ const LatestMetadata = (props) => {
data = dataSource.filter(ds => ds.parent == parent);
}
treeData = data.map(ds => {
allTreeNodeKeys.push({ name: ds.name, key: `${key}-${ds.id}`, id: ds.id })
return { title: renderTreeNode(ds, dataSource), key: `${key}-${ds.id}`, id: ds.id }
});
for (let d of treeData) {
@ -125,12 +144,10 @@ const LatestMetadata = (props) => {
onSelect={(keys, e) => {
if (e.selected) {
setSelectedKeys(keys);
// let keyArr = allTreeNodeKeys.filter(ak => ak.key.includes(keys[0]));
// let ids = keyArr.map(key => key.id);
// console.log('all-' + JSON.stringify(ids))
let id = keys[0].split('-').pop();
setResourceCatalogId(id);
getExpandKeys(keys);
}
sessionStorage.setItem('jumpSelectedKey', keys.length ? keys[0] : selectedKeys && selectedKeys[0]);
history.push(`/metadataManagement/latestMetadata`);
}}
onExpand={(keys) => {
setExpandedKeys(keys);
@ -139,7 +156,15 @@ const LatestMetadata = (props) => {
/>
</Col>
<Col style={{ width: 'calc(100% - 240px)' }}>
<MetadataTab resourceCatalogId={resourceCatalogId} />
{location.pathname.indexOf('detail') > -1 ?
<MetadataDetails resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey}
resourceCatalogPath={resourceCatalogPath} history={history} /> :
<MetadataTab resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey}
resourceCatalogPath={resourceCatalogPath} history={history} />
}
{/* {props.children} */}
</Col>
</Row>
{

2
web/client/src/sections/metadataManagement/containers/metaModelManagement.js

@ -3,8 +3,8 @@ import { Spin, Popconfirm, Tree, Row, Col, Button } from 'antd';
import { connect } from 'react-redux';
import ProTable from '@ant-design/pro-table';
import MetaModelModal from '../components/modelModal'
import { ModelTypes as DATABASE_TYPE } from '../constants/index';
const TreeNode = Tree.TreeNode;
const DATABASE_TYPE = ['目录', '库', '表', '字段', '主键', '外键', '索引'];
function MetaModelManagement(props) {
const { loading, clientHeight, actions, dispatch, metaModel } = props;
const [selectedKeys, setSelectKeys] = useState([DATABASE_TYPE[0]])

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

@ -4,9 +4,10 @@ import { Tabs } from 'antd';
import DatabaseTable from './databasesTable';
import FilesTable from './filesTable';
import RestapisTable from './restapisTable';
import { push } from 'react-router-redux';
const MetadataTab = (props) => {
const { resourceCatalogId, actions, dispatch } = props;
const { resourceCatalogId, resourceCatalogKey, resourceCatalogPath, actions, dispatch, history } = props;
const [activeKey, setActiveKey] = useState('databases');
useEffect(() => {
setActiveKey('databases');
@ -15,7 +16,11 @@ const MetadataTab = (props) => {
const onTabChange = (key) => {
setActiveKey(key)
}
return <>
const onView = (id) => {
sessionStorage.setItem('jumpSelectedKey', resourceCatalogKey);
history.push(`/metadataManagement/latestMetadata/detail/${id}`);
}
return <div>
<Tabs defaultActiveKey="databases"
onChange={onTabChange}
activeKey={activeKey}
@ -35,11 +40,14 @@ const MetadataTab = (props) => {
]}>
</Tabs>
{
activeKey === 'databases' && resourceCatalogId ? <DatabaseTable resourceCatalogId={resourceCatalogId} /> :
activeKey === 'files' && resourceCatalogId ? <FilesTable resourceCatalogId={resourceCatalogId} /> :
activeKey === 'restapis' && resourceCatalogId ? < RestapisTable resourceCatalogId={resourceCatalogId} /> : null
activeKey === 'databases' && resourceCatalogId ? <DatabaseTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} setView={onView} /> :
activeKey === 'files' && resourceCatalogId ? <FilesTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> :
activeKey === 'restapis' && resourceCatalogId ? < RestapisTable resourceCatalogId={resourceCatalogId}
resourceCatalogKey={resourceCatalogKey} resourceCatalogPath={resourceCatalogPath} /> : null
}
</>
</div>
}
function mapStateToProps(state) {
const { global, auth } = state;

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

@ -127,9 +127,9 @@ const TagManagement = (props) => {
{tagData.map(ts =>
<Panel header={header(ts)} key={`tagSet-${ts.tagSetId}`}>
{ts.tags.map(t =>
<Tag className='tags'>{tag(t)}</Tag>
<Tag className='tags' key={`tag-${ts.tagSetId}-${t.id}`}>{tag(t)}</Tag>
)}
<Tag className='tags'>{tag(null, ts.tagSetId)}</Tag>
<Tag className='tags' key={`tag-${ts.tagSetId}-`}>{tag(null, ts.tagSetId)}</Tag>
</Panel>)}
</Collapse>
{

16
web/client/src/sections/metadataManagement/routes.js

@ -1,5 +1,5 @@
'use strict';
import { LatestMetadata, BusinessMetadata, MetaModelManagement, TagManagement, MetadataDetails } from './containers';
import { LatestMetadata, MetadataTab, MetadataDetails, BusinessMetadata, MetaModelManagement, TagManagement } from './containers';
export default [{
type: 'inner',
route: {
@ -12,12 +12,20 @@ export default [{
key: 'latestMetadata',
component: LatestMetadata,
breadcrumb: '最新元数据',
childRoutes: [{
childRoutes: [
// {
// path: '/config',
// key: 'metadataConfig',
// component: MetadataTab,
// breadcrumb: '配置',
// },
{
path: '/detail/:id',
key: 'metadataDetail',
component: MetadataDetails,
component: LatestMetadata,
breadcrumb: '元数据详情'
}]
}
]
}, {
path: '/businessMetadata',
key: 'businessMetadata',

1
web/client/src/utils/webapi.js

@ -26,6 +26,7 @@ export const ApiTable = {
getMetadataDatabases: 'metadata/databases',
getMetadataFiles: 'metadata/files',
getMetadataRestapis: 'metadata/restapis',
getMetadataModels: 'metadata/models',
//元数据采集-数据源管理
pgCheckConnect: 'adapter/check/connect',

Loading…
Cancel
Save