fork from bc4552c5a8
This commit is contained in:
@@ -0,0 +1,641 @@
|
||||
import React, { PureComponent as Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
fetchInterfaceListMenu,
|
||||
fetchInterfaceList,
|
||||
fetchInterfaceCatList,
|
||||
fetchInterfaceData,
|
||||
deleteInterfaceData,
|
||||
deleteInterfaceCatData,
|
||||
initInterface
|
||||
} from '../../../../reducer/modules/interface.js';
|
||||
import { getProject } from '../../../../reducer/modules/project.js';
|
||||
import { Input, Icon, Button, Modal, message, Tree, Tooltip } from 'antd';
|
||||
import AddInterfaceForm from './AddInterfaceForm';
|
||||
import AddInterfaceCatForm from './AddInterfaceCatForm';
|
||||
import axios from 'axios';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import produce from 'immer';
|
||||
import { arrayChangeIndex } from '../../../../common.js';
|
||||
|
||||
import './interfaceMenu.scss';
|
||||
|
||||
const confirm = Modal.confirm;
|
||||
const TreeNode = Tree.TreeNode;
|
||||
const headHeight = 240; // menu顶部到网页顶部部分的高度
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
list: state.inter.list,
|
||||
inter: state.inter.curdata,
|
||||
curProject: state.project.currProject,
|
||||
expands: []
|
||||
};
|
||||
},
|
||||
{
|
||||
fetchInterfaceListMenu,
|
||||
fetchInterfaceData,
|
||||
deleteInterfaceCatData,
|
||||
deleteInterfaceData,
|
||||
initInterface,
|
||||
getProject,
|
||||
fetchInterfaceCatList,
|
||||
fetchInterfaceList
|
||||
}
|
||||
)
|
||||
class InterfaceMenu extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
inter: PropTypes.object,
|
||||
projectId: PropTypes.string,
|
||||
list: PropTypes.array,
|
||||
fetchInterfaceListMenu: PropTypes.func,
|
||||
curProject: PropTypes.object,
|
||||
fetchInterfaceData: PropTypes.func,
|
||||
addInterfaceData: PropTypes.func,
|
||||
deleteInterfaceData: PropTypes.func,
|
||||
initInterface: PropTypes.func,
|
||||
history: PropTypes.object,
|
||||
router: PropTypes.object,
|
||||
getProject: PropTypes.func,
|
||||
fetchInterfaceCatList: PropTypes.func,
|
||||
fetchInterfaceList: PropTypes.func
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
*/
|
||||
changeModal = (key, status) => {
|
||||
//visible add_cat_modal_visible change_cat_modal_visible del_cat_modal_visible
|
||||
let newState = {};
|
||||
newState[key] = status;
|
||||
this.setState(newState);
|
||||
};
|
||||
|
||||
handleCancel = () => {
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
curKey: null,
|
||||
visible: false,
|
||||
delIcon: null,
|
||||
curCatid: null,
|
||||
add_cat_modal_visible: false,
|
||||
change_cat_modal_visible: false,
|
||||
del_cat_modal_visible: false,
|
||||
curCatdata: {},
|
||||
expands: null,
|
||||
list: []
|
||||
};
|
||||
}
|
||||
|
||||
handleRequest() {
|
||||
this.props.initInterface();
|
||||
this.getList();
|
||||
}
|
||||
|
||||
async getList() {
|
||||
let r = await this.props.fetchInterfaceListMenu(this.props.projectId);
|
||||
this.setState({
|
||||
list: r.payload.data.data
|
||||
});
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.handleRequest();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (this.props.list !== nextProps.list) {
|
||||
// console.log('next', nextProps.list)
|
||||
this.setState({
|
||||
list: nextProps.list
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onSelect = selectedKeys => {
|
||||
const { history, match } = this.props;
|
||||
let curkey = selectedKeys[0];
|
||||
|
||||
if (!curkey || !selectedKeys) {
|
||||
return false;
|
||||
}
|
||||
let basepath = '/project/' + match.params.id + '/interface/api';
|
||||
if (curkey === 'root') {
|
||||
history.push(basepath);
|
||||
} else {
|
||||
history.push(basepath + '/' + curkey);
|
||||
}
|
||||
this.setState({
|
||||
expands: null
|
||||
});
|
||||
};
|
||||
|
||||
changeExpands = () => {
|
||||
this.setState({
|
||||
expands: null
|
||||
});
|
||||
};
|
||||
|
||||
handleAddInterface = (data, cb) => {
|
||||
data.project_id = this.props.projectId;
|
||||
axios.post('/api/interface/add', data).then(res => {
|
||||
if (res.data.errcode !== 0) {
|
||||
return message.error(res.data.errmsg);
|
||||
}
|
||||
message.success('接口添加成功');
|
||||
let interfaceId = res.data.data._id;
|
||||
this.props.history.push('/project/' + this.props.projectId + '/interface/api/' + interfaceId);
|
||||
this.getList();
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleAddInterfaceCat = data => {
|
||||
data.project_id = this.props.projectId;
|
||||
axios.post('/api/interface/add_cat', data).then(res => {
|
||||
if (res.data.errcode !== 0) {
|
||||
return message.error(res.data.errmsg);
|
||||
}
|
||||
message.success('接口分类添加成功');
|
||||
this.getList();
|
||||
this.props.getProject(data.project_id);
|
||||
this.setState({
|
||||
add_cat_modal_visible: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
handleChangeInterfaceCat = data => {
|
||||
data.project_id = this.props.projectId;
|
||||
|
||||
let params = {
|
||||
catid: this.state.curCatdata._id,
|
||||
name: data.name,
|
||||
desc: data.desc
|
||||
};
|
||||
|
||||
axios.post('/api/interface/up_cat', params).then(res => {
|
||||
if (res.data.errcode !== 0) {
|
||||
return message.error(res.data.errmsg);
|
||||
}
|
||||
message.success('接口分类更新成功');
|
||||
this.getList();
|
||||
this.props.getProject(data.project_id);
|
||||
this.setState({
|
||||
change_cat_modal_visible: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
showConfirm = data => {
|
||||
let that = this;
|
||||
let id = data._id;
|
||||
let catid = data.catid;
|
||||
const ref = confirm({
|
||||
title: '您确认删除此接口????',
|
||||
content: '温馨提示:接口删除后,无法恢复',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
await that.props.deleteInterfaceData(id, that.props.projectId);
|
||||
await that.getList();
|
||||
await that.props.fetchInterfaceCatList({ catid });
|
||||
ref.destroy();
|
||||
that.props.history.push(
|
||||
'/project/' + that.props.match.params.id + '/interface/api/cat_' + catid
|
||||
);
|
||||
},
|
||||
onCancel() {
|
||||
ref.destroy();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
showDelCatConfirm = catid => {
|
||||
let that = this;
|
||||
const ref = confirm({
|
||||
title: '确定删除此接口分类吗?',
|
||||
content: '温馨提示:该操作会删除该分类下所有接口,接口删除后无法恢复',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
await that.props.deleteInterfaceCatData(catid, that.props.projectId);
|
||||
await that.getList();
|
||||
// await that.props.getProject(that.props.projectId)
|
||||
await that.props.fetchInterfaceList({ project_id: that.props.projectId });
|
||||
that.props.history.push('/project/' + that.props.match.params.id + '/interface/api');
|
||||
ref.destroy();
|
||||
},
|
||||
onCancel() {}
|
||||
});
|
||||
};
|
||||
|
||||
copyInterface = async id => {
|
||||
let interfaceData = await this.props.fetchInterfaceData(id);
|
||||
// let data = JSON.parse(JSON.stringify(interfaceData.payload.data.data));
|
||||
// data.title = data.title + '_copy';
|
||||
// data.path = data.path + '_' + Date.now();
|
||||
let data = interfaceData.payload.data.data;
|
||||
let newData = produce(data, draftData => {
|
||||
draftData.title = draftData.title + '_copy';
|
||||
draftData.path = draftData.path + '_' + Date.now();
|
||||
});
|
||||
|
||||
axios.post('/api/interface/add', newData).then(async res => {
|
||||
if (res.data.errcode !== 0) {
|
||||
return message.error(res.data.errmsg);
|
||||
}
|
||||
message.success('接口添加成功');
|
||||
let interfaceId = res.data.data._id;
|
||||
await this.getList();
|
||||
this.props.history.push('/project/' + this.props.projectId + '/interface/api/' + interfaceId);
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
enterItem = id => {
|
||||
this.setState({ delIcon: id });
|
||||
};
|
||||
|
||||
leaveItem = () => {
|
||||
this.setState({ delIcon: null });
|
||||
};
|
||||
|
||||
onFilter = e => {
|
||||
this.setState({
|
||||
filter: e.target.value,
|
||||
list: JSON.parse(JSON.stringify(this.props.list))
|
||||
});
|
||||
};
|
||||
|
||||
onExpand = e => {
|
||||
this.setState({
|
||||
expands: e
|
||||
});
|
||||
};
|
||||
|
||||
onDrop = async e => {
|
||||
const dropCatIndex = e.node.props.pos.split('-')[1] - 1;
|
||||
const dragCatIndex = e.dragNode.props.pos.split('-')[1] - 1;
|
||||
if (dropCatIndex < 0 || dragCatIndex < 0) {
|
||||
return;
|
||||
}
|
||||
const { list } = this.props;
|
||||
const dropCatId = this.props.list[dropCatIndex]._id;
|
||||
const id = e.dragNode.props.eventKey;
|
||||
const dragCatId = this.props.list[dragCatIndex]._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('cat') === -1) {
|
||||
if (dropCatId === dragCatId) {
|
||||
// 同一个分类下的接口交换顺序
|
||||
let colList = list[dropCatIndex].list;
|
||||
let changes = arrayChangeIndex(colList, dragIndex, dropIndex);
|
||||
axios.post('/api/interface/up_index', changes).then();
|
||||
} else {
|
||||
await axios.post('/api/interface/up', { id, catid: dropCatId });
|
||||
}
|
||||
const { projectId, router } = this.props;
|
||||
this.props.fetchInterfaceListMenu(projectId);
|
||||
this.props.fetchInterfaceList({ project_id: projectId });
|
||||
if (router && isNaN(router.params.actionId)) {
|
||||
// 更新分类list下的数据
|
||||
let catid = router.params.actionId.substr(4);
|
||||
this.props.fetchInterfaceCatList({ catid });
|
||||
}
|
||||
} else {
|
||||
// 分类之间拖动
|
||||
let changes = arrayChangeIndex(list, dragIndex - 1, dropIndex - 1);
|
||||
axios.post('/api/interface/up_cat_index', changes).then();
|
||||
this.props.fetchInterfaceListMenu(this.props.projectId);
|
||||
}
|
||||
};
|
||||
// 数据过滤
|
||||
filterList = list => {
|
||||
let that = this;
|
||||
let arr = [];
|
||||
let menuList = produce(list, draftList => {
|
||||
draftList.filter(item => {
|
||||
let interfaceFilter = false;
|
||||
// arr = [];
|
||||
if (item.name.indexOf(that.state.filter) === -1) {
|
||||
item.list = item.list.filter(inter => {
|
||||
if (
|
||||
inter.title.indexOf(that.state.filter) === -1 &&
|
||||
inter.path.indexOf(that.state.filter) === -1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
//arr.push('cat_' + inter.catid)
|
||||
interfaceFilter = true;
|
||||
return true;
|
||||
});
|
||||
arr.push('cat_' + item._id);
|
||||
return interfaceFilter === true;
|
||||
}
|
||||
arr.push('cat_' + item._id);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
return { menuList, arr };
|
||||
};
|
||||
|
||||
render() {
|
||||
const matchParams = this.props.match.params;
|
||||
// let menuList = this.state.list;
|
||||
const searchBox = (
|
||||
<div className="interface-filter">
|
||||
<Input onChange={this.onFilter} value={this.state.filter} placeholder="搜索接口" />
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.changeModal('add_cat_modal_visible', true)}
|
||||
className="btn-filter"
|
||||
>
|
||||
添加分类
|
||||
</Button>
|
||||
{this.state.visible ? (
|
||||
<Modal
|
||||
title="添加接口"
|
||||
visible={this.state.visible}
|
||||
onCancel={() => this.changeModal('visible', false)}
|
||||
footer={null}
|
||||
className="addcatmodal"
|
||||
>
|
||||
<AddInterfaceForm
|
||||
catdata={this.props.curProject.cat}
|
||||
catid={this.state.curCatid}
|
||||
onCancel={() => this.changeModal('visible', false)}
|
||||
onSubmit={this.handleAddInterface}
|
||||
/>
|
||||
</Modal>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{this.state.add_cat_modal_visible ? (
|
||||
<Modal
|
||||
title="添加分类"
|
||||
visible={this.state.add_cat_modal_visible}
|
||||
onCancel={() => this.changeModal('add_cat_modal_visible', false)}
|
||||
footer={null}
|
||||
className="addcatmodal"
|
||||
>
|
||||
<AddInterfaceCatForm
|
||||
onCancel={() => this.changeModal('add_cat_modal_visible', false)}
|
||||
onSubmit={this.handleAddInterfaceCat}
|
||||
/>
|
||||
</Modal>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{this.state.change_cat_modal_visible ? (
|
||||
<Modal
|
||||
title="修改分类"
|
||||
visible={this.state.change_cat_modal_visible}
|
||||
onCancel={() => this.changeModal('change_cat_modal_visible', false)}
|
||||
footer={null}
|
||||
className="addcatmodal"
|
||||
>
|
||||
<AddInterfaceCatForm
|
||||
catdata={this.state.curCatdata}
|
||||
onCancel={() => this.changeModal('change_cat_modal_visible', false)}
|
||||
onSubmit={this.handleChangeInterfaceCat}
|
||||
/>
|
||||
</Modal>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const defaultExpandedKeys = () => {
|
||||
const { router, inter, list } = this.props,
|
||||
rNull = { expands: [], selects: [] };
|
||||
if (list.length === 0) {
|
||||
return rNull;
|
||||
}
|
||||
if (router) {
|
||||
if (!isNaN(router.params.actionId)) {
|
||||
if (!inter || !inter._id) {
|
||||
return rNull;
|
||||
}
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['cat_' + inter.catid],
|
||||
selects: [inter._id + '']
|
||||
};
|
||||
} else {
|
||||
let catid = router.params.actionId.substr(4);
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['cat_' + catid],
|
||||
selects: ['cat_' + catid]
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
expands: this.state.expands ? this.state.expands : ['cat_' + list[0]._id],
|
||||
selects: ['root']
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const itemInterfaceCreate = item => {
|
||||
return (
|
||||
<TreeNode
|
||||
title={
|
||||
<div
|
||||
className="container-title"
|
||||
onMouseEnter={() => this.enterItem(item._id)}
|
||||
onMouseLeave={this.leaveItem}
|
||||
>
|
||||
<Tooltip title= {item.title}>
|
||||
<Link
|
||||
className="interface-item"
|
||||
onClick={e => e.stopPropagation()}
|
||||
to={'/project/' + matchParams.id + '/interface/api/' + item._id}
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<div className="btns">
|
||||
<Tooltip title="删除接口">
|
||||
<Icon
|
||||
type="delete"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showConfirm(item);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="复制接口">
|
||||
<Icon
|
||||
type="copy"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.copyInterface(item._id);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/*<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon type='ellipsis' className="interface-delete-icon" style={{ opacity: this.state.delIcon == item._id ? 1 : 0 }}/>
|
||||
</Dropdown>*/}
|
||||
</div>
|
||||
}
|
||||
key={'' + item._id}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
let currentKes = defaultExpandedKeys();
|
||||
let menuList;
|
||||
if (this.state.filter) {
|
||||
let res = this.filterList(this.state.list);
|
||||
menuList = res.menuList;
|
||||
currentKes.expands = res.arr;
|
||||
} else {
|
||||
menuList = this.state.list;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{searchBox}
|
||||
{menuList.length > 0 ? (
|
||||
<div
|
||||
className="tree-wrappper"
|
||||
style={{ maxHeight: parseInt(document.body.clientHeight) - headHeight + 'px' }}
|
||||
>
|
||||
<Tree
|
||||
className="interface-list"
|
||||
defaultExpandedKeys={currentKes.expands}
|
||||
defaultSelectedKeys={currentKes.selects}
|
||||
expandedKeys={currentKes.expands}
|
||||
selectedKeys={currentKes.selects}
|
||||
onSelect={this.onSelect}
|
||||
onExpand={this.onExpand}
|
||||
draggable
|
||||
onDrop={this.onDrop}
|
||||
>
|
||||
<TreeNode
|
||||
className="item-all-interface"
|
||||
title={
|
||||
<Link
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.changeExpands();
|
||||
}}
|
||||
to={'/project/' + matchParams.id + '/interface/api'}
|
||||
>
|
||||
<Icon type="folder" style={{ marginRight: 5 }} />
|
||||
全部接口
|
||||
</Link>
|
||||
}
|
||||
key="root"
|
||||
/>
|
||||
{menuList.map(item => {
|
||||
return (
|
||||
<TreeNode
|
||||
title={
|
||||
<div
|
||||
className="container-title"
|
||||
onMouseEnter={() => this.enterItem(item._id)}
|
||||
onMouseLeave={this.leaveItem}
|
||||
>
|
||||
<Link
|
||||
className="interface-item"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.changeExpands();
|
||||
}}
|
||||
to={'/project/' + matchParams.id + '/interface/api/cat_' + item._id}
|
||||
>
|
||||
<Icon type="folder-open" style={{ marginRight: 5 }} />
|
||||
{item.name}
|
||||
</Link>
|
||||
<div className="btns">
|
||||
<Tooltip title="删除分类">
|
||||
<Icon
|
||||
type="delete"
|
||||
className="interface-delete-icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.showDelCatConfirm(item._id);
|
||||
}}
|
||||
style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="修改分类">
|
||||
<Icon
|
||||
type="edit"
|
||||
className="interface-delete-icon"
|
||||
style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.changeModal('change_cat_modal_visible', true);
|
||||
this.setState({
|
||||
curCatdata: item
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip title="添加接口">
|
||||
<Icon
|
||||
type="plus"
|
||||
className="interface-delete-icon"
|
||||
style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
this.changeModal('visible', true);
|
||||
this.setState({
|
||||
curCatid: item._id
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{/*<Dropdown overlay={menu(item)} trigger={['click']} onClick={e => e.stopPropagation()}>
|
||||
<Icon type='ellipsis' className="interface-delete-icon" />
|
||||
</Dropdown>*/}
|
||||
</div>
|
||||
}
|
||||
key={'cat_' + item._id}
|
||||
className={`interface-item-nav ${item.list.length ? '' : 'cat_switch_hidden'}`}
|
||||
>
|
||||
{item.list.map(itemInterfaceCreate)}
|
||||
</TreeNode>
|
||||
);
|
||||
})}
|
||||
</Tree>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(InterfaceMenu);
|
||||
Reference in New Issue
Block a user