feat: 接口运行高级参数输入功能

This commit is contained in:
gaoxiaolin.gao 2017-11-16 21:29:12 +08:00
parent 5034b4d20c
commit 0ac47cf6fa
6 changed files with 463 additions and 60 deletions

View File

@ -0,0 +1,106 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Row, Input, Radio, Icon } from 'antd';
import common from 'common/power-string.js'
import { autobind } from 'core-decorators';
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const Search = Input.Search;
const METHODS_LIST = [
{ name: 'md5', type: false },
{ name: 'lower', type: false },
{ name: 'length', type: false },
{ name: 'substr', type: true },
{ name: 'sha', type: false, subname: ['sha1', 'sha224', 'sha256', 'sha384', 'sha512'] },
{ name: 'base64', type: false },
{ name: 'unbase64', type: false },
{ name: 'concat', type: true },
{ name: 'lconcat', type: true },
{ name: 'upper', type: false }
]
// const list = METHODS_LIST.slice(0,4);
class MethodsList extends Component {
static propTypes = {
show: PropTypes.bool,
click: PropTypes.func,
clickValue: PropTypes.string
}
constructor(props) {
super(props)
this.state = {
filter: '',
list: METHODS_LIST.slice(0, 4),
moreFlag: true
}
}
componentDidMount() {
console.log('common', common);
}
componentWillReceiveProps(nextProps) {
// console.log("nextProps",nextProps);
if(this.props.show !==nextProps.show){
this.unshowMore();
}
}
@autobind
onFilter() {
}
@autobind
showMore() {
this.setState({
list: METHODS_LIST,
moreFlag: false
})
}
@autobind
unshowMore() {
this.setState({
list: METHODS_LIST.slice(0, 4),
moreFlag: true
})
}
render() {
const { list, moreFlag } = this.state;
const {click, clickValue} = this.props;
return (
<div className="modal-postman-form-method">
<h3 className="methods-title title">方法</h3>
<RadioGroup onChange={click} value={clickValue}>
{
list.map((item, index) => {
return <Row key={index} type="flex" align="middle" className="row methods-row" >
<RadioButton value={item.name}>{item.name}</RadioButton>
</Row>
})
}
</RadioGroup>
{
moreFlag && <div className="show-more" onClick={this.showMore}><Icon type="down" /><span style={{ paddingLeft: '4px' }}>更多</span></div>
}
</div>
)
}
}
export default MethodsList;

View File

@ -0,0 +1,81 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Row, Input, Radio } from 'antd';
import constants from '../../constants/variable.js'
import { autobind } from 'core-decorators';
const wordList = constants.MOCK_SOURCE;
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const Search = Input.Search;
class MockList extends Component {
static propTypes = {
click: PropTypes.func,
clickValue: PropTypes.string
}
constructor(props) {
super(props)
this.state = {
filter: '',
list: []
}
}
componentDidMount() {
this.setState({
list: wordList
})
}
@autobind
onFilter(e) {
const list = wordList.filter(item => {
return item.mock.indexOf(e.target.value) !== -1
});
this.setState({
filter: e.target.value,
list: list
})
}
@autobind
onSearch(v){
console.log(v);
this.props.click();
}
render() {
const { list, filter} = this.state;
const {click, clickValue} = this.props;
return (
<div className="modal-postman-form-mock">
<h3 className="mock-title title">mock数据</h3>
<Search
onChange={this.onFilter}
onSearch={this.onSearch}
value={filter}
placeholder="搜索mock数据"
className="mock-search"
/>
<RadioGroup onChange={click} value={clickValue}>
{
list.map((item, index) => {
return <Row key={index} type="flex" align="middle" className="row" >
<RadioButton value={item.mock}>{item.mock}</RadioButton>
</Row>
})
}
</RadioGroup>
</div>
)
}
}
export default MockList;

View File

