UNPKG

yapi-vendor

Version:
640 lines (601 loc) 20.3 kB
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 }); } componentWillMount() { this.handleRequest(); } 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} > <Link className="interface-item" onClick={e => e.stopPropagation()} to={'/project/' + matchParams.id + '/interface/api/' + item._id} > {item.title} </Link> <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);