From 57c10876b27e46471808fd7fd20e1e7405bb4917 Mon Sep 17 00:00:00 2001 From: zhangminghua Date: Thu, 6 Apr 2023 17:33:01 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=A2=9E=E5=88=A0=E6=94=B9=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=8C=E7=94=B3=E8=AF=B7=E8=B5=84=E6=BA=90=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=BF=AE=E6=94=B9=EF=BC=8C=E6=96=87=E4=BB=B6=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=8F=A3=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controllers/latestMetadata/index.js | 141 ++++++++++++++++-- api/app/lib/routes/latestMetadata/index.js | 9 ++ 2 files changed, 139 insertions(+), 11 deletions(-) diff --git a/api/app/lib/controllers/latestMetadata/index.js b/api/app/lib/controllers/latestMetadata/index.js index 850d4f1..270d518 100644 --- a/api/app/lib/controllers/latestMetadata/index.js +++ b/api/app/lib/controllers/latestMetadata/index.js @@ -499,8 +499,8 @@ async function getTagMetadata(ctx) { //申请资源 async function postMetadataResourceApplications(ctx) { try { - const { resourceName, applyBy } = ctx.request.body; - if (!resourceName || !applyBy) { + const { resourceName, applyBy, resourceType } = ctx.request.body; + if (!resourceName || !applyBy || !resourceType) { ctx.status = 400; ctx.body = { message: '参数不全,请重新申请资源' } } else { @@ -577,13 +577,12 @@ async function postMetadataFiles(ctx) { } } } - //修改文件元数据 async function putMetadataFiles(ctx) { try { const { id } = ctx.params; const { updateFileName } = ctx.query; - const { catalog, name } = ctx.request.body; + const { catalog, name, type } = ctx.request.body; const models = ctx.fs.dc.models; let metadataFileInfo = await models.MetadataFile.findOne({ where: { id } }); if (metadataFileInfo) { @@ -591,14 +590,19 @@ async function putMetadataFiles(ctx) { await models.MetadataFile.update({ updateAt: moment(), fileName: null }, { where: { id: id } }); ctx.status = 204; } else { - const putOne = await models.MetadataFile.findOne({ where: { id: { $not: id }, catalog: catalog, name: name } }); - if (putOne) { + if (!name || !catalog || !type) { + ctx.body = { message: '参数不全,请重新配置' } ctx.status = 400; - ctx.body = { message: '该元数据名称已存在' } } else { - await models.MetadataFile.update({ updateAt: moment(), ...ctx.request.body }, { where: { id: id } }); - ctx.status = 200; - ctx.body = { message: '修改元数据成功' } + const putOne = await models.MetadataFile.findOne({ where: { id: { $not: id }, catalog: catalog, name: name } }); + if (putOne) { + ctx.status = 400; + ctx.body = { message: '该元数据名称已存在' } + } else { + await models.MetadataFile.update({ updateAt: moment(), ...ctx.request.body }, { where: { id: id } }); + ctx.status = 200; + ctx.body = { message: '修改元数据成功' } + } } } } else { @@ -660,6 +664,118 @@ async function delMetadataFiles(ctx) { ctx.body = { message: '删除元数据失败' } } } + +//新建接口元数据 +async function postMetadataRestapis(ctx) { + try { + const { name, catalog, method, url } = ctx.request.body; + const models = ctx.fs.dc.models; + const postOne = await models.MetadataRestapi.findOne({ + where: { name: name, catalog: catalog } + }); + if (postOne) { + ctx.status = 400; + ctx.body = { message: '该资源目录下元数据名称已存在' } + } else { + if (!name || !catalog || !method || !url) { + ctx.body = { message: '参数不全,请重新配置' } + ctx.status = 400; + } else { + await models.MetadataRestapi.create({ createAt: moment(), ...ctx.request.body }); + ctx.body = { message: '新建元数据成功' } + ctx.status = 200; + } + } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { + "message": "新建元数据失败" + } + } +} + +//修改接口元数据 +async function putMetadataRestapis(ctx) { + try { + const { id } = ctx.params; + const { catalog, name, method, url } = ctx.request.body; + const models = ctx.fs.dc.models; + let metadataRestapiInfo = await models.MetadataRestapi.findOne({ where: { id } }); + if (metadataRestapiInfo) { + if (!name || !catalog || !method || !url) { + ctx.body = { message: '参数不全,请重新修改' } + ctx.status = 400; + } else { + const putOne = await models.MetadataRestapi.findOne({ where: { id: { $not: id }, catalog: catalog, name: name } }); + if (putOne) { + ctx.status = 400; + ctx.body = { message: '该元数据名称已存在' } + } else { + await models.MetadataRestapi.update({ updateAt: moment(), ...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 delMetadataRestapis(ctx) { + const transaction = await ctx.fs.dc.orm.transaction(); + try { + const models = ctx.fs.dc.models; + const { id } = ctx.params; + let metadataRestapiInfo = await models.MetadataRestapi.findOne({ where: { id } }); + if (metadataRestapiInfo) { + let deletable = true; + let tagRestapiInfo = await models.TagRestapi.findOne({ where: { restapi: id } }); + if (tagRestapiInfo) { + ctx.status = 400; + ctx.body = { message: '该元数据已被打标' } + deletable = false; + } else { + let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ + where: { + resourceName: metadataFileInfo.name, + resourceType: '接口' + } + }); + if (resourceConsumptionInfo) { + ctx.status = 400; + ctx.body = { message: '该元数据存在资源申请' } + deletable = false; + } + } + if (deletable) { + await models.MetadataRestapi.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: '删除元数据失败' } + } +} module.exports = { getResourceCatalog, postResourceCatalog, @@ -679,5 +795,8 @@ module.exports = { getMetadataResourceApplications, postMetadataFiles, putMetadataFiles, - delMetadataFiles + delMetadataFiles, + postMetadataRestapis, + putMetadataRestapis, + delMetadataRestapis } \ No newline at end of file diff --git a/api/app/lib/routes/latestMetadata/index.js b/api/app/lib/routes/latestMetadata/index.js index 50e4d4c..01022e1 100644 --- a/api/app/lib/routes/latestMetadata/index.js +++ b/api/app/lib/routes/latestMetadata/index.js @@ -59,4 +59,13 @@ module.exports = function (app, router, opts) { app.fs.api.logAttr['DEL/metadata/files/:id'] = { content: '删除文件元数据', visible: true }; router.delete('/metadata/files/:id', latestMetadata.delMetadataFiles); + + app.fs.api.logAttr['POST/metadata/restapis'] = { content: '新建接口元数据', visible: true }; + router.post('/metadata/restapis', latestMetadata.postMetadataRestapis); + + app.fs.api.logAttr['PUT/metadata/restapis/:id'] = { content: '修改接口元数据', visible: true }; + router.put('/metadata/restapis/:id', latestMetadata.putMetadataRestapis); + + app.fs.api.logAttr['DEL/metadata/restapis/:id'] = { content: '删除接口元数据', visible: true }; + router.delete('/metadata/restapis/:id', latestMetadata.delMetadataRestapis); }; \ No newline at end of file From 2efc9a6a18e01d604a4fefc2d5fc1a134e5ef223 Mon Sep 17 00:00:00 2001 From: zhangminghua Date: Thu, 6 Apr 2023 17:34:16 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=A2=9E=E5=88=A0=E6=94=B9action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metadataManagement/actions/metadata.js | 37 +++++++++++++++++++ web/client/src/utils/webapi.js | 4 ++ 2 files changed, 41 insertions(+) diff --git a/web/client/src/sections/metadataManagement/actions/metadata.js b/web/client/src/sections/metadataManagement/actions/metadata.js index e522737..b0ec1b7 100644 --- a/web/client/src/sections/metadataManagement/actions/metadata.js +++ b/web/client/src/sections/metadataManagement/actions/metadata.js @@ -231,3 +231,40 @@ export function delMetadataFiles(id) { } }); } + +export function postMetadataRestapis(data) { + return dispatch => basicAction({ + type: 'post', + data: data, + dispatch: dispatch, + actionType: 'POST_METADATA_RESTAPIS', + url: ApiTable.postMetadataRestapis, + msg: { option: '新建元数据' }, + reducer: {} + }); +} + +export function putMetadataRestapis(id, data) { + return dispatch => basicAction({ + type: 'put', + data: data, + dispatch, + actionType: 'PUT_METADATA_RESTAPIS', + url: ApiTable.putMetadataRestapis.replace('{id}', id), + msg: { + option: '修改元数据', + } + }); +} + +export function delMetadataRestapis(id) { + return dispatch => basicAction({ + type: 'del', + dispatch, + actionType: 'DELETE_METADATA_RESTAPIS', + url: ApiTable.delMetadataRestapis.replace('{id}', id), + msg: { + option: '删除元数据', + } + }); +} diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index 236a448..eca2a70 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -40,6 +40,10 @@ export const ApiTable = { postMetadataFiles: 'metadata/files', putMetadataFiles: 'metadata/files/{id}', delMetadataFiles: 'metadata/files/{id}', + //接口元数据增删改 + postMetadataRestapis: 'metadata/restapis', + putMetadataRestapis: 'metadata/restapis/{id}', + delMetadataRestapis: 'metadata/restapis/{id}', //元数据采集-数据源管理 pgCheckConnect: 'adapter/check/connect', From 814c3d635869769a95f092de248c0905bc95b542 Mon Sep 17 00:00:00 2001 From: zhangminghua Date: Fri, 7 Apr 2023 17:24:09 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5=E3=80=81=E6=89=93?= =?UTF-8?q?=E6=A0=87=E3=80=81=E8=B5=84=E6=BA=90=E7=94=B3=E8=AF=B7=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/controllers/latestMetadata/index.js | 4 +- .../metadataAcquisition/containers/adapter.js | 4 +- .../components/metadataRestapiModal.js | 196 +++++++++++++++ .../metadataManagement/constants/index.js | 1 + .../containers/restapisTable.js | 234 +++++++++++++++--- 5 files changed, 399 insertions(+), 40 deletions(-) create mode 100644 web/client/src/sections/metadataManagement/components/metadataRestapiModal.js diff --git a/api/app/lib/controllers/latestMetadata/index.js b/api/app/lib/controllers/latestMetadata/index.js index 270d518..707480a 100644 --- a/api/app/lib/controllers/latestMetadata/index.js +++ b/api/app/lib/controllers/latestMetadata/index.js @@ -169,6 +169,8 @@ async function getMetadataFiles(ctx) { const models = ctx.fs.dc.models; const { catalog, limit, offset, keywords, orderBy = 'updateAt', orderDirection = 'desc' } = ctx.query; const where = { catalog: catalog }; + //文件类型关键字查询时需匹配fileName不能为空。 + //因存在编辑时将文件删除,但未重新上传直接点击取消的情况,此时文件已删除不可恢复,数据字段fileName更新为null if (keywords) { where['$or'] = [{ name: { $iLike: `%${keywords}%` } }, { type: { $iLike: `%${keywords}%` }, fileName: { $not: null } }] } @@ -746,7 +748,7 @@ async function delMetadataRestapis(ctx) { } else { let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ where: { - resourceName: metadataFileInfo.name, + resourceName: metadataRestapiInfo.name, resourceType: '接口' } }); diff --git a/web/client/src/sections/metadataAcquisition/containers/adapter.js b/web/client/src/sections/metadataAcquisition/containers/adapter.js index 5855927..6601978 100644 --- a/web/client/src/sections/metadataAcquisition/containers/adapter.js +++ b/web/client/src/sections/metadataAcquisition/containers/adapter.js @@ -7,7 +7,7 @@ import moment from 'moment'; import { RELATION_DATABASE_TOOL_CONFIG } from '../constants/adapter'; import { useFsRequest, ApiTable } from '$utils'; -const LatestMetadata = (props) => { +const Adapter = (props) => { const { history, actions, dispatch, adapters } = props; const [isModalOpen, setIsModalOpen] = useState(false); const [refreshTree, setRefreshTree] = useState(1); @@ -114,4 +114,4 @@ function mapStateToProps(state) { dataSources: datasources?.data || {}, }; } -export default connect(mapStateToProps)(LatestMetadata) \ No newline at end of file +export default connect(mapStateToProps)(Adapter) \ No newline at end of file diff --git a/web/client/src/sections/metadataManagement/components/metadataRestapiModal.js b/web/client/src/sections/metadataManagement/components/metadataRestapiModal.js new file mode 100644 index 0000000..841989a --- /dev/null +++ b/web/client/src/sections/metadataManagement/components/metadataRestapiModal.js @@ -0,0 +1,196 @@ +import React, { useEffect, useState } from 'react'; +import { Modal, Input, Form, Select, InputNumber, Tooltip, Switch } from 'antd'; +import { RestapiMethods } from '../constants/index'; +const { TextArea } = Input; +const MetadataRestapiModal = (props) => { + const { onConfirm, onCancel, editData, metadataModels } = props; + const [form] = Form.useForm(); + const [bodyParamRequired, setBodyParamRequired] = useState(false); + const [returnRequired, setReturnRequired] = useState(false); + useEffect(() => { + // form.setFieldValue('enabled', editData.record?.enabled || false); + }, []); + const handleOk = () => { + form.validateFields().then(values => { + if (onConfirm) { + let dataSave = JSON.parse(JSON.stringify(values)); + dataSave.attributesParam = {}; + metadataModels.map(m => { + dataSave.attributesParam[m.attributeCode] = values[m.attributeCode]; + delete dataSave[m.attributeCode]; + }) + onConfirm(dataSave); + } + }) + } + const isObjectString = (value) => { + if (typeof value !== "string") { + return false; + } + try { + JSON.parse(value); + return true; + } catch (e) { + return false; + } + } + const validatorNull = (rule, value, getFieldValue, validateFields, label) => { + if (!value || !value.trim().length) { + return Promise.reject(new Error(`${label}不可空字符串`)); + } + return Promise.resolve(); + } + const renderModelItems = () => { + const items = metadataModels.filter(mm => mm.modelType === '接口').map(m => { + if (m.control === '文本框') { + const rules = [{ required: !m.nullable, message: '' }] + if (!m.nullable) { + rules.push(({ getFieldValue, validateFields }) => ({ + validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, m.attributeName) } + })) + rules.push({ max: m.length, message: `${m.attributeName}不超过${m.length}个字符` }) + } + return 10 ? + {m.attributeName.substring(0, 10) + '...'} + : m.attributeName} + name={m.attributeCode} + key={m.attributeCode} + rules={rules}> + + + } else if (m.control === '数字输入框') { + const rules = [{ required: !m.nullable, message: `${m.attributeName}不可空` }] + let maxValue = ''; + let length = m.length; + if (length) { + while (length > 0) { + maxValue += '9' + length--; + } + } + return 10 ? + {m.attributeName.substring(0, 10) + '...'} + : m.attributeName} + name={m.attributeCode} + key={m.attributeCode} + rules={rules}> + + + } else { + return 10 ? + {m.attributeName.substring(0, 10) + '...'} + : m.attributeName} + name={m.attributeCode} + key={m.attributeCode} + rules={[{ required: !m.nullable, message: `${m.attributeName}不可空` }]}> + + + } + }) + return items; + } + return ( + handleOk(null)} + onCancel={onCancel}> +
+ ({ + validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '接口名称') } + })]}> + + + ({ + validator(_, value) { return validatorNull(_, value, getFieldValue, validateFields, '接口路由') } + })]}> + + + + + + +