@ -0,0 +1,122 @@
import React, { Component } from 'react'
// import { connect } from 'react-redux'
// import axios from 'axios'
import PropTypes from 'prop-types'
import './index.scss'
// import { withRouter } from 'react-router-dom';
import { Modal, Row, Col, Icon } from 'antd';
import { autobind } from 'core-decorators';
import MockList from './MockList.js';
import MethodsList from './MethodsList.js'
class ModalPostman extends Component {
static propTypes = {
visible: PropTypes.bool,
handleCancel: PropTypes.func,
handleOk: PropTypes.func
}
constructor(props) {
super(props)
this.state = {
clickValue: '',
methodsShow: false,
methodsShowMore: false,
arr: [],
count: []
}
}
mockClick(index) {
return (e) => {
this.setState({
clickValue: e.target.value
})
if (index === -1) {
this.setState({
arr: []
})
this.createArrList([]);
} else {
let newArr = [].concat(this.state.arr);
newArr.splice(index + 1, newArr.length - index - 1)
this.setState({
arr: newArr
})
this.createArrList(newArr)
}
}
}
createArrList(arr) {
// let arr = [];
const ListSource = (props) => {
console.log(props)
return <MethodsList
show={this.state.methodsShowMore}
click={this.mockClick(props.index)}
clickValue={this.state.clickValue}
/>
}
// this.state.arr.push(ListSource)
this.setState({
arr: [].concat(arr, ListSource)
})
}
render() {
const { visible, handleCancel, handleOk } = this.props
const { clickValue, count } = this.state;
console.log('count', count);
return (
<Modal
title={<p><Icon type="edit" /> 高级参数设置</p>}
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
wrapClassName="modal-postman"
width={800}
>
<Row className="modal-postman-form" type="flex" flex-flow="row nowrap">
<Col span={8} className="modal-postman-col">
<MockList click={this.mockClick(-1)} clickValue={clickValue}></MockList>
<h3>变量</h3>
</Col>
{
this.state.arr.map((ListSourceComponent, index) => {
return <Col span={8} className="modal-postman-col" key={index}>
<ListSourceComponent index={index} />
</Col>
})
}
{/* <Col span={8} className="modal-postman-col">
{
methodsShow ? <MethodsList show={methodsShowMore} click={this.mockClick} clickValue={clickValue}></MethodsList> : <div></div>
}
</Col> */}
</Row>
<Row className="modal-postman-expression">
<Col span={6}><h3 className="title">输入值</h3></Col>
<Col span={18}><h3>{clickValue}</h3></Col>
</Row>
<Row className="modal-postman-preview">
<Col span={6}><h3 className="title">预览</h3></Col>
<Col span={18}><h3>输入值</h3></Col>
</Row>
</Modal>
)
}
}
export default ModalPostman;

View File

