mirror of
https://github.com/YMFE/yapi.git
synced 2025-04-12 15:10:23 +08:00
fix: 测试集合环境变量展示问题
This commit is contained in:
parent
52d1b51810
commit
e5aff7a41c
@ -10,23 +10,36 @@ import './index.scss';
|
||||
export default class CaseEnv extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// this.state = { envList: [] };
|
||||
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
envList: PropTypes.array,
|
||||
currProjectEnvChange: PropTypes.func
|
||||
|
||||
currProjectEnvChange: PropTypes.func,
|
||||
changeClose: PropTypes.func,
|
||||
collapseKey: PropTypes.any,
|
||||
envValue: PropTypes.object
|
||||
};
|
||||
|
||||
callback = (key) => {
|
||||
|
||||
this.props.changeClose && this.props.changeClose(key)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Collapse
|
||||
style={{
|
||||
margin: 0,
|
||||
marginBottom: '16px'
|
||||
}}
|
||||
onChange={this.callback}
|
||||
// activeKey={this.state.activeKey}
|
||||
activeKey={this.props.collapseKey}
|
||||
>
|
||||
<Panel
|
||||
header={
|
||||
@ -54,14 +67,14 @@ export default class CaseEnv extends React.Component {
|
||||
className="env-item"
|
||||
>
|
||||
<Col span={6} className="label">
|
||||
{item.name}
|
||||
:
|
||||
<Tooltip title={item.name} ><span className="label-name">{item.name}</span></Tooltip>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<Select
|
||||
style={{
|
||||
width: '100%'
|
||||
}}
|
||||
value={this.props.envValue[item._id]|| ""}
|
||||
defaultValue=""
|
||||
onChange={val => this.props.currProjectEnvChange(val, item._id)}
|
||||
>
|
||||
|
@ -1,7 +1,22 @@
|
||||
.case-env {
|
||||
.label {
|
||||
// width: 100%;
|
||||
text-align: right;
|
||||
padding-right: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label:after{
|
||||
content: ":";
|
||||
margin: 0 8px 0 2px;
|
||||
position: relative;
|
||||
top: -.5px;
|
||||
}
|
||||
.label-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.env-item {
|
||||
|
@ -61,6 +61,7 @@ class Interface extends Component {
|
||||
isShowCol: PropTypes.bool,
|
||||
getProject: PropTypes.func,
|
||||
setColData: PropTypes.func
|
||||
// fetchInterfaceColList: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@ -78,11 +79,11 @@ class Interface extends Component {
|
||||
this.props.history.push('/project/' + params.id + '/interface/' + action)
|
||||
|
||||
}
|
||||
componentWillMount(){
|
||||
async componentWillMount(){
|
||||
this.props.setColData({
|
||||
isShowCol: true
|
||||
})
|
||||
// this.props.getProject(this.props.match.params.id)
|
||||
// await this.props.fetchInterfaceColList(this.props.match.params.id)
|
||||
}
|
||||
render() {
|
||||
const { action } = this.props.match.params;
|
||||
|
@ -1,25 +1,19 @@
|
||||
import React, {PureComponent as Component} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {withRouter} from 'react-router';
|
||||
import {Link} from 'react-router-dom';
|
||||
import { withRouter } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
//import constants from '../../../../constants/variable.js'
|
||||
import { Tooltip, Icon, Button, Row, Col, Spin, Modal, message, Select, Switch } from 'antd';
|
||||
import {
|
||||
Tooltip,
|
||||
Icon,
|
||||
Button,
|
||||
Row,
|
||||
Col,
|
||||
Spin,
|
||||
Modal,
|
||||
message,
|
||||
Select,
|
||||
Switch
|
||||
} from 'antd';
|
||||
import {fetchInterfaceColList, fetchCaseList, setColData, fetchCaseEnvList} from '../../../../reducer/modules/interfaceCol';
|
||||
fetchInterfaceColList,
|
||||
fetchCaseList,
|
||||
setColData,
|
||||
fetchCaseEnvList
|
||||
} from '../../../../reducer/modules/interfaceCol';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import {getToken, getEnv} from '../../../../reducer/modules/project';
|
||||
import {DragDropContext} from 'react-dnd';
|
||||
import { getToken, getEnv } from '../../../../reducer/modules/project';
|
||||
import { DragDropContext } from 'react-dnd';
|
||||
import AceEditor from 'client/components/AceEditor/AceEditor';
|
||||
import * as Table from 'reactabular-table';
|
||||
import * as dnd from 'reactabular-dnd';
|
||||
@ -27,10 +21,15 @@ import * as resolve from 'table-resolver';
|
||||
import axios from 'axios';
|
||||
import CaseReport from './CaseReport.js';
|
||||
import _ from 'underscore';
|
||||
import {initCrossRequest} from 'client/components/Postman/CheckCrossInstall.js';
|
||||
import { initCrossRequest } from 'client/components/Postman/CheckCrossInstall.js';
|
||||
import produce from 'immer';
|
||||
const {handleParams, crossRequest, handleCurrDomain, checkNameIsExistInArray} = require('common/postmanLib.js');
|
||||
const {handleParamsValue, json_parse} = require('common/utils.js');
|
||||
const {
|
||||
handleParams,
|
||||
crossRequest,
|
||||
handleCurrDomain,
|
||||
checkNameIsExistInArray
|
||||
} = require('common/postmanLib.js');
|
||||
const { handleParamsValue, json_parse } = require('common/utils.js');
|
||||
import CaseEnv from 'client/components/CaseEnv';
|
||||
|
||||
const Option = Select.Option;
|
||||
@ -45,28 +44,31 @@ function handleReport(json) {
|
||||
}
|
||||
}
|
||||
|
||||
@connect(state => {
|
||||
return {
|
||||
interfaceColList: state.interfaceCol.interfaceColList,
|
||||
currColId: state.interfaceCol.currColId,
|
||||
currCaseId: state.interfaceCol.currCaseId,
|
||||
isShowCol: state.interfaceCol.isShowCol,
|
||||
isRander: state.interfaceCol.isRander,
|
||||
currCaseList: state.interfaceCol.currCaseList,
|
||||
currProject: state.project.currProject,
|
||||
token: state.project.token,
|
||||
envList: state.interfaceCol.envList,
|
||||
curProjectRole: state.project.currProject.role,
|
||||
projectEnv: state.project.projectEnv
|
||||
};
|
||||
}, {
|
||||
fetchInterfaceColList,
|
||||
fetchCaseList,
|
||||
setColData,
|
||||
getToken,
|
||||
getEnv,
|
||||
fetchCaseEnvList
|
||||
})
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
interfaceColList: state.interfaceCol.interfaceColList,
|
||||
currColId: state.interfaceCol.currColId,
|
||||
currCaseId: state.interfaceCol.currCaseId,
|
||||
isShowCol: state.interfaceCol.isShowCol,
|
||||
isRander: state.interfaceCol.isRander,
|
||||
currCaseList: state.interfaceCol.currCaseList,
|
||||
currProject: state.project.currProject,
|
||||
token: state.project.token,
|
||||
envList: state.interfaceCol.envList,
|
||||
curProjectRole: state.project.currProject.role,
|
||||
projectEnv: state.project.projectEnv
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceColList,
|
||||
fetchCaseList,
|
||||
setColData,
|
||||
getToken,
|
||||
getEnv,
|
||||
fetchCaseEnvList
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
@DragDropContext(HTML5Backend)
|
||||
class InterfaceColContent extends Component {
|
||||
@ -109,60 +111,45 @@ class InterfaceColContent extends Component {
|
||||
autoVisible: false,
|
||||
mode: 'html',
|
||||
email: false,
|
||||
currColEnvObj: {}
|
||||
currColEnvObj: {},
|
||||
collapseKey: ''
|
||||
};
|
||||
this.onRow = this
|
||||
.onRow
|
||||
.bind(this);
|
||||
this.onMoveRow = this
|
||||
.onMoveRow
|
||||
.bind(this);
|
||||
this.onRow = this.onRow.bind(this);
|
||||
this.onMoveRow = this.onMoveRow.bind(this);
|
||||
}
|
||||
|
||||
async componentWillMount() {
|
||||
const result = await this
|
||||
.props
|
||||
.fetchInterfaceColList(this.props.match.params.id);
|
||||
await this
|
||||
.props
|
||||
.getToken(this.props.match.params.id);
|
||||
let {currColId} = this.props;
|
||||
const result = await this.props.fetchInterfaceColList(this.props.match.params.id);
|
||||
await this.props.getToken(this.props.match.params.id);
|
||||
let { currColId } = this.props;
|
||||
const params = this.props.match.params;
|
||||
const {actionId} = params;
|
||||
const { actionId } = params;
|
||||
this.currColId = currColId = +actionId || result.payload.data.data[0]._id;
|
||||
this
|
||||
.props
|
||||
.history
|
||||
.push('/project/' + params.id + '/interface/col/' + currColId);
|
||||
this.props.history.push('/project/' + params.id + '/interface/col/' + currColId);
|
||||
if (currColId && currColId != 0) {
|
||||
let result = await this
|
||||
.props
|
||||
.fetchCaseList(currColId);
|
||||
let result = await this.props.fetchCaseList(currColId);
|
||||
|
||||
if (result.payload.data.errcode === 0) {
|
||||
this.reports = handleReport(result.payload.data.colData.test_report);
|
||||
}
|
||||
|
||||
await this
|
||||
.props
|
||||
.fetchCaseEnvList(currColId);
|
||||
this.props.setColData({
|
||||
currColId: +currColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
|
||||
this
|
||||
.props
|
||||
.setColData({
|
||||
currColId: + currColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
await this.props.fetchCaseEnvList(currColId);
|
||||
|
||||
|
||||
|
||||
this.handleColdata(this.props.currCaseList);
|
||||
}
|
||||
|
||||
this._crossRequestInterval = initCrossRequest(hasPlugin => {
|
||||
this.setState({hasPlugin: hasPlugin});
|
||||
this.setState({ hasPlugin: hasPlugin });
|
||||
});
|
||||
// console.log('project', this.props.currProject) const group_id =
|
||||
// this.props.currProject.group_id; await this.props.fetchProjectList(group_id)
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@ -174,8 +161,9 @@ class InterfaceColContent extends Component {
|
||||
let envItem = _.find(this.props.envList, item => {
|
||||
return item._id === project_id;
|
||||
});
|
||||
|
||||
// let env = this.props.currProject.env; console.log('env', case_env);
|
||||
let currDomain = handleCurrDomain(envItem.env, case_env);
|
||||
let currDomain = handleCurrDomain(envItem && envItem.env, case_env);
|
||||
let header = currDomain.header;
|
||||
// console.log('header', header)
|
||||
header.forEach(item => {
|
||||
@ -192,44 +180,42 @@ class InterfaceColContent extends Component {
|
||||
};
|
||||
|
||||
handleColdata = (rows, currColEnv = '', project_id = null) => {
|
||||
// let newRows = JSON.parse(JSON.stringify(rows)) newRows = newRows.map((item)
|
||||
// => { item.id = item._id; item._test_status = item.test_status;
|
||||
// item.case_env = this.state.currColEnv || item.case_env item.req_headers =
|
||||
// this.handleReqHeader(item.req_headers) return item; }) const { currColEnv,
|
||||
// curProjectId } = this.state; if (curProjectId && currColEnv) { }
|
||||
|
||||
let that = this;
|
||||
let newRows = produce(rows, draftRows => {
|
||||
draftRows.map(item => {
|
||||
item.id = item._id;
|
||||
item._test_status = item.test_status;
|
||||
item.case_env = item.project_id === project_id
|
||||
? currColEnv || item.case_env
|
||||
: item.case_env;
|
||||
item.case_env =
|
||||
item.project_id === project_id ? currColEnv || item.case_env : item.case_env;
|
||||
item.req_headers = that.handleReqHeader(item.project_id, item.req_headers, item.case_env);
|
||||
return item;
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({rows: newRows});
|
||||
this.setState({ rows: newRows });
|
||||
};
|
||||
|
||||
executeTests = async() => {
|
||||
executeTests = async () => {
|
||||
for (let i = 0, l = this.state.rows.length, newRows, curitem; i < l; i++) {
|
||||
let {rows} = this.state;
|
||||
let { rows } = this.state;
|
||||
|
||||
let envItem = _.find(this.props.envList, item => {
|
||||
return item._id === rows[i].project_id;
|
||||
});
|
||||
|
||||
curitem = Object.assign({}, rows[i], {
|
||||
env: envItem.env,
|
||||
pre_script: this.props.currProject.pre_script,
|
||||
after_script: this.props.currProject.after_script
|
||||
}, {test_status: 'loading'});
|
||||
curitem = Object.assign(
|
||||
{},
|
||||
rows[i],
|
||||
{
|
||||
env: envItem.env,
|
||||
pre_script: this.props.currProject.pre_script,
|
||||
after_script: this.props.currProject.after_script
|
||||
},
|
||||
{ test_status: 'loading' }
|
||||
);
|
||||
newRows = [].concat([], rows);
|
||||
newRows[i] = curitem;
|
||||
this.setState({rows: newRows});
|
||||
this.setState({ rows: newRows });
|
||||
// console.log('newRows', newRows);
|
||||
let status = 'error',
|
||||
result;
|
||||
@ -255,10 +241,10 @@ class InterfaceColContent extends Component {
|
||||
body: result.res_body
|
||||
};
|
||||
|
||||
curitem = Object.assign({}, rows[i], {test_status: status});
|
||||
curitem = Object.assign({}, rows[i], { test_status: status });
|
||||
newRows = [].concat([], rows);
|
||||
newRows[i] = curitem;
|
||||
this.setState({rows: newRows});
|
||||
this.setState({ rows: newRows });
|
||||
}
|
||||
await axios.post('/api/col/up_col', {
|
||||
col_id: this.props.currColId,
|
||||
@ -295,12 +281,15 @@ class InterfaceColContent extends Component {
|
||||
|
||||
let validRes = [];
|
||||
|
||||
let responseData = Object.assign({}, {
|
||||
status: data.res.status,
|
||||
body: res,
|
||||
header: data.res.header,
|
||||
statusText: data.res.statusText
|
||||
});
|
||||
let responseData = Object.assign(
|
||||
{},
|
||||
{
|
||||
status: data.res.status,
|
||||
body: res,
|
||||
header: data.res.header,
|
||||
statusText: data.res.statusText
|
||||
}
|
||||
);
|
||||
await this.handleScriptTest(interfaceData, responseData, validRes, requestParams);
|
||||
if (validRes.length === 0) {
|
||||
result.code = 0;
|
||||
@ -330,7 +319,7 @@ class InterfaceColContent extends Component {
|
||||
};
|
||||
|
||||
//response, validRes
|
||||
handleScriptTest = async(interfaceData, response, validRes, requestParams) => {
|
||||
handleScriptTest = async (interfaceData, response, validRes, requestParams) => {
|
||||
if (interfaceData.enable_script !== true) {
|
||||
return null;
|
||||
}
|
||||
@ -342,13 +331,9 @@ class InterfaceColContent extends Component {
|
||||
params: requestParams
|
||||
});
|
||||
if (test.data.errcode !== 0) {
|
||||
test
|
||||
.data
|
||||
.data
|
||||
.logs
|
||||
.forEach(item => {
|
||||
validRes.push({message: item});
|
||||
});
|
||||
test.data.data.logs.forEach(item => {
|
||||
validRes.push({ message: item });
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
validRes.push({
|
||||
@ -376,80 +361,85 @@ class InterfaceColContent extends Component {
|
||||
};
|
||||
|
||||
onRow(row) {
|
||||
return {rowId: row.id, onMove: this.onMoveRow, onDrop: this.onDrop};
|
||||
return { rowId: row.id, onMove: this.onMoveRow, onDrop: this.onDrop };
|
||||
}
|
||||
|
||||
onDrop = () => {
|
||||
let changes = [];
|
||||
this
|
||||
.state
|
||||
.rows
|
||||
.forEach((item, index) => {
|
||||
changes.push({id: item._id, index: index});
|
||||
});
|
||||
axios
|
||||
.post('/api/col/up_case_index', changes)
|
||||
.then(() => {
|
||||
this
|
||||
.props
|
||||
.fetchInterfaceColList(this.props.match.params.id);
|
||||
});
|
||||
this.state.rows.forEach((item, index) => {
|
||||
changes.push({ id: item._id, index: index });
|
||||
});
|
||||
axios.post('/api/col/up_case_index', changes).then(() => {
|
||||
this.props.fetchInterfaceColList(this.props.match.params.id);
|
||||
});
|
||||
};
|
||||
onMoveRow({sourceRowId, targetRowId}) {
|
||||
let rows = dnd.moveRows({sourceRowId, targetRowId})(this.state.rows);
|
||||
onMoveRow({ sourceRowId, targetRowId }) {
|
||||
let rows = dnd.moveRows({ sourceRowId, targetRowId })(this.state.rows);
|
||||
|
||||
if (rows) {
|
||||
this.setState({rows});
|
||||
this.setState({ rows });
|
||||
}
|
||||
}
|
||||
|
||||
async componentWillReceiveProps(nextProps) {
|
||||
let newColId = !isNaN(nextProps.match.params.actionId)
|
||||
? + nextProps.match.params.actionId
|
||||
: 0;
|
||||
|
||||
let newColId = !isNaN(nextProps.match.params.actionId) ? +nextProps.match.params.actionId : 0;
|
||||
|
||||
if ((newColId && this.currColId && newColId !== this.currColId) || nextProps.isRander) {
|
||||
this.currColId = newColId;
|
||||
await this
|
||||
.props
|
||||
.fetchCaseList(newColId);
|
||||
this
|
||||
.props
|
||||
.setColData({
|
||||
currColId: + newColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
this.props.setColData({
|
||||
currColId: +newColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
await this.props.fetchCaseList(newColId);
|
||||
await this.props.fetchCaseEnvList(newColId);
|
||||
this.changeCollapseClose();
|
||||
this.handleColdata(this.props.currCaseList);
|
||||
await this
|
||||
.props
|
||||
.fetchCaseEnvList(newColId);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试用例环境面板折叠
|
||||
changeCollapseClose = key => {
|
||||
if (key) {
|
||||
this.setState({
|
||||
collapseKey: key
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
collapseKey: '',
|
||||
currColEnvObj: {}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
openReport = id => {
|
||||
if (!this.reports[id]) {
|
||||
return message.warn('还没有生成报告');
|
||||
}
|
||||
this.setState({visible: true, curCaseid: id});
|
||||
this.setState({ visible: true, curCaseid: id });
|
||||
};
|
||||
|
||||
openAdv = id => {
|
||||
let findCase = _.find(this.props.currCaseList, item => item.id === id);
|
||||
|
||||
this.setState({enableScript: findCase.enable_script, curScript: findCase.test_script, advVisible: true, curCaseid: id});
|
||||
this.setState({
|
||||
enableScript: findCase.enable_script,
|
||||
curScript: findCase.test_script,
|
||||
advVisible: true,
|
||||
curCaseid: id
|
||||
});
|
||||
};
|
||||
|
||||
handleScriptChange = d => {
|
||||
this.setState({curScript: d.text});
|
||||
this.setState({ curScript: d.text });
|
||||
};
|
||||
|
||||
handleAdvCancel = () => {
|
||||
this.setState({advVisible: false});
|
||||
this.setState({ advVisible: false });
|
||||
};
|
||||
|
||||
handleAdvOk = async() => {
|
||||
const {curCaseid, enableScript, curScript} = this.state;
|
||||
handleAdvOk = async () => {
|
||||
const { curCaseid, enableScript, curScript } = this.state;
|
||||
const res = await axios.post('/api/col/up_case', {
|
||||
id: curCaseid,
|
||||
test_script: curScript,
|
||||
@ -458,42 +448,37 @@ class InterfaceColContent extends Component {
|
||||
if (res.data.errcode === 0) {
|
||||
message.success('更新成功');
|
||||
}
|
||||
this.setState({advVisible: false});
|
||||
this.setState({ advVisible: false });
|
||||
let currColId = this.currColId;
|
||||
await this
|
||||
.props
|
||||
.fetchCaseList(currColId);
|
||||
this
|
||||
.props
|
||||
.setColData({
|
||||
currColId: + currColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
this.props.setColData({
|
||||
currColId: +currColId,
|
||||
isShowCol: true,
|
||||
isRander: false
|
||||
});
|
||||
await this.props.fetchCaseList(currColId);
|
||||
|
||||
this.handleColdata(this.props.currCaseList);
|
||||
};
|
||||
|
||||
handleCancel = () => {
|
||||
this.setState({visible: false});
|
||||
this.setState({ visible: false });
|
||||
};
|
||||
|
||||
// colEnvChange = envName => { this.setState( { currColEnv: envName
|
||||
// }, () => this.handleColdata(this.props.currCaseList) ); }; 处理各项目下的环境变量
|
||||
currProjectEnvChange = (envName, project_id) => {
|
||||
let currColEnvObj = {
|
||||
...this.state.currColEnvObj,
|
||||
[project_id]: envName
|
||||
};
|
||||
this.setState({currColEnvObj});
|
||||
this.setState({ currColEnvObj });
|
||||
this.handleColdata(this.props.currCaseList, envName, project_id);
|
||||
};
|
||||
|
||||
autoTests = () => {
|
||||
this.setState({autoVisible: true});
|
||||
this.setState({ autoVisible: true, currColEnvObj: {}, collapseKey: ''});
|
||||
};
|
||||
|
||||
handleAuto = () => {
|
||||
this.setState({autoVisible: false, email: false, mode: 'html'});
|
||||
this.setState({ autoVisible: false, email: false, mode: 'html', currColEnvObj: {}, collapseKey: '' });
|
||||
};
|
||||
|
||||
copyUrl = url => {
|
||||
@ -502,19 +487,17 @@ class InterfaceColContent extends Component {
|
||||
};
|
||||
|
||||
modeChange = mode => {
|
||||
this.setState({mode});
|
||||
this.setState({ mode });
|
||||
};
|
||||
|
||||
emailChange = email => {
|
||||
this.setState({email});
|
||||
this.setState({ email });
|
||||
};
|
||||
|
||||
handleColEnvObj = envObj => {
|
||||
let str = '';
|
||||
for (let key in envObj) {
|
||||
str += envObj[key]
|
||||
? `&env_${key}=${envObj[key]}`
|
||||
: '';
|
||||
str += envObj[key] ? `&env_${key}=${envObj[key]}` : '';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
@ -534,27 +517,43 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
},
|
||||
cell: {
|
||||
formatters: [(text, {rowData}) => {
|
||||
formatters: [
|
||||
(text, { rowData }) => {
|
||||
let record = rowData;
|
||||
return (
|
||||
<Link to={'/project/' + currProjectId + '/interface/case/' + record._id}>
|
||||
{record.casename.length > 23
|
||||
? record
|
||||
.casename
|
||||
.substr(0, 20) + '...'
|
||||
? record.casename.substr(0, 20) + '...'
|
||||
: record.casename}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
header: {
|
||||
label: 'key',
|
||||
formatters: [() => {
|
||||
formatters: [
|
||||
() => {
|
||||
return (
|
||||
<Tooltip
|
||||
title={<span> 每个用例都有唯一的key,用于获取所匹配接口的响应数据,例如使用 {' '} <a href = "https://yapi.ymfe.org/case.html#变量参数" className = "link-tooltip" target = "blank" > 变量参数 </a>{' '} 功能 </span>}>
|
||||
title={
|
||||
<span>
|
||||
{' '}
|
||||
每个用例都有唯一的key,用于获取所匹配接口的响应数据,例如使用{' '}
|
||||
<a
|
||||
href="https://yapi.ymfe.org/case.html#变量参数"
|
||||
className="link-tooltip"
|
||||
target="blank"
|
||||
>
|
||||
{' '}
|
||||
变量参数{' '}
|
||||
</a>{' '}
|
||||
功能{' '}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
Key
|
||||
</Tooltip>
|
||||
);
|
||||
@ -567,12 +566,14 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
},
|
||||
cell: {
|
||||
formatters: [(value, {rowData}) => {
|
||||
formatters: [
|
||||
(value, { rowData }) => {
|
||||
return <span>{rowData._id}</span>;
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
property: 'test_status',
|
||||
header: {
|
||||
label: '状态'
|
||||
@ -583,15 +584,14 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
},
|
||||
cell: {
|
||||
formatters: [(value, {rowData}) => {
|
||||
formatters: [
|
||||
(value, { rowData }) => {
|
||||
let id = rowData._id;
|
||||
let code = this.reports[id]
|
||||
? this.reports[id].code
|
||||
: 0;
|
||||
let code = this.reports[id] ? this.reports[id].code : 0;
|
||||
if (rowData.test_status === 'loading') {
|
||||
return (
|
||||
<div>
|
||||
<Spin/>
|
||||
<Spin />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -603,9 +603,10 @@ class InterfaceColContent extends Component {
|
||||
<Tooltip title="Pass">
|
||||
<Icon
|
||||
style={{
|
||||
color: '#00a854'
|
||||
}}
|
||||
type="check-circle"/>
|
||||
color: '#00a854'
|
||||
}}
|
||||
type="check-circle"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
@ -616,8 +617,9 @@ class InterfaceColContent extends Component {
|
||||
<Icon
|
||||
type="info-circle"
|
||||
style={{
|
||||
color: '#f04134'
|
||||
}}/>
|
||||
color: '#f04134'
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
@ -628,8 +630,9 @@ class InterfaceColContent extends Component {
|
||||
<Icon
|
||||
type="exclamation-circle"
|
||||
style={{
|
||||
color: '#ffbf00'
|
||||
}}/>
|
||||
color: '#ffbf00'
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
@ -638,36 +641,38 @@ class InterfaceColContent extends Component {
|
||||
<div>
|
||||
<Icon
|
||||
style={{
|
||||
color: '#00a854'
|
||||
}}
|
||||
type="check-circle"/>
|
||||
color: '#00a854'
|
||||
}}
|
||||
type="check-circle"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
property: 'path',
|
||||
header: {
|
||||
label: '接口路径'
|
||||
},
|
||||
cell: {
|
||||
formatters: [(text, {rowData}) => {
|
||||
formatters: [
|
||||
(text, { rowData }) => {
|
||||
let record = rowData;
|
||||
return (
|
||||
<Tooltip title="跳转到对应接口">
|
||||
<Link to={`/project/${record.project_id}/interface/api/${record.interface_id}`}>
|
||||
{record.path.length > 23
|
||||
? record.path + '...'
|
||||
: record.path}
|
||||
{record.path.length > 23 ? record.path + '...' : record.path}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
header: {
|
||||
label: '测试报告'
|
||||
},
|
||||
@ -677,7 +682,8 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
},
|
||||
cell: {
|
||||
formatters: [(text, {rowData}) => {
|
||||
formatters: [
|
||||
(text, { rowData }) => {
|
||||
let reportFun = () => {
|
||||
if (!this.reports[rowData.id]) {
|
||||
return null;
|
||||
@ -690,7 +696,7 @@ class InterfaceColContent extends Component {
|
||||
}
|
||||
}
|
||||
];
|
||||
const {rows} = this.state;
|
||||
const { rows } = this.state;
|
||||
const components = {
|
||||
header: {
|
||||
cell: dnd.Header
|
||||
@ -699,34 +705,39 @@ class InterfaceColContent extends Component {
|
||||
row: dnd.Row
|
||||
}
|
||||
};
|
||||
const resolvedColumns = resolve.columnChildren({columns});
|
||||
const resolvedRows = resolve.resolve({columns: resolvedColumns, method: resolve.nested})(rows);
|
||||
const resolvedColumns = resolve.columnChildren({ columns });
|
||||
const resolvedRows = resolve.resolve({ columns: resolvedColumns, method: resolve.nested })(
|
||||
rows
|
||||
);
|
||||
|
||||
const localUrl = location.protocol + '//' + location.hostname + (location.port !== ''
|
||||
? ':' + location.port
|
||||
: '');
|
||||
const localUrl =
|
||||
location.protocol +
|
||||
'//' +
|
||||
location.hostname +
|
||||
(location.port !== '' ? ':' + location.port : '');
|
||||
let currColEnvObj = this.handleColEnvObj(this.state.currColEnvObj);
|
||||
const autoTestsUrl = `/api/open/run_auto_test?id=${this.props.currColId}&token=${
|
||||
this.props.token}${currColEnvObj
|
||||
? currColEnvObj
|
||||
: ''}&mode=${this.state.mode}&email=${this.state.email}`;
|
||||
this.props.token
|
||||
}${currColEnvObj ? currColEnvObj : ''}&mode=${this.state.mode}&email=${this.state.email}`;
|
||||
|
||||
return (
|
||||
<div className="interface-col">
|
||||
<Row type="flex" justify="center" align="top">
|
||||
<Col span={6}>
|
||||
<Col span={5}>
|
||||
<h2
|
||||
className="interface-title"
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
margin: '8px 20px 16px'
|
||||
}}>
|
||||
display: 'inline-block',
|
||||
margin: '8px 20px 16px'
|
||||
}}
|
||||
>
|
||||
测试集合 <a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://yapi.ymfe.org/documents/case.html">
|
||||
href="https://yapi.ymfe.org/documents/case.html"
|
||||
>
|
||||
<Tooltip title="点击查看文档">
|
||||
<Icon type="question-circle-o"/>
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</a>
|
||||
</h2>
|
||||
@ -735,45 +746,49 @@ class InterfaceColContent extends Component {
|
||||
<CaseEnv
|
||||
envList={this.props.envList}
|
||||
currProjectEnvChange={this.currProjectEnvChange}
|
||||
envValue={this.state.currColEnvObj}
|
||||
collapseKey={this.state.collapseKey}
|
||||
changeClose={this.changeCollapseClose}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
{this.state.hasPlugin
|
||||
? (
|
||||
<div
|
||||
style={{
|
||||
<Col span={7}>
|
||||
{this.state.hasPlugin ? (
|
||||
<div
|
||||
style={{
|
||||
float: 'right',
|
||||
paddingTop: '8px'
|
||||
}}>
|
||||
{this.props.curProjectRole !== 'guest' && (
|
||||
<Tooltip title="在 YApi 服务端跑自动化测试,测试环境不能为私有网络,请确保 YApi 服务器可以访问到自动化测试环境domain">
|
||||
<Button
|
||||
style={{
|
||||
}}
|
||||
>
|
||||
{this.props.curProjectRole !== 'guest' && (
|
||||
<Tooltip title="在 YApi 服务端跑自动化测试,测试环境不能为私有网络,请确保 YApi 服务器可以访问到自动化测试环境domain">
|
||||
<Button
|
||||
style={{
|
||||
marginRight: '8px'
|
||||
}}
|
||||
onClick={this.autoTests}>
|
||||
服务端测试
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Button type="primary" onClick={this.executeTests}>
|
||||
开始测试
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<Tooltip title="请安装 cross-request Chrome 插件">
|
||||
<Button
|
||||
disabled
|
||||
type="primary"
|
||||
style={{
|
||||
onClick={this.autoTests}
|
||||
>
|
||||
服务端测试
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Button type="primary" onClick={this.executeTests}>
|
||||
开始测试
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Tooltip title="请安装 cross-request Chrome 插件">
|
||||
<Button
|
||||
disabled
|
||||
type="primary"
|
||||
style={{
|
||||
float: 'right',
|
||||
marginTop: '8px'
|
||||
}}>
|
||||
开始测试
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
}}
|
||||
>
|
||||
开始测试
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -781,74 +796,86 @@ class InterfaceColContent extends Component {
|
||||
components={components}
|
||||
columns={resolvedColumns}
|
||||
style={{
|
||||
width: '100%',
|
||||
borderCollapse: 'collapse'
|
||||
}}>
|
||||
width: '100%',
|
||||
borderCollapse: 'collapse'
|
||||
}}
|
||||
>
|
||||
<Table.Header
|
||||
className="interface-col-table-header"
|
||||
headerRows={resolve.headerRows({columns})}/>
|
||||
headerRows={resolve.headerRows({ columns })}
|
||||
/>
|
||||
|
||||
<Table.Body
|
||||
className="interface-col-table-body"
|
||||
rows={resolvedRows}
|
||||
rowKey="id"
|
||||
onRow={this.onRow}/>
|
||||
onRow={this.onRow}
|
||||
/>
|
||||
</Table.Provider>
|
||||
<Modal
|
||||
title="测试报告"
|
||||
width="900px"
|
||||
style={{
|
||||
minHeight: '500px'
|
||||
}}
|
||||
minHeight: '500px'
|
||||
}}
|
||||
visible={this.state.visible}
|
||||
onCancel={this.handleCancel}
|
||||
footer={null}>
|
||||
<CaseReport {...this.reports[this.state.curCaseid]}/>
|
||||
footer={null}
|
||||
>
|
||||
<CaseReport {...this.reports[this.state.curCaseid]} />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="自定义测试脚本"
|
||||
width="660px"
|
||||
style={{
|
||||
minHeight: '500px'
|
||||
}}
|
||||
minHeight: '500px'
|
||||
}}
|
||||
visible={this.state.advVisible}
|
||||
onCancel={this.handleAdvCancel}
|
||||
onOk={this.handleAdvOk}
|
||||
maskClosable={false}>
|
||||
maskClosable={false}
|
||||
>
|
||||
<h3>
|
||||
是否开启:
|
||||
<Switch
|
||||
checked={this.state.enableScript}
|
||||
onChange={e => this.setState({enableScript: e})}/>
|
||||
onChange={e => this.setState({ enableScript: e })}
|
||||
/>
|
||||
</h3>
|
||||
<AceEditor
|
||||
className="case-script"
|
||||
data={this.state.curScript}
|
||||
onChange={this.handleScriptChange}/>
|
||||
onChange={this.handleScriptChange}
|
||||
/>
|
||||
</Modal>
|
||||
<Modal
|
||||
{this.state.autoVisible && <Modal
|
||||
title="服务端自动化测试"
|
||||
width="780px"
|
||||
style={{
|
||||
minHeight: '500px'
|
||||
}}
|
||||
minHeight: '500px'
|
||||
}}
|
||||
visible={this.state.autoVisible}
|
||||
onCancel={this.handleAuto}
|
||||
className="autoTestsModal"
|
||||
footer={null}>
|
||||
footer={null}
|
||||
>
|
||||
<Row type="flex" justify="space-around" className="row" align="top">
|
||||
<Col span={3} className="label" style={{paddingTop: '16px'}}>
|
||||
<Col span={3} className="label" style={{ paddingTop: '16px' }}>
|
||||
选择环境
|
||||
<Tooltip title="默认使用测试用例选择的环境">
|
||||
<Icon type="question-circle-o"/>
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>
|
||||
:
|
||||
</Col>
|
||||
<Col span={21}>
|
||||
<CaseEnv
|
||||
envList={this.props.envList}
|
||||
currProjectEnvChange={this.currProjectEnvChange}/>
|
||||
currProjectEnvChange={this.currProjectEnvChange}
|
||||
envValue={this.state.currColEnvObj}
|
||||
collapseKey={this.state.collapseKey}
|
||||
changeClose={this.changeCollapseClose}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row type="flex" justify="space-around" className="row" align="middle">
|
||||
@ -873,8 +900,9 @@ class InterfaceColContent extends Component {
|
||||
<Icon
|
||||
type="question-circle-o"
|
||||
style={{
|
||||
width: '10px'
|
||||
}}/>
|
||||
width: '10px'
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
:
|
||||
</Col>
|
||||
@ -883,7 +911,8 @@ class InterfaceColContent extends Component {
|
||||
checked={this.state.email}
|
||||
checkedChildren="开"
|
||||
unCheckedChildren="关"
|
||||
onChange={this.emailChange}/>
|
||||
onChange={this.emailChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -894,9 +923,7 @@ class InterfaceColContent extends Component {
|
||||
</a>
|
||||
</Col>
|
||||
<Col span={3}>
|
||||
<Button
|
||||
className="copy-btn"
|
||||
onClick={() => this.copyUrl(localUrl + autoTestsUrl)}>
|
||||
<Button className="copy-btn" onClick={() => this.copyUrl(localUrl + autoTestsUrl)}>
|
||||
复制
|
||||
</Button>
|
||||
</Col>
|
||||
@ -904,7 +931,7 @@ class InterfaceColContent extends Component {
|
||||
<div className="autoTestMsg">
|
||||
注:访问该URL,可以测试所有用例,请确保YApi服务器可以访问到环境配置的 domain
|
||||
</div>
|
||||
</Modal>
|
||||
</Modal>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,51 +1,45 @@
|
||||
import React, { PureComponent as Component } from 'react'
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router'
|
||||
import PropTypes from 'prop-types'
|
||||
import { fetchInterfaceColList, fetchInterfaceCaseList, setColData, fetchCaseList } from '../../../../reducer/modules/interfaceCol'
|
||||
import { withRouter } from 'react-router';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
fetchInterfaceColList,
|
||||
fetchInterfaceCaseList,
|
||||
setColData,
|
||||
fetchCaseList
|
||||
} from '../../../../reducer/modules/interfaceCol';
|
||||
// import { fetchInterfaceListMenu } from '../../../../reducer/modules/interface.js';
|
||||
import { fetchProjectList } from '../../../../reducer/modules/project'
|
||||
import { fetchProjectList } from '../../../../reducer/modules/project';
|
||||
import axios from 'axios';
|
||||
// import { Input, Icon, Button, Modal, message, Tooltip, Tree, Dropdown, Menu, Form } from 'antd';
|
||||
import ImportInterface from './ImportInterface'
|
||||
import ImportInterface from './ImportInterface';
|
||||
import { Input, Icon, Button, Modal, message, Tooltip, Tree, Form } from 'antd';
|
||||
// import produce from 'immer'
|
||||
import { arrayChangeIndex } from '../../../../common.js'
|
||||
import { arrayChangeIndex } from '../../../../common.js';
|
||||
|
||||
const TreeNode = Tree.TreeNode;
|
||||
const FormItem = Form.Item;
|
||||
const confirm = Modal.confirm;
|
||||
|
||||
import './InterfaceColMenu.scss'
|
||||
import './InterfaceColMenu.scss';
|
||||
|
||||
const ColModalForm = Form.create()((props) => {
|
||||
const ColModalForm = Form.create()(props => {
|
||||
const { visible, onCancel, onCreate, form, title } = props;
|
||||
const { getFieldDecorator } = form;
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={title}
|
||||
onCancel={onCancel}
|
||||
onOk={onCreate}
|
||||
|
||||
>
|
||||
<Modal visible={visible} title={title} onCancel={onCancel} onOk={onCreate}>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="集合名">
|
||||
{getFieldDecorator('colName', {
|
||||
rules: [{ required: true, message: '请输入集合命名!' }]
|
||||
})(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="简介">
|
||||
{getFieldDecorator('colDesc')(<Input type="textarea" />)}
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="简介">{getFieldDecorator('colDesc')(<Input type="textarea" />)}</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
@ -57,7 +51,7 @@ const ColModalForm = Form.create()((props) => {
|
||||
// 当前项目的信息
|
||||
curProject: state.project.currProject
|
||||
// projectList: state.project.projectList
|
||||
}
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceColList,
|
||||
@ -70,7 +64,6 @@ const ColModalForm = Form.create()((props) => {
|
||||
)
|
||||
@withRouter
|
||||
export default class InterfaceColMenu extends Component {
|
||||
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
interfaceColList: PropTypes.array,
|
||||
@ -88,7 +81,7 @@ export default class InterfaceColMenu extends Component {
|
||||
curProject: PropTypes.object,
|
||||
fetchProjectList: PropTypes.func
|
||||
// projectList: PropTypes.array
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
colModalType: '',
|
||||
@ -102,31 +95,31 @@ export default class InterfaceColMenu extends Component {
|
||||
list: [],
|
||||
delIcon: null,
|
||||
selectedProject: null
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.getList()
|
||||
this.getList();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.interfaceColList !== nextProps.interfaceColList) {
|
||||
|
||||
this.setState({
|
||||
list: nextProps.interfaceColList
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getList() {
|
||||
|
||||
let r = await this.props.fetchInterfaceColList(this.props.match.params.id);
|
||||
this.setState({
|
||||
list: r.payload.data.data
|
||||
})
|
||||
return r
|
||||
});
|
||||
return r;
|
||||
}
|
||||
|
||||
addorEditCol = async () => {
|
||||
@ -135,9 +128,9 @@ export default class InterfaceColMenu extends Component {
|
||||
const project_id = this.props.match.params.id;
|
||||
let res = {};
|
||||
if (colModalType === 'add') {
|
||||
res = await axios.post('/api/col/add_col', { name, desc, project_id })
|
||||
res = await axios.post('/api/col/add_col', { name, desc, project_id });
|
||||
} else if (colModalType === 'edit') {
|
||||
res = await axios.post('/api/col/up_col', { name, desc, col_id })
|
||||
res = await axios.post('/api/col/up_col', { name, desc, col_id });
|
||||
}
|
||||
if (!res.data.errcode) {
|
||||
this.setState({
|
||||
@ -149,45 +142,44 @@ export default class InterfaceColMenu extends Component {
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onExpand = (keys) => {
|
||||
this.setState({ expands: keys })
|
||||
onExpand = keys => {
|
||||
this.setState({ expands: keys });
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
onSelect = (keys) => {
|
||||
onSelect = keys => {
|
||||
if (keys.length) {
|
||||
const type = keys[0].split('_')[0];
|
||||
const id = keys[0].split('_')[1];
|
||||
const project_id = this.props.match.params.id
|
||||
const project_id = this.props.match.params.id;
|
||||
if (type === 'col') {
|
||||
this.props.setColData({
|
||||
isRander: false
|
||||
})
|
||||
this.props.history.push('/project/' + project_id + '/interface/col/' + id)
|
||||
});
|
||||
this.props.history.push('/project/' + project_id + '/interface/col/' + id);
|
||||
} else {
|
||||
this.props.setColData({
|
||||
isRander: false
|
||||
})
|
||||
this.props.history.push('/project/' + project_id + '/interface/case/' + id)
|
||||
});
|
||||
this.props.history.push('/project/' + project_id + '/interface/case/' + id);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
expands: null
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
showDelColConfirm = (colId) => {
|
||||
showDelColConfirm = colId => {
|
||||
let that = this;
|
||||
const params = this.props.match.params;
|
||||
confirm({
|
||||
title: '您确认删除此测试集合',
|
||||
content: '温馨提示:该操作会删除该集合下所有测试用例,用例删除后无法恢复',
|
||||
okText:"确认",
|
||||
cancelText:"取消",
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
const res = await axios.get('/api/col/del_col?col_id=' + colId)
|
||||
const res = await axios.get('/api/col/del_col?col_id=' + colId);
|
||||
if (!res.data.errcode) {
|
||||
message.success('删除集合成功');
|
||||
const result = await that.getList();
|
||||
@ -199,11 +191,10 @@ export default class InterfaceColMenu extends Component {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 复制测试集合
|
||||
copyInterface = async (item) => {
|
||||
// 复制测试集合
|
||||
copyInterface = async item => {
|
||||
if (this._copyInterfaceSign === true) {
|
||||
return;
|
||||
}
|
||||
@ -227,7 +218,7 @@ export default class InterfaceColMenu extends Component {
|
||||
new_col_id,
|
||||
col_id,
|
||||
project_id
|
||||
})
|
||||
});
|
||||
this._copyInterfaceSign = false;
|
||||
|
||||
if (add_case_list_res.data.errcode) {
|
||||
@ -235,72 +226,72 @@ export default class InterfaceColMenu extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
// 刷新接口列表
|
||||
// 刷新接口列表
|
||||
// await this.props.fetchInterfaceColList(project_id);
|
||||
this.getList()
|
||||
this.props.setColData({ isRander: true })
|
||||
message.success('克隆测试集成功')
|
||||
|
||||
}
|
||||
this.getList();
|
||||
this.props.setColData({ isRander: true });
|
||||
message.success('克隆测试集成功');
|
||||
};
|
||||
|
||||
showNoDelColConfirm = () => {
|
||||
confirm({
|
||||
title: '此测试集合为最后一个集合',
|
||||
content: '温馨提示:建议不要删除'
|
||||
});
|
||||
}
|
||||
showDelCaseConfirm = (caseId) => {
|
||||
};
|
||||
showDelCaseConfirm = caseId => {
|
||||
let that = this;
|
||||
const params = this.props.match.params;
|
||||
confirm({
|
||||
title: '您确认删除此测试用例',
|
||||
content: '温馨提示:用例删除后无法恢复',
|
||||
okText:"确认",
|
||||
cancelText:"取消",
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
const res = await axios.get('/api/col/del_case?caseid=' + caseId)
|
||||
const res = await axios.get('/api/col/del_case?caseid=' + caseId);
|
||||
if (!res.data.errcode) {
|
||||
message.success('删除用例成功');
|
||||
that.getList()
|
||||
that.getList();
|
||||
// 如果删除当前选中 case,切换路由到集合
|
||||
if (+caseId === +that.props.currCaseId) {
|
||||
that.props.history.push('/project/' + params.id + '/interface/col/')
|
||||
that.props.history.push('/project/' + params.id + '/interface/col/');
|
||||
} else {
|
||||
// that.props.fetchInterfaceColList(that.props.match.params.id);
|
||||
that.props.setColData({ isRander: true })
|
||||
that.props.setColData({ isRander: true });
|
||||
}
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
showColModal = (type, col) => {
|
||||
const editCol = type === 'edit' ? { colName: col.name, colDesc: col.desc } : { colName: '', colDesc: '' };
|
||||
const editCol =
|
||||
type === 'edit' ? { colName: col.name, colDesc: col.desc } : { colName: '', colDesc: '' };
|
||||
this.setState({
|
||||
colModalVisible: true,
|
||||
colModalType: type || 'add',
|
||||
editColId: col && col._id
|
||||
})
|
||||
this.form.setFieldsValue(editCol)
|
||||
}
|
||||
saveFormRef = (form) => {
|
||||
});
|
||||
this.form.setFieldsValue(editCol);
|
||||
};
|
||||
saveFormRef = form => {
|
||||
this.form = form;
|
||||
}
|
||||
};
|
||||
|
||||
selectInterface = (importInterIds, selectedProject) => {
|
||||
|
||||
this.setState({ importInterIds, selectedProject })
|
||||
}
|
||||
this.setState({ importInterIds, selectedProject });
|
||||
};
|
||||
|
||||
showImportInterfaceModal = async (colId) => {
|
||||
showImportInterfaceModal = async colId => {
|
||||
// const projectId = this.props.match.params.id;
|
||||
// console.log('project', this.props.curProject)
|
||||
const groupId = this.props.curProject.group_id
|
||||
await this.props.fetchProjectList(groupId)
|
||||
const groupId = this.props.curProject.group_id;
|
||||
await this.props.fetchProjectList(groupId);
|
||||
// await this.props.fetchInterfaceListMenu(projectId)
|
||||
this.setState({ importInterVisible: true, importColId: colId })
|
||||
}
|
||||
this.setState({ importInterVisible: true, importColId: colId });
|
||||
};
|
||||
|
||||
handleImportOk = async () => {
|
||||
const project_id = this.state.selectedProject || this.props.match.params.id;
|
||||
const { importColId, importInterIds } = this.state;
|
||||
@ -308,23 +299,23 @@ export default class InterfaceColMenu extends Component {
|
||||
interface_list: importInterIds,
|
||||
col_id: importColId,
|
||||
project_id
|
||||
})
|
||||
});
|
||||
if (!res.data.errcode) {
|
||||
this.setState({ importInterVisible: false })
|
||||
this.setState({ importInterVisible: false });
|
||||
message.success('导入集合成功');
|
||||
// await this.props.fetchInterfaceColList(project_id);
|
||||
this.getList()
|
||||
this.getList();
|
||||
|
||||
this.props.setColData({ isRander: true })
|
||||
this.props.setColData({ isRander: true });
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
}
|
||||
};
|
||||
handleImportCancel = () => {
|
||||
this.setState({ importInterVisible: false })
|
||||
}
|
||||
this.setState({ importInterVisible: false });
|
||||
};
|
||||
|
||||
filterCol = (e) => {
|
||||
filterCol = e => {
|
||||
const value = e.target.value;
|
||||
// console.log('list', this.props.interfaceColList);
|
||||
// const newList = produce(this.props.interfaceColList, draftList => {})
|
||||
@ -333,10 +324,10 @@ export default class InterfaceColMenu extends Component {
|
||||
filterValue: value,
|
||||
list: JSON.parse(JSON.stringify(this.props.interfaceColList))
|
||||
// list: newList
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onDrop = async (e) => {
|
||||
onDrop = async e => {
|
||||
// const projectId = this.props.match.params.id;
|
||||
const { interfaceColList } = this.props;
|
||||
const dropColIndex = e.node.props.pos.split('-')[1];
|
||||
@ -350,31 +341,31 @@ export default class InterfaceColMenu extends Component {
|
||||
const dragPos = e.dragNode.props.pos.split('-');
|
||||
const dragIndex = Number(dragPos[dragPos.length - 1]);
|
||||
|
||||
if (id.indexOf('col') === -1 ) {
|
||||
if (id.indexOf('col') === -1) {
|
||||
if (dropColId === dragColId) {
|
||||
// 同一个测试集合下的接口交换顺序
|
||||
let caseList = interfaceColList[dropColIndex].caseList;
|
||||
let changes = arrayChangeIndex(caseList, dragIndex, dropIndex)
|
||||
axios.post('/api/col/up_case_index', changes).then()
|
||||
let changes = arrayChangeIndex(caseList, dragIndex, dropIndex);
|
||||
axios.post('/api/col/up_case_index', changes).then();
|
||||
}
|
||||
await axios.post('/api/col/up_case', { id: id.split('_')[1], col_id: dropColId });
|
||||
// this.props.fetchInterfaceColList(projectId);
|
||||
this.getList()
|
||||
this.props.setColData({ isRander: true })
|
||||
this.getList();
|
||||
this.props.setColData({ isRander: true });
|
||||
} else {
|
||||
let changes = arrayChangeIndex(interfaceColList, dragIndex, dropIndex);
|
||||
axios.post('/api/col/up_col_index', changes).then()
|
||||
this.getList()
|
||||
let changes = arrayChangeIndex(interfaceColList, dragIndex, dropIndex);
|
||||
axios.post('/api/col/up_col_index', changes).then();
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enterItem = (id) => {
|
||||
this.setState({ delIcon: id })
|
||||
}
|
||||
enterItem = id => {
|
||||
this.setState({ delIcon: id });
|
||||
};
|
||||
|
||||
leaveItem = () => {
|
||||
this.setState({ delIcon: null })
|
||||
}
|
||||
this.setState({ delIcon: null });
|
||||
};
|
||||
|
||||
render() {
|
||||
// const { currColId, currCaseId, isShowCol } = this.props;
|
||||
@ -399,7 +390,8 @@ export default class InterfaceColMenu extends Component {
|
||||
// };
|
||||
|
||||
const defaultExpandedKeys = () => {
|
||||
const { router, currCase, interfaceColList } = this.props, rNull = { expands: [], selects: [] };
|
||||
const { router, currCase, interfaceColList } = this.props,
|
||||
rNull = { expands: [], selects: [] };
|
||||
if (interfaceColList.length === 0) {
|
||||
return rNull;
|
||||
}
|
||||
@ -410,69 +402,77 @@ export default class InterfaceColMenu extends Component {
|
||||
}
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['col_' + currCase.col_id],
|
||||
selects: ['case_' + currCase._id + ""]
|
||||
}
|
||||
selects: ['case_' + currCase._id + '']
|
||||
};
|
||||
} else {
|
||||
let col_id = router.params.actionId;
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['col_' + col_id],
|
||||
selects: ['col_' + col_id]
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['col_' + interfaceColList[0]._id],
|
||||
selects: ['root']
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const item_interface_col_create = (interfaceCase) => {
|
||||
|
||||
const item_interface_col_create = interfaceCase => {
|
||||
return (
|
||||
<TreeNode
|
||||
style={{ width: '100%' }}
|
||||
key={'case_' + interfaceCase._id}
|
||||
title={
|
||||
<div className="menu-title" onMouseEnter={() => this.enterItem(interfaceCase._id)} onMouseLeave={this.leaveItem} title={interfaceCase.casename}>
|
||||
title={
|
||||
<div
|
||||
className="menu-title"
|
||||
onMouseEnter={() => this.enterItem(interfaceCase._id)}
|
||||
onMouseLeave={this.leaveItem}
|
||||
title={interfaceCase.casename}
|
||||
>
|
||||
<span className="casename">{interfaceCase.casename}</span>
|
||||
<Tooltip title="删除用例">
|
||||
<Icon type='delete' className="case-delete-icon" onClick={(e) => { e.stopPropagation(); this.showDelCaseConfirm(interfaceCase._id) }} style={{ display: this.state.delIcon == interfaceCase._id ? 'block' : 'none' }} />
|
||||
<Icon
|
||||
type="delete"
|
||||
className="case-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showDelCaseConfirm(interfaceCase._id);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == interfaceCase._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
}
|
||||
></TreeNode>
|
||||
)
|
||||
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
let currentKes = defaultExpandedKeys();
|
||||
// console.log('currentKey', currentKes)
|
||||
|
||||
|
||||
let list = this.state.list;
|
||||
|
||||
if (this.state.filterValue) {
|
||||
let arr = [];
|
||||
list = list.filter((item) => {
|
||||
list = list.filter(item => {
|
||||
let interfaceFilter = false;
|
||||
if (item.name.indexOf(this.state.filterValue) === -1) {
|
||||
item.caseList = item.caseList.filter(inter => {
|
||||
|
||||
if (inter.casename.indexOf(this.state.filterValue) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//arr.push('cat_' + inter.catid)
|
||||
interfaceFilter = true;
|
||||
return true;
|
||||
|
||||
})
|
||||
arr.push('col_' + item._id)
|
||||
return interfaceFilter === true
|
||||
});
|
||||
arr.push('col_' + item._id);
|
||||
return interfaceFilter === true;
|
||||
}
|
||||
arr.push('col_' + item._id)
|
||||
arr.push('col_' + item._id);
|
||||
return true;
|
||||
})
|
||||
});
|
||||
// console.log('arr', arr);
|
||||
if (arr.length > 0) {
|
||||
currentKes.expands = arr;
|
||||
@ -487,7 +487,14 @@ export default class InterfaceColMenu extends Component {
|
||||
<div className="interface-filter">
|
||||
<Input placeholder="搜索测试集合" onChange={this.filterCol} />
|
||||
<Tooltip placement="bottom" title="添加集合">
|
||||
<Button type="primary" style={{ marginLeft: "16px" }} onClick={() => this.showColModal('add')} className="btn-filter" >添加集合</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginLeft: '16px' }}
|
||||
onClick={() => this.showColModal('add')}
|
||||
className="btn-filter"
|
||||
>
|
||||
添加集合
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Tree
|
||||
@ -501,49 +508,78 @@ export default class InterfaceColMenu extends Component {
|
||||
draggable
|
||||
onExpand={this.onExpand}
|
||||
onDrop={this.onDrop}
|
||||
|
||||
>
|
||||
{
|
||||
list.map((col) => (
|
||||
<TreeNode
|
||||
key={'col_' + col._id}
|
||||
title={
|
||||
<div className="menu-title" >
|
||||
<span><Icon type="folder-open" style={{ marginRight: 5 }} /><span>{col.name}</span></span>
|
||||
<div className="btns">
|
||||
|
||||
<Tooltip title="删除集合">
|
||||
<Icon type='delete' style={{ display: list.length > 1 ? '' : 'none' }} className="interface-delete-icon" onClick={() => { this.showDelColConfirm(col._id) }} />
|
||||
</Tooltip>
|
||||
<Tooltip title="编辑集合">
|
||||
<Icon type='edit' className="interface-delete-icon" onClick={(e) => { e.stopPropagation(); this.showColModal('edit', col) }} />
|
||||
</Tooltip>
|
||||
<Tooltip title="导入接口">
|
||||
<Icon type='plus' className="interface-delete-icon" onClick={(e) => { e.stopPropagation(); this.showImportInterfaceModal(col._id) }} />
|
||||
</Tooltip>
|
||||
<Tooltip title="克隆集合">
|
||||
<Icon type='copy' className="interface-delete-icon" onClick={(e) => { e.stopPropagation(); this.copyInterface(col) }} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/*<Dropdown overlay={menu(col)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
{list.map(col => (
|
||||
<TreeNode
|
||||
key={'col_' + col._id}
|
||||
title={
|
||||
<div className="menu-title">
|
||||
<span>
|
||||
<Icon type="folder-open" style={{ marginRight: 5 }} />
|
||||
<span>{col.name}</span>
|
||||
</span>
|
||||
<div className="btns">
|
||||
<Tooltip title="删除集合">
|
||||
<Icon
|
||||
type="delete"
|
||||
style={{ display: list.length > 1 ? '' : 'none' }}
|
||||
className="interface-delete-icon"
|
||||
onClick={() => {
|
||||
this.showDelColConfirm(col._id);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="编辑集合">
|
||||
<Icon
|
||||
type="edit"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showColModal('edit', col);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="导入接口">
|
||||
<Icon
|
||||
type="plus"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showImportInterfaceModal(col._id);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="克隆集合">
|
||||
<Icon
|
||||
type="copy"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.copyInterface(col);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/*<Dropdown overlay={menu(col)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon className="opts-icon" type='ellipsis'/>
|
||||
</Dropdown>*/}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{col.caseList.map(item_interface_col_create)}
|
||||
|
||||
</TreeNode>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{col.caseList.map(item_interface_col_create)}
|
||||
</TreeNode>
|
||||
))}
|
||||
</Tree>
|
||||
<ColModalForm
|
||||
ref={this.saveFormRef}
|
||||
type={colModalType}
|
||||
visible={colModalVisible}
|
||||
onCancel={() => { this.setState({ colModalVisible: false }) }}
|
||||
onCancel={() => {
|
||||
this.setState({ colModalVisible: false });
|
||||
}}
|
||||
onCreate={this.addorEditCol}
|
||||
></ColModalForm>
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="导入接口到集合"
|
||||
visible={importInterVisible}
|
||||
@ -555,6 +591,6 @@ export default class InterfaceColMenu extends Component {
|
||||
<ImportInterface currProjectId={currProjectId} selectInterface={this.selectInterface} />
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,7 @@ export function fetchVariableParamsList(colId) {
|
||||
}
|
||||
|
||||
export function setColData(data) {
|
||||
|
||||
return {
|
||||
type: SET_COL_DATA,
|
||||
payload: data
|
||||
|
Loading…
x
Reference in New Issue
Block a user