diff --git a/client/Application.js b/client/Application.js index 52d1c2cb..327266dd 100755 --- a/client/Application.js +++ b/client/Application.js @@ -10,6 +10,7 @@ import Loading from './components/Loading/Loading'; import { checkLoginState } from './reducer/modules/user'; import { requireAuthentication } from './components/AuthenticatedComponent'; + const LOADING_STATUS = 0; @connect( diff --git a/client/components/ErrMsg/ErrMsg.js b/client/components/ErrMsg/ErrMsg.js index 5cbd7eaa..57a36a95 100755 --- a/client/components/ErrMsg/ErrMsg.js +++ b/client/components/ErrMsg/ErrMsg.js @@ -58,7 +58,7 @@ class ErrMsg extends Component { break; case 'noProject': title = '该分组还没有项目呢'; - desc = 请点击右上角 “” 按钮新建项目; + desc = 请点击右上角添加项目按钮新建项目; break; case 'noData': title = '暂无数据'; diff --git a/client/components/Header/Header.scss b/client/components/Header/Header.scss index 2c8fb63e..c778d69e 100755 --- a/client/components/Header/Header.scss +++ b/client/components/Header/Header.scss @@ -1,4 +1,3 @@ -@import '../../styles/common.scss'; @import '../../styles/mixin.scss'; .nav-tooltip { diff --git a/client/components/Postman/Postman.js b/client/components/Postman/Postman.js index 27eb111b..f81df4e9 100755 --- a/client/components/Postman/Postman.js +++ b/client/components/Postman/Postman.js @@ -192,7 +192,7 @@ export default class Run extends Component { const href = URL.format({ protocol: urlObj.protocol || 'http', host: urlObj.host, - pathname: path, + pathname: urlObj.pathname? urlObj.pathname + path : path, query: this.getQueryObj(query) }); diff --git a/client/components/UsernameAutoComplete/UsernameAutoComplete.js b/client/components/UsernameAutoComplete/UsernameAutoComplete.js index 05c4ec6f..6f8e9235 100755 --- a/client/components/UsernameAutoComplete/UsernameAutoComplete.js +++ b/client/components/UsernameAutoComplete/UsernameAutoComplete.js @@ -91,15 +91,8 @@ class UsernameAutoComplete extends Component { dataSource: userList }); if (userList.length) { - userList.forEach((item) => { - if (item.username === this.state.changeName) { - // 每次取回搜索值后,没选择时默认选择第一位 - this.changeState(userList[0].id, userList[0].username); - } else { - // 有候选词但没有对应输入框中的字符串,此时应清空候选 uid 和 username - this.changeState(-1, ''); - } - }); + // 每次取回搜索值后,没选择时默认选择第一位 + this.changeState(userList[0].id, userList[0].username); } else { // 如果没有搜索结果,则清空候选 uid 和 username this.changeState(-1, ''); diff --git a/client/containers/AddProject/AddProject.js b/client/containers/AddProject/AddProject.js index b3d80554..28f1b551 100755 --- a/client/containers/AddProject/AddProject.js +++ b/client/containers/AddProject/AddProject.js @@ -32,7 +32,8 @@ const formItemLayout = { @connect( state => { return { - groupList: state.group.groupList + groupList: state.group.groupList, + currGroup: state.group.currGroup } }, { @@ -46,12 +47,14 @@ class ProjectList extends Component { constructor(props) { super(props); this.state = { - groupList: [] + groupList: [], + currGroupId: null } } static propTypes = { groupList: PropTypes.array, form: PropTypes.object, + currGroup: PropTypes.object, addProject: PropTypes.func, history: PropTypes.object, setBreadcrumb: PropTypes.func, @@ -88,7 +91,15 @@ class ProjectList extends Component { async componentWillMount() { this.props.setBreadcrumb([{name: '新建项目'}]); - await this.props.fetchGroupList(); + if(!this.props.currGroup._id){ + await this.props.fetchGroupList(); + } + if(this.props.groupList.length === 0){ + return null; + } + this.setState({ + currGroupId: this.props.currGroup._id ? this.props.currGroup._id : this.props.groupList[0]._id + }) this.setState({groupList: this.props.groupList}); } @@ -114,7 +125,7 @@ class ProjectList extends Component { label="所属分组" > {getFieldDecorator('group', { - initialValue: this.state.groupList.length > 0? this.state.groupList[0]._id.toString() : null , + initialValue: this.state.currGroupId+'' , rules: [{ required: true, message: '请选择项目所属的分组!' }] diff --git a/client/containers/Group/GroupList/GroupList.js b/client/containers/Group/GroupList/GroupList.js index a331bc03..b8306441 100755 --- a/client/containers/Group/GroupList/GroupList.js +++ b/client/containers/Group/GroupList/GroupList.js @@ -1,10 +1,10 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { Button, Icon, Modal,Alert, Input, message, Menu, Row, Col } from 'antd' +import { Icon, Modal, Alert, Input, message, Menu, Row, Col } from 'antd' import { autobind } from 'core-decorators'; import axios from 'axios'; -import { withRouter } from 'react-router'; +import { withRouter } from 'react-router-dom'; const { TextArea } = Input; const Search = Input.Search; const TYPE_EDIT = 'edit'; @@ -63,18 +63,18 @@ export default class GroupList extends Component { const groupId = !isNaN(this.props.match.params.groupId) ? parseInt(this.props.match.params.groupId) : 0; await this.props.fetchGroupList(); let currGroup = this.props.groupList[0] || { group_name: '', group_desc: '' }; - if(this.props.groupList.length && groupId){ - for(let i = 0;i { + showConfirm = () => { let that = this; confirm({ - title: "确认删除 "+that.props.currGroup.group_name+" 分组吗?", - content:
+ title: "确认删除 " + that.props.currGroup.group_name + " 分组吗?", + content:
-
+

请输入分组名称确认此操作:

, onOk() { let groupName = document.getElementById('group_name').value; - if(that.props.currGroup.group_name !== groupName){ + if (that.props.currGroup.group_name !== groupName) { message.error('分组名称有误') - return new Promise((resolve, reject)=>{ + return new Promise((resolve, reject) => { reject('error') }) - }else{ + } else { that.deleteGroup() } @@ -198,14 +198,14 @@ export default class GroupList extends Component { async deleteGroup() { const self = this; const { currGroup } = self.props; - const res = await axios.post('/api/group/del', {id: currGroup._id}) + const res = await axios.post('/api/group/del', { id: currGroup._id }) if (res.data.errcode) { message.error(res.data.errmsg); } else { message.success('删除成功') await self.props.fetchGroupList() const currGroup = self.props.groupList[0] || { group_name: '', group_desc: '' }; - self.setState({groupList: self.props.groupList}); + self.setState({ groupList: self.props.groupList }); self.props.setCurrGroup(currGroup) } } @@ -215,17 +215,17 @@ export default class GroupList extends Component { const v = value || e.target.value; const { groupList } = this.props; if (v === '') { - this.setState({groupList}) + this.setState({ groupList }) } else { - this.setState({groupList: groupList.filter(group => new RegExp(v, 'i').test(group.group_name))}) + this.setState({ groupList: groupList.filter(group => new RegExp(v, 'i').test(group.group_name)) }) } } - render () { + render() { const { currGroup } = this.props; - const delmark = this.showModal(TYPE_EDIT)}/> - const editmark = {this.showConfirm()}} type="delete" title="删除分组"/> - + const delmark = this.showModal(TYPE_EDIT)} /> + const editmark = { this.showConfirm() }} type="delete" title="删除分组" /> + const addmark = return ( @@ -235,10 +235,13 @@ export default class GroupList extends Component {
{currGroup.group_name}
{ - this.props.curUserRole === "admin"?(editmark):'' + this.props.curUserRole === "admin" ? (editmark) : '' } { - this.props.curUserRole === "admin"?(delmark):'' + this.props.curUserRole === "admin" ? (delmark) : '' + } + { + this.props.curUserRole === 'admin' ? (addmark) : '' }
@@ -246,12 +249,8 @@ export default class GroupList extends Component {
- this.searchGroup(null, v)}/> + this.searchGroup(null, v)} />
- { - this.props.curUserRole === "admin"?():'' - } -
简介:
- + diff --git a/client/containers/Group/ProjectList/ProjectList.js b/client/containers/Group/ProjectList/ProjectList.js index 1049978b..bae8dca7 100755 --- a/client/containers/Group/ProjectList/ProjectList.js +++ b/client/containers/Group/ProjectList/ProjectList.js @@ -1,12 +1,13 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { Row, Col } from 'antd'; -import { addProject, fetchProjectList, delProject, changeUpdateModal } from '../../../reducer/modules/project'; +import { Row, Col, Button, Tooltip } from 'antd'; +import { Link } from 'react-router-dom'; +import { addProject, fetchProjectList, delProject, changeUpdateModal } from '../../../reducer/modules/project'; import ProjectCard from '../../../components/ProjectCard/ProjectCard.js'; import ErrMsg from '../../../components/ErrMsg/ErrMsg.js'; import { autobind } from 'core-decorators'; -import { setBreadcrumb } from '../../../reducer/modules/user'; +import { setBreadcrumb } from '../../../reducer/modules/user'; import './ProjectList.scss' @@ -75,7 +76,7 @@ class ProjectList extends Component { } componentWillReceiveProps(nextProps) { - this.props.setBreadcrumb([{name: '分组: ' + (nextProps.currGroup.group_name || '')}]); + this.props.setBreadcrumb([{ name: '' + (nextProps.currGroup.group_name || '') }]); // 切换分组 if (this.props.currGroup !== nextProps.currGroup) { @@ -100,14 +101,29 @@ class ProjectList extends Component { render() { const projectData = this.state.projectData; return ( -
+
+ + + {this.props.currGroup.group_name}分组 共 {projectData.length} 个项目 + + + + + {this.props.currGroup.role ? + : + } + + + + + {projectData.length ? projectData.map((item, index) => { return ( ); - }) : } + }) : }
); diff --git a/client/containers/Group/ProjectList/ProjectList.scss b/client/containers/Group/ProjectList/ProjectList.scss index 804bd706..bc1b1b62 100755 --- a/client/containers/Group/ProjectList/ProjectList.scss +++ b/client/containers/Group/ProjectList/ProjectList.scss @@ -3,6 +3,7 @@ margin-bottom: 0; } + .m-panel{ background-color: #fff; padding: 24px; @@ -12,6 +13,21 @@ margin-top: 0; } +.project-list{ + .project-list-header{ + background: #eee; + height: 64px; + line-height: 40px; + border-radius: 4px; + text-align: right; + padding: 12px 15px; + font-weight: bold; + margin-bottom: 15px; + } +} + + + .ant-input-group-wrapper { width: 100%; } diff --git a/client/containers/Project/Interface/InterfaceCol/InterfaceColContent.js b/client/containers/Project/Interface/InterfaceCol/InterfaceColContent.js index 9564a9cc..0e56fbd1 100755 --- a/client/containers/Project/Interface/InterfaceCol/InterfaceColContent.js +++ b/client/containers/Project/Interface/InterfaceCol/InterfaceColContent.js @@ -52,8 +52,11 @@ export default class InterfaceColContent extends Component { result.payload.data.data.find(item => +item._id === +currColId) && +currColId || result.payload.data.data[0]._id; this.props.history.push('/project/' + params.id + '/interface/col/' + currColId) - this.props.fetchCaseList(currColId); - this.props.setColData({currColId: +currColId, isShowCol: true}) + if(currColId && currColId != 0){ + this.props.fetchCaseList(currColId); + this.props.setColData({currColId: +currColId, isShowCol: true}) + } + } componentWillReceiveProps(nextProps) { @@ -63,8 +66,11 @@ export default class InterfaceColContent extends Component { if (!interfaceColList.find(item => +item._id === +newColId)) { this.props.history.push('/project/' + id + '/interface/col/' + interfaceColList[0]._id) } else if (oldColId !== newColId) { - this.props.fetchCaseList(newColId); - this.props.setColData({currColId: +newColId, isShowCol: true}) + if(newColId && newColId != 0){ + this.props.fetchCaseList(newColId); + this.props.setColData({currColId: +newColId, isShowCol: true}) + } + } } diff --git a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js index 4a8e966c..0652d741 100755 --- a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js +++ b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js @@ -4,13 +4,15 @@ import _ from 'underscore' import constants from '../../../../constants/variable.js' import { handlePath, nameLengthLimit } from '../../../../common.js' import json5 from 'json5' -import {message} from 'antd' +import { message, Tabs } from 'antd' +import Editor from 'wangeditor' +const TabPane = Tabs.TabPane; -const validJson = (json)=>{ - try{ +const validJson = (json) => { + try { json5.parse(json); return true; - }catch(e){ + } catch (e) { return false; } } @@ -90,34 +92,33 @@ class InterfaceEditForm extends Component { res_body: '', desc: '', res_body_mock: '', + jsonType: 'tpl', mockUrl: this.props.mockUrl }, curdata) } handleSubmit = (e) => { e.preventDefault(); - this.props.form.validateFields((err, values) => { - if (!err) { + if (!err) { + values.desc = this.editor.txt.html(); if (values.res_body_type === 'json') { - if(validJson(this.state.res_body) === false){ - return message.error('返回json格式有问题,请检查!') + if (this.state.res_body && validJson(this.state.res_body) === false) { + return message.error('返回body json格式有问题,请检查!') } - values.res_body = this.state.res_body + values.res_body = this.state.res_body; } if (values.req_body_type === 'json') { - if(validJson(this.state.req_body_other) === false){ - return message.error('请求json格式有问题,请检查!') + if (this.state.req_body_other && validJson(this.state.req_body_other) === false) { + return message.error('响应Body json格式有问题,请检查!'); } values.req_body_other = this.state.req_body_other; } - - values.method = this.state.method; values.req_params = values.req_params || []; let isfile = false, isHavaContentType = false; - if (values.req_body_type === 'form') { + if (values.req_body_type === 'form') { values.req_body_form.forEach((item) => { if (item.type === 'file') { isfile = true; @@ -179,7 +180,7 @@ class InterfaceEditForm extends Component { container: 'res_body_json', data: that.state.res_body, onChange: function (d) { - if (d.format === true){ + if (d.format === true) { mockPreview.editor.setValue(d.mockText) } that.setState({ @@ -194,6 +195,9 @@ class InterfaceEditForm extends Component { data: resBodyEditor.curData.mockText, readOnly: true }) + + let editor = this.editor = new Editor('#desc'); + editor.create(); } addParams = (name, data) => { @@ -214,6 +218,13 @@ class InterfaceEditForm extends Component { this.setState(newValue) } + handleJsonType = (key)=>{ + key = key || 'tpl'; + this.setState({ + jsonType: key + }) + } + handlePath = (e) => { let val = e.target.value, queue = []; val = handlePath(val) @@ -316,7 +327,7 @@ class InterfaceEditForm extends Component { const requestBodyTpl = (data, index) => { return - + {getFieldDecorator('req_body_form[' + index + '].name', { initialValue: data.name })( @@ -328,8 +339,18 @@ class InterfaceEditForm extends Component { initialValue: data.type })( + )} + + + {getFieldDecorator('req_body_form[' + index + '].required', { + initialValue: data.required + })( + )} @@ -471,16 +492,6 @@ class InterfaceEditForm extends Component { )} - - {getFieldDecorator('desc', { initialValue: this.state.desc })( - - )} - - - - -

基于mockjs和json5,可直接写mock模板和注释,具体使用方法请查看文档

-
+ + + + + + + + + + + + +
+

基于mockjs和json5,可直接写mock模板和注释,具体使用方法请查看文档

+
+
+
+
- - { }} value={this.state.mockUrl} /> - - - -
- -
-
- - {getFieldDecorator('res_body', { initialValue: this.state.res_body })( @@ -635,12 +639,27 @@ class InterfaceEditForm extends Component { + + +
+ {/* {getFieldDecorator('desc', { initialValue: this.state.desc })( + + )} */} +
+ + + + - {getFieldDecorator('switch_notice', { valuePropName: 'checked', initialValue: false })( + {getFieldDecorator('switch_notice', { valuePropName: 'checked', initialValue: true })( )} diff --git a/client/containers/Project/Interface/InterfaceList/InterfaceMenu.js b/client/containers/Project/Interface/InterfaceList/InterfaceMenu.js index 23b62ae0..c1dfea9f 100755 --- a/client/containers/Project/Interface/InterfaceList/InterfaceMenu.js +++ b/client/containers/Project/Interface/InterfaceList/InterfaceMenu.js @@ -14,9 +14,9 @@ const TreeNode = Tree.TreeNode; @connect( - + state => { - + return { list: state.inter.list, inter: state.inter.curdata, @@ -174,12 +174,12 @@ class InterfaceMenu extends Component { title: '您确认删除此接口', content: '温馨提示:接口删除后,无法恢复', async onOk() { - + await that.props.deleteInterfaceData(id, that.props.projectId) await that.getList() ref.destroy() that.props.history.push('/project/' + that.props.match.params.id + '/interface/api') - + }, async onCancel() { ref.destroy() @@ -227,8 +227,8 @@ class InterfaceMenu extends Component { const matchParams = this.props.match.params; let menuList = this.state.list; const searchBox =
- - this.changeModal('add_cat_modal_visible', true)} style={{ marginLeft: "16px" }} > + + this.changeModal('add_cat_modal_visible', true)} className="btn-filter" > this.changeModal('change_cat_modal_visible', false)} + onCancel={() => this.changeModal('change_cat_modal_visible', false)} footer={null} > this.changeModal('change_cat_modal_visible', false)} onSubmit={this.handleChangeInterfaceCat} /> @@ -297,7 +297,7 @@ class InterfaceMenu extends Component { // case 'DELETE': color = 'red'; break; // default: color = "yellow"; // } - return this.enterItem(item._id)} onMouseLeave={this.leaveItem} > {item.title} { this.showConfirm(item._id) }} style={{ display: this.state.delIcon == item._id ? 'block' : 'none' }} /> @@ -335,7 +335,7 @@ class InterfaceMenu extends Component { let currentKes = defaultExpandedKeys(); - + if (this.state.filter) { let arr = []; menuList = menuList.filter( (item) => { @@ -343,12 +343,12 @@ class InterfaceMenu extends Component { if (item.name.indexOf(this.state.filter) === -1) { item.list = item.list.filter(inter=>{ if(inter.title.indexOf(this.state.filter) === -1 && inter.path.indexOf(this.state.filter)){ - return false; + return false; } //arr.push('cat_' + inter.catid) interfaceFilter = true; return true; - + }) return interfaceFilter === true } @@ -379,7 +379,7 @@ class InterfaceMenu extends Component {
} - key={'cat_' + item._id} + key={'cat_' + item._id} className={`interface-item-nav ${item.list.length?"":"cat_switch_hidden"}`} > {item.list.map(item_interface_create)} diff --git a/client/containers/Project/Interface/InterfaceList/View.js b/client/containers/Project/Interface/InterfaceList/View.js index 3b34177d..fda39499 100755 --- a/client/containers/Project/Interface/InterfaceList/View.js +++ b/client/containers/Project/Interface/InterfaceList/View.js @@ -45,7 +45,7 @@ class View extends Component { key: 'type', render: (text)=>{ text = text || ""; - return text.toLowerCase()==="text"?T文本:文件 + return text.toLowerCase()==="text"?T文本:文件 } },{ title: '是否必须', @@ -250,7 +250,7 @@ class View extends Component { if(!methodColor) methodColor = "get"; let res =
- 接口名: + 接口名称: {this.props.curData.title}
@@ -262,7 +262,7 @@ class View extends Component { {this.props.currProject.basepath}{this.props.curData.path}
- 状态: + 状  态: {status[this.props.curData.status]}
@@ -278,8 +278,8 @@ class View extends Component { {location.protocol + '//' + location.hostname + (location.port !== "" ? ":" + location.port : "") + `/mock/${this.props.currProject._id}${this.props.currProject.basepath}${this.props.curData.path}`}
{this.props.curData.desc?
- 接口描述: - {this.props.curData.desc} + 接口备注: +
:""} {req_dataSource.length?
路径参数: diff --git a/client/containers/Project/Interface/InterfaceList/View.scss b/client/containers/Project/Interface/InterfaceList/View.scss index cb029284..034cd390 100755 --- a/client/containers/Project/Interface/InterfaceList/View.scss +++ b/client/containers/Project/Interface/InterfaceList/View.scss @@ -21,7 +21,7 @@ margin: 0px; .colKey{ padding-bottom: 0px; - + } } .ace_print-margin{ @@ -37,12 +37,19 @@ } } .colBody{ - .ant-table-row{ - span{ - i{ - margin-right: 4px; - } - } + .query-icon { + display: inline-block; + width: .12rem; + margin-right: 4px; + position: relative; + &.text:after { + content: 'T'; + display: block; + position: absolute; + right: 2px; + bottom: -2px; + transform: scale(.7); + } } } .colDesc{ @@ -108,4 +115,4 @@ // margin-left: 50px; // overflow:visible; // } -} \ No newline at end of file +} diff --git a/client/containers/Project/Interface/interface.scss b/client/containers/Project/Interface/interface.scss index 5b93f045..5ee7b73e 100755 --- a/client/containers/Project/Interface/interface.scss +++ b/client/containers/Project/Interface/interface.scss @@ -42,13 +42,23 @@ height: 40px; line-height: 31px; } - + .ant-input { + width: 100%; + } .interface-filter{ + padding-top:7px; padding-left: 10px; + padding-right: 50px; height:45px; line-height: 32px; - padding-top:7px; - background-color: #efefef + background-color: #efefef; + position: relative; + } + .btn-filter { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); } .interface-list{ .cat_switch_hidden{ @@ -56,7 +66,7 @@ visibility: hidden; } } - + a{ color: #333 @@ -71,7 +81,6 @@ } .interface-item{ display: inline-block; - width: 180px; overflow: hidden; top: 0px; line-height: 100%; @@ -94,7 +103,7 @@ } } } - + .right-content{ margin:3px; min-height: 5rem; diff --git a/client/containers/Project/Setting/ProjectMember/ProjectMember.js b/client/containers/Project/Setting/ProjectMember/ProjectMember.js index 92ed6053..663133cc 100755 --- a/client/containers/Project/Setting/ProjectMember/ProjectMember.js +++ b/client/containers/Project/Setting/ProjectMember/ProjectMember.js @@ -162,7 +162,7 @@ class ProjectMember extends Component { render () { const columns = [{ - title: ' 项目成员 ('+this.state.projectMemberList.length + ') 人', + title: this.props.projectMsg.name + ' 项目成员 ('+this.state.projectMemberList.length + ') 人', dataIndex: 'username', key: 'username', render: (text, record) => { diff --git a/client/containers/Project/Setting/ProjectMessage/ProjectMessage.js b/client/containers/Project/Setting/ProjectMessage/ProjectMessage.js index ac940a45..b1551f79 100755 --- a/client/containers/Project/Setting/ProjectMessage/ProjectMessage.js +++ b/client/containers/Project/Setting/ProjectMessage/ProjectMessage.js @@ -231,14 +231,14 @@ class ProjectMessage extends Component { validator(rule, value, callback) { if (value) { if (value.length === 0) { - callback('请输入环境域名'); + callback('请输入环境名称'); } else if (!/\S/.test(value)) { - callback('请输入环境域名'); + callback('请输入环境名称'); } else { return callback(); } } else { - callback('请输入环境域名'); + callback('请输入环境名称'); } } }] @@ -266,8 +266,6 @@ class ProjectMessage extends Component { callback('请输入环境域名!'); } else if (/\s/.test(value)) { callback('环境域名不允许出现空格!'); - } else if (/\//.test(value)) { - callback('环境域名不允许出现‘\/’!'); } else { return callback(); } @@ -328,7 +326,7 @@ class ProjectMessage extends Component {

{this.state.currGroup + ' / ' + projectMsg.name}

-

{projectMsg.desc}

+ {/*

{projectMsg.desc}

*/}
@@ -403,10 +401,10 @@ class ProjectMessage extends Component { {getFieldDecorator('desc', { initialValue: initFormValues.desc, rules: [{ - required: false, message: '描述不超过100字!', max: 100 + required: false }] })( -