feat: 增加swagger URL 导入

This commit is contained in:
gaoxiaolin.gao 2018-07-09 16:04:25 +08:00
parent 9155572a18
commit a68f26ca6a
3 changed files with 254 additions and 116 deletions

View File

@ -1,6 +1,7 @@
### v1.3.19
* 增加项目文档记录wiki
* 支持swagger URL 导入
#### Bug Fixed

View File

@ -1,29 +1,42 @@
import React, { PureComponent as Component } from 'react'
import { Upload, Icon, message, Select, Tooltip, Button, Spin, Switch, Modal,Radio } from 'antd';
import React, { PureComponent as Component } from 'react';
import {
Upload,
Icon,
message,
Select,
Tooltip,
Button,
Spin,
Switch,
Modal,
Radio,
Input
} from 'antd';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import './ProjectData.scss';
import axios from 'axios';
import URL from 'url'
import URL from 'url';
const Dragger = Upload.Dragger;
import { saveImportData } from '../../../../reducer/modules/interface';
import { fetchUpdateLogData } from '../../../../reducer/modules/news.js'
import { fetchUpdateLogData } from '../../../../reducer/modules/news.js';
const Option = Select.Option;
const confirm = Modal.confirm;
const plugin = require('client/plugin.js');
const RadioGroup = Radio.Group;
const importDataModule = {};
const exportDataModule = {};
const HandleImportData = require('common/HandleImportData')
const HandleImportData = require('common/HandleImportData');
function handleExportRouteParams (url, value) {
if(!url) {
return
function handleExportRouteParams(url, value) {
if (!url) {
return;
}
let urlObj = URL.parse(url, true), query = {};
query = Object.assign(query, urlObj.query, {status: value});
let urlObj = URL.parse(url, true),
query = {};
query = Object.assign(query, urlObj.query, { status: value });
return URL.format({
pathname: urlObj.pathname,
query
@ -37,31 +50,31 @@ function handleExportRouteParams (url, value) {
// }
@connect(
state => {
return {
curCatid: -(-state.inter.curdata.catid),
basePath: state.project.currProject.basepath,
updateLogList: state.news.updateLogList
}
}, {
};
},
{
saveImportData,
fetchUpdateLogData
}
)
class ProjectData extends Component {
constructor(props) {
super(props);
this.state = {
selectCatid: "",
selectCatid: '',
menuList: [],
curImportType: null,
curExportType: null,
showLoading: false,
dataSync: false,
exportContent: 'all'
}
exportContent: 'all',
isSwaggerUrl: false,
swaggerUrl: ''
};
}
static propTypes = {
match: PropTypes.object,
@ -70,30 +83,28 @@ class ProjectData extends Component {
saveImportData: PropTypes.func,
fetchUpdateLogData: PropTypes.func,
updateLogList: PropTypes.array
}
};
componentWillMount() {
axios.get(`/api/interface/getCatMenu?project_id=${this.props.match.params.id}`).then((data) => {
axios.get(`/api/interface/getCatMenu?project_id=${this.props.match.params.id}`).then(data => {
if (data.data.errcode === 0) {
let menuList = data.data.data;
this.setState({
menuList: menuList
})
});
}
});
plugin.emitHook('import_data', importDataModule);
plugin.emitHook('export_data', exportDataModule, this.props.match.params.id);
}
selectChange(value) {
this.setState({
selectCatid: +value
})
});
}
uploadChange = (info) => {
uploadChange = info => {
const status = info.file.status;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
@ -103,9 +114,9 @@ class ProjectData extends Component {
} else if (status === 'error') {
message.error(`${info.file.name} 文件上传失败`);
}
}
};
handleAddInterface = async (res)=>{
handleAddInterface = async res => {
return await HandleImportData(
res,
this.props.match.params.id,
@ -113,14 +124,14 @@ class ProjectData extends Component {
this.state.menuList,
this.props.basePath,
this.state.dataSync,
message.error,
message.success,
()=> this.setState({ showLoading: false })
)
}
message.error,
message.success,
() => this.setState({ showLoading: false })
);
};
handleFile = (info) => {
// 本地文件上传
handleFile = info => {
if (!this.state.curImportType) {
return message.error('请选择导入数据的方式');
}
@ -135,27 +146,28 @@ class ProjectData extends Component {
this.showConfirm(res);
} else {
// 未开启同步
await this.handleAddInterface(res)
await this.handleAddInterface(res);
}
}
};
} else {
message.error("请选择上传的默认分类");
message.error('请选择上传的默认分类');
}
};
}
showConfirm = async (res) => {
showConfirm = async res => {
let that = this;
let typeid = this.props.match.params.id;
let apiCollections = res.apis.map(item=>{
let apiCollections = res.apis.map(item => {
return {
method:item.method,
method: item.method,
path: item.path
}
})
let result = await this.props.fetchUpdateLogData({ type: 'project', typeid, apis: apiCollections })
};
});
let result = await this.props.fetchUpdateLogData({
type: 'project',
typeid,
apis: apiCollections
});
let domainData = result.payload.data.data;
const ref = confirm({
title: '您确认要进行数据同步????',
@ -163,59 +175,99 @@ class ProjectData extends Component {
okType: 'danger',
iconType: 'exclamation-circle',
className: 'dataImport-confirm',
okText: "确认",
cancelText: "取消",
okText: '确认',
cancelText: '取消',
content: (
<div className="postman-dataImport-modal">
<div className="postman-dataImport-modal-content">
{
domainData.map((item, index) => {
return (
<div key={index} className="postman-dataImport-show-diff">
<span className="logcontent" dangerouslySetInnerHTML={{ __html: item.content }}>
</span>
</div>
)
})
}
{domainData.map((item, index) => {
return (
<div key={index} className="postman-dataImport-show-diff">
<span className="logcontent" dangerouslySetInnerHTML={{ __html: item.content }} />
</div>
);
})}
</div>
<p className="info">温馨提示 数据同步后可能会造成原本的修改数据丢失</p>
</div>
),
async onOk() {
await that.handleAddInterface(res)
await that.handleAddInterface(res);
},
onCancel() {
that.setState({ showLoading: false, dataSync: false })
ref.destroy()
that.setState({ showLoading: false, dataSync: false });
ref.destroy();
}
});
}
};
handleImportType = (val) => {
handleImportType = val => {
this.setState({
curImportType: val
})
}
});
};
handleExportType = (val) => {
handleExportType = val => {
this.setState({
curExportType: val
})
}
});
};
onChange = (checked) => {
// 处理导入信息同步
onChange = checked => {
this.setState({
dataSync: checked
})
}
});
};
handleChange = (e) => {
// 处理swagger URL 导入
handleUrlChange = checked => {
this.setState({
isSwaggerUrl: checked
});
};
// 记录输入的url
swaggerUrlInput = url => {
this.setState({
swaggerUrl: url
});
};
// url导入上传
onUrlUpload = async () => {
if (!this.state.curImportType) {
return message.error('请选择导入数据的方式');
}
if(!this.state.swaggerUrl) {
return message.error('url 不能为空');
}
if (this.state.selectCatid) {
this.setState({ showLoading: true });
try {
let content = await axios(this.state.swaggerUrl);
content = content.data;
let res = await importDataModule[this.state.curImportType].run(content);
if (this.state.dataSync) {
// 开启同步
this.showConfirm(res);
} else {
// 未开启同步
await this.handleAddInterface(res);
}
} catch (e) {
message.error(e.message);
}
} else {
message.error('请选择上传的默认分类');
}
};
handleChange = e => {
this.setState({ exportContent: e.target.value });
}
};
/**
*
@ -231,9 +283,12 @@ class ProjectData extends Component {
action: '/api/interface/interUpload',
customRequest: this.handleFile,
onChange: this.uploadChange
}
};
let exportUrl = this.state.curExportType && exportDataModule[this.state.curExportType] && exportDataModule[this.state.curExportType].route;
let exportUrl =
this.state.curExportType &&
exportDataModule[this.state.curExportType] &&
exportDataModule[this.state.curExportType].route;
let exportHref = handleExportRouteParams(exportUrl, this.state.exportContent);
// console.log('inter', this.state.exportContent);
@ -242,14 +297,27 @@ class ProjectData extends Component {
<div className="m-panel">
<div className="postman-dataImport">
<div className="dataImportCon">
<div ><h3>数据导入&nbsp;<a target="_blank" rel="noopener noreferrer" href="https://yapi.ymfe.org/documents/data.html" >
<Tooltip title="点击查看文档"><Icon type="question-circle-o" /></Tooltip>
</a></h3></div>
<div>
<h3>
数据导入&nbsp;<a
target="_blank"
rel="noopener noreferrer"
href="https://yapi.ymfe.org/documents/data.html"
>
<Tooltip title="点击查看文档">
<Icon type="question-circle-o" />
</Tooltip>
</a>
</h3>
</div>
<div className="dataImportTile">
<Select placeholder="请选择导入数据的方式" onChange={this.handleImportType}>
{Object.keys(importDataModule).map((name) => {
return <Option key={name} value={name}>{importDataModule[name].name}</Option>
{Object.keys(importDataModule).map(name => {
return (
<Option key={name} value={name}>
{importDataModule[name].name}
</Option>
);
})}
</Select>
</div>
@ -260,40 +328,94 @@ class ProjectData extends Component {
placeholder="请选择数据导入的默认分类"
optionFilterProp="children"
onChange={this.selectChange.bind(this)}
filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{this.state.menuList.map((item, key) => {
return <Option key={key} value={item._id + ""}>{item.name}</Option>;
return (
<Option key={key} value={item._id + ''}>
{item.name}
</Option>
);
})}
</Select>
</div>
<div className="dataSync">
<span>开启数据同步<Tooltip title="开启数据同步后会覆盖项目中原本的数据"><Icon type="question-circle-o" /></Tooltip> :</span>
<span>
开启数据同步<Tooltip title="开启数据同步后会覆盖项目中原本的数据">
<Icon type="question-circle-o" />
</Tooltip>{' '}
:
</span>
<Switch checked={this.state.dataSync} onChange={this.onChange} />
</div>
{this.state.curImportType === 'swagger' && (
<div className="dataSync">
<span>
开启url导入<Tooltip title="swagger url 导入">
<Icon type="question-circle-o" />
</Tooltip>{' '}
&nbsp;&nbsp;:
</span>
</div>
<div style={{ marginTop: 16, height: 180 }}>
<Spin spinning={this.state.showLoading} tip="上传中...">
<Dragger {...uploadMess}>
<p className="ant-upload-drag-icon">
<Icon type="inbox" />
</p>
<p className="ant-upload-text">点击或者拖拽文件到上传区域</p>
<p className="ant-upload-hint" onClick={(e)=>{
e.stopPropagation();
}} dangerouslySetInnerHTML={{__html: this.state.curImportType ? importDataModule[this.state.curImportType].desc : null}} ></p>
</Dragger>
</Spin>
</div>
<Switch checked={this.state.isSwaggerUrl} onChange={this.handleUrlChange} />
</div>
)}
{this.state.isSwaggerUrl ? (
<div className="import-content url-import-content">
<Input
placeholder="http://demo.swagger.io/v2/swagger.json"
onChange={e => this.swaggerUrlInput(e.target.value)}
/>
<Button type="primary" className="url-btn" onClick={this.onUrlUpload} loading={this.state.showLoading}>
上传
</Button>
</div>
) : (
<div className="import-content">
<Spin spinning={this.state.showLoading} tip="上传中...">
<Dragger {...uploadMess}>
<p className="ant-upload-drag-icon">
<Icon type="inbox" />
</p>
<p className="ant-upload-text">点击或者拖拽文件到上传区域</p>
<p
className="ant-upload-hint"
onClick={e => {
e.stopPropagation();
}}
dangerouslySetInnerHTML={{
__html: this.state.curImportType
? importDataModule[this.state.curImportType].desc
: null
}}
/>
</Dragger>
</Spin>
</div>
)}
</div>
<div className="dataImportCon" style={{ marginLeft: '20px', display: Object.keys(exportDataModule).length > 0 ? '' : 'none' }}>
<div ><h3>数据导出</h3></div>
<div
className="dataImportCon"
style={{
marginLeft: '20px',
display: Object.keys(exportDataModule).length > 0 ? '' : 'none'
}}
>
<div>
<h3>数据导出</h3>
</div>
<div className="dataImportTile">
<Select placeholder="请选择导出数据的方式" onChange={this.handleExportType}>
{Object.keys(exportDataModule).map((name) => {
return <Option key={name} value={name}>{exportDataModule[name].name}</Option>
{Object.keys(exportDataModule).map(name => {
return (
<Option key={name} value={name}>
{exportDataModule[name].name}
</Option>
);
})}
</Select>
</div>
@ -304,25 +426,28 @@ class ProjectData extends Component {
</RadioGroup>
</div>
<div className="export-content">
{this.state.curExportType ?
{this.state.curExportType ? (
<div>
<p className="export-desc">{exportDataModule[this.state.curExportType].desc}</p>
<a target="_blank" href={exportHref} >
<Button className="export-button" type="primary" size="large"> 导出 </Button>
<a target="_blank" href={exportHref}>
<Button className="export-button" type="primary" size="large">
{' '}
导出{' '}
</Button>
</a>
</div>
:
<Button disabled className="export-button" type="primary" size="large"> 导出 </Button>
}
) : (
<Button disabled className="export-button" type="primary" size="large">
{' '}
导出{' '}
</Button>
)}
</div>
</div>
</div>
</div>
</div>
)
);
}
}

View File

@ -35,6 +35,18 @@
}
}
.import-content {
margin-top: 16px;
height: 180px;
}
.url-import-content {
text-align: center;
.url-btn{
margin-top: 16px;
}
}
.export-content{
text-align: center;
}