fork from bc4552c5a8
This commit is contained in:
524
client/containers/Project/Setting/ProjectData/ProjectData.js
Normal file
524
client/containers/Project/Setting/ProjectData/ProjectData.js
Normal file
@@ -0,0 +1,524 @@
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import {
|
||||
Upload,
|
||||
Icon,
|
||||
message,
|
||||
Select,
|
||||
Tooltip,
|
||||
Button,
|
||||
Spin,
|
||||
Switch,
|
||||
Modal,
|
||||
Radio,
|
||||
Input,
|
||||
Checkbox
|
||||
} from 'antd';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import './ProjectData.scss';
|
||||
import axios from 'axios';
|
||||
|
||||
import URL from 'url';
|
||||
|
||||
const Dragger = Upload.Dragger;
|
||||
import { saveImportData } from '../../../../reducer/modules/interface';
|
||||
import { fetchUpdateLogData } from '../../../../reducer/modules/news.js';
|
||||
import { handleSwaggerUrlData } from '../../../../reducer/modules/project';
|
||||
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');
|
||||
function handleExportRouteParams(url, status, isWiki) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
let urlObj = URL.parse(url, true),
|
||||
query = {};
|
||||
query = Object.assign(query, urlObj.query, { status, isWiki });
|
||||
return URL.format({
|
||||
pathname: urlObj.pathname,
|
||||
query
|
||||
});
|
||||
}
|
||||
|
||||
// exportDataModule.pdf = {
|
||||
// name: 'Pdf',
|
||||
// route: '/api/interface/download_crx',
|
||||
// desc: '导出项目接口文档为 pdf 文件'
|
||||
// }
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
curCatid: -(-state.inter.curdata.catid),
|
||||
basePath: state.project.currProject.basepath,
|
||||
updateLogList: state.news.updateLogList,
|
||||
swaggerUrlData: state.project.swaggerUrlData
|
||||
};
|
||||
},
|
||||
{
|
||||
saveImportData,
|
||||
fetchUpdateLogData,
|
||||
handleSwaggerUrlData
|
||||
}
|
||||
)
|
||||
class ProjectData extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectCatid: '',
|
||||
menuList: [],
|
||||
curImportType: 'swagger',
|
||||
curExportType: null,
|
||||
showLoading: false,
|
||||
dataSync: 'merge',
|
||||
exportContent: 'all',
|
||||
isSwaggerUrl: false,
|
||||
swaggerUrl: '',
|
||||
isWiki: false
|
||||
};
|
||||
}
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
curCatid: PropTypes.number,
|
||||
basePath: PropTypes.string,
|
||||
saveImportData: PropTypes.func,
|
||||
fetchUpdateLogData: PropTypes.func,
|
||||
updateLogList: PropTypes.array,
|
||||
handleSwaggerUrlData: PropTypes.func,
|
||||
swaggerUrlData: PropTypes.string
|
||||
};
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
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,
|
||||
selectCatid: menuList[0]._id
|
||||
});
|
||||
}
|
||||
});
|
||||
plugin.emitHook('import_data', importDataModule);
|
||||
plugin.emitHook('export_data', exportDataModule, this.props.match.params.id);
|
||||
}
|
||||
|
||||
selectChange(value) {
|
||||
this.setState({
|
||||
selectCatid: +value
|
||||
});
|
||||
}
|
||||
|
||||
uploadChange = info => {
|
||||
const status = info.file.status;
|
||||
if (status !== 'uploading') {
|
||||
console.log(info.file, info.fileList);
|
||||
}
|
||||
if (status === 'done') {
|
||||
message.success(`${info.file.name} 文件上传成功`);
|
||||
} else if (status === 'error') {
|
||||
message.error(`${info.file.name} 文件上传失败`);
|
||||
}
|
||||
};
|
||||
|
||||
handleAddInterface = async res => {
|
||||
return await HandleImportData(
|
||||
res,
|
||||
this.props.match.params.id,
|
||||
this.state.selectCatid,
|
||||
this.state.menuList,
|
||||
this.props.basePath,
|
||||
this.state.dataSync,
|
||||
message.error,
|
||||
message.success,
|
||||
() => this.setState({ showLoading: false })
|
||||
);
|
||||
};
|
||||
|
||||
// 本地文件上传
|
||||
handleFile = info => {
|
||||
if (!this.state.curImportType) {
|
||||
return message.error('请选择导入数据的方式');
|
||||
}
|
||||
if (this.state.selectCatid) {
|
||||
this.setState({ showLoading: true });
|
||||
let reader = new FileReader();
|
||||
reader.readAsText(info.file);
|
||||
reader.onload = async res => {
|
||||
res = await importDataModule[this.state.curImportType].run(res.target.result);
|
||||
if (this.state.dataSync === 'merge') {
|
||||
// 开启同步
|
||||
this.showConfirm(res);
|
||||
} else {
|
||||
// 未开启同步
|
||||
await this.handleAddInterface(res);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
message.error('请选择上传的默认分类');
|
||||
}
|
||||
};
|
||||
|
||||
showConfirm = async res => {
|
||||
let that = this;
|
||||
let typeid = this.props.match.params.id;
|
||||
let apiCollections = res.apis.map(item => {
|
||||
return {
|
||||
method: item.method,
|
||||
path: item.path
|
||||
};
|
||||
});
|
||||
let result = await this.props.fetchUpdateLogData({
|
||||
type: 'project',
|
||||
typeid,
|
||||
apis: apiCollections
|
||||
});
|
||||
let domainData = result.payload.data.data;
|
||||
const ref = confirm({
|
||||
title: '您确认要进行数据同步????',
|
||||
width: 600,
|
||||
okType: 'danger',
|
||||
iconType: 'exclamation-circle',
|
||||
className: 'dataImport-confirm',
|
||||
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 }} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<p className="info">温馨提示: 数据同步后,可能会造成原本的修改数据丢失</p>
|
||||
</div>
|
||||
),
|
||||
async onOk() {
|
||||
await that.handleAddInterface(res);
|
||||
},
|
||||
onCancel() {
|
||||
that.setState({ showLoading: false, dataSync: 'normal' });
|
||||
ref.destroy();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleImportType = val => {
|
||||
this.setState({
|
||||
curImportType: val,
|
||||
isSwaggerUrl: false
|
||||
});
|
||||
};
|
||||
|
||||
handleExportType = val => {
|
||||
this.setState({
|
||||
curExportType: val,
|
||||
isWiki: false
|
||||
});
|
||||
};
|
||||
|
||||
// 处理导入信息同步
|
||||
onChange = checked => {
|
||||
this.setState({
|
||||
dataSync: checked
|
||||
});
|
||||
};
|
||||
|
||||
// 处理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 {
|
||||
// 处理swagger url 导入
|
||||
await this.props.handleSwaggerUrlData(this.state.swaggerUrl);
|
||||
// let result = json5_parse(this.props.swaggerUrlData)
|
||||
let res = await importDataModule[this.state.curImportType].run(this.props.swaggerUrlData);
|
||||
if (this.state.dataSync === 'merge') {
|
||||
// merge
|
||||
this.showConfirm(res);
|
||||
} else {
|
||||
// 未开启同步
|
||||
await this.handleAddInterface(res);
|
||||
}
|
||||
} catch (e) {
|
||||
this.setState({ showLoading: false });
|
||||
message.error(e.message);
|
||||
}
|
||||
} else {
|
||||
message.error('请选择上传的默认分类');
|
||||
}
|
||||
};
|
||||
|
||||
// 处理导出接口是全部还是公开
|
||||
handleChange = e => {
|
||||
this.setState({ exportContent: e.target.value });
|
||||
};
|
||||
|
||||
// 处理是否开启wiki导出
|
||||
handleWikiChange = e => {
|
||||
this.setState({
|
||||
isWiki: e.target.checked
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns
|
||||
* @memberof ProjectData
|
||||
*/
|
||||
render() {
|
||||
const uploadMess = {
|
||||
name: 'interfaceData',
|
||||
multiple: true,
|
||||
showUploadList: false,
|
||||
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 exportHref = handleExportRouteParams(
|
||||
exportUrl,
|
||||
this.state.exportContent,
|
||||
this.state.isWiki
|
||||
);
|
||||
|
||||
// console.log('inter', this.state.exportContent);
|
||||
return (
|
||||
<div className="g-row">
|
||||
<div className="m-panel">
|
||||
<div className="postman-dataImport">
|
||||
<div className="dataImportCon">
|
||||
<div>
|
||||
<h3>
|
||||
数据导入
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://hellosean1025.github.io/yapi/documents/data.html"
|
||||
>
|
||||
<Tooltip title="点击查看文档">
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="dataImportTile">
|
||||
<Select
|
||||
placeholder="请选择导入数据的方式"
|
||||
value={this.state.curImportType}
|
||||
onChange={this.handleImportType}
|
||||
>
|
||||
{Object.keys(importDataModule).map(name => {
|
||||
return (
|
||||
<Option key={name} value={name}>
|
||||
{importDataModule[name].name}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
<div className="catidSelect">
|
||||
<Select
|
||||
value={this.state.selectCatid + ''}
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
placeholder="请选择数据导入的默认分类"
|
||||
optionFilterProp="children"
|
||||
onChange={this.selectChange.bind(this)}
|
||||
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>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
<div className="dataSync">
|
||||
<span className="label">
|
||||
数据同步
|
||||
<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>
|
||||
<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">
|
||||
<span className="label">
|
||||
开启url导入
|
||||
<Tooltip title="swagger url 导入">
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>{' '}
|
||||
|
||||
</span>
|
||||
|
||||
<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="dataImportTile">
|
||||
<Select placeholder="请选择导出数据的方式" onChange={this.handleExportType}>
|
||||
{Object.keys(exportDataModule).map(name => {
|
||||
return (
|
||||
<Option key={name} value={name}>
|
||||
{exportDataModule[name].name}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="dataExport">
|
||||
<RadioGroup defaultValue="all" onChange={this.handleChange}>
|
||||
<Radio value="all">全部接口</Radio>
|
||||
<Radio value="open">公开接口</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="export-content">
|
||||
{this.state.curExportType ? (
|
||||
<div>
|
||||
<p className="export-desc">{exportDataModule[this.state.curExportType].desc}</p>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={exportHref}>
|
||||
<Button className="export-button" type="primary" size="large">
|
||||
{' '}
|
||||
导出{' '}
|
||||
</Button>
|
||||
</a>
|
||||
<Checkbox
|
||||
checked={this.state.isWiki}
|
||||
onChange={this.handleWikiChange}
|
||||
className="wiki-btn"
|
||||
disabled={this.state.curExportType === 'json'}
|
||||
>
|
||||
添加wiki
|
||||
<Tooltip title="开启后 html 和 markdown 数据导出会带上wiki数据">
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>{' '}
|
||||
</Checkbox>
|
||||
</div>
|
||||
) : (
|
||||
<Button disabled className="export-button" type="primary" size="large">
|
||||
{' '}
|
||||
导出{' '}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProjectData;
|
||||
Reference in New Issue
Block a user