diff --git a/client/components/Postman/Postman.js b/client/components/Postman/Postman.js new file mode 100644 index 00000000..1711e9ec --- /dev/null +++ b/client/components/Postman/Postman.js @@ -0,0 +1,597 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +// import { connect } from 'react-redux' +import { Button, Input, Select, Card, Alert, Spin, Icon, Collapse, Radio, Tooltip } from 'antd' +import { autobind } from 'core-decorators'; +import crossRequest from 'cross-request'; +// import { withRouter } from 'react-router'; +// import axios from 'axios'; +import URL from 'url'; +// import AddColModal from './AddColModal' + +// import { +// } from '../../../reducer/modules/group.js' + +// import './Run.scss' + +const { TextArea } = Input; +const InputGroup = Input.Group; +const Option = Select.Option; +const Panel = Collapse.Panel; +const RadioButton = Radio.Button; +const RadioGroup = Radio.Group; + +// @connect( +// state => ({ +// currInterface: state.inter.curdata, +// currProject: state.project.currProject +// }) +// ) +// @withRouter +export default class Run extends Component { + + static propTypes = { + data: PropTypes.object + // match: PropTypes.object, + // currProject: PropTypes.object, + // currInterface: PropTypes.object, + // reqBody: PropTypes.string, + // interfaceName: PropTypes.string + } + + state = { + res: '', + method: 'GET', + domains: [], + pathname: '', + query: [], + bodyForm: [], + headers: [], + currDomain: '', + bodyType: '', + bodyOther: '' + // addColModalVisible: false + } + + constructor(props) { + super(props) + } + + componentWillMount() { + this.getInterfaceState() + } + + componentWillReceiveProps(nextProps) { + this.getInterfaceState(nextProps) + } + + @autobind + getInterfaceState(nextProps) { + const props = nextProps || this.props; + const { data } = props; + const { + method = '', + path: url = '', + req_headers = [], + req_body_type, + req_query = [], + req_params = [], + req_body_other = '', + req_body_form = [], + prd_host = '', + basepath = '', + protocol = '', + env = [] + } = data; + console.log('error', basepath, url) + const pathname = (basepath + url).replace(/\/+/g, '/'); + + const domains = {prd: protocol + '://' + prd_host}; + env.forEach(item => { + domains[item.name] = item.domain; + }) + + let hasContentType = false; + req_headers.forEach(headerItem => { + // TODO 'Content-Type' 排除大小写不同格式影响 + if (headerItem.name === 'Content-Type'){ + hasContentType = true; + headerItem.value = headerItem.value || 'application/x-www-form-urlencoded'; + } + }) + if (!hasContentType) { + req_headers.push({name: 'Content-Type', value: 'application/x-www-form-urlencoded'}); + } + + this.setState({ + method, + domains, + pathParam: req_params.concat(), + pathname, + query: req_query.concat(), + bodyForm: req_body_form.concat(), + headers: req_headers.concat(), + bodyOther: req_body_other, + currDomain: domains.prd, + bodyType: req_body_type || 'form', + loading: false + }); + } + + @autobind + reqRealInterface() { + const { headers, bodyForm, bodyOther, currDomain, method, pathname, query, bodyType } = this.state; + const urlObj = URL.parse(currDomain); + + const href = URL.format({ + protocol: urlObj.protocol || 'http', + host: urlObj.host, + pathname, + query: this.getQueryObj(query) + }); + + this.setState({ loading: true }) + + crossRequest({ + url: href, + method, + headers: this.getHeadersObj(headers), + data: bodyType === 'form' ? this.arrToObj(bodyForm) : bodyOther, + files: bodyType === 'form' ? this.getFiles(bodyForm) : {}, + success: (res) => { + try { + res = JSON.parse(res) + } catch (e) { + null + } + this.setState({res}) + this.setState({ loading: false }) + }, + error: (err) => { + this.setState({res: err || '请求失败'}) + this.setState({ loading: false }) + } + }) + } + + @autobind + changeDomain(value) { + this.setState({ currDomain: value }); + } + + @autobind + selectDomain(value) { + this.setState({ currDomain: value }); + } + + @autobind + changeHeader(e, index, isName) { + const headers = JSON.parse(JSON.stringify(this.state.headers)); + const v = e.target.value; + if (isName) { + headers[index].name = v; + } else { + headers[index].value = v; + } + this.setState({ headers }); + } + @autobind + addHeader() { + const { headers } = this.state; + this.setState({headers: headers.concat([{name: '', value: ''}])}) + } + @autobind + deleteHeader(index) { + const { headers } = this.state; + this.setState({headers: headers.filter((item, i) => +index !== +i)}); + } + @autobind + setContentType(type) { + const headersObj = this.getHeadersObj(this.state.headers); + headersObj['Content-Type'] = type; + this.setState({headers: this.objToArr(headersObj)}) + } + + @autobind + changeQuery(e, index, isKey) { + const query = JSON.parse(JSON.stringify(this.state.query)); + const v = e.target.value; + if (isKey) { + query[index].name = v; + } else { + query[index].value = v; + } + this.setState({ query }); + } + @autobind + addQuery() { + const { query } = this.state; + this.setState({query: query.concat([{name: '', value: ''}])}) + } + @autobind + deleteQuery(index) { + const { query } = this.state; + this.setState({query: query.filter((item, i) => +index !== +i)}); + } + + @autobind + changePathParam(e, index, isKey) { + const pathParam = JSON.parse(JSON.stringify(this.state.pathParam)); + const v = e.target.value; + const name = pathParam[index].name; + let newPathname = this.state.pathname; + if (isKey) { + if (!name && v) { + newPathname += `/:${v}`; + } else { + newPathname = newPathname.replace(`/:${name}`, v ? `/:${v}` : '') + } + pathParam[index].name = v; + } else { + pathParam[index].value = v; + } + this.setState({ pathParam, pathname: newPathname }); + } + @autobind + addPathParam() { + const { pathParam } = this.state; + this.setState({pathParam: pathParam.concat([{name: '', value: ''}])}) + } + @autobind + deletePathParam(index) { + const { pathParam } = this.state; + const name = pathParam[index].name; + const newPathname = this.state.pathname.replace(`/:${name}`, ''); + this.setState({pathParam: pathParam.filter((item, i) => +index !== +i), pathname: newPathname}); + } + + @autobind + changeBody(e, index, type) { + const bodyForm = JSON.parse(JSON.stringify(this.state.bodyForm)); + switch (type) { + case 'key': + bodyForm[index].name = e.target.value + break; + case 'type': + bodyForm[index].type = e + break; + case 'value': + if (bodyForm[index].type === 'file') { + bodyForm[index].value = e.target.id + } else { + bodyForm[index].value = e.target.value + } + break; + default: + break; + } + if (type === 'type' && e === 'file') { + this.setContentType('multipart/form-data') + } + this.setState({ bodyForm }); + } + @autobind + addBody() { + const { bodyForm } = this.state; + this.setState({bodyForm: bodyForm.concat([{name: '', value: '', type: 'text'}])}) + } + @autobind + deleteBody(index) { + const { bodyForm } = this.state; + this.setState({bodyForm: bodyForm.filter((item, i) => +index !== +i)}); + } + + @autobind + changeMethod(value) { + this.setState({ method: value }); + } + + @autobind + changePath(e) { + const path = e.target.value; + const urlObj = URL.parse(path, true); + this.setState({ + query: this.objToArr(urlObj.query), + pathname: urlObj.pathname + }) + } + + @autobind + changeBodyType(value) { + this.setState({bodyType: value}) + } + + hasCrossRequestPlugin() { + const dom = document.getElementById('y-request'); + return dom.getAttribute('key') === 'yapi'; + } + + objToArr(obj, key, value) { + const keyName = key || 'name'; + const valueName = value || 'value'; + const arr = [] + Object.keys(obj).forEach((_key) => { + if (_key) { + arr.push({[keyName]: _key, [valueName]: obj[_key]}); + } + }) + return arr; + } + arrToObj(arr) { + const obj = {}; + arr.forEach(item => { + if (item.name && item.type !== 'file') { + obj[item.name] = item.value || ''; + } + }) + return obj; + } + getFiles(bodyForm) { + const files = {}; + bodyForm.forEach(item => { + if (item.name && item.type === 'file') { + files[item.name] = item.value + } + }) + return files; + } + getQueryObj(query) { + const queryObj = {}; + query.forEach(item => { + if (item.name) { + queryObj[item.name] = item.value || ''; + } + }) + return queryObj; + } + getHeadersObj(headers) { + const headersObj = {}; + headers.forEach(item => { + if (item.name && item.value) { + headersObj[item.name] = item.value; + } + }) + return headersObj; + } + + @autobind + fileChange(e, index) { + console.log(e) + console.log(index) + } + + // saveToCol = async (colId, caseName) => { + // const project_id = this.props.match.params.id; + // const { + // currDomain: domain, + // pathname: path, + // method, + // pathParam: req_params, + // query: req_query, + // headers: req_headers, + // bodyType: req_body_type, + // bodyForm: req_body_form, + // bodyOther: req_body_other + // } = this.state; + // const res = await axios.post('/api/col/add_case', { + // casename: caseName, + // col_id: colId, + // project_id, + // env: '', + // domain, + // path, + // method, + // req_params, + // req_query, + // req_headers, + // req_body_type, + // req_body_form, + // req_body_other + // }); + // if (res.data.errcode) { + // message.error(res.data.errmsg) + // } else { + // message.success('添加成功') + // this.setState({addColModalVisible: false}) + // } + // } + + render () { + + const { method, domains, pathParam, pathname, query, headers, bodyForm, bodyOther, currDomain, bodyType } = this.state; + const hasPlugin = this.hasCrossRequestPlugin(); + let path = pathname; + pathParam.forEach(item => { + path = path.replace(`:${item.name}`, item.value || `:${item.name}`); + }); + const search = decodeURIComponent(URL.format({query: this.getQueryObj(query)})); + + return ( +
+
+ { + hasPlugin ? '' : + + 温馨提示:当前正在使用接口测试服务,请安装我们为您免费提供的  + 测试增强插件 [点击获取]! +
+ } + type="warning" + /> + } +
+ + +
+ + + + + + + + + + + +
+ + + + { + pathParam.map((item, index) => { + return ( +
+ this.changePathParam(e, index, true)} className="key" /> + = + this.changePathParam(e, index)} className="value" /> + this.deletePathParam(index)} /> +
+ ) + }) + } + +
+ + { + query.map((item, index) => { + return ( +
+ this.changeQuery(e, index, true)} className="key" /> + = + this.changeQuery(e, index)} className="value" /> + this.deleteQuery(index)} /> +
+ ) + }) + } + +
+ + { + headers.map((item, index) => { + return ( +
+ this.changeHeader(e, index, true)} className="key" /> + = + this.changeHeader(e, index)} className="value" /> + this.deleteHeader(index)} /> +
+ ) + }) + } + +
+ +
BODY
+
e.stopPropagation()} style={{marginRight: 5}}> + +
+ + } + key="3" + > + { method === 'POST' && bodyType !== 'form' && bodyType !== 'file' && +
+ + JSON + TEXT + XML + HTML + + +
+ } + { + method === 'POST' && bodyType === 'form' && +
+ { + bodyForm.map((item, index) => { + return ( +
+ this.changeBody(e, index, 'key')} className="key" /> + [ + + ] + = + { + item.type === 'file' ? this.changeBody(e, index, 'value')} multiple className="value" /> : + this.changeBody(e, index, 'value')} className="value" /> + } + this.deleteBody(index)} /> +
+ ) + }) + } + +
+ } + { + method === 'POST' && bodyType === 'file' && +
+ +
+ } + { + method !== 'POST' && +
GET 请求没有 BODY。
+ } +
+
+
+ + + +
+
+ +
+
+
+
+ {/* this.setState({addColModalVisible: false})} + onOk={this.saveToCol} + >*/} + + ) + } +} diff --git a/client/containers/Project/Interface/InterfaceList/InterfaceContent.js b/client/containers/Project/Interface/InterfaceList/InterfaceContent.js index 89b72aac..acf8fc07 100644 --- a/client/containers/Project/Interface/InterfaceList/InterfaceContent.js +++ b/client/containers/Project/Interface/InterfaceList/InterfaceContent.js @@ -48,7 +48,7 @@ class Content extends Component { if(params.actionId !== this.actionId){ this.actionId = params.actionId; this.handleRequest(nextProps) - } + } } handleRequest(nextProps) { diff --git a/client/containers/Project/Interface/InterfaceList/Run/Run.js b/client/containers/Project/Interface/InterfaceList/Run/Run.js index 444f6835..27729a74 100644 --- a/client/containers/Project/Interface/InterfaceList/Run/Run.js +++ b/client/containers/Project/Interface/InterfaceList/Run/Run.js @@ -1,25 +1,16 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { Button, Input, Select, Card, Alert, Spin, Icon, Collapse, Radio, Tooltip, message } from 'antd' -import { autobind } from 'core-decorators'; -import crossRequest from 'cross-request'; import { withRouter } from 'react-router'; import axios from 'axios'; -import URL from 'url'; -import AddColModal from './AddColModal' +import { message } from 'antd'; +import { Postman } from '../../../../../components' // import { // } from '../../../reducer/modules/group.js' import './Run.scss' -const { TextArea } = Input; -const InputGroup = Input.Group; -const Option = Select.Option; -const Panel = Collapse.Panel; -const RadioButton = Radio.Button; -const RadioGroup = Radio.Group; @connect( state => ({ @@ -31,25 +22,12 @@ const RadioGroup = Radio.Group; export default class Run extends Component { static propTypes = { - match: PropTypes.object, currProject: PropTypes.object, currInterface: PropTypes.object, - reqBody: PropTypes.string, - interfaceName: PropTypes.string + match: PropTypes.object } state = { - res: '', - method: 'GET', - domains: [], - pathname: '', - query: [], - bodyForm: [], - headers: [], - currDomain: '', - bodyType: '', - bodyOther: '', - addColModalVisible: false } constructor(props) { @@ -57,303 +35,11 @@ export default class Run extends Component { } componentWillMount() { - this.getInterfaceState() } - componentWillReceiveProps(nextProps) { - this.getInterfaceState(nextProps) + componentWillReceiveProps() { } - @autobind - getInterfaceState(nextProps) { - const props = nextProps || this.props; - const { currInterface, currProject } = props; - const { - method, - path: url, - req_headers = [], - req_body_type, - req_query = [], - req_params = [], - req_body_other = '', - req_body_form = [] - } = currInterface; - const { prd_host, basepath, protocol, env } = currProject; - const pathname = (basepath + url).replace(/\/+/g, '/'); - - const domains = {prd: protocol + '://' + prd_host}; - env.forEach(item => { - domains[item.name] = item.domain; - }) - - let hasContentType = false; - req_headers.forEach(headerItem => { - // TODO 'Content-Type' 排除大小写不同格式影响 - if (headerItem.name === 'Content-Type'){ - hasContentType = true; - headerItem.value = headerItem.value || 'application/x-www-form-urlencoded'; - } - }) - if (!hasContentType) { - req_headers.push({name: 'Content-Type', value: 'application/x-www-form-urlencoded'}); - } - - this.setState({ - method, - domains, - pathParam: req_params.concat(), - pathname, - query: req_query.concat(), - bodyForm: req_body_form.concat(), - headers: req_headers.concat(), - bodyOther: req_body_other, - currDomain: domains.prd, - bodyType: req_body_type || 'form', - loading: false - }); - } - - @autobind - reqRealInterface() { - const { headers, bodyForm, bodyOther, currDomain, method, pathname, query, bodyType } = this.state; - const urlObj = URL.parse(currDomain); - - const href = URL.format({ - protocol: urlObj.protocol || 'http', - host: urlObj.host, - pathname, - query: this.getQueryObj(query) - }); - - this.setState({ loading: true }) - - crossRequest({ - url: href, - method, - headers: this.getHeadersObj(headers), - data: bodyType === 'form' ? this.arrToObj(bodyForm) : bodyOther, - files: bodyType === 'form' ? this.getFiles(bodyForm) : {}, - success: (res) => { - try { - res = JSON.parse(res) - } catch (e) { - null - } - this.setState({res}) - this.setState({ loading: false }) - }, - error: (err) => { - this.setState({res: err || '请求失败'}) - this.setState({ loading: false }) - } - }) - } - - @autobind - changeDomain(value) { - this.setState({ currDomain: value }); - } - - @autobind - selectDomain(value) { - this.setState({ currDomain: value }); - } - - @autobind - changeHeader(e, index, isName) { - const headers = JSON.parse(JSON.stringify(this.state.headers)); - const v = e.target.value; - if (isName) { - headers[index].name = v; - } else { - headers[index].value = v; - } - this.setState({ headers }); - } - @autobind - addHeader() { - const { headers } = this.state; - this.setState({headers: headers.concat([{name: '', value: ''}])}) - } - @autobind - deleteHeader(index) { - const { headers } = this.state; - this.setState({headers: headers.filter((item, i) => +index !== +i)}); - } - @autobind - setContentType(type) { - const headersObj = this.getHeadersObj(this.state.headers); - headersObj['Content-Type'] = type; - this.setState({headers: this.objToArr(headersObj)}) - } - - @autobind - changeQuery(e, index, isKey) { - const query = JSON.parse(JSON.stringify(this.state.query)); - const v = e.target.value; - if (isKey) { - query[index].name = v; - } else { - query[index].value = v; - } - this.setState({ query }); - } - @autobind - addQuery() { - const { query } = this.state; - this.setState({query: query.concat([{name: '', value: ''}])}) - } - @autobind - deleteQuery(index) { - const { query } = this.state; - this.setState({query: query.filter((item, i) => +index !== +i)}); - } - - @autobind - changePathParam(e, index, isKey) { - const pathParam = JSON.parse(JSON.stringify(this.state.pathParam)); - const v = e.target.value; - const name = pathParam[index].name; - let newPathname = this.state.pathname; - if (isKey) { - if (!name && v) { - newPathname += `/:${v}`; - } else { - newPathname = newPathname.replace(`/:${name}`, v ? `/:${v}` : '') - } - pathParam[index].name = v; - } else { - pathParam[index].value = v; - } - this.setState({ pathParam, pathname: newPathname }); - } - @autobind - addPathParam() { - const { pathParam } = this.state; - this.setState({pathParam: pathParam.concat([{name: '', value: ''}])}) - } - @autobind - deletePathParam(index) { - const { pathParam } = this.state; - const name = pathParam[index].name; - const newPathname = this.state.pathname.replace(`/:${name}`, ''); - this.setState({pathParam: pathParam.filter((item, i) => +index !== +i), pathname: newPathname}); - } - - @autobind - changeBody(e, index, type) { - const bodyForm = JSON.parse(JSON.stringify(this.state.bodyForm)); - switch (type) { - case 'key': - bodyForm[index].name = e.target.value - break; - case 'type': - bodyForm[index].type = e - break; - case 'value': - if (bodyForm[index].type === 'file') { - bodyForm[index].value = e.target.id - } else { - bodyForm[index].value = e.target.value - } - break; - default: - break; - } - if (type === 'type' && e === 'file') { - this.setContentType('multipart/form-data') - } - this.setState({ bodyForm }); - } - @autobind - addBody() { - const { bodyForm } = this.state; - this.setState({bodyForm: bodyForm.concat([{name: '', value: '', type: 'text'}])}) - } - @autobind - deleteBody(index) { - const { bodyForm } = this.state; - this.setState({bodyForm: bodyForm.filter((item, i) => +index !== +i)}); - } - - @autobind - changeMethod(value) { - this.setState({ method: value }); - } - - @autobind - changePath(e) { - const path = e.target.value; - const urlObj = URL.parse(path, true); - this.setState({ - query: this.objToArr(urlObj.query), - pathname: urlObj.pathname - }) - } - - @autobind - changeBodyType(value) { - this.setState({bodyType: value}) - } - - hasCrossRequestPlugin() { - const dom = document.getElementById('y-request'); - return dom.getAttribute('key') === 'yapi'; - } - - objToArr(obj, key, value) { - const keyName = key || 'name'; - const valueName = value || 'value'; - const arr = [] - Object.keys(obj).forEach((_key) => { - if (_key) { - arr.push({[keyName]: _key, [valueName]: obj[_key]}); - } - }) - return arr; - } - arrToObj(arr) { - const obj = {}; - arr.forEach(item => { - if (item.name && item.type !== 'file') { - obj[item.name] = item.value || ''; - } - }) - return obj; - } - getFiles(bodyForm) { - const files = {}; - bodyForm.forEach(item => { - if (item.name && item.type === 'file') { - files[item.name] = item.value - } - }) - return files; - } - getQueryObj(query) { - const queryObj = {}; - query.forEach(item => { - if (item.name) { - queryObj[item.name] = item.value || ''; - } - }) - return queryObj; - } - getHeadersObj(headers) { - const headersObj = {}; - headers.forEach(item => { - if (item.name && item.value) { - headersObj[item.name] = item.value; - } - }) - return headersObj; - } - - @autobind - fileChange(e, index) { - console.log(e) - console.log(index) - } saveToCol = async (colId, caseName) => { const project_id = this.props.match.params.id; @@ -392,200 +78,12 @@ export default class Run extends Component { } render () { - - const { method, domains, pathParam, pathname, query, headers, bodyForm, bodyOther, currDomain, bodyType } = this.state; - const hasPlugin = this.hasCrossRequestPlugin(); - let path = pathname; - pathParam.forEach(item => { - path = path.replace(`:${item.name}`, item.value || `:${item.name}`); - }); - const search = decodeURIComponent(URL.format({query: this.getQueryObj(query)})); + const { currInterface, currProject } = this.props; + const data = Object.assign({}, currInterface, currProject) return ( -
-
- { - hasPlugin ? '' : - - 温馨提示:当前正在使用接口测试服务,请安装我们为您免费提供的  - 测试增强插件 [点击获取]! -
- } - type="warning" - /> - } -
- - -
- - - - - - - - - - - -
- - - - { - pathParam.map((item, index) => { - return ( -
- this.changePathParam(e, index, true)} className="key" /> - = - this.changePathParam(e, index)} className="value" /> - this.deletePathParam(index)} /> -
- ) - }) - } - -
- - { - query.map((item, index) => { - return ( -
- this.changeQuery(e, index, true)} className="key" /> - = - this.changeQuery(e, index)} className="value" /> - this.deleteQuery(index)} /> -
- ) - }) - } - -
- - { - headers.map((item, index) => { - return ( -
- this.changeHeader(e, index, true)} className="key" /> - = - this.changeHeader(e, index)} className="value" /> - this.deleteHeader(index)} /> -
- ) - }) - } - -
- -
BODY
-
e.stopPropagation()} style={{marginRight: 5}}> - -
- - } - key="3" - > - { method === 'POST' && bodyType !== 'form' && bodyType !== 'file' && -
- - JSON - TEXT - XML - HTML - - -
- } - { - method === 'POST' && bodyType === 'form' && -
- { - bodyForm.map((item, index) => { - return ( -
- this.changeBody(e, index, 'key')} className="key" /> - [ - - ] - = - { - item.type === 'file' ? this.changeBody(e, index, 'value')} multiple className="value" /> : - this.changeBody(e, index, 'value')} className="value" /> - } - this.deleteBody(index)} /> -
- ) - }) - } - -
- } - { - method === 'POST' && bodyType === 'file' && -
- -
- } - { - method !== 'POST' && -
GET 请求没有 BODY。
- } -
-
-
- - - -
-
- -
-
-
-
- this.setState({addColModalVisible: false})} - onOk={this.saveToCol} - > +
+
) }