Files
yapi/client/containers/Project/Setting/ProjectData/ProjectData.js
2024-03-01 20:28:14 +08:00

525 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
数据导入&nbsp;
<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">
数据同步&nbsp;
<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导入&nbsp;
<Tooltip title="swagger url 导入">
<Icon type="question-circle-o" />
</Tooltip>{' '}
&nbsp;&nbsp;
</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&nbsp;
<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;