peng.peng 2 years ago
parent
commit
f961057b88
  1. 97
      api/app/lib/controllers/latestMetadata/index.js
  2. 8
      api/app/lib/routes/latestMetadata/index.js
  3. 6
      scripts/0.0.4/01_alter_t_metadata_database&t_resource_consumption.sql
  4. 8
      web/client/src/sections/metadataManagement/actions/metadata.js
  5. 14
      web/client/src/sections/metadataManagement/components/metadataDatabaseModal.js
  6. 20
      web/client/src/sections/metadataManagement/containers/databasesTable.js
  7. 6
      web/client/src/sections/metadataManagement/containers/metadataDetails.js

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

@ -265,25 +265,108 @@ async function postMeatadataDatabases(ctx) {
const { name, code, catalog } = ctx.request.body; const { name, code, catalog } = ctx.request.body;
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const postOne = await models.MetadataDatabase.findOne({ const postOne = await models.MetadataDatabase.findOne({
where: { $or: [{ name: name }, { code: code, catalog: catalog }] } where: { $or: [{ name: name }, { code: code }], catalog: catalog }
}); });
if (postOne) { if (postOne) {
ctx.status = 400; ctx.status = 400;
ctx.body = { message: '该资源目录下库表元数据名称或代码已存在' } ctx.body = { message: '该资源目录下元数据名称或代码已存在' }
} else { } else {
await models.MetadataDatabase.create({ createAt: moment(), ...ctx.request.body }); await models.MetadataDatabase.create({ createAt: moment(), ...ctx.request.body });
ctx.body = { message: '新建库表元数据成功' } ctx.body = { message: '新建元数据成功' }
ctx.status = 200; ctx.status = 200;
} }
} catch (error) { } catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
"message": "新建库表元数据失败" "message": "新建元数据失败"
} }
} }
} }
//修改库表元数据
async function putMeatadataDatabases(ctx) {
try {
const { id } = ctx.params;
const { catalog, name, code } = ctx.request.body;
const models = ctx.fs.dc.models;
let metadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { id } });
if (metadataDatabaseInfo) {
const putOne = await models.MetadataDatabase.findOne({ where: { id: { $not: id }, catalog: catalog, $or: [{ name: name }, { code: code }] } });
if (putOne) {
ctx.status = 400;
ctx.body = { message: '该元数据名称或代码已存在' }
} else {
await models.MetadataDatabase.update(ctx.request.body, { where: { id: id } });
ctx.status = 200;
ctx.body = { message: '修改元数据成功' }
}
} else {
ctx.status = 400;
ctx.body = { message: '该元数据不存在' }
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "修改元数据失败"
}
}
}
//删除库表元数据
async function delMeatadataDatabases(ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
let metadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { id } });
if (metadataDatabaseInfo) {
let deletable = true;
let childMetadataDatabaseInfo = await models.MetadataDatabase.findOne({ where: { parent: id } });
if (childMetadataDatabaseInfo) {
ctx.status = 400;
ctx.body = { message: '存在关联子类元数据,请删除相关数据,再删除该元数据' }
deletable = false;
} else {
let tagDatabaseInfo = await models.TagDatabase.findOne({ where: { database: id } });
if (tagDatabaseInfo) {
ctx.status = 400;
ctx.body = { message: '该元数据已被打标' }
deletable = false;
} else {
let resourceConsumptionInfo = await models.ResourceConsumption.findOne({
where: {
resourceName: metadataDatabaseInfo.name,
resourceType: '库表'
}
});
if (resourceConsumptionInfo) {
ctx.status = 400;
ctx.body = { message: '该元数据存在资源申请' }
deletable = false;
}
}
}
if (deletable) {
await models.MetadataDatabase.destroy({
where: { id: id },
transaction
})
await transaction.commit();
ctx.status = 200;
ctx.body = { message: '删除元数据成功' }
}
} else {
ctx.status = 400;
ctx.body = { message: '该元数据不存在' }
}
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '删除元数据失败' }
}
}
//获取库表元数据基本信息 //获取库表元数据基本信息
async function getMetadataDatabasesById(ctx) { async function getMetadataDatabasesById(ctx) {
try { try {
@ -310,7 +393,7 @@ async function getMetadataDatabasesById(ctx) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400; ctx.status = 400;
ctx.body = { ctx.body = {
"message": "获取库表元数据基本信息失败" "message": "获取元数据基本信息失败"
} }
} }
} }
@ -324,7 +407,7 @@ module.exports = {
getMetadataRestapis, getMetadataRestapis,
getMetadataModels, getMetadataModels,
postMeatadataDatabases, postMeatadataDatabases,
// putMeatadataDatabases, putMeatadataDatabases,
// delMeatadataDatabases, delMeatadataDatabases,
getMetadataDatabasesById getMetadataDatabasesById
} }

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

