Browse Source

rest服务接口访问完成

master
wenlele 1 year ago
parent
commit
515eafa4ef
  1. 63
      api/app/lib/controllers/dataService/index.js
  2. 109
      api/app/lib/controllers/latestMetadata/index.js
  3. 8
      api/app/lib/index.js
  4. 2
      api/app/lib/models/resource_consumption.js
  5. 2
      api/app/lib/models/restful_api.js
  6. 8
      api/app/lib/routes/dataService/index.js
  7. 177
      api/app/lib/routes/latestMetadata/index.js
  8. 4
      scripts/0.0.9/01_alter_t_restful_api.sql
  9. 12
      web/client/src/sections/dataService/actions/serviceManagement.js
  10. 88
      web/client/src/sections/dataService/components/editModal.js
  11. 118
      web/client/src/sections/dataService/components/fileModal.js
  12. 66
      web/client/src/sections/dataService/components/groupModal.js
  13. 79
      web/client/src/sections/dataService/components/resourceModal.js
  14. 104
      web/client/src/sections/dataService/components/ruleModal.js
  15. 94
      web/client/src/sections/dataService/containers/serviceManagement.js
  16. 122
      web/client/src/sections/dataService/containers/serviceView.js
  17. 8
      web/client/src/sections/dataService/nav-item.js
  18. 5
      web/client/src/sections/metadataManagement/components/releaseModal.js
  19. 1
      web/client/src/sections/resourceConsumption/containers/myApplication.js
  20. 1
      web/client/src/utils/webapi.js

63
api/app/lib/controllers/dataService/index.js

