mirror of
https://github.com/YMFE/yapi.git
synced 2025-03-19 14:30:31 +08:00
Merge branch 'dev' of http://gitlab.corp.qunar.com/mfe/yapi into dev
This commit is contained in:
commit
715cd2e012
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Mock from 'mockjs'
|
||||
import { Button, Input, Select, Alert, Spin, Icon, Collapse, Tooltip, message, AutoComplete } from 'antd'
|
||||
import { Button, Input, Select, Alert, Spin, Icon, Collapse, Tooltip, message, AutoComplete, Switch } from 'antd'
|
||||
import { autobind } from 'core-decorators';
|
||||
import constants from '../../constants/variable.js'
|
||||
|
||||
@ -40,7 +40,7 @@ const mockDataSource = wordList.map(item => {
|
||||
});
|
||||
|
||||
|
||||
const { TextArea } = Input;
|
||||
// const { TextArea } = Input;
|
||||
const InputGroup = Input.Group;
|
||||
const Option = Select.Option;
|
||||
const Panel = Collapse.Panel;
|
||||
@ -71,7 +71,10 @@ export default class Run extends Component {
|
||||
loading: false,
|
||||
validRes: [],
|
||||
hasPlugin: true,
|
||||
test_status: null
|
||||
test_status: null,
|
||||
resTest: false,
|
||||
resStatusCode: null,
|
||||
resStatusText: ''
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@ -214,7 +217,12 @@ export default class Run extends Component {
|
||||
data: bodyType === 'form' ? this.arrToObj(bodyForm) : bodyOther,
|
||||
files: bodyType === 'form' ? this.getFiles(bodyForm) : {},
|
||||
file: bodyType === 'file' ? 'single-file' : null,
|
||||
success: (res, header) => {
|
||||
success: (res, header, third) => {
|
||||
console.log('suc',third);
|
||||
this.setState({
|
||||
resStatusCode: third.res.status,
|
||||
resStatusText: third.res.statusText
|
||||
})
|
||||
try {
|
||||
if (isJsonData(header)) {
|
||||
res = json_parse(res);
|
||||
@ -259,7 +267,12 @@ export default class Run extends Component {
|
||||
console.error(e.message)
|
||||
}
|
||||
},
|
||||
error: (err, header) => {
|
||||
error: (err, header, third) => {
|
||||
console.log('err',third);
|
||||
this.setState({
|
||||
resStatusCode: third.res.status,
|
||||
resStatusText: third.res.statusText
|
||||
})
|
||||
try {
|
||||
err = json_parse(err);
|
||||
} catch (e) {
|
||||
@ -496,6 +509,13 @@ export default class Run extends Component {
|
||||
console.log(index)
|
||||
}
|
||||
|
||||
@autobind
|
||||
onTestSwitched(checked) {
|
||||
this.setState({
|
||||
resTest: checked
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { method, domains, pathParam, pathname, query, headers, bodyForm, caseEnv, bodyType, resHeader, loading, validRes } = this.state;
|
||||
HTTP_METHOD[method] = HTTP_METHOD[method] || {}
|
||||
@ -722,30 +742,59 @@ export default class Run extends Component {
|
||||
</Collapse>
|
||||
|
||||
<h2 className="interface-title">返回结果</h2>
|
||||
<Spin spinning={this.state.loading}>
|
||||
<div className="res-code"></div>
|
||||
<Collapse defaultActiveKey={['0', '1']} bordered={true}>
|
||||
{this.state.resStatusCode ?
|
||||
<Spin spinning={this.state.loading}>
|
||||
<h2 className={'res-code ' + ((this.state.resStatusCode >= 200 && this.state.resStatusCode < 400 && !this.state.loading) ? 'success' : 'fail')}>{this.state.resStatusCode + ' ' + this.state.resStatusText}</h2>
|
||||
|
||||
<div className="container-header-body">
|
||||
<div className="header">
|
||||
<div className="container-title">
|
||||
<h4>Headers</h4>
|
||||
</div>
|
||||
<div id="res-headers-pretty" className="pretty-editor-header"></div>
|
||||
</div>
|
||||
<div className="resizer">
|
||||
<div className="container-title">
|
||||
<h4 style={{visibility: 'hidden'}}>1</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div className="container-title">
|
||||
<h4>Body</h4>
|
||||
</div>
|
||||
<div id="res-body-pretty" className="pretty-editor-body" style={{ display: isResJson ? '' : 'none' }}></div>
|
||||
<div
|
||||
style={{display: isResJson ? 'none' : ''}}
|
||||
className="res-body-text"
|
||||
>{this.state.res && this.state.res.toString()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin> : <p>发送请求后在这里查看返回结果。</p>}
|
||||
|
||||
{/*<Collapse defaultActiveKey={['0', '1']} bordered={true}>
|
||||
<Panel header="BODY" key="0" >
|
||||
<div id="res-body-pretty" className="pretty-editor-body" style={{ display: isResJson ? '' : 'none' }}></div>
|
||||
<TextArea
|
||||
<div id="res-body-pretty" className="pretty-editor-body" style={{ display: isResJson ? '' : 'none' }}></div>*/}
|
||||
{/*<TextArea
|
||||
style={{ display: isResJson ? 'none' : '' }}
|
||||
value={this.state.res && this.state.res.toString()}
|
||||
autosize={{ minRows: 10, maxRows: 20 }}
|
||||
></TextArea>
|
||||
<h3 style={{ marginTop: '15px', display: isResJson ? '' : 'none' }}>返回 Body 验证结果:</h3>
|
||||
<div style={{ display: isResJson ? '' : 'none' }}>
|
||||
{validResView}
|
||||
</div>
|
||||
</Panel>
|
||||
<Panel header="HEADERS" key="1" >
|
||||
{/*<TextArea
|
||||
></TextArea>*/}
|
||||
{/*</Panel>
|
||||
<Panel header="HEADERS" key="1" >*/}
|
||||
{/*<TextArea
|
||||
value={typeof this.state.resHeader === 'object' ? JSON.stringify(this.state.resHeader, null, 2) : this.state.resHeader.toString()}
|
||||
autosize={{ minRows: 2, maxRows: 10 }}
|
||||
></TextArea>*/}
|
||||
<div id="res-headers-pretty" className="pretty-editor-header"></div>
|
||||
{/*<div id="res-headers-pretty" className="pretty-editor-header"></div>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</Spin>
|
||||
</Collapse>*/}
|
||||
|
||||
<h2 className="interface-title">数据结构验证
|
||||
<Switch style={{verticalAlign: 'text-bottom', marginLeft: '8px'}} checked={this.state.resTest} onChange={this.onTestSwitched} />
|
||||
</h2>
|
||||
<div className={(isResJson && this.state.resTest) ? '' : 'none' }>
|
||||
{(isResJson && this.state.resTest) ? validResView : <div><p>若开启此功能,则发送请求后在这里查看验证结果。</p><p>数据结构验证在接口编辑页面配置,YApi 将根据 Response body 验证请求返回的结果。</p></div>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -127,9 +127,9 @@ class InterfaceColContent extends Component {
|
||||
status = 'ok';
|
||||
} else if (result.code === 1) {
|
||||
status = 'invalid'
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
status = 'error';
|
||||
status = 'error';
|
||||
result = e;
|
||||
}
|
||||
this.reports[curitem._id] = result;
|
||||
@ -177,7 +177,7 @@ class InterfaceColContent extends Component {
|
||||
headers: that.getHeadersObj(interfaceData.req_headers),
|
||||
data: interfaceData.req_body_type === 'form' ? that.arrToObj(interfaceData.req_body_form) : interfaceData.req_body_other,
|
||||
success: (res, header) => {
|
||||
res = json_parse(res);
|
||||
res = json_parse(res);
|
||||
result.res_header = header;
|
||||
result.res_body = res;
|
||||
if (res && typeof res === 'object') {
|
||||
@ -206,7 +206,7 @@ class InterfaceColContent extends Component {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
|
||||
err = err || '请求异常';
|
||||
result.code = 400;
|
||||
result.res_header = header;
|
||||
@ -442,7 +442,7 @@ class InterfaceColContent extends Component {
|
||||
|
||||
return (
|
||||
<div className="interface-col">
|
||||
<h2 style={{ marginBottom: '10px', display: 'inline-block' }}>测试集合 <a target="_blank" rel="noopener noreferrer" href="https://yapi.ymfe.org/case.html" >
|
||||
<h2 className="interface-title" style={{ display: 'inline-block', margin: 0, marginBottom: '16px' }}>测试集合 <a target="_blank" rel="noopener noreferrer" href="https://yapi.ymfe.org/case.html" >
|
||||
<Tooltip title="点击查看文档"><Icon type="question-circle-o" /></Tooltip>
|
||||
</a></h2>
|
||||
<Button type="primary" style={{ float: 'right' }} onClick={this.executeTests}>开始测试</Button>
|
||||
@ -478,4 +478,4 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default InterfaceColContent
|
||||
export default InterfaceColContent
|
||||
|
@ -89,12 +89,11 @@
|
||||
}
|
||||
|
||||
.interface-col{
|
||||
padding: 16px;
|
||||
padding: 24px;
|
||||
.interface-col-table-header{
|
||||
background-color: rgb(238, 238, 238);
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size:14px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
@import '../../../../styles/mixin.scss';
|
||||
|
||||
.interface-edit{
|
||||
padding: 24px;
|
||||
.interface-edit-item{
|
||||
@ -61,3 +63,71 @@
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
// 容器:左侧是header 右侧是body
|
||||
.container-header-body {
|
||||
display: flex;
|
||||
padding-bottom: .36rem;
|
||||
.header, .body {
|
||||
flex: 1 0 300px;
|
||||
.pretty-editor-header, .pretty-editor-body {
|
||||
height: 100%;
|
||||
}
|
||||
.postman .pretty-editor-body {
|
||||
min-height: 200px;
|
||||
}
|
||||
.ace_print-margin {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
max-width: 400px;
|
||||
}
|
||||
.container-title {
|
||||
padding: .08rem 0;
|
||||
}
|
||||
.resizer {
|
||||
flex: 0 0 21px;
|
||||
position: relative;
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background-color: $color-text-dark;
|
||||
opacity: .8;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
}
|
||||
}
|
||||
// res body 无返回json时显示text信息
|
||||
.res-body-text {
|
||||
height: 100%;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
.ant-spin-blur {
|
||||
.res-code.success {
|
||||
background-color: transparent;
|
||||
}
|
||||
.res-code.fail {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.res-code {
|
||||
padding: .08rem .28rem;
|
||||
color: #fff;
|
||||
margin-left: -.28rem;
|
||||
margin-right: -.28rem;
|
||||
transition: all .2s;
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
}
|
||||
.res-code.success {
|
||||
background-color: $color-antd-green;
|
||||
}
|
||||
.res-code.fail {
|
||||
background-color: $color-antd-red;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ class View extends Component {
|
||||
return <p style={{whiteSpace: 'pre-wrap'}}>{item.example}</p>;
|
||||
}
|
||||
}, {
|
||||
title: '备注',
|
||||
title: '备注',
|
||||
dataIndex: 'desc',
|
||||
key: 'desc',
|
||||
render(_, item) {
|
||||
@ -304,11 +304,11 @@ class View extends Component {
|
||||
<Row className="row">
|
||||
<Col span={4} className="colKey">接口名称:</Col>
|
||||
<Col span={8}>{this.props.curData.title}</Col>
|
||||
<Col span={4} className="colKey">创建人:</Col>
|
||||
<Col span={4} className="colKey">创 建 人:</Col>
|
||||
<Col span={8} className="colValue"><Link className="user-name" to={"/user/profile/" + this.props.curData.uid} ><img src={'/api/user/avatar?uid=' + this.props.curData.uid} className="user-img" />{this.props.curData.username}</Link></Col>
|
||||
</Row>
|
||||
<Row className="row">
|
||||
<Col span={4} className="colKey">状 态:</Col>
|
||||
<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(this.props.curData.up_time)}</Col>
|
||||
|
@ -149,6 +149,17 @@
|
||||
.right-content{
|
||||
min-height: 5rem;
|
||||
background: #fff;
|
||||
.caseContainer {
|
||||
table {
|
||||
border-radius: 4px;
|
||||
// border-collapse: collapse;
|
||||
}
|
||||
.ant-table-small .ant-table-thead > tr > th {
|
||||
text-align: left;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
tr:nth-child(even){background: #f8f8f8;}
|
||||
}
|
||||
.interface-content{
|
||||
.ant-tabs-nav{
|
||||
width:100%;
|
||||
@ -195,11 +206,17 @@
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
background-color: #f8f8f8;
|
||||
text-indent: .4em;
|
||||
}
|
||||
tr {
|
||||
text-indent: .4em;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px;
|
||||
}
|
||||
tr:nth-child(odd){background: rgba(236, 238, 241, 0.67);}
|
||||
tr:nth-child(odd){background: #f8f8f8;}
|
||||
tr:nth-child(even){background: #fff;}
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ class ProjectMember extends Component {
|
||||
</Row>
|
||||
</Modal>
|
||||
<Table columns={columns} dataSource={this.state.projectMemberList} pagination={false} locale={{emptyText: <ErrMsg type="noMemberInProject"/>}} className="setting-project-member"/>
|
||||
<Card title={this.state.groupName + ' 分组成员 ' + '(' + this.state.groupMemberList.length + ') 人'} noHovering className="setting-group">
|
||||
<Card bordered={false} title={this.state.groupName + ' 分组成员 ' + '(' + this.state.groupMemberList.length + ') 人'} noHovering className="setting-group">
|
||||
{this.state.groupMemberList.length ? this.state.groupMemberList.map((item, index) => {
|
||||
return (<div key={index} className="card-item">
|
||||
<img src={location.protocol + '//' + location.host + '/api/user/avatar?uid=' + item.uid} className="item-img" />
|
||||
|
@ -25,14 +25,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.setting-project-member {
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 2px;
|
||||
}
|
||||
// .setting-project-member {
|
||||
// border: 1px solid #e9e9e9;
|
||||
// border-radius: 4px;
|
||||
// }
|
||||
|
||||
.setting-group {
|
||||
margin-top: .48rem;
|
||||
border-radius: 2px;
|
||||
border-bottom: 1px solid #eee;
|
||||
.ant-card-head {
|
||||
background-color: #eee;
|
||||
padding: 0 .08rem !important;
|
||||
|
@ -8,6 +8,16 @@ $color-black-light: #404040;
|
||||
$color-bg-dark: #32363a; // 背景色 - header 用的深蓝色
|
||||
$box-shadow-panel: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
|
||||
|
||||
$color-text-dark: rgba(13, 27, 62, 0.65);
|
||||
|
||||
$color-antd-green: #00a854;
|
||||
$color-antd-yellow: #ffbf00;
|
||||
$color-antd-red: #f56a00;
|
||||
$color-antd-pink: #f5317f;
|
||||
$color-antd-cyan: #00a2ae;
|
||||
$color-antd-gray: #bfbfbf;
|
||||
$color-antd-purple: #7265e6;
|
||||
|
||||
@mixin row-width-limit {
|
||||
max-width: 12.2rem;
|
||||
min-width: 10.2rem;
|
||||
|
@ -8,7 +8,7 @@
|
||||
"install-server": " node server/install.js",
|
||||
"dev-client": "ykit s -p 4000",
|
||||
"dev": "npm run dev-server & npm run dev-client",
|
||||
"server": " node server/app.js"
|
||||
"start": " node server/app.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -14,7 +14,7 @@ const WEBCONFIG = config;
|
||||
|
||||
fs.ensureDirSync(WEBROOT_LOG);
|
||||
|
||||
if (WEBCONFIG.mail) {
|
||||
if (WEBCONFIG.mail && WEBCONFIG.mail.enable ) {
|
||||
mail = nodemailer.createTransport(WEBCONFIG.mail);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user