@ -30,11 +30,11 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['POST /meatadata/databases'] = { content: '新建库表元数据', visible: true }; app.fs.api.logAttr['POST /meatadata/databases'] = { content: '新建库表元数据', visible: true };
router.post('/meatadata/databases', latestMetadata.postMeatadataDatabases); router.post('/meatadata/databases', latestMetadata.postMeatadataDatabases);
// app.fs.api.logAttr['PUT /meatadata/databases/:id'] = { content: '修改库表元数据', visible: true }; app.fs.api.logAttr['PUT /meatadata/databases/:id'] = { content: '修改库表元数据', visible: true };
// router.put('/meatadata/databases/:id', latestMetadata.putMeatadataDatabases); router.put('/meatadata/databases/:id', latestMetadata.putMeatadataDatabases);
// app.fs.api.logAttr['DEL /meatadata/databases/:id'] = { content: '删除库表元数据', visible: true }; app.fs.api.logAttr['DEL /meatadata/databases/:id'] = { content: '删除库表元数据', visible: true };
// router.delete('/meatadata/databases/:id', latestMetadata.delMeatadataDatabases); router.delete('/meatadata/databases/:id', latestMetadata.delMeatadataDatabases);
app.fs.api.logAttr['GET/metadata/databases/:id'] = { content: '获取库表元数据基本信息', visible: false }; app.fs.api.logAttr['GET/metadata/databases/:id'] = { content: '获取库表元数据基本信息', visible: false };
router.get('/metadata/databases/:id', latestMetadata.getMetadataDatabasesById); router.get('/metadata/databases/:id', latestMetadata.getMetadataDatabasesById);

6
scripts/0.0.4/01_alter_t_metadata_database&t_resource_consumption.sql

@ -1,10 +1,16 @@
alter table t_metadata_database alter column type type varchar(255) using type::varchar(255); 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); 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_metadata_type";
DROP TYPE "public"."enum_approve_state"; DROP TYPE "public"."enum_approve_state";
alter table t_metadata_database alter table t_metadata_database
add "catalogKey" varchar(255) not null; add "catalogKey" varchar(255) not null;
alter table t_metadata_file alter table t_metadata_file
add "catalogKey" varchar(255) not null; add "catalogKey" varchar(255) not null;
alter table t_metadata_restapi alter table t_metadata_restapi
add "catalogKey" varchar(255) not null; add "catalogKey" varchar(255) not null;
-- update_at integer型需先转为varchar再转timestamp,不可直接由integer型转为timestamp
alter table t_metadata_database alter column update_at type varchar(255) using update_at::varchar(255);
alter table t_metadata_database alter column update_at type timestamp with time zone using update_at::timestamp with time zone;

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

