mirror of
https://github.com/YMFE/yapi.git
synced 2025-02-17 13:49:43 +08:00
feat: 数据导入新增智能合并策略
This commit is contained in:
parent
1758aab8ac
commit
df98e27723
@ -71,7 +71,7 @@ class ProjectData extends Component {
|
||||
curImportType: null,
|
||||
curExportType: null,
|
||||
showLoading: false,
|
||||
dataSync: false,
|
||||
dataSync: 'good',
|
||||
exportContent: 'all',
|
||||
isSwaggerUrl: false,
|
||||
swaggerUrl: '',
|
||||
@ -92,8 +92,10 @@ class ProjectData extends Component {
|
||||
if (data.data.errcode === 0) {
|
||||
let menuList = data.data.data;
|
||||
this.setState({
|
||||
menuList: menuList
|
||||
menuList: menuList,
|
||||
selectCatid: menuList[0]._id
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
plugin.emitHook('import_data', importDataModule);
|
||||
@ -143,7 +145,7 @@ class ProjectData extends Component {
|
||||
reader.readAsText(info.file);
|
||||
reader.onload = async res => {
|
||||
res = await importDataModule[this.state.curImportType].run(res.target.result);
|
||||
if (this.state.dataSync) {
|
||||
if (this.state.dataSync === 'merge') {
|
||||
// 开启同步
|
||||
this.showConfirm(res);
|
||||
} else {
|
||||
@ -197,7 +199,7 @@ class ProjectData extends Component {
|
||||
await that.handleAddInterface(res);
|
||||
},
|
||||
onCancel() {
|
||||
that.setState({ showLoading: false, dataSync: false });
|
||||
that.setState({ showLoading: false, dataSync: 'normal' });
|
||||
ref.destroy();
|
||||
}
|
||||
});
|
||||
@ -253,10 +255,10 @@ class ProjectData extends Component {
|
||||
let content = await axios(this.state.swaggerUrl);
|
||||
content = content.data;
|
||||
let res = await importDataModule[this.state.curImportType].run(content);
|
||||
if (this.state.dataSync) {
|
||||
// 开启同步
|
||||
if (this.state.dataSync === 'merge') {
|
||||
// merge
|
||||
this.showConfirm(res);
|
||||
} else {
|
||||
}else {
|
||||
// 未开启同步
|
||||
await this.handleAddInterface(res);
|
||||
}
|
||||
@ -323,7 +325,7 @@ class ProjectData extends Component {
|
||||
</h3>
|
||||
</div>
|
||||
<div className="dataImportTile">
|
||||
<Select placeholder="请选择导入数据的方式" onChange={this.handleImportType}>
|
||||
<Select defaultValue="swagger" placeholder="请选择导入数据的方式" onChange={this.handleImportType}>
|
||||
{Object.keys(importDataModule).map(name => {
|
||||
return (
|
||||
<Option key={name} value={name}>
|
||||
@ -335,6 +337,7 @@ class ProjectData extends Component {
|
||||
</div>
|
||||
<div className="catidSelect">
|
||||
<Select
|
||||
value={this.state.selectCatid+''}
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
placeholder="请选择数据导入的默认分类"
|
||||
@ -355,12 +358,26 @@ class ProjectData extends Component {
|
||||
</div>
|
||||
<div className="dataSync">
|
||||
<span className="label">
|
||||
开启数据同步 <Tooltip title="开启数据同步后会覆盖项目中原本的数据">
|
||||
数据同步 <Tooltip title={<div>
|
||||
<h3 style={{color: "white"}}>普通模式</h3>
|
||||
<p>不导入已存在的接口</p>
|
||||
<br />
|
||||
<h3 style={{color: "white"}}>智能合并</h3>
|
||||
<p>已存在的接口,将合并返回数据的 response,适用于导入了 swagger 数据,保留对数据结构的改动</p>
|
||||
<br />
|
||||
<h3 style={{color: "white"}}>完全覆盖</h3>
|
||||
<p>不保留旧数据,完全使用新数据,适用于接口定义完全交给后端定义</p>
|
||||
</div>}>
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>{' '}
|
||||
</span>
|
||||
|
||||
<Switch checked={this.state.dataSync} onChange={this.onChange} />
|
||||
<Select value={this.state.dataSync} onChange={this.onChange}>
|
||||
<Option value="normal">普通模式</Option>
|
||||
<Option value="good">智能合并</Option>
|
||||
<Option value="merge">完全覆盖</Option>
|
||||
</Select>
|
||||
|
||||
{/* <Switch checked={this.state.dataSync} onChange={this.onChange} /> */}
|
||||
</div>
|
||||
{this.state.curImportType === 'swagger' && (
|
||||
<div className="dataSync">
|
||||
|
@ -1,5 +1,7 @@
|
||||
const _ = require('underscore');
|
||||
const axios = require('axios');
|
||||
|
||||
|
||||
const isNode = typeof global == 'object' && global.global === global;
|
||||
|
||||
async function handle(
|
||||
@ -84,13 +86,14 @@ async function handle(
|
||||
}
|
||||
data.token = token;
|
||||
|
||||
if (dataSync) {
|
||||
if (dataSync !== 'normal') {
|
||||
// 开启同步功能
|
||||
count++;
|
||||
let apipath = '/api/interface/save';
|
||||
if (isNode) {
|
||||
apipath = 'http://127.0.0.1:' + port + apipath;
|
||||
}
|
||||
data.dataSync = dataSync;
|
||||
let result = await axios.post(apipath, data);
|
||||
if (result.data.errcode) {
|
||||
successNum--;
|
||||
|
37
common/mergeJsonSchema.js
Normal file
37
common/mergeJsonSchema.js
Normal file
@ -0,0 +1,37 @@
|
||||
function isPlainObject(obj) {
|
||||
return obj ? typeof obj === 'object' && Object.getPrototypeOf(obj) === Object.prototype : false;
|
||||
}
|
||||
|
||||
function handleProperties(sourceProperties, mergeProperties){
|
||||
if(!isPlainObject(mergeProperties)){
|
||||
return mergeProperties
|
||||
}
|
||||
if(! isPlainObject(sourceProperties)){
|
||||
return mergeProperties
|
||||
}
|
||||
Object.keys(mergeProperties).forEach(key=>{
|
||||
if(key === 'field_1'){
|
||||
console.log(1)
|
||||
}
|
||||
mergeProperties[key]= handleSchema(sourceProperties[key], mergeProperties[key])
|
||||
})
|
||||
return mergeProperties;
|
||||
}
|
||||
|
||||
|
||||
function handleSchema(source, merge){
|
||||
if(!isPlainObject(source)) return merge;
|
||||
if(!isPlainObject(merge)) return merge;
|
||||
let result = {}
|
||||
Object.assign(result, source, merge)
|
||||
if(merge.type === 'object'){
|
||||
result.properties = handleProperties(source.properties, merge.properties);
|
||||
}else if(merge.type === 'array'){
|
||||
result.items = handleSchema(source.items, merge.items);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = function(sourceJsonSchema, mergeJsonSchema){
|
||||
return handleSchema(sourceJsonSchema, mergeJsonSchema)
|
||||
}
|
1846
package-lock.json
generated
1846
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -55,5 +55,5 @@ app.use(koaStatic(yapi.path.join(yapi.WEBROOT, 'static'), { index: indexFile, gz
|
||||
|
||||
app.listen(yapi.WEBCONFIG.port);
|
||||
commons.log(
|
||||
`the server is start at 127.0.0.1${yapi.WEBCONFIG.port == '80' ? '' : ':' + yapi.WEBCONFIG.port}`
|
||||
`服务已启动,请打开下面链接访问: \nhttp://127.0.0.1${yapi.WEBCONFIG.port == '80' ? '' : ':' + yapi.WEBCONFIG.port}/`
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ const projectModel = require('../models/project.js');
|
||||
const jsondiffpatch = require('jsondiffpatch');
|
||||
const formattersHtml = jsondiffpatch.formatters.html;
|
||||
const showDiffMsg = require('../../common/diff-view.js');
|
||||
const mergeJsonSchema = require('../../common/mergeJsonSchema');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
@ -115,7 +116,8 @@ class interfaceController extends baseController {
|
||||
title: minLengthStringField,
|
||||
path: minLengthStringField,
|
||||
method: minLengthStringField,
|
||||
message: minLengthStringField
|
||||
message: minLengthStringField,
|
||||
dataSync: 'string'
|
||||
},
|
||||
addAndUpCommonField
|
||||
)
|
||||
@ -281,7 +283,7 @@ class interfaceController extends baseController {
|
||||
|
||||
async save(ctx) {
|
||||
let params = ctx.params;
|
||||
|
||||
|
||||
if (!this.$tokenAuth) {
|
||||
let auth = await this.checkAuth(params.project_id, 'project', 'edit');
|
||||
if (!auth) {
|
||||
@ -301,16 +303,25 @@ class interfaceController extends baseController {
|
||||
));
|
||||
}
|
||||
|
||||
let result = await this.Model.getByPath(params.project_id, params.path, params.method, '_id');
|
||||
let result = await this.Model.getByPath(params.project_id, params.path, params.method, '_id res_body');
|
||||
|
||||
if (result.length > 0) {
|
||||
result.forEach(async item => {
|
||||
params.id = item._id;
|
||||
// console.log(this.schemaMap['up'])
|
||||
let validResult = yapi.commons.validateParams(this.schemaMap['up'], params);
|
||||
let validParams = Object.assign({}, params)
|
||||
let validResult = yapi.commons.validateParams(this.schemaMap['up'], validParams);
|
||||
if (validResult.valid) {
|
||||
let data = {};
|
||||
data.params = params;
|
||||
data.params = validParams;
|
||||
|
||||
if(params.res_body_is_json_schema && params.dataSync === 'good'){
|
||||
try{
|
||||
let new_res_body = yapi.commons.json_parse(params.res_body)
|
||||
let old_res_body = yapi.commons.json_parse(item.res_body)
|
||||
data.params.res_body = JSON.stringify(mergeJsonSchema(old_res_body, new_res_body),null,2);
|
||||
}catch(err){}
|
||||
}
|
||||
await this.up(data);
|
||||
} else {
|
||||
return (ctx.body = yapi.commons.resReturn(null, 400, validResult.message));
|
||||
|
129
test/common/mergeJsonSchema.test.js
Normal file
129
test/common/mergeJsonSchema.test.js
Normal file
@ -0,0 +1,129 @@
|
||||
import test from 'ava';
|
||||
import mergeJsonSchema from '../../common/mergeJsonSchema';
|
||||
|
||||
test('base', t=>{
|
||||
let schema1 = {
|
||||
type: 'string',
|
||||
default: 'xxx'
|
||||
}
|
||||
|
||||
let schema2 = {
|
||||
type: 'string',
|
||||
format: 'email'
|
||||
}
|
||||
|
||||
let result = mergeJsonSchema(schema1, schema2)
|
||||
|
||||
t.deepEqual(result, {
|
||||
type:'string',
|
||||
default: 'xxx',
|
||||
format: 'email'
|
||||
})
|
||||
})
|
||||
|
||||
test('object', t=>{
|
||||
let schema1 = {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"xxx": 1,
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let schema2 = {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "string",
|
||||
"description": "dd"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = mergeJsonSchema(schema1, schema2)
|
||||
|
||||
t.deepEqual(result, {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"xxx": 1,
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "dd"
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('array', t=>{
|
||||
let schema1 = {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "array",
|
||||
"tt":1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"xxx": "2",
|
||||
"properties": {
|
||||
"field_3": {
|
||||
"format": 'ttt',
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let schema2 = {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"field_3": {
|
||||
"type": "string",
|
||||
"enum": [1,2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = mergeJsonSchema(schema1, schema2)
|
||||
|
||||
t.deepEqual(result, {
|
||||
"type": "object",
|
||||
"title": "empty object",
|
||||
"properties": {
|
||||
"field_1": {
|
||||
"type": "array",
|
||||
"tt":1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"xxx": "2",
|
||||
"properties": {
|
||||
"field_3": {
|
||||
"format": 'ttt',
|
||||
"type": "string",
|
||||
"enum": [1,2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user