| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- 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';
- 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);
- }
- componentWillMount() {
- 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;
- }
- 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 = 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
- });
- };
- 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: ['root']
- };
- }
- };
- 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>
- );
- }
- }
|