yapi-vendor
Version:
586 lines (557 loc) • 17 kB
JavaScript
import './View.scss';
import React, { PureComponent as Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Table, Icon, Row, Col, Tooltip, message } from 'antd';
import { Link } from 'react-router-dom';
import AceEditor from 'client/components/AceEditor/AceEditor';
import { formatTime, safeArray } from '../../../../common.js';
import ErrMsg from '../../../../components/ErrMsg/ErrMsg.js';
import variable from '../../../../constants/variable';
import constants from '../../../../constants/variable.js';
import copy from 'copy-to-clipboard';
import SchemaTable from '../../../../components/SchemaTable/SchemaTable.js';
const HTTP_METHOD = constants.HTTP_METHOD;
(state => {
return {
curData: state.inter.curdata,
custom_field: state.group.field,
currProject: state.project.currProject
};
})
class View extends Component {
constructor(props) {
super(props);
this.state = {
init: true,
enter: false
};
}
static propTypes = {
curData: PropTypes.object,
currProject: PropTypes.object,
custom_field: PropTypes.object
};
req_body_form(req_body_type, req_body_form) {
if (req_body_type === 'form') {
const columns = [
{
title: '参数名称',
dataIndex: 'name',
key: 'name',
width: 140
},
{
title: '参数类型',
dataIndex: 'type',
key: 'type',
width: 100,
render: text => {
text = text || '';
return text.toLowerCase() === 'text' ? (
<span>
<i className="query-icon text">T</i>文本
</span>
) : (
<span>
<Icon type="file" className="query-icon" />文件
</span>
);
}
},
{
title: '是否必须',
dataIndex: 'required',
key: 'required',
width: 100
},
{
title: '示例',
dataIndex: 'example',
key: 'example',
width: 80,
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.example}</p>;
}
},
{
title: '备注',
dataIndex: 'value',
key: 'value',
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.value}</p>;
}
}
];
const dataSource = [];
if (req_body_form && req_body_form.length) {
req_body_form.map((item, i) => {
dataSource.push({
key: i,
name: item.name,
value: item.desc,
example: item.example,
required: item.required == 0 ? '否' : '是',
type: item.type
});
});
}
return (
<div style={{ display: dataSource.length ? '' : 'none' }} className="colBody">
<Table
bordered
size="small"
pagination={false}
columns={columns}
dataSource={dataSource}
/>
</div>
);
}
}
res_body(res_body_type, res_body, res_body_is_json_schema) {
if (res_body_type === 'json') {
if (res_body_is_json_schema) {
return <SchemaTable dataSource={res_body} />;
} else {
return (
<div className="colBody">
{/* <div id="vres_body_json" style={{ minHeight: h * 16 + 100 }}></div> */}
<AceEditor data={res_body} readOnly={true} style={{ minHeight: 600 }} />
</div>
);
}
} else if (res_body_type === 'raw') {
return (
<div className="colBody">
<AceEditor data={res_body} readOnly={true} mode="text" style={{ minHeight: 300 }} />
</div>
);
}
}
req_body(req_body_type, req_body_other, req_body_is_json_schema) {
if (req_body_other) {
if (req_body_is_json_schema && req_body_type === 'json') {
return <SchemaTable dataSource={req_body_other} />;
} else {
return (
<div className="colBody">
<AceEditor
data={req_body_other}
readOnly={true}
style={{ minHeight: 300 }}
mode={req_body_type === 'json' ? 'javascript' : 'text'}
/>
</div>
);
}
}
}
req_query(query) {
const columns = [
{
title: '参数名称',
dataIndex: 'name',
width: 140,
key: 'name'
},
{
title: '是否必须',
width: 100,
dataIndex: 'required',
key: 'required'
},
{
title: '示例',
dataIndex: 'example',
key: 'example',
width: 80,
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.example}</p>;
}
},
{
title: '备注',
dataIndex: 'value',
key: 'value',
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.value}</p>;
}
}
];
const dataSource = [];
if (query && query.length) {
query.map((item, i) => {
dataSource.push({
key: i,
name: item.name,
value: item.desc,
example: item.example,
required: item.required == 0 ? '否' : '是'
});
});
}
return (
<Table bordered size="small" pagination={false} columns={columns} dataSource={dataSource} />
);
}
countEnter(str) {
let i = 0;
let c = 0;
if (!str || !str.indexOf) {
return 0;
}
while (str.indexOf('\n', i) > -1) {
i = str.indexOf('\n', i) + 2;
c++;
}
return c;
}
componentDidMount() {
if (!this.props.curData.title && this.state.init) {
this.setState({ init: false });
}
}
enterItem = () => {
this.setState({
enter: true
});
};
leaveItem = () => {
this.setState({
enter: false
});
};
copyUrl = url => {
copy(url);
message.success('已经成功复制到剪切板');
};
flagMsg = (mock, strice) => {
if (mock && strice) {
return <span>( 全局mock & 严格模式 )</span>;
} else if (!mock && strice) {
return <span>( 严格模式 )</span>;
} else if (mock && !strice) {
return <span>( 全局mock )</span>;
} else {
return;
}
};
render() {
const dataSource = [];
if (this.props.curData.req_headers && this.props.curData.req_headers.length) {
this.props.curData.req_headers.map((item, i) => {
dataSource.push({
key: i,
name: item.name,
required: item.required == 0 ? '否' : '是',
value: item.value,
example: item.example,
desc: item.desc
});
});
}
const req_dataSource = [];
if (this.props.curData.req_params && this.props.curData.req_params.length) {
this.props.curData.req_params.map((item, i) => {
req_dataSource.push({
key: i,
name: item.name,
desc: item.desc,
example: item.example
});
});
}
const req_params_columns = [
{
title: '参数名称',
dataIndex: 'name',
key: 'name',
width: 140
},
{
title: '示例',
dataIndex: 'example',
key: 'example',
width: 80,
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.example}</p>;
}
},
{
title: '备注',
dataIndex: 'desc',
key: 'desc',
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.desc}</p>;
}
}
];
const columns = [
{
title: '参数名称',
dataIndex: 'name',
key: 'name',
width: '200px'
},
{
title: '参数值',
dataIndex: 'value',
key: 'value',
width: '300px'
},
{
title: '是否必须',
dataIndex: 'required',
key: 'required',
width: '100px'
},
{
title: '示例',
dataIndex: 'example',
key: 'example',
width: '80px',
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.example}</p>;
}
},
{
title: '备注',
dataIndex: 'desc',
key: 'desc',
render(_, item) {
return <p style={{ whiteSpace: 'pre-wrap' }}>{item.desc}</p>;
}
}
];
let status = {
undone: '未完成',
done: '已完成'
};
let bodyShow =
this.props.curData.req_body_other ||
(this.props.curData.req_body_type === 'form' &&
this.props.curData.req_body_form &&
this.props.curData.req_body_form.length);
let requestShow =
(dataSource && dataSource.length) ||
(req_dataSource && req_dataSource.length) ||
(this.props.curData.req_query && this.props.curData.req_query.length) ||
bodyShow;
let methodColor =
variable.METHOD_COLOR[
this.props.curData.method ? this.props.curData.method.toLowerCase() : 'get'
];
// statusColor = statusColor[this.props.curData.status?this.props.curData.status.toLowerCase():"undone"];
// const aceEditor = <div style={{ display: this.props.curData.req_body_other && (this.props.curData.req_body_type !== "form") ? "block" : "none" }} className="colBody">
// <AceEditor data={this.props.curData.req_body_other} readOnly={true} style={{ minHeight: 300 }} mode={this.props.curData.req_body_type === 'json' ? 'javascript' : 'text'} />
// </div>
if (!methodColor) {
methodColor = 'get';
}
const { tag, up_time, title, uid, username } = this.props.curData;
let res = (
<div className="caseContainer">
<h2 className="interface-title" style={{ marginTop: 0 }}>
基本信息
</h2>
<div className="panel-view">
<Row className="row">
<Col span={4} className="colKey">
接口名称:
</Col>
<Col span={8} className="colName">
<span title={title}>{title}</span>
</Col>
<Col span={4} className="colKey">
创 建 人:
</Col>
<Col span={8} className="colValue">
<Link className="user-name" to={'/user/profile/' + uid}>
<img src={'/api/user/avatar?uid=' + uid} className="user-img" />
{username}
</Link>
</Col>
</Row>
<Row className="row">
<Col span={4} className="colKey">
状  态:
</Col>
<Col span={8} className={'tag-status ' + this.props.curData.status}>
{status[this.props.curData.status]}
</Col>
<Col span={4} className="colKey">
更新时间:
</Col>
<Col span={8}>{formatTime(up_time)}</Col>
</Row>
{safeArray(tag) &&
safeArray(tag).length > 0 && (
<Row className="row remark">
<Col span={4} className="colKey">
Tag :
</Col>
<Col span={18} className="colValue">
{tag.join(' , ')}
</Col>
</Row>
)}
<Row className="row">
<Col span={4} className="colKey">
接口路径:
</Col>
<Col
span={18}
className="colValue"
onMouseEnter={this.enterItem}
onMouseLeave={this.leaveItem}
>
<span
style={{ color: methodColor.color, backgroundColor: methodColor.bac }}
className="colValue tag-method"
>
{this.props.curData.method}
</span>
<span className="colValue">
{this.props.currProject.basepath}
{this.props.curData.path}
</span>
<Tooltip title="复制路径">
<Icon
type="copy"
className="interface-url-icon"
onClick={() => this.copyUrl(this.props.currProject.basepath + this.props.curData.path)}
style={{ display: this.state.enter ? 'inline-block' : 'none' }}
/>
</Tooltip>
</Col>
</Row>
<Row className="row">
<Col span={4} className="colKey">
Mock地址:
</Col>
<Col span={18} className="colValue">
{this.flagMsg(this.props.currProject.is_mock_open, this.props.currProject.strice)}
<span
className="href"
onClick={() =>
window.open(
location.protocol +
'//' +
location.hostname +
(location.port !== '' ? ':' + location.port : '') +
`/mock/${this.props.currProject._id}${this.props.currProject.basepath}${
this.props.curData.path
}`,
'_blank'
)
}
>
{location.protocol +
'//' +
location.hostname +
(location.port !== '' ? ':' + location.port : '') +
`/mock/${this.props.currProject._id}${this.props.currProject.basepath}${
this.props.curData.path
}`}
</span>
</Col>
</Row>
{this.props.curData.custom_field_value &&
this.props.custom_field.enable && (
<Row className="row remark">
<Col span={4} className="colKey">
{this.props.custom_field.name}:
</Col>
<Col span={18} className="colValue">
{this.props.curData.custom_field_value}
</Col>
</Row>
)}
</div>
{this.props.curData.desc && <h2 className="interface-title">备注</h2>}
{this.props.curData.desc && (
<div
className="tui-editor-contents"
style={{ margin: '0px', padding: '0px 20px', float: 'none' }}
dangerouslySetInnerHTML={{ __html: this.props.curData.desc }}
/>
)}
<h2 className="interface-title" style={{ display: requestShow ? '' : 'none' }}>
请求参数
</h2>
{req_dataSource.length ? (
<div className="colHeader">
<h3 className="col-title">路径参数:</h3>
<Table
bordered
size="small"
pagination={false}
columns={req_params_columns}
dataSource={req_dataSource}
/>
</div>
) : (
''
)}
{dataSource.length ? (
<div className="colHeader">
<h3 className="col-title">Headers:</h3>
<Table
bordered
size="small"
pagination={false}
columns={columns}
dataSource={dataSource}
/>
</div>
) : (
''
)}
{this.props.curData.req_query && this.props.curData.req_query.length ? (
<div className="colQuery">
<h3 className="col-title">Query:</h3>
{this.req_query(this.props.curData.req_query)}
</div>
) : (
''
)}
<div
style={{
display:
this.props.curData.method &&
HTTP_METHOD[this.props.curData.method.toUpperCase()].request_body
? ''
: 'none'
}}
>
<h3 style={{ display: bodyShow ? '' : 'none' }} className="col-title">
Body:
</h3>
{this.props.curData.req_body_type === 'form'
? this.req_body_form(this.props.curData.req_body_type, this.props.curData.req_body_form)
: this.req_body(
this.props.curData.req_body_type,
this.props.curData.req_body_other,
this.props.curData.req_body_is_json_schema
)}
</div>
<h2 className="interface-title">返回数据</h2>
{this.res_body(
this.props.curData.res_body_type,
this.props.curData.res_body,
this.props.curData.res_body_is_json_schema
)}
</div>
);
if (!this.props.curData.title) {
if (this.state.init) {
res = <div />;
} else {
res = <ErrMsg type="noData" />;
}
}
return res;
}
}
export default View;