@ -107,7 +107,7 @@ export function postMeatadataDatabases(data) {
dispatch: dispatch, dispatch: dispatch,
actionType: 'POST_METADATA_DATABASES', actionType: 'POST_METADATA_DATABASES',
url: ApiTable.postMeatadataDatabases, url: ApiTable.postMeatadataDatabases,
msg: { option: '新建库表元数据' }, msg: { option: '新建元数据' },
reducer: {} reducer: {}
}); });
} }
@ -120,7 +120,7 @@ export function putMeatadataDatabases(id, data) {
actionType: 'PUT_METADATA_DATABASES', actionType: 'PUT_METADATA_DATABASES',
url: ApiTable.putMeatadataDatabases.replace('{id}', id), url: ApiTable.putMeatadataDatabases.replace('{id}', id),
msg: { msg: {
option: '修改库表元数据', option: '修改元数据',
} }
}); });
} }
@ -132,7 +132,7 @@ export function delMeatadataDatabases(id) {
actionType: 'DELETE_METADATA_DATABASES', actionType: 'DELETE_METADATA_DATABASES',
url: ApiTable.delMeatadataDatabases.replace('{id}', id), url: ApiTable.delMeatadataDatabases.replace('{id}', id),
msg: { msg: {
option: '删除库表元数据', option: '删除元数据',
} }
}); });
} }
@ -143,7 +143,7 @@ export function getMetadataDatabasesById(id) {
dispatch: dispatch, dispatch: dispatch,
actionType: 'GET_METADATA_DATABASES_Info', actionType: 'GET_METADATA_DATABASES_Info',
url: ApiTable.getMetadataDatabasesById.replace('{id}', id), url: ApiTable.getMetadataDatabasesById.replace('{id}', id),
msg: { error: '获取库表元数据基本信息失败' }, msg: { error: '获取元数据基本信息失败' },
reducer: { name: 'metadataDatabasesInfo' } reducer: { name: 'metadataDatabasesInfo' }
}); });
} }

14
web/client/src/sections/metadataManagement/components/metadataDatabModal.js → web/client/src/sections/metadataManagement/components/metadataDatabaseModal.js

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Modal, Input, Form, Select, InputNumber } from 'antd'; import { Modal, Input, Form, Select, InputNumber, Tooltip } from 'antd';
const { TextArea } = Input; const { TextArea } = Input;
const MetadataDatabaseModal = (props) => { const MetadataDatabaseModal = (props) => {
const { onConfirm, onCancel, editData, metadataModels, modelTypes } = props; const { onConfirm, onCancel, editData, metadataModels, modelTypes } = props;
@ -37,7 +37,9 @@ const MetadataDatabaseModal = (props) => {
rules.push({ max: m.length, message: `${m.attributeName}不超过${m.length}个字符` }) rules.push({ max: m.length, message: `${m.attributeName}不超过${m.length}个字符` })
} }
return <Form.Item return <Form.Item
label={m.attributeName} label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}>
{m.attributeName.substring(0, 10) + '...'}
</Tooltip> : m.attributeName}
name={m.attributeCode} name={m.attributeCode}
rules={rules}> rules={rules}>
<Input style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} /> <Input style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} />
@ -52,14 +54,18 @@ const MetadataDatabaseModal = (props) => {
} }
} }
return <Form.Item return <Form.Item
label={m.attributeName} label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}>
{m.attributeName.substring(0, 10) + '...'}
</Tooltip> : m.attributeName}
name={m.attributeCode} name={m.attributeCode}
rules={rules}> rules={rules}>
<InputNumber min={0} max={maxValue ? parseInt(maxValue) : 0} precision={0} style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} /> <InputNumber min={0} max={maxValue ? parseInt(maxValue) : 0} precision={0} style={{ width: '90%' }} placeholder={`请输入${m.attributeName}`} />
</Form.Item> </Form.Item>
} else { } else {
return <Form.Item return <Form.Item
label={m.attributeName} label={m.attributeName.length > 10 ? <Tooltip title={m.attributeName}>
{m.attributeName.substring(0, 10) + '...'}
</Tooltip> : m.attributeName}
name={m.attributeCode} name={m.attributeCode}
rules={[{ required: !m.nullable, message: `${m.attributeName}不可空` }]}> rules={[{ required: !m.nullable, message: `${m.attributeName}不可空` }]}>
<Select <Select

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

@ -4,7 +4,7 @@ import { Spin, Table, Popconfirm, Button, Input } from 'antd';
import { ButtonGroup } from '$components'; import { ButtonGroup } from '$components';
import moment from 'moment'; import moment from 'moment';
import FileSaver from 'file-saver'; import FileSaver from 'file-saver';
import MetadataDatabaseModal from '../components/metadataDatabModal'; import MetadataDatabaseModal from '../components/metadataDatabaseModal';
import { ModelTypes } from '../constants/index'; import { ModelTypes } from '../constants/index';
const DatabaseTable = (props) => { const DatabaseTable = (props) => {
@ -47,7 +47,13 @@ const DatabaseTable = (props) => {
} }
}) })
} }
const confirmDelete = (id) => { } const confirmDelete = (id) => {
dispatch(metadataManagement.delMeatadataDatabases(id)).then(res => {
if (res.success) {
onSearch(); setModalVisible(false);
}
});
}
const marking = (id) => { } const marking = (id) => { }
const applyResources = (id) => { } const applyResources = (id) => { }
@ -121,11 +127,11 @@ const DatabaseTable = (props) => {
<a onClick={() => onView(record)}>查看</a> <a onClick={() => onView(record)}>查看</a>
<a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a> <a style={{ marginLeft: 10 }} onClick={() => onEdit(record)}>编辑</a>
<Popconfirm <Popconfirm
title="是否确认删除该元数据?若确认删除则关联的数据将一并删除!" title="是否确认删除该元数据?"
onConfirm={() => confirmDelete(record.id)} onConfirm={() => confirmDelete(record.id)}
> <a style={{ marginLeft: 10 }}>删除</a></Popconfirm> > <a style={{ marginLeft: 10 }}>删除</a></Popconfirm>
<a style={{ marginLeft: 10 }} onClick={() => marking(record.id)}>打标</a> {record.type === '表' ? <a style={{ marginLeft: 10 }} onClick={() => marking(record.id)}>打标</a> : null}
<a style={{ marginLeft: 10 }} onClick={() => applyResources(record.id)}>申请资源</a> {record.type === '表' ? <a style={{ marginLeft: 10 }} onClick={() => applyResources(record.id)}>申请资源</a> : null}
</ButtonGroup> </ButtonGroup>
} }
}]; }];
@ -186,8 +192,10 @@ const DatabaseTable = (props) => {
}); });
} else { } else {
obj = { catalog: resourceCatalogId, catalogKey: resourceCatalogKey, ...values } obj = { catalog: resourceCatalogId, catalogKey: resourceCatalogKey, ...values }
dispatch(metadataManagement.putMeatadataDatabases(editData.record.id, obj)).then(() => { dispatch(metadataManagement.putMeatadataDatabases(editData.record.id, obj)).then(res => {
if (res.success) {
onSearch(); setModalVisible(false); onSearch(); setModalVisible(false);
}
}); });
} }
} }

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