@ -0,0 +1,87 @@
.modal-postman {
.ant-modal-body {
padding: 0;
}
.ant-modal-footer {
background-color: #f5f5f5;
}
.modal-postman-form {
padding: 16px;
padding-top: 0;
max-height: 300px;
overflow-y: scroll;
.ant-radio-group{
width:100%;
}
.mock-search {
padding-right: 8px;
margin-bottom: 16px;
}
.mock-checked{
color:#fff;
background-color:#2395f1;
width:100%
}
.row {
margin-bottom: 8px;
width:100%;
.ant-radio-button-wrapper{
border :0
}
.ant-radio-button-wrapper-checked{
color:#fff;
background-color:#2395f1;
width:100%
}
}
}
.modal-postman-expression, .modal-postman-preview {
border-top: 1px solid #e9e9e9;
padding: 8px 16px;
}
.modal-postman-expression {
}
.modal-postman-preview {
background-color: #f5f5f5;
}
.title {
border-left: 3px solid #2395f1;
padding-left: 8px;
}
.modal-postman-form-mock{
max-height: 200px;
overflow-y: scroll;
}
.mock-title, .methods-title{
margin-bottom: 8px
}
.modal-postman-form-method{
margin-left: 8px;
max-height: 300px;
overflow: auto;
}
.methods-row{
// border-bottom: 1px solid #e9e9e9;
}
.modal-postman-col{
border-right: 1px solid #e9e9e9;
padding-top: 16px;
}
.show-more{
color: #2395f1;
padding-left: 8px;
}
.ant-row-flex {
flex-wrap: nowrap
}
}

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Mock from 'mockjs'
import { Button, Input, Checkbox, Select, Alert, Spin, Icon, Collapse, Tooltip, message, Switch, Modal, Row, Col } from 'antd'
import { Button, Input, Checkbox, Select, Alert, Spin, Icon, Collapse, Tooltip, message, Switch } from 'antd'
import { autobind } from 'core-decorators';
import constants from '../../constants/variable.js'
@ -11,8 +11,9 @@ import URL from 'url';
const MockExtra = require('common/mock-extra.js')
import './Postman.scss';
import json5 from 'json5'
import { isJson, handleJson, handleParamsValue } from '../../common.js'
import { isJson, handleJson, handleParamsValue } from '../../common.js'
import _ from "underscore"
import ModalPostman from '../ModalPostman/index.js'
function json_parse(data) {
try {
@ -33,7 +34,7 @@ function isJsonData(headers) {
return isResJson;
}
const wordList = constants.MOCK_SOURCE;
// const wordList = constants.MOCK_SOURCE;
// const mockDataSource = wordList.map(item => {
// return <AutoComplete.Option key={item.mock} value={item.mock}>
@ -41,12 +42,12 @@ const wordList = constants.MOCK_SOURCE;
// </AutoComplete.Option>
// });
const MockModalList = wordList.map((item, index) => {
return <Row key={index} type="flex" align="middle" className="row">
<Col span={6}><label>{item.mock}</label></Col>
<Col span={18}><Input /></Col>
</Row>
})
// const MockModalList = wordList.map((item, index) => {
// return <Row key={index} type="flex" align="middle" className="row">
// <Col span={6}><label>{item.mock}</label></Col>
// <Col span={18}><Input /></Col>
// </Row>
// })
@ -130,7 +131,7 @@ export default class Run extends Component {
}
}
handleValue (val) {
handleValue(val) {
return handleParamsValue(val, {});
}
@ -211,18 +212,18 @@ export default class Run extends Component {
return;
}
const { headers, bodyForm, pathParam, bodyOther, caseEnv, domains, method, pathname, query, bodyType } = this.state;
let path = pathname;
pathParam.forEach(item => {
path = path.replace(`:${item.name}`, this.handleValue(item.value) || `:${item.name}`);
});
const urlObj = URL.parse(URL.resolve(_.find(domains, item => item.name === caseEnv).domain, '.' + path));
let pathQuery = {};
urlObj.query && urlObj.query.split('&').forEach(item=>{
if(item){
urlObj.query && urlObj.query.split('&').forEach(item => {
if (item) {
item = item.split('=');
pathQuery[item[0]] = item[1];
}
@ -235,16 +236,16 @@ export default class Run extends Component {
query: Object.assign(pathQuery, this.getQueryObj(query))
});
let reqBody;
if(bodyType === 'form'){
if (bodyType === 'form') {
reqBody = this.arrToObj(bodyForm)
}else{
} else {
reqBody = isJson(bodyOther);
if(reqBody === false){
if(bodyType === 'json'){
if (reqBody === false) {
if (bodyType === 'json' && HTTP_METHOD[method].request_body) {
return message.error('请求 Body 的 json 格式有误')
}
}
reqBody = bodyOther;
}else{
} else {
reqBody = handleJson(reqBody, this.handleValue)
}
@ -368,8 +369,8 @@ export default class Run extends Component {
@autobind
changeQuery(v, index, key) {
v = v.target.value
key = key || 'value';
v = v.target.value;
const query = json_parse(JSON.stringify(this.state.query));
if (key == 'enable') {
query[index].enable = v;
@ -600,8 +601,8 @@ export default class Run extends Component {
const pathObj = URL.parse(path);
path = pathObj.pathname;
let pathQuery = {};
pathObj.query && pathObj.query.split('&').forEach(item=>{
if(item){
pathObj.query && pathObj.query.split('&').forEach(item => {
if (item) {
item = item.split('=');
pathQuery[item[0]] = item[1];
}
@ -618,7 +619,13 @@ export default class Run extends Component {
return (
<div className="interface-test postman">
<Modal
<ModalPostman
visible={this.state.modalVisible}
handleCancel={this.handleCancel}
handleOk={this.handleOk}
>
</ModalPostman>
{/* <Modal
title={<p><Icon type="bulb" /> Basic Modal</p>}
visible={this.state.modalVisible}
onOk={this.handleOk}
@ -636,7 +643,7 @@ export default class Run extends Component {
<Col span={6}><h3 className="title">预览</h3></Col>
<Col span={18}><h3>输入值</h3></Col>
</Row>
</Modal>
</Modal> */}
<div className={hasPlugin ? null : 'has-plugin'} >
{hasPlugin ? '' : <Alert
message={
@ -720,7 +727,7 @@ export default class Run extends Component {
<div key={index} className="key-value-wrap">
<Input disabled value={item.name} onChange={e => this.changePathParam(e, index, true)} className="key" />
<span className="eq-symbol">=</span>
<Input addonAfter={<Icon type="setting" />} defaultValue={item.value} />
<Input addonAfter={<Icon type="setting" />} defaultValue={item.value} onChange={e => this.changePathParam(e, index, false)} />
<Icon style={{ display: 'none' }} type="delete" className="icon-btn" onClick={() => this.deletePathParam(index)} />
</div>
)
@ -731,10 +738,10 @@ export default class Run extends Component {
<Panel header="QUERY PARAMETERS" key="1" className={query.length === 0 ? 'hidden' : ''}>
{
query.map((item, index) => {
console.log(item.value);
console.log(item.value);
return (
<div key={index} className="key-value-wrap">
<Input disabled value={item.name} className="key" />
<Input disabled value={item.name} className="key" />
&nbsp;
{item.required == 1 ?
<Checkbox checked={true} disabled >enable</Checkbox> :
@ -747,9 +754,9 @@ export default class Run extends Component {
className="value"
onChange={e => this.changeQuery(e, index)}
placeholder="参数值"
addonAfter={<Icon type="bulb" onClick={this.showModal}/>}
addonAfter={<Icon type="edit" onClick={this.showModal} />}
/>
<Icon style={{ display: 'none' }} type="delete" className="icon-btn" onClick={() => this.deleteQuery(index)} />
</div>
)

View File

@ -21,32 +21,32 @@
}
}
.modal-postman {
.ant-modal-body {
padding: 0;
}
.ant-modal-footer {
background-color: #f5f5f5;
}
.modal-postman-form {
padding: 16px;
max-height: 300px;
overflow-y: scroll;
.row {
margin-bottom: 8px;
}
}
.modal-postman-expression, .modal-postman-preview {
border-top: 1px solid #e9e9e9;
padding: 8px 16px;
}
.modal-postman-expression {
}
.modal-postman-preview {
background-color: #f5f5f5;
}
.title {
border-left: 3px solid #2395f1;
padding-left: 8px;
}
}
// .modal-postman {
// .ant-modal-body {
// padding: 0;
// }
// .ant-modal-footer {
// background-color: #f5f5f5;
// }
// .modal-postman-form {
// padding: 16px;
// max-height: 300px;
// overflow-y: scroll;
// .row {
// margin-bottom: 8px;
// }
// }
// .modal-postman-expression, .modal-postman-preview {
// border-top: 1px solid #e9e9e9;
// padding: 8px 16px;
// }
// .modal-postman-expression {
// }
// .modal-postman-preview {
// background-color: #f5f5f5;
// }
// .title {
// border-left: 3px solid #2395f1;
// padding-left: 8px;
// }
// }