feat: 添加分组可以添加多个组长

This commit is contained in:
zwjamnsss 2017-09-27 18:21:01 +08:00
parent b2102a9753
commit 1bfdeff722
10 changed files with 251 additions and 96 deletions

View File

@ -21,7 +21,7 @@ module.exports = {
"rules": {
"indent": [
"error",
2,
4,
{
"SwitchCase": 1
}

View File

@ -1,8 +1,10 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { AutoComplete } from 'antd';
import { Select } from 'antd';
import axios from 'axios';
const Option = Select.Option;
/**
* 用户名输入框自动完成组件
*
@ -12,7 +14,7 @@ import axios from 'axios';
* * 用户名输入框自动完成组件
* * 用户名输入框自动完成组件
*
*
*s
*/
/**
@ -37,12 +39,14 @@ import axios from 'axios';
class UsernameAutoComplete extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
uid: 0,
username: '',
changeName: ''
}
}
state = {
dataSource: []
// value: []
// uid: 0,
// username: ''
// changeName: ''
}
static propTypes = {
@ -50,27 +54,38 @@ class UsernameAutoComplete extends Component {
}
// 改变本组件 state并回调给父组件
changeState = (uid, username) => {
// 设置本组件 state
this.setState({ uid, username });
// 回调 将当前选中的uid和username回调给父组件
this.props.callbackState({ uid, username });
}
// changeState = (value) => {
// // 设置本组件 state
// // this.setState({ value });
// // 回调 将当前选中的uid和username回调给父组件
// this.props.callbackState({ value });
// }
// 输入框中的值改变时
onChange = (userName) => {
this.setState({
changeName: userName
});
}
// onChange = (userName) => {
// this.setState({
// changeName: userName
// });
// }
// process(value) {
// return value.map(item => {
// const index = item.index('_')
// const id = item.substring(0, index);
// const username = item.substring(index + 1);
// return { id, username }
// });
// }
// 选中候选词时
onSelect = (userName) => {
this.state.dataSource.forEach((item) => {
if (item.username === userName) {
this.changeState(item.id, item.username);
}
});
handleChange = (value) => {
// this.state.dataSource.forEach((item) => {
// if (item.username === userName) {
// this.changeState(item.id, item.username);
// }
// });
// this.changeState({ value: this.process(value) })
this.props.callbackState(value);
}
// 搜索回调
@ -90,28 +105,45 @@ class UsernameAutoComplete extends Component {
this.setState({
dataSource: userList
});
if (userList.length) {
// 每次取回搜索值后,没选择时默认选择第一位
this.changeState(userList[0].id, userList[0].username);
} else {
// 如果没有搜索结果,则清空候选 uid 和 username
this.changeState(-1, '');
}
// if (userList.length) {
// // 每次取回搜索值后,没选择时默认选择第一位
// // this.changeState(userList[0].id, userList[0].username);
// } else {
// // 如果没有搜索结果,则清空候选 uid 和 username
// // this.changeState(-1, '');
// this.changeState([]);
// }
}
});
}
render () {
const { dataSource } = this.state;
return (
<AutoComplete
dataSource={this.state.dataSource.map(i => i.username)}
// <AutoComplete
// dataSource={this.state.dataSource.map(i => i.username)}
// style={{ width: '100%' }}
// onChange={this.onChange}
// onSelect={this.onSelect}
// onSearch={this.handleSearch}
// placeholder="请输入用户名"
// size="large"
// />
<Select
mode="multiple"
style={{ width: '100%' }}
onChange={this.onChange}
onSelect={this.onSelect}
onSearch={this.handleSearch}
placeholder="请输入用户名"
onSearch={this.handleSearch}
onChange={this.handleChange}
onBlur={() => this.setState({dataSource: []})}
size="large"
/>
>
{dataSource.map((item, index) => (
<Option key={index} value={'' + item.id}>{item.username}</Option>
))}
</Select>
)
}
}

View File

@ -52,7 +52,7 @@ export default class GroupList extends Component {
currGroupName: '',
currGroupDesc: '',
groupList: [],
owner_uid: 0
owner_uids: []
}
constructor(props) {
@ -103,20 +103,20 @@ export default class GroupList extends Component {
this.setState({
newGroupName: '',
group_name: '',
owner_uid: 0,
owner_uids: [],
addGroupModalVisible: false
});
}
}
@autobind
async addGroup() {
const { newGroupName: group_name, newGroupDesc: group_desc, owner_uid } = this.state;
const res = await axios.post('/api/group/add', { group_name, group_desc, owner_uid })
const { newGroupName: group_name, newGroupDesc: group_desc, owner_uids } = this.state;
const res = await axios.post('/api/group/add', { group_name, group_desc, owner_uids })
if (!res.data.errcode) {
this.setState({
newGroupName: '',
group_name: '',
owner_uid: 0,
owner_uids: [],
addGroupModalVisible: false
});
await this.props.fetchGroupList();
@ -168,9 +168,9 @@ export default class GroupList extends Component {
}
@autobind
onUserSelect(childState) {
onUserSelect(uids) {
this.setState({
owner_uid: childState.uid
owner_uids: uids
})
}

View File

@ -43,7 +43,7 @@ class MemberList extends Component {
role: '',
visible: false,
dataSource: [],
inputUid: 0,
inputUids: [],
inputRole: 'dev'
}
}
@ -82,7 +82,7 @@ class MemberList extends Component {
handleOk() {
this.props.addMember({
id: this.props.currGroup._id,
member_uid: this.state.inputUid,
member_uids: this.state.inputUids,
role: this.state.inputRole
}).then((res) => {
if (!res.payload.data.errcode) {
@ -169,9 +169,9 @@ class MemberList extends Component {
}
@autobind
onUserSelect(childState) {
onUserSelect(uids) {
this.setState({
inputUid: childState.uid
inputUids: uids
})
}

View File

@ -0,0 +1,41 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
// import { connect } from 'react-redux'
// import { Table } from 'antd'
// import { fetchInterfaceList } from '../../../../reducer/modules/interface.js';
// @connect(
// state => {
// return {
// list: state.inter.list
// }
// },
// {
// fetchInterfaceList
// }
// )
export default class ImportInterface extends Component {
constructor(props) {
super(props)
}
static propTypes = {
// colId: PropTypes.number,
// fetchInterfaceList: PropTypes.func,
// projectId: PropTypes.number,
list: PropTypes.array
}
// componentWillMount() {
// this.props.fetchInterfaceList(this.props.projectId);
// }
render() {
console.log(this.props.list)
return (
<div>
<div>{this.props.list}</div>
</div>
)
}
}

View File

@ -3,9 +3,11 @@ import { connect } from 'react-redux';
import { withRouter } from 'react-router'
import PropTypes from 'prop-types'
import { fetchInterfaceColList, fetchInterfaceCaseList, setColData } from '../../../../reducer/modules/interfaceCol'
import { fetchInterfaceList } from '../../../../reducer/modules/interface.js';
import { autobind } from 'core-decorators';
import axios from 'axios';
import { Input, Icon, Button, Modal, message, Tooltip, Tree, Dropdown, Menu, Form } from 'antd';
import ImportInterface from './ImportInterface'
const TreeNode = Tree.TreeNode;
const FormItem = Form.Item;
@ -45,12 +47,14 @@ const ColModalForm = Form.create()((props) => {
interfaceColList: state.interfaceCol.interfaceColList,
currColId: state.interfaceCol.currColId,
currCaseId: state.interfaceCol.currCaseId,
isShowCol: state.interfaceCol.isShowCol
isShowCol: state.interfaceCol.isShowCol,
list: state.inter.list
}
},
{
fetchInterfaceColList,
fetchInterfaceCaseList,
fetchInterfaceList,
setColData
}
)
@ -62,11 +66,13 @@ export default class InterfaceColMenu extends Component {
interfaceColList: PropTypes.array,
fetchInterfaceColList: PropTypes.func,
fetchInterfaceCaseList: PropTypes.func,
fetchInterfaceList: PropTypes.func,
setColData: PropTypes.func,
history: PropTypes.object,
currColId: PropTypes.number,
currCaseId: PropTypes.number,
isShowCol: PropTypes.bool
isShowCol: PropTypes.bool,
list: PropTypes.array
}
state = {
@ -74,7 +80,9 @@ export default class InterfaceColMenu extends Component {
colModalType: '',
colModalVisible: false,
editColId: 0,
filterValue: ''
filterValue: '',
// importInterVisible: false,
importInterIds: []
}
constructor(props) {
@ -188,6 +196,25 @@ export default class InterfaceColMenu extends Component {
this.form = form;
}
selectInterface = (importInterIds) => {
this.setState({ importInterIds })
}
showImportInterface = async (colId) => {
const projectId = this.props.match.params.id;
await fetchInterfaceList(projectId)
confirm({
title: '请选择添加到集合的接口',
content: <ImportInterface onSelect={this.selectInterface} list={this.props.list} />,
onOk() {
console.log(colId);
},
onCancel() {
console.log('Cancel');
}
});
}
filterCol = (e) => {
const value = e.target.value;
this.setState({filterValue: value})
@ -208,6 +235,9 @@ export default class InterfaceColMenu extends Component {
this.showDelColConfirm(col._id)
}}>删除集合</span>
</Menu.Item>
<Menu.Item>
<span onClick={() => this.showImportInterface(col._id)}>导入接口</span>
</Menu.Item>
</Menu>
)
};

View File

@ -49,7 +49,7 @@ class ProjectMember extends Component {
role: '',
visible: false,
dataSource: [],
inputUid: 0,
inputUids: [],
inputRole: 'dev'
}
}
@ -90,7 +90,7 @@ class ProjectMember extends Component {
handleOk() {
this.props.addMember({
id: this.props.match.params.id,
member_uid: this.state.inputUid,
member_uids: this.state.inputUids,
role: this.state.inputRole
}).then((res) => {
if (!res.payload.data.errcode) {
@ -144,9 +144,9 @@ class ProjectMember extends Component {
}
@autobind
onUserSelect(childState) {
onUserSelect(uids) {
this.setState({
inputUid: childState.uid
inputUids: uids
})
}

View File

@ -46,7 +46,7 @@ class groupController extends baseController {
* @foldnumber 10
* @param {String} group_name 项目分组名称不能为空
* @param {String} [group_desc] 项目分组描述
* @param {String} owner_uid 组长uid
* @param {String} [owner_uids] 组长[uid]
* @returns {Object}
* @example ./api/group/add.json
*/
@ -67,17 +67,22 @@ class groupController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组名不能为空');
}
// if (!params.owner_uid) {
// return ctx.body = yapi.commons.resReturn(null, 400, '项目分组必须添加一个组长');
// }
if (!params.owner_uids || !params.owner_uids.length) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组必须添加一个组长');
}
let groupUserdata = null;
if (params.owner_uid) {
groupUserdata = await this.getUserdata(params.owner_uid, 'owner');
if (groupUserdata === null) {
return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
let owners = [];
for(let i = 0, len = params.owner_uids.length; i < len; i++) {
let id = params.owner_uids[i]
let groupUserdata = await this.getUserdata(id, 'owner');
if (groupUserdata) {
owners.push(groupUserdata)
}
}
// groupUserdata = await this.getUserdata(params.owner_uid, 'owner');
if (!owners.length) {
return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
}
let groupInst = yapi.getInst(groupModel);
@ -93,7 +98,7 @@ class groupController extends baseController {
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time(),
members: groupUserdata ? [groupUserdata] : []
members: owners
};
try {
@ -130,7 +135,7 @@ class groupController extends baseController {
* @category group
* @foldnumber 10
* @param {String} id 项目分组id
* @param {String} member_uid 项目分组成员uid
* @param {String} member_uids 项目分组成员[uid]
* @param {String} role 成员角色owner or dev or guest
* @returns {Object}
* @example
@ -142,7 +147,7 @@ class groupController extends baseController {
let params = ctx.request.body;
let groupInst = yapi.getInst(groupModel);
if (!params.member_uid) {
if (!params.member_uids || !params.member_uids.length) {
return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
}
if (!params.id) {
@ -150,22 +155,46 @@ class groupController extends baseController {
}
params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
let add_members = [];
let exist_members = [];
let no_members = []
for(let i = 0, len = params.member_uids.length; i < len; i++) {
let id = params.member_uids[i];
let check = await groupInst.checkMemberRepeat(params.id, id);
let userdata = await this.getUserdata(id, params.role);
console.log(userdata)
if (check > 0) {
exist_members.push(userdata)
} else if (!userdata) {
no_members.push(id)
} else {
userdata.role !== 'admin' && add_members.push(userdata);
delete userdata._role;
}
}
var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '成员已存在');
}
let groupUserdata = await this.getUserdata(params.member_uid, params.role);
if (groupUserdata === null) {
return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
}
if (groupUserdata._role === 'admin') {
return ctx.body = yapi.commons.resReturn(null, 400, '不能邀请管理员')
}
delete groupUserdata._role;
// params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
// var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
// if (check > 0) {
// return ctx.body = yapi.commons.resReturn(null, 400, '成员已存在');
// }
// let groupUserdata = await this.getUserdata(params.member_uid, params.role);
// if (groupUserdata === null) {
// return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
// }
// if (groupUserdata._role === 'admin') {
// return ctx.body = yapi.commons.resReturn(null, 400, '不能邀请管理员')
// }
// delete groupUserdata._role;
try {
let result = await groupInst.addMember(params.id, groupUserdata);
ctx.body = yapi.commons.resReturn(result);
let result = await groupInst.addMember(params.id, add_members);
ctx.body = yapi.commons.resReturn({
result,
add_members,
exist_members,
no_members
});
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}

View File

@ -159,7 +159,7 @@ class projectController extends baseController {
*/
async addMember(ctx) {
let params = ctx.request.body;
if (!params.member_uid) {
if (!params.member_uids || !params.member_uids.length) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员uid不能为空');
}
if (!params.id) {
@ -170,30 +170,52 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员已存在');
}
params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
let add_members = [];
let exist_members = [];
let no_members = []
params.member_uids.forEach(async id => {
let check = await this.Model.checkMemberRepeat(params.id, id);
let userdata = await this.getUserdata(id, params.role);
if (!check) {
exist_members.push(userdata)
} else if (!userdata) {
no_members.push(id)
} else {
add_members.push(userdata)
}
});
let userdata = await this.getUserdata(params.member_uid, params.role);
if (userdata === null) {
return ctx.body = yapi.commons.resReturn(null, 400, '成员uid不存在')
}
// var check = await this.Model.checkMemberRepeat(params.id, params.member_uids);
// if (check > 0) {
// // return ctx.body = yapi.commons.resReturn(null, 400, '项目成员已存在');
// }
// params.role = ['owner', 'dev', 'guest'].find(v => v === params.role) || 'dev';
// let userdata = await this.getUserdata(params.member_uid, params.role);
// if (userdata === null) {
// // return ctx.body = yapi.commons.resReturn(null, 400, '成员uid不存在')
// }
try {
let result = await this.Model.addMember(params.id, userdata);
let result = await this.Model.addMember(params.id, add_members);
let username = this.getUsername();
yapi.commons.saveLog({
content: `用户 "${username}" 添加了项目成员 "${userdata.username}"`,
content: `用户 "${username}" 添加了项目成员 "${add_members.reduce((str, item) => (str ? str + '、' : '') + item.username, '')}"`,
type: 'project',
uid: this.getUid(),
username: username,
typeid: params.id
});
ctx.body = yapi.commons.resReturn(result);
ctx.body = yapi.commons.resReturn({
result,
add_members,
exist_members,
no_members
});
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}

View File

@ -52,7 +52,8 @@ class groupModel extends baseModel {
{
_id: id
}, {
$push: { members: data }
// $push: { members: data },
$push: { members: { $each: data } }
}
);
}