@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { Tabs, Spin, Table, Button, Divider, message } from 'antd'; import { Tabs, Spin, Table, Button, Divider, message } from 'antd';
import moment from 'moment'; import moment from 'moment';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
import MetadataDatabaseModal from '../components/metadataDatabModal'; import MetadataDatabaseModal from '../components/metadataDatabaseModal';
import { ModelTypes, ConfigurableTypes } from '../constants/index'; import { ModelTypes, ConfigurableTypes } from '../constants/index';
const MetadataDetails = (props) => { const MetadataDetails = (props) => {
@ -56,7 +56,7 @@ const MetadataDetails = (props) => {
<Divider orientation="left" orientationMargin="5" plain>属性</Divider> <Divider orientation="left" orientationMargin="5" plain>属性</Divider>
< div style={{ lineHeight: '35px', marginLeft: 32 }}> < div style={{ lineHeight: '35px', marginLeft: 32 }}>
{databasesRecord.attributesParam ? metadataModels && metadataModels.filter(mm => mm.modelType === databasesRecord.type).map(mm => {databasesRecord.attributesParam ? metadataModels && metadataModels.filter(mm => mm.modelType === databasesRecord.type).map(mm =>
<div > {mm.attributeName}<span style={{ color: '#7F7F7F' }}>{databasesRecord.attributesParam[mm.attributeCode]}</span></div>) : ''} <div title={mm.attributeName}> {mm.attributeName.length > 10 ? mm.attributeName.substring(0, 10) + '...' : mm.attributeName}<span style={{ color: '#7F7F7F' }}>{databasesRecord.attributesParam[mm.attributeCode]}</span></div>) : ''}
</div > </div >
</div > : <></> </div > : <></>
} }
@ -105,7 +105,7 @@ const MetadataDetails = (props) => {
} }
}]; }];
return databasesRecord && ConfigurableTypes['表'].includes(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 }}>
<Button type='primary' onClick={() => { <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] } });

Loading…
Cancel
Save