fork from bc4552c5a8
This commit is contained in:
125
client/containers/Project/Interface/InterfaceCol/CaseReport.js
Normal file
125
client/containers/Project/Interface/InterfaceCol/CaseReport.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Row, Col, Tabs } from 'antd';
|
||||
const TabPane = Tabs.TabPane;
|
||||
function jsonFormat(json) {
|
||||
// console.log('json',json)
|
||||
if (json && typeof json === 'object') {
|
||||
return JSON.stringify(json, null, ' ');
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
const CaseReport = function(props) {
|
||||
let params = jsonFormat(props.data);
|
||||
let headers = jsonFormat(props.headers, null, ' ');
|
||||
let res_header = jsonFormat(props.res_header, null, ' ');
|
||||
let res_body = jsonFormat(props.res_body);
|
||||
let httpCode = props.status;
|
||||
let validRes;
|
||||
if (props.validRes && Array.isArray(props.validRes)) {
|
||||
validRes = props.validRes.map((item, index) => {
|
||||
return <div key={index}>{item.message}</div>;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="report">
|
||||
<Tabs defaultActiveKey="request">
|
||||
<TabPane className="case-report-pane" tab="Request" key="request">
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Url
|
||||
</Col>
|
||||
<Col span="18">{props.url}</Col>
|
||||
</Row>
|
||||
{props.query ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Query
|
||||
</Col>
|
||||
<Col span="18">{props.query}</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
|
||||
{props.headers ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Headers
|
||||
</Col>
|
||||
<Col span="18">
|
||||
<pre>{headers}</pre>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
|
||||
{params ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Body
|
||||
</Col>
|
||||
<Col span="18">
|
||||
<pre style={{ whiteSpace: 'pre-wrap' }}>{params}</pre>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</TabPane>
|
||||
<TabPane className="case-report-pane" tab="Response" key="response">
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
HttpCode
|
||||
</Col>
|
||||
<Col span="18">
|
||||
<pre>{httpCode}</pre>
|
||||
</Col>
|
||||
</Row>
|
||||
{props.res_header ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Headers
|
||||
</Col>
|
||||
<Col span="18">
|
||||
<pre>{res_header}</pre>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
{props.res_body ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
Body
|
||||
</Col>
|
||||
<Col span="18">
|
||||
<pre>{res_body}</pre>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</TabPane>
|
||||
<TabPane className="case-report-pane" tab="验证结果" key="valid">
|
||||
{props.validRes ? (
|
||||
<Row className="case-report">
|
||||
<Col className="case-report-title" span="6">
|
||||
验证结果
|
||||
</Col>
|
||||
<Col span="18"><pre>
|
||||
{validRes}
|
||||
</pre></Col>
|
||||
</Row>
|
||||
) : null}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CaseReport.propTypes = {
|
||||
url: PropTypes.string,
|
||||
data: PropTypes.any,
|
||||
headers: PropTypes.object,
|
||||
res_header: PropTypes.object,
|
||||
res_body: PropTypes.any,
|
||||
query: PropTypes.string,
|
||||
validRes: PropTypes.array,
|
||||
status: PropTypes.number
|
||||
};
|
||||
|
||||
export default CaseReport;
|
||||
@@ -0,0 +1,241 @@
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Table, Select, Tooltip, Icon } from 'antd';
|
||||
import variable from '../../../../constants/variable';
|
||||
import { connect } from 'react-redux';
|
||||
const Option = Select.Option;
|
||||
import { fetchInterfaceListMenu } from '../../../../reducer/modules/interface.js';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
projectList: state.project.projectList,
|
||||
list: state.inter.list
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceListMenu
|
||||
}
|
||||
)
|
||||
export default class ImportInterface extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
state = {
|
||||
selectedRowKeys: [],
|
||||
categoryCount: {},
|
||||
project: this.props.currProjectId
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
list: PropTypes.array,
|
||||
selectInterface: PropTypes.func,
|
||||
projectList: PropTypes.array,
|
||||
currProjectId: PropTypes.string,
|
||||
fetchInterfaceListMenu: PropTypes.func
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
// console.log(this.props.currProjectId)
|
||||
await this.props.fetchInterfaceListMenu(this.props.currProjectId);
|
||||
}
|
||||
|
||||
// 切换项目
|
||||
onChange = async val => {
|
||||
this.setState({
|
||||
project: val,
|
||||
selectedRowKeys: [],
|
||||
categoryCount: {}
|
||||
});
|
||||
await this.props.fetchInterfaceListMenu(val);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { list, projectList } = this.props;
|
||||
|
||||
// const { selectedRowKeys } = this.state;
|
||||
const data = list.map(item => {
|
||||
return {
|
||||
key: 'category_' + item._id,
|
||||
title: item.name,
|
||||
isCategory: true,
|
||||
children: item.list
|
||||
? item.list.map(e => {
|
||||
e.key = e._id;
|
||||
e.categoryKey = 'category_' + item._id;
|
||||
e.categoryLength = item.list.length;
|
||||
return e;
|
||||
})
|
||||
: []
|
||||
};
|
||||
});
|
||||
const self = this;
|
||||
const rowSelection = {
|
||||
// onChange: (selectedRowKeys) => {
|
||||
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
// if (selectedRows.isCategory) {
|
||||
// const selectedRowKeys = selectedRows.children.map(item => item._id)
|
||||
// this.setState({ selectedRowKeys })
|
||||
// }
|
||||
// this.props.onChange(selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1));
|
||||
// },
|
||||
onSelect: (record, selected) => {
|
||||
// console.log(record, selected, selectedRows);
|
||||
const oldSelecteds = self.state.selectedRowKeys;
|
||||
const categoryCount = self.state.categoryCount;
|
||||
const categoryKey = record.categoryKey;
|
||||
const categoryLength = record.categoryLength;
|
||||
let selectedRowKeys = [];
|
||||
if (record.isCategory) {
|
||||
selectedRowKeys = record.children.map(item => item._id).concat(record.key);
|
||||
if (selected) {
|
||||
selectedRowKeys = selectedRowKeys
|
||||
.filter(id => oldSelecteds.indexOf(id) === -1)
|
||||
.concat(oldSelecteds);
|
||||
categoryCount[categoryKey] = categoryLength;
|
||||
} else {
|
||||
selectedRowKeys = oldSelecteds.filter(id => selectedRowKeys.indexOf(id) === -1);
|
||||
categoryCount[categoryKey] = 0;
|
||||
}
|
||||
} else {
|
||||
if (selected) {
|
||||
selectedRowKeys = oldSelecteds.concat(record._id);
|
||||
if (categoryCount[categoryKey]) {
|
||||
categoryCount[categoryKey] += 1;
|
||||
} else {
|
||||
categoryCount[categoryKey] = 1;
|
||||
}
|
||||
if (categoryCount[categoryKey] === record.categoryLength) {
|
||||
selectedRowKeys.push(categoryKey);
|
||||
}
|
||||
} else {
|
||||
selectedRowKeys = oldSelecteds.filter(id => id !== record._id);
|
||||
if (categoryCount[categoryKey]) {
|
||||
categoryCount[categoryKey] -= 1;
|
||||
}
|
||||
selectedRowKeys = selectedRowKeys.filter(id => id !== categoryKey);
|
||||
}
|
||||
}
|
||||
self.setState({ selectedRowKeys, categoryCount });
|
||||
self.props.selectInterface(
|
||||
selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1),
|
||||
self.state.project
|
||||
);
|
||||
},
|
||||
onSelectAll: selected => {
|
||||
// console.log(selected, selectedRows, changeRows);
|
||||
let selectedRowKeys = [];
|
||||
let categoryCount = self.state.categoryCount;
|
||||
if (selected) {
|
||||
data.forEach(item => {
|
||||
if (item.children) {
|
||||
categoryCount['category_' + item._id] = item.children.length;
|
||||
selectedRowKeys = selectedRowKeys.concat(item.children.map(item => item._id));
|
||||
}
|
||||
});
|
||||
selectedRowKeys = selectedRowKeys.concat(data.map(item => item.key));
|
||||
} else {
|
||||
categoryCount = {};
|
||||
selectedRowKeys = [];
|
||||
}
|
||||
self.setState({ selectedRowKeys, categoryCount });
|
||||
self.props.selectInterface(
|
||||
selectedRowKeys.filter(id => ('' + id).indexOf('category') === -1),
|
||||
self.state.project
|
||||
);
|
||||
},
|
||||
selectedRowKeys: self.state.selectedRowKeys
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '接口名称',
|
||||
dataIndex: 'title',
|
||||
width: '30%'
|
||||
},
|
||||
{
|
||||
title: '接口路径',
|
||||
dataIndex: 'path',
|
||||
width: '40%'
|
||||
},
|
||||
{
|
||||
title: '请求方法',
|
||||
dataIndex: 'method',
|
||||
render: item => {
|
||||
let methodColor = variable.METHOD_COLOR[item ? item.toLowerCase() : 'get'];
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
color: methodColor.color,
|
||||
backgroundColor: methodColor.bac,
|
||||
borderRadius: 4
|
||||
}}
|
||||
className="colValue"
|
||||
>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<span>
|
||||
状态{' '}
|
||||
<Tooltip title="筛选满足条件的接口集合">
|
||||
<Icon type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
),
|
||||
dataIndex: 'status',
|
||||
render: text => {
|
||||
return (
|
||||
text &&
|
||||
(text === 'done' ? (
|
||||
<span className="tag-status done">已完成</span>
|
||||
) : (
|
||||
<span className="tag-status undone">未完成</span>
|
||||
))
|
||||
);
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
text: '已完成',
|
||||
value: 'done'
|
||||
},
|
||||
{
|
||||
text: '未完成',
|
||||
value: 'undone'
|
||||
}
|
||||
],
|
||||
onFilter: (value, record) => {
|
||||
let arr = record.children.filter(item => {
|
||||
return item.status.indexOf(value) === 0;
|
||||
});
|
||||
return arr.length > 0;
|
||||
// record.status.indexOf(value) === 0
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="select-project">
|
||||
<span>选择要导入的项目: </span>
|
||||
<Select value={this.state.project} style={{ width: 200 }} onChange={this.onChange}>
|
||||
{projectList.map(item => {
|
||||
return item.projectname ? (
|
||||
''
|
||||
) : (
|
||||
<Option value={`${item._id}`} key={item._id}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</div>
|
||||
<Table columns={columns} rowSelection={rowSelection} dataSource={data} pagination={false} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
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 axios from 'axios';
|
||||
import { message, Tooltip, Input } from 'antd';
|
||||
import { getEnv } from '../../../../reducer/modules/project';
|
||||
import {
|
||||
fetchInterfaceColList,
|
||||
setColData,
|
||||
fetchCaseData,
|
||||
fetchCaseList
|
||||
} from '../../../../reducer/modules/interfaceCol';
|
||||
import { Postman } from '../../../../components';
|
||||
|
||||
import './InterfaceCaseContent.scss';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
interfaceColList: state.interfaceCol.interfaceColList,
|
||||
currColId: state.interfaceCol.currColId,
|
||||
currCaseId: state.interfaceCol.currCaseId,
|
||||
currCase: state.interfaceCol.currCase,
|
||||
isShowCol: state.interfaceCol.isShowCol,
|
||||
currProject: state.project.currProject,
|
||||
projectEnv: state.project.projectEnv,
|
||||
curUid: state.user.uid
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceColList,
|
||||
fetchCaseData,
|
||||
setColData,
|
||||
fetchCaseList,
|
||||
getEnv
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
export default class InterfaceCaseContent extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
interfaceColList: PropTypes.array,
|
||||
fetchInterfaceColList: PropTypes.func,
|
||||
fetchCaseData: PropTypes.func,
|
||||
setColData: PropTypes.func,
|
||||
fetchCaseList: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
currColId: PropTypes.number,
|
||||
currCaseId: PropTypes.number,
|
||||
currCase: PropTypes.object,
|
||||
isShowCol: PropTypes.bool,
|
||||
currProject: PropTypes.object,
|
||||
getEnv: PropTypes.func,
|
||||
projectEnv: PropTypes.object,
|
||||
curUid: PropTypes.number
|
||||
};
|
||||
|
||||
state = {
|
||||
isEditingCasename: true,
|
||||
editCasename: ''
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
getColId(colList, currCaseId) {
|
||||
let currColId = 0;
|
||||
colList.forEach(col => {
|
||||
col.caseList.forEach(caseItem => {
|
||||
if (+caseItem._id === +currCaseId) {
|
||||
currColId = col._id;
|
||||
}
|
||||
});
|
||||
});
|
||||
return currColId;
|
||||
}
|
||||
|
||||
async UNSAFE_componentWillMount() {
|
||||
const result = await this.props.fetchInterfaceColList(this.props.match.params.id);
|
||||
let { currCaseId } = this.props;
|
||||
const params = this.props.match.params;
|
||||
const { actionId } = params;
|
||||
currCaseId = +actionId || +currCaseId || result.payload.data.data[0].caseList[0]._id;
|
||||
let currColId = this.getColId(result.payload.data.data, currCaseId);
|
||||
// this.props.history.push('/project/' + params.id + '/interface/case/' + currCaseId);
|
||||
await this.props.fetchCaseData(currCaseId);
|
||||
this.props.setColData({ currCaseId: +currCaseId, currColId, isShowCol: false });
|
||||
// 获取当前case 下的环境变量
|
||||
await this.props.getEnv(this.props.currCase.project_id);
|
||||
// await this.getCurrEnv()
|
||||
|
||||
this.setState({ editCasename: this.props.currCase.casename });
|
||||
}
|
||||
|
||||
async UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const oldCaseId = this.props.match.params.actionId;
|
||||
const newCaseId = nextProps.match.params.actionId;
|
||||
const { interfaceColList } = nextProps;
|
||||
let currColId = this.getColId(interfaceColList, newCaseId);
|
||||
if (oldCaseId !== newCaseId) {
|
||||
await this.props.fetchCaseData(newCaseId);
|
||||
this.props.setColData({ currCaseId: +newCaseId, currColId, isShowCol: false });
|
||||
await this.props.getEnv(this.props.currCase.project_id);
|
||||
// await this.getCurrEnv()
|
||||
this.setState({ editCasename: this.props.currCase.casename });
|
||||
}
|
||||
}
|
||||
|
||||
savePostmanRef = postman => {
|
||||
this.postman = postman;
|
||||
};
|
||||
|
||||
updateCase = async () => {
|
||||
const {
|
||||
case_env,
|
||||
req_params,
|
||||
req_query,
|
||||
req_headers,
|
||||
req_body_type,
|
||||
req_body_form,
|
||||
req_body_other,
|
||||
test_script,
|
||||
enable_script,
|
||||
test_res_body,
|
||||
test_res_header
|
||||
} = this.postman.state;
|
||||
|
||||
const { editCasename: casename } = this.state;
|
||||
const { _id: id } = this.props.currCase;
|
||||
let params = {
|
||||
id,
|
||||
casename,
|
||||
case_env,
|
||||
req_params,
|
||||
req_query,
|
||||
req_headers,
|
||||
req_body_type,
|
||||
req_body_form,
|
||||
req_body_other,
|
||||
test_script,
|
||||
enable_script,
|
||||
test_res_body,
|
||||
test_res_header
|
||||
};
|
||||
|
||||
const res = await axios.post('/api/col/up_case', params);
|
||||
if (this.props.currCase.casename !== casename) {
|
||||
this.props.fetchInterfaceColList(this.props.match.params.id);
|
||||
}
|
||||
if (res.data.errcode) {
|
||||
message.error(res.data.errmsg);
|
||||
} else {
|
||||
message.success('更新成功');
|
||||
this.props.fetchCaseData(id);
|
||||
}
|
||||
};
|
||||
|
||||
triggerEditCasename = () => {
|
||||
this.setState({
|
||||
isEditingCasename: true,
|
||||
editCasename: this.props.currCase.casename
|
||||
});
|
||||
};
|
||||
cancelEditCasename = () => {
|
||||
this.setState({
|
||||
isEditingCasename: false,
|
||||
editCasename: this.props.currCase.casename
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { currCase, currProject, projectEnv } = this.props;
|
||||
const { isEditingCasename, editCasename } = this.state;
|
||||
|
||||
const data = Object.assign(
|
||||
{},
|
||||
currCase,
|
||||
{
|
||||
env: projectEnv.env,
|
||||
pre_script: currProject.pre_script,
|
||||
after_script: currProject.after_script
|
||||
},
|
||||
{ _id: currCase._id }
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ padding: '6px 0' }} className="case-content">
|
||||
<div className="case-title">
|
||||
{!isEditingCasename && (
|
||||
<Tooltip title="点击编辑" placement="bottom">
|
||||
<div className="case-name" onClick={this.triggerEditCasename}>
|
||||
{currCase.casename}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{isEditingCasename && (
|
||||
<div className="edit-case-name">
|
||||
<Input
|
||||
value={editCasename}
|
||||
onChange={e => this.setState({ editCasename: e.target.value })}
|
||||
style={{ fontSize: 18 }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span className="inter-link" style={{ margin: '0px 8px 0px 6px', fontSize: 12 }}>
|
||||
<Link
|
||||
className="text"
|
||||
to={`/project/${currCase.project_id}/interface/api/${currCase.interface_id}`}
|
||||
>
|
||||
对应接口
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
{Object.keys(currCase).length > 0 && (
|
||||
<Postman
|
||||
data={data}
|
||||
type="case"
|
||||
saveTip="更新保存修改"
|
||||
save={this.updateCase}
|
||||
ref={this.savePostmanRef}
|
||||
interfaceId={currCase.interface_id}
|
||||
projectId={currCase.project_id}
|
||||
curUid={this.props.curUid}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
.case-content {
|
||||
padding: 6px 0;
|
||||
.case-title {
|
||||
display: flex;
|
||||
.case-name {
|
||||
margin-left: 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0 5px;
|
||||
background-color: #eee;
|
||||
font-size: 20px;
|
||||
flex-grow: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.case-name:hover {
|
||||
color: rgba(0,0,0,.65);
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
.edit-case-name {
|
||||
margin-left: 8px;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.inter-link {
|
||||
flex-basis: 50px;
|
||||
position: relative;
|
||||
}
|
||||
.inter-link .text {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,630 @@
|
||||
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,
|
||||
fetchCaseData
|
||||
} from '../../../../reducer/modules/interfaceCol';
|
||||
import { fetchProjectList } from '../../../../reducer/modules/project';
|
||||
import axios from 'axios';
|
||||
import ImportInterface from './ImportInterface';
|
||||
import { Input, Icon, Button, Modal, message, Tooltip, Tree, Form } from 'antd';
|
||||
import { arrayChangeIndex } from '../../../../common.js';
|
||||
import _ from 'underscore'
|
||||
|
||||
const TreeNode = Tree.TreeNode;
|
||||
const FormItem = Form.Item;
|
||||
const confirm = Modal.confirm;
|
||||
const headHeight = 240; // menu顶部到网页顶部部分的高度
|
||||
|
||||
import './InterfaceColMenu.scss';
|
||||
|
||||
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}>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="集合名">
|
||||
{getFieldDecorator('colName', {
|
||||
rules: [{ required: true, message: '请输入集合命名!' }]
|
||||
})(<Input />)}
|
||||
</FormItem>
|
||||
<FormItem label="简介">{getFieldDecorator('colDesc')(<Input type="textarea" />)}</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
});
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
interfaceColList: state.interfaceCol.interfaceColList,
|
||||
currCase: state.interfaceCol.currCase,
|
||||
isRander: state.interfaceCol.isRander,
|
||||
currCaseId: state.interfaceCol.currCaseId,
|
||||
// list: state.inter.list,
|
||||
// 当前项目的信息
|
||||
curProject: state.project.currProject
|
||||
// projectList: state.project.projectList
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceColList,
|
||||
fetchInterfaceCaseList,
|
||||
fetchCaseData,
|
||||
// fetchInterfaceListMenu,
|
||||
fetchCaseList,
|
||||
setColData,
|
||||
fetchProjectList
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
export default class InterfaceColMenu extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
interfaceColList: PropTypes.array,
|
||||
fetchInterfaceColList: PropTypes.func,
|
||||
fetchInterfaceCaseList: PropTypes.func,
|
||||
// fetchInterfaceListMenu: PropTypes.func,
|
||||
fetchCaseList: PropTypes.func,
|
||||
fetchCaseData: PropTypes.func,
|
||||
setColData: PropTypes.func,
|
||||
currCaseId: PropTypes.number,
|
||||
history: PropTypes.object,
|
||||
isRander: PropTypes.bool,
|
||||
// list: PropTypes.array,
|
||||
router: PropTypes.object,
|
||||
currCase: PropTypes.object,
|
||||
curProject: PropTypes.object,
|
||||
fetchProjectList: PropTypes.func
|
||||
// projectList: PropTypes.array
|
||||
};
|
||||
|
||||
state = {
|
||||
colModalType: '',
|
||||
colModalVisible: false,
|
||||
editColId: 0,
|
||||
filterValue: '',
|
||||
importInterVisible: false,
|
||||
importInterIds: [],
|
||||
importColId: 0,
|
||||
expands: null,
|
||||
list: [],
|
||||
delIcon: null,
|
||||
selectedProject: null
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getList();
|
||||
}
|
||||
|
||||
UNSAFE_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;
|
||||
}
|
||||
|
||||
addorEditCol = async () => {
|
||||
const { colName: name, colDesc: desc } = this.form.getFieldsValue();
|
||||
const { colModalType, editColId: col_id } = this.state;
|
||||
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 });
|
||||
} else if (colModalType === 'edit') {
|
||||
res = await axios.post('/api/col/up_col', { name, desc, col_id });
|
||||
}
|
||||
if (!res.data.errcode) {
|
||||
this.setState({
|
||||
colModalVisible: false
|
||||
});
|
||||
message.success(colModalType === 'edit' ? '修改集合成功' : '添加集合成功');
|
||||
// await this.props.fetchInterfaceColList(project_id);
|
||||
this.getList();
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
};
|
||||
|
||||
onExpand = keys => {
|
||||
this.setState({ expands: keys });
|
||||
};
|
||||
|
||||
onSelect = _.debounce(keys => {
|
||||
if (keys.length) {
|
||||
const type = keys[0].split('_')[0];
|
||||
const id = keys[0].split('_')[1];
|
||||
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);
|
||||
} else {
|
||||
this.props.setColData({
|
||||
isRander: false
|
||||
});
|
||||
this.props.history.push('/project/' + project_id + '/interface/case/' + id);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
expands: null
|
||||
});
|
||||
}, 500);
|
||||
|
||||
showDelColConfirm = colId => {
|
||||
let that = this;
|
||||
const params = this.props.match.params;
|
||||
confirm({
|
||||
title: '您确认删除此测试集合',
|
||||
content: '温馨提示:该操作会删除该集合下所有测试用例,用例删除后无法恢复',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
const res = await axios.get('/api/col/del_col?col_id=' + colId);
|
||||
if (!res.data.errcode) {
|
||||
message.success('删除集合成功');
|
||||
const result = await that.getList();
|
||||
const nextColId = result.payload.data.data[0]._id;
|
||||
|
||||
that.props.history.push('/project/' + params.id + '/interface/col/' + nextColId);
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 复制测试集合
|
||||
copyInterface = async item => {
|
||||
if (this._copyInterfaceSign === true) {
|
||||
return;
|
||||
}
|
||||
this._copyInterfaceSign = true;
|
||||
const { desc, project_id, _id: col_id } = item;
|
||||
let { name } = item;
|
||||
name = `${name} copy`;
|
||||
|
||||
// 添加集合
|
||||
const add_col_res = await axios.post('/api/col/add_col', { name, desc, project_id });
|
||||
|
||||
if (add_col_res.data.errcode) {
|
||||
message.error(add_col_res.data.errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
const new_col_id = add_col_res.data.data._id;
|
||||
|
||||
// 克隆集合
|
||||
const add_case_list_res = await axios.post('/api/col/clone_case_list', {
|
||||
new_col_id,
|
||||
col_id,
|
||||
project_id
|
||||
});
|
||||
this._copyInterfaceSign = false;
|
||||
|
||||
if (add_case_list_res.data.errcode) {
|
||||
message.error(add_case_list_res.data.errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
// 刷新接口列表
|
||||
// await this.props.fetchInterfaceColList(project_id);
|
||||
this.getList();
|
||||
this.props.setColData({ isRander: true });
|
||||
message.success('克隆测试集成功');
|
||||
};
|
||||
|
||||
showNoDelColConfirm = () => {
|
||||
confirm({
|
||||
title: '此测试集合为最后一个集合',
|
||||
content: '温馨提示:建议不要删除'
|
||||
});
|
||||
};
|
||||
caseCopy = async caseId=> {
|
||||
let that = this;
|
||||
let caseData = await that.props.fetchCaseData(caseId);
|
||||
let data = caseData.payload.data.data;
|
||||
data = JSON.parse(JSON.stringify(data));
|
||||
data.casename=`${data.casename}_copy`
|
||||
delete data._id
|
||||
const res = await axios.post('/api/col/add_case',data);
|
||||
if (!res.data.errcode) {
|
||||
message.success('克隆用例成功');
|
||||
let colId = res.data.data.col_id;
|
||||
let projectId=res.data.data.project_id;
|
||||
await this.getList();
|
||||
this.props.history.push('/project/' + projectId + '/interface/col/' + colId);
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
};
|
||||
showDelCaseConfirm = caseId => {
|
||||
let that = this;
|
||||
const params = this.props.match.params;
|
||||
confirm({
|
||||
title: '您确认删除此测试用例',
|
||||
content: '温馨提示:用例删除后无法恢复',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
const res = await axios.get('/api/col/del_case?caseid=' + caseId);
|
||||
if (!res.data.errcode) {
|
||||
message.success('删除用例成功');
|
||||
that.getList();
|
||||
// 如果删除当前选中 case,切换路由到集合
|
||||
if (+caseId === +that.props.currCaseId) {
|
||||
that.props.history.push('/project/' + params.id + '/interface/col/');
|
||||
} else {
|
||||
// that.props.fetchInterfaceColList(that.props.match.params.id);
|
||||
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: '' };
|
||||
this.setState({
|
||||
colModalVisible: true,
|
||||
colModalType: type || 'add',
|
||||
editColId: col && col._id
|
||||
});
|
||||
this.form.setFieldsValue(editCol);
|
||||
};
|
||||
saveFormRef = form => {
|
||||
this.form = form;
|
||||
};
|
||||
|
||||
selectInterface = (importInterIds, selectedProject) => {
|
||||
this.setState({ importInterIds, selectedProject });
|
||||
};
|
||||
|
||||
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);
|
||||
// await this.props.fetchInterfaceListMenu(projectId)
|
||||
this.setState({ importInterVisible: true, importColId: colId });
|
||||
};
|
||||
|
||||
handleImportOk = async () => {
|
||||
const project_id = this.state.selectedProject || this.props.match.params.id;
|
||||
const { importColId, importInterIds } = this.state;
|
||||
const res = await axios.post('/api/col/add_case_list', {
|
||||
interface_list: importInterIds,
|
||||
col_id: importColId,
|
||||
project_id
|
||||
});
|
||||
if (!res.data.errcode) {
|
||||
this.setState({ importInterVisible: false });
|
||||
message.success('导入集合成功');
|
||||
// await this.props.fetchInterfaceColList(project_id);
|
||||
this.getList();
|
||||
|
||||
this.props.setColData({ isRander: true });
|
||||
} else {
|
||||
message.error(res.data.errmsg);
|
||||
}
|
||||
};
|
||||
handleImportCancel = () => {
|
||||
this.setState({ importInterVisible: false });
|
||||
};
|
||||
|
||||
filterCol = e => {
|
||||
const value = e.target.value;
|
||||
// console.log('list', this.props.interfaceColList);
|
||||
// const newList = produce(this.props.interfaceColList, draftList => {})
|
||||
// console.log('newList',newList);
|
||||
this.setState({
|
||||
filterValue: value,
|
||||
list: JSON.parse(JSON.stringify(this.props.interfaceColList))
|
||||
// list: newList
|
||||
});
|
||||
};
|
||||
|
||||
onDrop = async e => {
|
||||
// const projectId = this.props.match.params.id;
|
||||
const { interfaceColList } = this.props;
|
||||
const dropColIndex = e.node.props.pos.split('-')[1];
|
||||
const dropColId = interfaceColList[dropColIndex]._id;
|
||||
const id = e.dragNode.props.eventKey;
|
||||
const dragColIndex = e.dragNode.props.pos.split('-')[1];
|
||||
const dragColId = interfaceColList[dragColIndex]._id;
|
||||
|
||||
const dropPos = e.node.props.pos.split('-');
|
||||
const dropIndex = Number(dropPos[dropPos.length - 1]);
|
||||
const dragPos = e.dragNode.props.pos.split('-');
|
||||
const dragIndex = Number(dragPos[dragPos.length - 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();
|
||||
}
|
||||
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 });
|
||||
} else {
|
||||
let changes = arrayChangeIndex(interfaceColList, dragIndex, dropIndex);
|
||||
axios.post('/api/col/up_col_index', changes).then();
|
||||
this.getList();
|
||||
}
|
||||
};
|
||||
|
||||
enterItem = id => {
|
||||
this.setState({ delIcon: id });
|
||||
};
|
||||
|
||||
leaveItem = () => {
|
||||
this.setState({ delIcon: null });
|
||||
};
|
||||
|
||||
render() {
|
||||
// const { currColId, currCaseId, isShowCol } = this.props;
|
||||
const { colModalType, colModalVisible, importInterVisible } = this.state;
|
||||
const currProjectId = this.props.match.params.id;
|
||||
// const menu = (col) => {
|
||||
// return (
|
||||
// <Menu>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => this.showColModal('edit', col)}>修改集合</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => {
|
||||
// this.showDelColConfirm(col._id)
|
||||
// }}>删除集合</span>
|
||||
// </Menu.Item>
|
||||
// <Menu.Item>
|
||||
// <span onClick={() => this.showImportInterface(col._id)}>导入接口</span>
|
||||
// </Menu.Item>
|
||||
// </Menu>
|
||||
// )
|
||||
// };
|
||||
|
||||
const defaultExpandedKeys = () => {
|
||||
const { router, currCase, interfaceColList } = this.props,
|
||||
rNull = { expands: [], selects: [] };
|
||||
if (interfaceColList.length === 0) {
|
||||
return rNull;
|
||||
}
|
||||
if (router) {
|
||||
if (router.params.action === 'case') {
|
||||
if (!currCase || !currCase._id) {
|
||||
return rNull;
|
||||
}
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['col_' + currCase.col_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: ['col_' + interfaceColList[0]._id]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const itemInterfaceColCreate = 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}
|
||||
>
|
||||
<span className="casename">{interfaceCase.casename}</span>
|
||||
<div className="btns">
|
||||
<Tooltip title="删除用例">
|
||||
<Icon
|
||||
type="delete"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showDelCaseConfirm(interfaceCase._id);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == interfaceCase._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="克隆用例">
|
||||
<Icon
|
||||
type="copy"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.caseCopy(interfaceCase._id);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == interfaceCase._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
let currentKes = defaultExpandedKeys();
|
||||
// console.log('currentKey', currentKes)
|
||||
|
||||
let list = this.state.list;
|
||||
|
||||
if (this.state.filterValue) {
|
||||
let arr = [];
|
||||
list = list.filter(item => {
|
||||
|
||||
item.caseList = item.caseList.filter(inter => {
|
||||
if (inter.casename.indexOf(this.state.filterValue) === -1
|
||||
&& inter.path.indexOf(this.state.filterValue) === -1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
arr.push('col_' + item._id);
|
||||
return true;
|
||||
});
|
||||
// console.log('arr', arr);
|
||||
if (arr.length > 0) {
|
||||
currentKes.expands = arr;
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('list', list);
|
||||
// console.log('currentKey', currentKes)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<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>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="tree-wrapper" style={{ maxHeight: parseInt(document.body.clientHeight) - headHeight + 'px'}}>
|
||||
<Tree
|
||||
className="col-list-tree"
|
||||
defaultExpandedKeys={currentKes.expands}
|
||||
defaultSelectedKeys={currentKes.selects}
|
||||
expandedKeys={currentKes.expands}
|
||||
selectedKeys={currentKes.selects}
|
||||
onSelect={this.onSelect}
|
||||
autoExpandParent
|
||||
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()}>
|
||||
<Icon className="opts-icon" type='ellipsis'/>
|
||||
</Dropdown>*/}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{col.caseList.map(itemInterfaceColCreate)}
|
||||
</TreeNode>
|
||||
))}
|
||||
</Tree>
|
||||
</div>
|
||||
<ColModalForm
|
||||
ref={this.saveFormRef}
|
||||
type={colModalType}
|
||||
visible={colModalVisible}
|
||||
onCancel={() => {
|
||||
this.setState({ colModalVisible: false });
|
||||
}}
|
||||
onCreate={this.addorEditCol}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="导入接口到集合"
|
||||
visible={importInterVisible}
|
||||
onOk={this.handleImportOk}
|
||||
onCancel={this.handleImportCancel}
|
||||
className="import-case-modal"
|
||||
width={800}
|
||||
>
|
||||
<ImportInterface currProjectId={currProjectId} selectInterface={this.selectInterface} />
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
.col-list-tree {
|
||||
line-height: 25px;
|
||||
.ant-tree-node-content-wrapper {
|
||||
width: calc(100% - 28px);
|
||||
}
|
||||
.opts-icon,
|
||||
.case-delete-icon {
|
||||
line-height: 25px;
|
||||
width: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.opts-icon:hover,
|
||||
.case-delete-icon:hover {
|
||||
color: #2395f1;
|
||||
}
|
||||
.menu-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
.casename {
|
||||
overflow: hidden;
|
||||
}
|
||||
.case-delete-icon {
|
||||
margin-left: 5px;
|
||||
display: none;
|
||||
}
|
||||
.btns {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.menu-title:hover {
|
||||
.case-delete-icon {
|
||||
display: block;
|
||||
}
|
||||
.btns {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
/*
|
||||
* note that styling gu-mirror directly is a bad practice because it's too generic.
|
||||
* you're better off giving the draggable elements a unique class and styling that directly!
|
||||
*/
|
||||
.gu-mirror {
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
transition: opacity 0.4s ease-in-out;
|
||||
}
|
||||
.container div {
|
||||
cursor: move;
|
||||
cursor: grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: -webkit-grab;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.container div:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.gu-mirror {
|
||||
cursor: grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: -webkit-grabbing;
|
||||
}
|
||||
.container .ex-moved {
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
.container.ex-over {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
.handle {
|
||||
padding: 0 5px;
|
||||
margin-right: 5px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
cursor: move;
|
||||
}
|
||||
.report {
|
||||
min-height: 500px;
|
||||
.case-report-pane {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.url {
|
||||
overflow: auto;
|
||||
}
|
||||
.case-report {
|
||||
margin: 10px;
|
||||
|
||||
.case-report-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.interface-col {
|
||||
padding: 24px;
|
||||
.interface-col-table-header {
|
||||
background-color: rgb(238, 238, 238);
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.interface-col-table-body {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.interface-col-table-header th {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.interface-col-table-body td {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.interface-col-table-action button {
|
||||
margin-right: 5px;
|
||||
padding: 5px 10px;
|
||||
max-width: 90px;
|
||||
}
|
||||
.component-label-wrapper {
|
||||
margin-top: -10px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.import-case-modal {
|
||||
.ant-modal-body {
|
||||
max-height: 800px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.select-project {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.autoTestsModal {
|
||||
.autoTestUrl {
|
||||
overflow: auto;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #f1f1f1ce;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.autoTestMsg {
|
||||
padding: 8px 0 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
margin-left: 16px;
|
||||
height: 50px;
|
||||
font-size: 14px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
padding-top: 32px;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 0.24rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-wrapper {
|
||||
min-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
Reference in New Issue
Block a user