@ -13,6 +13,10 @@ function getServiceManagement (opts) {
let option = {
where: {},
order: [["id", "desc"]],
include: [{
model: models.ResourceConsumption,
}],
distinct: true
}
if (keyword) {
option.where.name = { $iLike: `%${keyword}%` }
@ -45,9 +49,9 @@ function postServiceManagement (opts) {
try {
const models = ctx.fs.dc.models;
const { id, name, endbled } = ctx.request.body;
const { id, name, enabled } = ctx.request.body;
await models.RestfulApi.update({ name, endbled }, { where: { id: id } })
await models.RestfulApi.update({ name: name, enabled: enabled }, { where: { id: id } })
ctx.status = 204;
} catch (error) {
@ -80,9 +84,62 @@ function delServiceManagement (opts) {
}
}
//获取表字段
function getLookField (opts) {
return async function (ctx, next) {
const models = ctx.fs.dc.models;
const { table, fields } = ctx.query;
try {
let option = {
where: {
$or: []
// code: table,
// 'metadataDatabase.code': fields
},
order: [["id", "desc"]],
include: [{
model: models.MetadataDatabase,
include: [{
model: models.MetadataDatabase,
}],
distinct: true
}],
distinct: true
}
option.where.$or.push(
{
code: table,
}
)
option.where.$or.push(
{
'$metadataDatabase.code$': fields
},
)
let res = await models.MetadataDatabase.findOne(option)
ctx.status = 200;
ctx.body = res
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '获取表字段失败' }
}
}
}
module.exports = {
getServiceManagement,
postServiceManagement,
delServiceManagement
delServiceManagement,
getLookField
}

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

@ -3,7 +3,7 @@
const moment = require("moment/moment");
//获取资源目录
async function getResourceCatalog(ctx) {
async function getResourceCatalog (ctx) {
try {
const models = ctx.fs.dc.models;
const rslt = await models.ResourceCatalog.findAll({
@ -20,7 +20,7 @@ async function getResourceCatalog(ctx) {
}
}
//新建资源目录
async function postResourceCatalog(ctx) {
async function postResourceCatalog (ctx) {
try {
const { name, code } = ctx.request.body;
const models = ctx.fs.dc.models;
@ -49,7 +49,7 @@ async function postResourceCatalog(ctx) {
}
}
//修改资源目录
async function putResourceCatalog(ctx) {
async function putResourceCatalog (ctx) {
try {
const { id } = ctx.params;
const { name, code, description } = ctx.request.body;
@ -78,7 +78,7 @@ async function putResourceCatalog(ctx) {
}
}
//删除资源目录
async function delResourceCatalog(ctx) {
async function delResourceCatalog (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
@ -117,7 +117,7 @@ async function delResourceCatalog(ctx) {
}
}
//获取库表元数据列表
async function getMetadataDatabases(ctx) {
async function getMetadataDatabases (ctx) {
try {
const models = ctx.fs.dc.models;
const { catalog, limit, offset, keywords, orderBy = 'createAt', orderDirection = 'desc', id = null, resourceId } = ctx.query;
@ -169,7 +169,7 @@ async function getMetadataDatabases(ctx) {
}
}
//获取文件元数据列表
async function getMetadataFiles(ctx) {
async function getMetadataFiles (ctx) {
try {
const models = ctx.fs.dc.models;
const { catalog, limit, offset, keywords, orderBy = 'updateAt', orderDirection = 'desc', resourceId } = ctx.query;
@ -214,7 +214,7 @@ async function getMetadataFiles(ctx) {
}
}
//获取接口元数据列表
async function getMetadataRestapis(ctx) {
async function getMetadataRestapis (ctx) {
try {
const models = ctx.fs.dc.models;
const { catalog, limit, offset, keywords, orderBy = 'createAt', orderDirection = 'desc', resourceId } = ctx.query;
@ -257,7 +257,7 @@ async function getMetadataRestapis(ctx) {
}
}
//获取元数据模型
async function getMetadataModels(ctx) {
async function getMetadataModels (ctx) {
try {
const models = ctx.fs.dc.models;
const { modelTypes } = ctx.query;
@ -281,7 +281,7 @@ async function getMetadataModels(ctx) {
}
//新建库表元数据
async function postMetadataDatabases(ctx) {
async function postMetadataDatabases (ctx) {
try {
const { name, code, catalog, parent } = ctx.request.body;
const models = ctx.fs.dc.models;
@ -318,7 +318,7 @@ async function postMetadataDatabases(ctx) {
}
//修改库表元数据
async function putMetadataDatabases(ctx) {
async function putMetadataDatabases (ctx) {
try {
const { id } = ctx.params;
const { catalog, name, code } = ctx.request.body;
@ -354,7 +354,7 @@ async function putMetadataDatabases(ctx) {
}
}
//删除库表元数据
async function delMetadataDatabases(ctx) {
async function delMetadataDatabases (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
@ -409,7 +409,7 @@ async function delMetadataDatabases(ctx) {
}
}
//获取库表元数据基本信息
async function getMetadataDatabasesById(ctx) {
async function getMetadataDatabasesById (ctx) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
@ -440,7 +440,7 @@ async function getMetadataDatabasesById(ctx) {
}
//打标元数据
async function postTagMetadata(ctx) {
async function postTagMetadata (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const { tags, database, file, restapi } = ctx.request.body;
@ -481,7 +481,7 @@ async function postTagMetadata(ctx) {
}
//获取元数据已打标数据
async function getTagMetadata(ctx) {
async function getTagMetadata (ctx) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
@ -525,14 +525,20 @@ async function getTagMetadata(ctx) {
}
}
//申请资源
async function postMetadataResourceApplications(ctx) {
async function postMetadataResourceApplications (ctx) {
try {
const { resourceName, applyBy, resourceType, resourceId } = ctx.request.body;
const { resourceName, applyBy, resourceType, resourceId, restServiceId } = ctx.request.body;
const models = ctx.fs.dc.models;
if (restServiceId) {
await models.ResourceConsumption.create({ applyAt: moment(), approveState: '审批中', ...ctx.request.body });
ctx.body = { message: '申请资源成功' }
ctx.status = 200;
} else {
if (!resourceName || !applyBy || !resourceType || !resourceId) {
ctx.status = 400;
ctx.body = { message: '参数不全,请重新申请资源' }
} else {
const models = ctx.fs.dc.models;
const postOne = await models.ResourceConsumption.findOne({
where: { applyBy: applyBy, resourceName: resourceName, resourceId, resourceType, approve_remarks: null }
});
@ -545,6 +551,8 @@ async function postMetadataResourceApplications(ctx) {
ctx.status = 200;
}
}
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
@ -555,7 +563,7 @@ async function postMetadataResourceApplications(ctx) {
}
//获取元数据资源申请记录
async function getMetadataResourceApplications(ctx) {
async function getMetadataResourceApplications (ctx) {
try {
const models = ctx.fs.dc.models;
const { resourceNames, type } = ctx.query;
@ -577,7 +585,7 @@ async function getMetadataResourceApplications(ctx) {
}
//新建文件元数据
async function postMetadataFiles(ctx) {
async function postMetadataFiles (ctx) {
try {
const { name, catalog, type, fileName } = ctx.request.body;
const models = ctx.fs.dc.models;
@ -606,7 +614,7 @@ async function postMetadataFiles(ctx) {
}
}
//修改文件元数据
async function putMetadataFiles(ctx) {
async function putMetadataFiles (ctx) {
try {
const { id } = ctx.params;
const { updateFileName } = ctx.query;
@ -646,7 +654,7 @@ async function putMetadataFiles(ctx) {
}
}
//删除文件元数据
async function delMetadataFiles(ctx) {
async function delMetadataFiles (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
@ -694,7 +702,7 @@ async function delMetadataFiles(ctx) {
}
//新建接口元数据
async function postMetadataRestapis(ctx) {
async function postMetadataRestapis (ctx) {
try {
const { name, catalog, method, url } = ctx.request.body;
const models = ctx.fs.dc.models;
@ -724,7 +732,7 @@ async function postMetadataRestapis(ctx) {
}
//修改接口元数据
async function putMetadataRestapis(ctx) {
async function putMetadataRestapis (ctx) {
try {
const { id } = ctx.params;
const { catalog, name, method, url } = ctx.request.body;
@ -758,7 +766,7 @@ async function putMetadataRestapis(ctx) {
}
}
//删除接口元数据
async function delMetadataRestapis(ctx) {
async function delMetadataRestapis (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
@ -806,7 +814,7 @@ async function delMetadataRestapis(ctx) {
}
//获取对表的库与字段信息
async function listStructuredData(ctx) {
async function listStructuredData (ctx) {
try {
const models = ctx.fs.dc.models;
const { id, parent } = ctx.query;
@ -828,34 +836,37 @@ async function listStructuredData(ctx) {
}
}
//发布REST服务
async function publishingServices (ctx) {
let message = "发布REST服务失败"
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
const { method, url } = data
// //发布REST服务
// function publishingServices (opts) {
// return async function (ctx, next) {
// let message = "发布REST服务失败"
// try {
// const models = ctx.fs.dc.models;
// const data = ctx.request.body;
// const { method, url } = data
const postOne = await models.RestfulApi.findOne({ where: { method: method, url: url } });
if (postOne) {
message = '路由和请求方式重复'
throw ''
}
// const postOne = await models.RestfulApi.findOne({ where: { method: method, url: url } });
// if (postOne) {
// message = '路由和请求方式重复'
// throw ''
// }
await models.RestfulApi.create(data)
// await models.RestfulApi.create(data)
ctx.body = { message: '发布REST服务成功' }
ctx.status = 200;
// ctx.body = { message: '发布REST服务成功' }
// ctx.status = 200;
// } catch (error) {
// ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
// ctx.status = 400;
// ctx.body = {
// "message": message
// }
// }
// }
// }
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": message
}
}
}
module.exports = {
getResourceCatalog,
postResourceCatalog,
@ -880,5 +891,5 @@ module.exports = {
putMetadataRestapis,
delMetadataRestapis,
listStructuredData,
publishingServices
// publishingServices
}

8
api/app/lib/index.js

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

2
api/app/lib/models/resource_consumption.js

@ -18,7 +18,7 @@ module.exports = dc => {
},
resourceId: {
type: DataTypes.INTEGER,
allowNull: false,
allowNull: true,
defaultValue: null,
comment: "资源id",
primaryKey: false,

2
api/app/lib/models/restful_api.js

@ -53,7 +53,7 @@ module.exports = dc => {
autoIncrement: false
},
conditions: {
type: DataTypes.JSONB,
type: DataTypes.TEXT,
allowNull: true,
defaultValue: null,
comment: "数据库表查询条件",

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

@ -13,4 +13,12 @@ module.exports = function (app, router, opts, AuthCode) {
app.fs.api.logAttr['DEL/service-management/:id'] = { content: '删除REST服务', visible: true };
router.del('/service-management/:id', model.delServiceManagement(opts))
app.fs.api.logAttr['GET/lookField'] = { content: '获取表字段', visible: true };
router.get('/lookField', model.getLookField(opts));
};

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

@ -1,4 +1,7 @@
'use strict';
const { Pool } = require('pg');
const moment = require('moment')
const latestMetadata = require('../../controllers/latestMetadata');
@ -72,7 +75,179 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/listStructuredData'] = { content: '获取对表的库与字段信息', visible: true };
router.get('/listStructuredData', latestMetadata.listStructuredData);
app.fs.api.logAttr['POST/publishing/services'] = { content: '发布REST服务', visible: true };
router.post('/publishing/services', latestMetadata.publishingServices);
router.post('/publishing/services', async (ctx) => {
const data = ctx.request.body;
opts.exclude.push({ p: data.url, o: 'GET' });
router.get(data.url, async (ctx) => {
let message = "获取库表元数据列表失败"
try {
const models = ctx.fs.dc.models;
const { token } = ctx.query;
if (!token) {
message = '缺少访问令牌'
throw ''
} else {
let tokens
let findOne = await models.RestfulApi.findOne({
where: { url: data.url, method: data.method },
order: [["id", "desc"]],
include: [{
model: models.ResourceConsumption,
}],
distinct: true
});
findOne && findOne.resourceConsumptions.map(s => {
if (!tokens && s.token) {
tokens = s.token
}
})
if (tokens && tokens == token) {
if (findOne.enabled) {
const pool = new Pool({
user: ctx.fs.dc.orm.config.username,
host: ctx.fs.dc.orm.config.host,
database: findOne.table,
password: ctx.fs.dc.orm.config.password,
port: ctx.fs.dc.orm.config.port,
})
const client = await pool.connect()
const res = await client.query(findOne.conditions, [])
await models.RestfulApiRecord.create({
restServiceId: findOne.id,
visitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
token: tokens
})
ctx.status = 200;
ctx.body = res;
} else {
message = '该REST服务被禁用'
throw ''
}
} else {
message = '该服务令牌错误'
throw ''
}
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": message
}
}
});
let message = "发布REST服务失败"
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
const { method, url } = data
const postOne = await models.RestfulApi.findOne({ where: { method: method, url: url } });
if (postOne) {
message = '路由和请求方式重复'
throw ''
}
await models.RestfulApi.create(data)
ctx.body = { message: '发布REST服务成功' }
ctx.status = 200;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": message
}
}
});
async function release (apps, opts) {
const models = apps.fs.dc.models;
const list = await models.RestfulApi.findAll({
order: [["id", "desc"]],
include: [{
model: models.ResourceConsumption,
}],
distinct: true
}) || []
list.map(v => {
opts.exclude.push({ p: v.url, o: 'GET' });
router.get(v.url, async (ctx) => {
let message = "获取库表元数据列表失败"
try {
const { token } = ctx.query;
if (!token) {
message = '缺少访问令牌'
throw ''
} else {
let tokens
v.resourceConsumptions.map(s => {
if (!tokens && s.token) {
tokens = s.token
}
})
if (tokens && tokens == token) {
if (v.enabled) {
const pool = new Pool({
user: ctx.fs.dc.orm.config.username,
host: ctx.fs.dc.orm.config.host,
database: v.table,
password: ctx.fs.dc.orm.config.password,
port: ctx.fs.dc.orm.config.port,
})
const client = await pool.connect()
const res = await client.query(v.conditions, [])
await models.RestfulApiRecord.create({
restServiceId: v.id,
visitTime: moment().format('YYYY-MM-DD HH:mm:ss'),
token: tokens
})
ctx.status = 200;
ctx.body = res;
} else {
message = '该REST服务被禁用'
throw ''
}
} else {
message = '该服务令牌错误'
throw ''
}
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": message
}
}
});
})
}
release(app, opts)
};

4
scripts/0.0.9/01_alter_t_restful_api.sql

@ -3,11 +3,11 @@ create table t_restful_api
id serial not null,
"table" varchar(255) not null,
fields varchar(255) not null,
conditions jsonb not null,
conditions text not null,
name varchar(255) not null,
method varchar(10) not null,
url varchar(255) not null,
enabled boolean default true not null
enabled boolean not null
);
comment on table t_restful_api is 'REST服务';

12
web/client/src/sections/dataService/actions/serviceManagement.js

@ -39,4 +39,14 @@ export function delServiceManagement (id) {
});
}
export function getLookField (query = {}) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_LOOK_FIELD',
url: `${ApiTable.lookField}`,
msg: { error: '获取表字段失败' },
reducer: { name: '' }
});
}

88
web/client/src/sections/dataService/components/editModal.js

@ -0,0 +1,88 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux';
import moment from 'moment';
import { UploadLocal } from '$components';
import { Tabs, Form, Input, DatePicker, Button, Modal, Select, Tag } from 'antd';
function EditModal ({ loading, parent, user, actions, editData = {}, dispatch, close, success, viewDetails }) {
const { dataService } = actions
const [lookFiold, setLookFiold] = useState([]);
const [interfaceName, setInterfaceName] = useState()
useEffect(() => {
setInterfaceName(editData?.name);
dispatch(dataService.getLookField({ table: editData?.table, fields: editData?.fields })).then(res => {
if (res.success) {
setLookFiold(res.payload.data)
}
})
}, [])
return <>
<Modal title={viewDetails ? '查看REST服务详情' : "编辑REST服务"} open={true} width={600}
onOk={e => {
if (viewDetails) {
close()
} else {
dispatch(dataService.postServiceManagement({
id: editData.id, name: interfaceName, enabled: editData?.enabled
})).then(res => {
if (res.success) {
close()
success()
}
})
}
}}
onCancel={() => {
close()
}}
>
<div style={{ display: 'flex' }}>接口名称
<Input style={{ width: 180 }} value={interfaceName} disabled={viewDetails} onChange={e => {
setInterfaceName(e.target.value)
}} /></div>
<div style={{ display: 'flex', margin: '10px 0' }}>接口路由
<Input style={{ width: 180 }} value={editData?.url} disabled={true} />
</div>
<div style={{ margin: '10px 0 10px 0' }} >接口类型
<Input style={{ width: 180 }} value={editData?.method} disabled={true} />
</div>
<div style={{ display: 'flex' }}>返回值
<div style={{ display: 'flex', width: 400, flexDirection: 'column', alignItems: 'center' }}>
<div style={{ display: 'flex' }}>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>名称</div>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>意义</div>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>说明</div>
</div>
{lookFiold?.metadataDatabases?.map((s, index) => {
return <div key={'lookFiold' + index} style={{ display: 'flex' }}>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>{s.code}</div>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>{s.name}</div>
<div style={{ width: 120, border: '1px solid #dcc', textAlign: 'center' }}>{s.description}</div>
</div>
})}
</div>
</div>
</Modal >
</>
}
function mapStateToProps (state) {
const { global, auth, resourceCatalog } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
// resourceCatalog: resourceCatalog?.data || [],
// isRequesting: resourceCatalog.isRequesting
};
}
export default connect(mapStateToProps)(EditModal)

118
web/client/src/sections/dataService/components/fileModal.js

@ -1,118 +0,0 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux';
import moment from 'moment';
import { UploadLocal } from '$components';
import { Tabs, Form, Input, DatePicker, Button, Modal, Select, Tag } from 'antd';
function FileModal ({ loading, parent, user, actions, editData = {}, dispatch, close, success,remove }) {
const { dataQuality } = actions
const [tabsKey, setTabsKey] = useState("stay")
const [query, setQuery] = useState({ page: 0, limit: 10 });
const [proTableList, setProTableList] = useState({ rows: [], count: 0 });
const [approve, setApprove] = useState()
const [form] = Form.useForm();
const [editUrl, setEditUrl] = useState([]);
useEffect(() => {
}, [])
const vsjunct = (params) => {
if (params.length) {
let appendix = []
for (let p of params) {
appendix.push({
fName: p.name,
size: p.size,
fileSize: p.size,
storageUrl: p.storageUrl,//必须有storageUrl
})
}
setEditUrl(appendix)
} else {
setEditUrl([])
}
}
return <>
<Modal title="标准文档上传" open={true} width={600}
onOk={e => {
form.validateFields().then(v => {
dispatch(dataQuality.postStandardDocs({
...v,
path: v?.files[0]?.url, docName: v?.files[0]?.name,
folder: parent || null,
})).then(res => {
if (res.success) {
close()
success()
}
})
})
}}
onCancel={() => {
if (form.getFieldValue('files') && form.getFieldValue('files').length) {
remove(form.getFieldValue('files')[0]?.url)
}
close()
}}
>
<Form
style={{ marginLeft: 20 }}
form={form}
onValuesChange={v => {
}}
autoComplete="off"
labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}
>
<Form.Item label="标准类型" name="standardType" rules={[{ required: true, message: '请选择标准类型' }]}>
<Select style={{ width: 200, }} allowClear
options={[{ value: '国家标准', label: '国家标准', }, { value: '行业标准', label: '行业标准', }, { value: '地方标准', label: '地方标准', },]}
/>
</Form.Item>
<Form.Item label="标签" name="tags" >
<Input allowClear placeholder='请输入标签' maxLength={50} style={{ width: 300, marginRight: 16 }} />
</Form.Item>
<Form.Item
label='文件'
name='files'
key='files'
rules={[{ required: true, message: '文件不可为空' }]}>
<UploadLocal
// addNew={editData.add || !editData.record.files.length}
isLocal={true}
maxFilesNum={1}
maxFileSize={40}
onChange={vsjunct}
fileTypes={["jpg", "png", "gif", "txt", "doc", "docx", "pdf", "xls", "xlsx", "zip", "rar"]}
value={editUrl}
// fileList={editData.record.files || []}
/>
</Form.Item>
<Form.Item style={{ marginLeft: 42 }} key='tip'>
<Tag color="orange">文件大小不超过40MB开放资源包含多个文件建议将文件进行压缩形成压缩包再上传</Tag>
<Tag color="orange">支持的文件格式jpg,png,gif,txt,doc,docx,pdf,xsl,xlsx,zip,rar</Tag>
</Form.Item>
</Form>
</Modal >
</>
}
function mapStateToProps (state) {
const { global, auth, resourceCatalog } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
// resourceCatalog: resourceCatalog?.data || [],
// isRequesting: resourceCatalog.isRequesting
};
}
export default connect(mapStateToProps)(FileModal)

66
web/client/src/sections/dataService/components/groupModal.js

@ -1,66 +0,0 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux';
import moment from 'moment';
import { v4 as uuidv4 } from 'uuid'
import { Tabs, Form, Input, DatePicker, Button, Modal, Radio } from 'antd';
function GroupModal ({ loading, parent, user, actions, dispatch, close, success, }) {
const { dataQuality } = actions
const [form] = Form.useForm();
useEffect(() => {
}, [])
return <>
<Modal title="新建分组" open={true}
onOk={e => {
form.validateFields().then(v => {
dispatch(dataQuality.postStandardDocFolders({
...v,
parent: parent || null,
})).then(res => {
if (res.success) {
close()
success()
}
})
})
}}
onCancel={() => {
close()
}}
>
<Form
style={{ marginLeft: 20 }}
form={form}
onValuesChange={v => {
}}
autoComplete="off"
>
<Form.Item label="名称" name="name" rules={[{ required: true, message: '请输入分组名称,最多50字', max: 50 },]}>
<Input allowClear placeholder='请输入分组名称' style={{ width: 300, }} />
</Form.Item>
</Form>
</Modal >
</>
}
function mapStateToProps (state) {
const { global, auth, resourceCatalog } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
// resourceCatalog: resourceCatalog?.data || [],
// isRequesting: resourceCatalog.isRequesting
};
}
export default connect(mapStateToProps)(GroupModal)

79
web/client/src/sections/dataService/components/resourceModal.js

@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Modal, Input, Form } from 'antd';
const { TextArea } = Input;
const ResourceModal = (props) => {
const { actions, dispatch, success, close, editData, user } = props;
const { dataService, metadataManagement } = actions
const [form] = Form.useForm();
useEffect(() => {
}, []);
const handleOk = () => {
form.validateFields().then(values => {
if (success) {
dispatch(metadataManagement.postMetadataResourceApplications({
...values,
resourceType: '数据服务',
applyBy: user?.id,
approveState: '审批中',
restServiceId: editData?.id
})).then(res => {
if (res.success) {
success()
close()
}
});
}
})
}
const validatorNull = (rule, value, getFieldValue, validateFields, label) => {
if (!value || !value.trim().length) {
return Promise.reject(new Error(`${label}不可空字符串`));
}
return Promise.resolve();
}
return (
<Modal title={'申请资源'} open={true} destroyOnClose
okText='确定' width={800}
onOk={() => handleOk(null)}
onCancel={()=>close()}>
<Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }} initialValues={editData.record || {}}>
<Form.Item
label='资源名称'
name='resourceName'
rules={[{ required: true, message: '资源名称不可空' }]}>
<Input style={{ width: '90%' }} />
</Form.Item>
<Form.Item
label='申请人'
name='applyByName'
rules={[{ required: true, message: '申请人不可空' }]}>
<Input style={{ width: '90%' }} />
</Form.Item>
<Form.Item
label='需求描述'
name='requirements'
rules={[{ required: true, message: '' }, { max: 255, message: `需求描述不超过255个字符` },
({ getFieldValue, validateFields }) => ({
validator (_, value) { return validatorNull(_, value, getFieldValue, validateFields, '需求描述') }
})]}>
<TextArea rows={4} style={{ width: '90%' }} placeholder={`请输入需求描述`} />
</Form.Item>
</Form>
</Modal >
)
}
function mapStateToProps (state) {
const { global, auth, resourceCatalog } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
// resourceCatalog: resourceCatalog?.data || [],
// isRequesting: resourceCatalog.isRequesting
};
}
export default connect(mapStateToProps)(ResourceModal)

104
web/client/src/sections/dataService/components/ruleModal.js

@ -1,104 +0,0 @@
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux';
import moment from 'moment';
import { v4 as uuidv4 } from 'uuid'
import { Tabs, Form, Input, DatePicker, Button, Modal, Radio, Select, TreeSelect } from 'antd';
const { TextArea } = Input;
const { Option, OptGroup } = Select;
function RuleModal ({ loading, parent, user, actions, dispatch, close, success, treeList, editData }) {
const { dataQuality } = actions
const [tabsKey, setTabsKey] = useState("stay")
const [query, setQuery] = useState({ page: 0, limit: 10 });
const [proTableList, setProTableList] = useState({ rows: [], count: 0 });
const [approve, setApprove] = useState()
const [form] = Form.useForm();
useEffect(() => {
}, [])
return <>
<Modal title={editData?.id ? '编辑业务规则' : "新建业务规则"} open={true}
onOk={e => {
form.validateFields().then(v => {
// console.log(v);
dispatch(dataQuality.postBusinessRules({
...v, id: editData?.id
})).then(res => {
if (res.success) {
close()
success()
}
})
})
}}
onCancel={() => {
close()
}}
>
<Form
style={{ marginLeft: 20 }}
form={form}
onValuesChange={v => {
}}
autoComplete="off"
labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}
>
<Form.Item label="名称" name="name" initialValue={editData?.name} rules={[{ required: true, message: '请输入分组名称,最多50字', max: 50}]}>
<Input allowClear placeholder='请输入分组名称' style={{ width: 300 }} />
</Form.Item>
<Form.Item label="描述" name="description" initialValue={editData?.description} rules={[{ required: true, message: '请输入分组名称' }]}>
<TextArea allowClear autoSize={{ minRows: 2 }} placeholder='描述' style={{ width: 300, }} />
</Form.Item>
<Form.Item label="问题类型" name="problemType" initialValue={editData?.problemType} rules={[{ required: true, message: '请输入分组名称' }]}>
<Select style={{ width: 300, }} placeholder='问题类型'
options={[{ value: '一致性', label: '一致性', }, { value: '准确性', label: '准确性', }, { value: '完整性', label: '完整性', }, { value: '有效性', label: '有效性', }, { value: '及时性', label: '及时性', }, { value: '规范性', label: '规范性', },]}
/>
</Form.Item>
<Form.Item label="问题级别" name="problemLevel" initialValue={editData?.problemLevel} rules={[{ required: true, message: '请输入分组名称' }]}>
<Select style={{ width: 300, }} placeholder='问题级别'
options={[{ value: '一般', label: '一般', }, { value: '重要', label: '重要', }, { value: '严重', label: '严重', },]}
/>
</Form.Item>
<Form.Item label="制定依据" name="ruleBasis" initialValue={editData?.ruleBasis} rules={[{ required: true, message: '请输入分组名称' }]}>
<TreeSelect
showSearch
style={{
width: 300,
}}
// value={}
dropdownStyle={{
maxHeight: 300,
overflow: 'auto',
}}
placeholder=""
allowClear
treeDefaultExpandAll
// onChange={onChange}
treeData={treeList || []}
/>
</Form.Item>
</Form>
</Modal >
</>
}
function mapStateToProps (state) {
const { global, auth, resourceCatalog } = state;
return {
user: auth.user,
actions: global.actions,
clientHeight: global.clientHeight,
// resourceCatalog: resourceCatalog?.data || [],
// isRequesting: resourceCatalog.isRequesting
};
}
export default connect(mapStateToProps)(RuleModal)

94
web/client/src/sections/dataService/containers/serviceManagement.js

@ -6,34 +6,28 @@ import { RouteTable } from '$utils'
import { Tabs, Form, Input, Space, Button, Table, Popconfirm } from 'antd';
const { Search } = Input;
import { CreditCardFilled, FilePdfOutlined } from '@ant-design/icons';
import { agent } from 'superagent';
import RuleModal from '../components/ruleModal';
import EditModal from '../components/editModal';
function ServiceManagement ({ loading, clientHeight, actions, dispatch, }) {
const { dataService } = actions
const [query, setQuery] = useState({ page: 0, limit: 10 });
const [ruleModal, setRuleModal] = useState(false)
const [editModal, setEditModal] = useState(false)
const [editData, setEditData] = useState({})
const [keyword, setKeyword] = useState()
const [tableList, setTableList] = useState({ rows: [], count: 0 });
const [treeList, setTreeLista] = useState([])
const [viewDetails, setViewDetails] = useState(false)
useEffect(() => {
resourceData()
// dispatch(dataQuality.getServiceManagement()).then(res => {
// if (res.success) {
// setTreeLista(res.payload.data)
// }
// })
}, [])
let resourceData = (data) => {
let params = data || query
dispatch(dataService.getServiceManagement({ keyword: keyword, ...params, })).then(res => {
dispatch(dataService.getServiceManagement({ ...query, keyword: keyword, ...params, })).then(res => {
if (res.success) {
setTableList({ rows: res.payload.data?.rows, count: res.payload.data?.count })
@ -46,30 +40,35 @@ function ServiceManagement ({ loading, clientHeight, actions, dispatch, }) {
dataIndex: 'name',
}, {
title: '接口路由',
dataIndex: 'description',
dataIndex: 'url',
}, {
title: '接口类型',
dataIndex: 'problemType',
dataIndex: 'method',
}, {
title: '状态',
dataIndex: 'problemLevel'
dataIndex: 'enabled',
render: (text, record) => text ? '启用' : '禁用'
}, {
title: '操作',
dataIndex: 'handle',
width: '250px',
// ellipsis: true,
render: (text, record) => <div style={{ width: 126 }}>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>查看详情</Button>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>编辑</Button>
render: (text, record) => <div style={{ width: 200, display: 'flex', justifyContent: 'space-evenly' }}>
<a onClick={() => {
setEditData(record)
setEditModal(true)
setViewDetails(true)
}}>查看详情</a>
<a onClick={() => {
setEditData(record)
setEditModal(true)
}}>编辑</a>
{/* {record?.enabled ? */}
<Popconfirm
title="是否确认删除该业务规则?"
onConfirm={() => {
dispatch(dataQuality.delBusinessRules(record.id)).then(res => {
dispatch(dataService.delBusinessRules(record.id)).then(res => {
if (res.success) {
setQuery({ limit: 10, page: 0 });
resourceData({ limit: 10, page: 0, keyword })
@ -77,13 +76,37 @@ function ServiceManagement ({ loading, clientHeight, actions, dispatch, }) {
})
}}
>
<Button type="link">删除</Button>
<a >删除</a>
</Popconfirm>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>禁用</Button>
</div>
{/* // } */}
{record?.enabled ?
<Popconfirm
title="禁用后该服务将不可用"
onConfirm={() => {
dispatch(dataService.postServiceManagement({
id: record.id, name: record?.name, enabled: false
})).then(res => {
if (res.success) {
resourceData({ keyword })
}
})
}}
>
<a>禁用</a>
</Popconfirm>
: <a onClick={() => {
dispatch(dataService.postServiceManagement({
id: record.id, name: record?.name, enabled: true
})).then(res => {
if (res.success) {
resourceData({ keyword })
}
})
}}>启用</a>
}
</div >
},
];
@ -113,7 +136,7 @@ function ServiceManagement ({ loading, clientHeight, actions, dispatch, }) {
<Table
columns={columns}
dataSource={tableList?.rows || []}
scroll={{ scrollToFirstRowOnChange: true, y: clientHeight - 260 }}
scroll={{ y: clientHeight - 260 }}
pagination={{
current: query?.page + 1,
pageSize: query?.limit,
@ -129,13 +152,14 @@ function ServiceManagement ({ loading, clientHeight, actions, dispatch, }) {
/>
{
ruleModal ?
<RuleModal
treeList={treeList}
editModal ?
<EditModal
editData={editData}
viewDetails={viewDetails}
close={() => {
setRuleModal(false);
setEditModal(false);
setEditData({})
setViewDetails(false)
}}
success={() => {
resourceData({ limit: 10, page: 0, keyword })

122
web/client/src/sections/dataService/containers/serviceView.js

@ -4,41 +4,40 @@ import moment from 'moment';
import { RouteRequest } from '@peace/utils';
import { RouteTable } from '$utils'
import { Tabs, Form, Input, Space, Button, Table, Popconfirm } from 'antd';
import { Tabs, Form, Input, Space, Button, Table, message } from 'antd';
const { Search } = Input;
import { CreditCardFilled, FilePdfOutlined } from '@ant-design/icons';
import { agent } from 'superagent';
import RuleModal from '../components/ruleModal';
import EditModal from '../components/editModal';
import ResourceModal from '../components/resourceModal';
import { If } from 'react-if';
function ServiceView ({ loading, clientHeight, actions, dispatch, }) {
const { dataService } = actions
const { dataService, metadataManagement } = actions
const [query, setQuery] = useState({ page: 0, limit: 10 });
const [ruleModal, setRuleModal] = useState(false)
const [editModal, setEditModal] = useState(false)
const [editData, setEditData] = useState({})
const [keyword, setKeyword] = useState()
const [tableList, setTableList] = useState({ rows: [], count: 0 });
const [treeList, setTreeLista] = useState([])
const [viewDetails, setViewDetails] = useState(false)
const [resourceModal, setResourceModal] = useState(false)
useEffect(() => {
resourceData()
// dispatch(dataQuality.getRegularBasis()).then(res => {
// if (res.success) {
// setTreeLista(res.payload.data)
// }
// })
}, [])
let resourceData = (data) => {
// let params = data || query
// dispatch(dataService.getBusinessRules({ keyword: keyword, ...params, })).then(res => {
// if (res.success) {
// setTableList({ rows: res.payload.data?.rows, count: res.payload.data?.count })
let params = data || query
dispatch(dataService.getServiceManagement({ ...query, keyword: keyword, ...params, })).then(res => {
if (res.success) {
setTableList({ rows: res.payload.data?.rows, count: res.payload.data?.count })
// }
// })
}
})
}
const columns = [{
@ -46,48 +45,53 @@ function ServiceView ({ loading, clientHeight, actions, dispatch, }) {
dataIndex: 'name',
}, {
title: '接口路由',
dataIndex: 'description',
dataIndex: 'url',
}, {
title: '接口类型',
dataIndex: 'problemType',
}, {
title: '状态',
dataIndex: 'problemLevel'
dataIndex: 'method',
}, {
title: '操作',
dataIndex: 'handle',
width: '250px',
// ellipsis: true,
render: (text, record) => <div style={{ width: 126 }}>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>查看详情</Button>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>编辑</Button>
<Popconfirm
title="是否确认删除该业务规则?"
onConfirm={() => {
dispatch(dataQuality.delBusinessRules(record.id)).then(res => {
if (res.success) {
setQuery({ limit: 10, page: 0 });
resourceData({ limit: 10, page: 0, keyword })
render: (text, record) => <div style={{ width: 200, display: 'flex', justifyContent: 'space-evenly' }}>
<a onClick={() => {
setEditData(record)
setEditModal(true)
setViewDetails(true)
}}>查看详情</a>
<a onClick={() => {
let result
record?.resourceConsumptions?.map(v => {
if (result != '已有申请成功的资源' && result != '资源审批中') {
if (v.token) {
result = '已有申请成功的资源'
} else if (v.approveState == '审批中') {
result = '资源审批中'
}
}
})
}}
>
<Button type="link">删除</Button>
</Popconfirm>
<Button type="link" onClick={() => {
// setEditData(record)
// setRuleModal(true);
}}>禁用</Button>
</div>
if (result) {
message.warning({
duration: 1,
content: result,
})
} else {
setEditData(record)
setResourceModal(true)
}
}}>申请资源</a>
</div >
},
];
return <>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<div style={{ display: 'flex', }}>
<Input
@ -111,7 +115,7 @@ function ServiceView ({ loading, clientHeight, actions, dispatch, }) {
<Table
columns={columns}
dataSource={tableList?.rows || []}
scroll={{ scrollToFirstRowOnChange: true, y: clientHeight - 260 }}
scroll={{ y: clientHeight - 260 }}
pagination={{
current: query?.page + 1,
pageSize: query?.limit,
@ -127,12 +131,28 @@ function ServiceView ({ loading, clientHeight, actions, dispatch, }) {
/>
{
ruleModal ?
<RuleModal
treeList={treeList}
editModal ?
<EditModal
editData={editData}
viewDetails={viewDetails}
close={() => {
setEditModal(false);
setEditData({})
setViewDetails(false)
}}
success={() => {
resourceData({ limit: 10, page: 0, keyword })
}
}
/> : ""
}
{
resourceModal ?
<ResourceModal
editData={editData}
close={() => {
setRuleModal(false);
setResourceModal(false);
setEditData({})
}}
success={() => {

8
web/client/src/sections/dataService/nav-item.js

@ -8,12 +8,12 @@ export function getNavItem (user) {
return (
<SubMenu key="dataService" icon={<CarryOutOutlined />} title='数据服务'>
<Menu.Item key="serviceManagement">
{user?.role == '系统管理员' && <Menu.Item key="serviceManagement">
<Link to="/dataService/serviceManagement">服务管理</Link>
</Menu.Item>
<Menu.Item key="serviceView">
</Menu.Item>}
{user?.role != '系统管理员' && <Menu.Item key="serviceView">
<Link to="/dataService/serviceView">服务查看</Link>
</Menu.Item>
</Menu.Item>}
</ SubMenu >
);
}

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

@ -150,7 +150,6 @@ const ReleaseModal = ({ actions, dispatch, onConfirm, onCancel, editData = {} })
onClick={() => {
let whereOption = []
let integrity = true
console.log(fromData);
fromData.map(u => {
if (integrity) {
if (u.field && u.condition && u.value) {
@ -208,7 +207,7 @@ const ReleaseModal = ({ actions, dispatch, onConfirm, onCancel, editData = {} })
return <div key={'fieldData' + index} style={{ display: 'flex' }}>
<div style={{ width: 100, border: '1px solid #dcc', textAlign: 'center' }}>{s.code}</div>
<div style={{ width: 100, border: '1px solid #dcc', textAlign: 'center' }}>{s.name}</div>
<div style={{ width: 100, border: '1px solid #dcc', textAlign: 'center' }}>{s.type}</div>
<div style={{ width: 100, border: '1px solid #dcc', textAlign: 'center' }}>{s.description}</div>
</div>
})}
</div>
@ -252,7 +251,7 @@ const ReleaseModal = ({ actions, dispatch, onConfirm, onCancel, editData = {} })
dispatch(metadataManagement.publishingServices({
table: database?.code,
fields: editData?.code,
conditions: fromData,
conditions: sql,
name: interfaceName,
method: interfaceMode,
url: interfaceUrl,

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

@ -44,6 +44,7 @@ function MyApplication ({ loading, clientHeight, actions, dispatch, user }) {
}, {
title: '数据类型',
dataIndex: 'resourceType',
render: (text, record) => text == '数据服务' ? 'REST服务' : text || '--'
}, {
title: '令牌',
dataIndex: 'token',

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

@ -113,6 +113,7 @@ export const ApiTable = {
//REST服务
serviceManagement: 'service-management',
delServiceManagement: 'service-management/{id}',
lookField:'lookField',
};

Loading…
Cancel
Save