一、用法说明:
1、el-checkbox标签内的内容,绑定点击事件,点击的时候会触发选中/不选中,如果不希望事件冒泡,可以使用
event.preventDefault();
如我:
<el-checkbox-group v-model="codes">
<template v-for="(item, index) in allCodes">
<el-checkbox
:label="item.value"
:key="item.value"
@click.native="handleCheckRegion($event, item.value)"
>{{ item.value }}
<a class="detail-btn" :key="index" @click="clickToDetail($event, item.value)"
>详情</a
>
</el-checkbox>
</template>
</el-checkbox-group>
clickToDetail(e, code) {
if (e.target.tagName !== 'A') return;
//阻止选中
e.preventDefault();
//你的逻辑
}
2、在checkBox中加上按钮:
<el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
<template v-for="(role, index) in allRoles">
<el-checkbox
:label="role.value"
:key="role.value"
@click.native="handleCheckRole($event, role)"
:indeterminate="role.indeterminate"
>{{ role.text }}
<a class="detail-btn" @click="clickRoleToRegionDetail($event, role)" :key="index">详情</a>
</el-checkbox>
</template>
</el-checkbox-group>
现在希望按钮统一排列在最有侧:给按钮加上右浮动,并修改.el-checkbox__label的display属性使按钮的浮动生效即可:
/deep/ .el-checkbox__label {
display: inline;
padding-left: 10px;
line-height: 19px;
font-size: 14px;
}
.detail-btn {
float: right;
}
二、举例
1、例1,现有通讯录,点击出现通讯录选择弹框。弹框右侧为选择的用户列表,可以点击删除,左侧默认为角色列表,可以勾选角色,也可以点击角色进入角色详情页勾选具体的用户。还可以在左侧上方搜索用户名或者账号出来用户列表来勾选。其中,角色列表复选框、搜索用户列表复选框、选中的用户列表复选框,三者的选中状态需要关联(不勾选、半选、全选)。
代码实现:
父组件:
<div class="user-div" @click="openSelectUserDialog">
<template v-for="(item, index) in formValidate.sendUers">
<span class="user-item" :title="item" :key="index">{{
item.userName + '(' + item.userAccount + ')'
}}</span></template
>
</div>
<!--弹框-->
<div>
<SelectUser
:selectUserDialogVisible="selectUserDialogVisible"
:initUers="formValidate.sendUers"
v-if="selectUserDialogVisible"
@cancelSelectUser="cancelSelectUser"
@changeSelectUser="changeSelectUser"
></SelectUser>
</div>
//选择用户弹框
openSelectUserDialog() {
this.selectUserDialogVisible = true;
},
//关闭用户选择弹框
cancelSelectUser() {
this.selectUserDialogVisible = false;
},
//选择用户
changeSelectUser(users) {
this.formValidate.sendUers = users;
this.cancelSelectUser();
},
子组件:
<!-- @format -->
<template>
<div>
<el-dialog title="通讯录" :visible.sync="dialogVisible" width="60%" @close="cancel">
<el-row class="user-row">
<el-col :span="12" class="department-user-col scoll-col">
<div class="header-query">
<el-input v-model="userNameOrAccount"
><i class="el-icon-search" slot="suffix" @click="queryUser"></i
></el-input>
</div>
<div class="department-user">
<!--用户列表复选框-->
<template v-if="queryUsers && queryUsers.length > 0">
<el-checkbox
:indeterminate="userIsIndeterminate"
@change="handleCheckAllUserChange"
v-model="userCheckAll"
>全选</el-checkbox
>
<el-checkbox-group v-model="checkedUserAccounts">
<el-checkbox
v-for="user in queryUsers"
:label="user.userAccount"
:key="user.userAccount"
@click.native="clickUser($event, user)"
>{{ user.userName + '(' + user.userAccount + ')' }}</el-checkbox
>
</el-checkbox-group>
</template>
<!--角色复选框-->
<template v-else>
<el-checkbox :indeterminate="roleIsIndeterminate" @change="handleCheckAllRole" v-model="roleCheckAll"
>全选</el-checkbox
>
<el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
<template v-for="(role, index) in allRoles">
<el-checkbox
:label="role.value"
:key="role.value"
@click.native="clickRole($event, role)"
:indeterminate="role.indeterminate"
>{{ role.text }}
<a class="detail-btn" @click="clickToRoleDetail($event, role)" :key="index">详情</a>
</el-checkbox>
</template>
</el-checkbox-group>
</template>
</div>
</el-col>
<!--右侧-->
<el-col :span="12" class="user-col scoll-col">
<!--选中的用户列表-->
<div class="user-item" v-for="(user, index) in addUsers" :key="index">
{{ user.userName + '(' + user.userAccount + ')' }}
<a href="javascript:void(0);" @click="deleteAddUser(index)" class="delete-icon">X</a>
</div>
</el-col>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel()">取 消</el-button>
<el-button type="primary" @click="ok()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
selectUserDialogVisible: {},
//初始化的用户列表
initUers: {}
},
data() {
return {
dialogVisible: false,
userNameOrAccount: '',
//本界面的用户列表
addUsers: [],
//勾选的用户账号列表
checkedUserAccounts: [],
//用户列表
queryUsers: [], //所有可以选择的用户
//用户多选框
userIsIndeterminate: true,
userCheckAll: false,
//角色列表
allRoles: [], //所有可以选择的角色
//勾选的角色code
checkedRoleCodes: [],
//角色选择复选框
roleIsIndeterminate: true,
roleCheckAll: false
//从角色列表中选择的用户
};
},
created() {
this.init();
},
methods: {
init() {
this.findRoles();
this.addUsers = this.addUsers.concat(this.initUers);
this.handleCheckedValue();
this.dialogVisible = this.selectUserDialogVisible;
},
//从全量用户中获取勾选的账号和角色编码信息,去重
handleCheckedValue() {
//勾选的用户
this.handleCheckUser();
//勾选的角色
this.handleCheckRoleCode();
},
handleCheckUser() {
let checkedUserAccounts = this.addUsers.map(function(item) {
return item.userAccount;
});
this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
},
handleCheckRoleCode() {
let checkedRoleCodes = this.addUsers.map(function(item) {
return item.roleCode;
});
this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
},
findRoles() {
this.$api['role/getAllRoles']({
}).then(data => {
data.forEach(item => {
item.indeterminate = false;
});
this.allRoles = data;
});
},
cancel() {
this.dialogVisible = false;
this.$emit('cancelSelectUser');
},
ok() {
this.dialogVisible = false;
//发送对象 = 初始化的用户+用户列表中选择的用户+角色列表选择的用户
this.$emit('changeSelectUser', this.addUsers);
},
//角色全选/全部取消,全量
handleCheckAllRole(val) {
if (val) {
//全选
this.checkedRoleCodes = this.allRoles.map(function(item) {
return item.value;
});
this.getUsersByRoles(this.checkedRoleCodes).then(users => {
this.addUsers = users;
});
this.handleCheckUser();
} else {
//取消全选
this.addUsers = [];
this.checkedUserAccounts = [];
this.checkedRoleCodes = [];
}
this.roleIsIndeterminate = false;
},
//角色复选框点击事件
clickRole(e, role) {
// 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
let roleCode = role.value;
if (this.checkedRoleCodes.indexOf(roleCode) === -1) {
//选中
this.getUsersByRoles(new Array(roleCode)).then(users => {
let addUsers = this.addUsers.concat(users);
this.addUsers = this.unique(addUsers);
});
} else {
//取消
role.indeterminate = false;
this.addUsers = this.addUsers.filter(function(item) {
return item.roleCode !== roleCode;
});
}
this.handleCheckUser();
},
//角色详情单击事件详情,取A标签的事件
clickToRoleDetail(e, role) {
if (e.target.tagName !== 'A') return;
let roleCode = role.value;
//阻止选中
// this.checkedRoleCodes = this.checkedRoleCodes.filter(item => {
// return item !== roleCode;
// });
this.getUsersByRoles(new Array(roleCode)).then(users => {
this.queryUsers = users;
let addUsers = this.addUsers.concat(users);
this.addUsers = this.unique(addUsers);
this.handleCheckUser();
});
},
//角色选择改变
handleCheckedRoleChange(roleCodes) {
let checkedCount = roleCodes.length;
let totalCount = this.allRoles.length;
this.roleCheckAll = checkedCount === totalCount;
this.roleIsIndeterminate = checkedCount > 0 && checkedCount < totalCount;
},
async getUsersByRoles(roleCodes) {
let roleCodeStr = roleCodes.join(',');
let queryUsers = [];
await this.$api['personDetail/listPersonnelDetailByPositionTypeCodes']({
positionTypeCodeList: roleCodeStr
}).then(data => {
queryUsers = data;
});
return queryUsers;
},
//搜索用户
queryUser() {
if (this.userNameOrAccount) {
this.$api['personDetail/listPersonnelDetailByNameOrAccount']({
nameOrAccount: this.userNameOrAccount
}).then(data => {
this.queryUsers = data;
});
} else {
this.queryUsers = [];
}
},
//用户全选,用户是角色的子集,故用户新增/删除需要做比对
handleCheckAllUserChange(val) {
if (val) {
//全选,addUsers加上queryUsers,去重
this.addUsers = this.addUsers.concat(this.queryUsers);
} else {
//全部取消,addUsers去掉所有queryUsers
let queryUserAccounts = this.queryUsers.map(function(item) {
return item.userAccount;
});
this.addUsers = this.addUsers.filter(function(item) {
return queryUserAccounts.every(function(item1) {
return item.userAccount !== item1;
});
});
}
this.addUsers = this.unique(this.addUsers);
//复选框勾选绑定值改变
this.handleCheckedValue();
this.userIsIndeterminate = false;
},
//用户复选框点击事件
clickUser(e, user) {
// 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
let userAccount = user.userAccount;
let roleCode = user.roleCode;
if (this.checkedUserAccounts.indexOf(userAccount) === -1) {
//选中
let addUser = this.queryUsers.find(item => {
return item.userAccount === userAccount;
});
this.addUsers.push(addUser);
this.addUsers = this.unique(this.addUsers);
} else {
//取消
this.addUsers = this.addUsers.filter(function(item) {
return item.userAccount !== userAccount;
});
}
//全选状态改变
this.userAndRoleAllCheckStatusChange();
//角色选中值变化
this.handleCheckedValue();
//角色复选框选中状态改变
this.roleUserCheckStatusChange(roleCode);
},
//用户、角色全选框选中状态改变
userAndRoleAllCheckStatusChange() {
//右侧用户列表包含左侧复选框用户列表,userCheckAll为true,userIsIndeterminate为false
let userCheckAll = true;
this.queryUsers.forEach(item => {
if (this.checkedUserAccounts.indexOf(item.userAccount) < 0) {
userCheckAll = false;
return;
}
});
this.userCheckAll = userCheckAll;
this.userIsIndeterminate = !this.userCheckAll;
//角色
this.handleCheckedRoleChange(this.checkedRoleCodes);
},
//角色复选框选中状态改变
roleUserCheckStatusChange(roleCode) {
this.allRoles.forEach(item => {
if (item.value === roleCode) {
if (this.checkedRoleCodes.indexOf(roleCode) !== -1) {
item.indeterminate = true;
} else {
item.indeterminate = false;
}
}
});
},
//去重
unique(arr) {
var obj = {};
arr = arr.reduce(function(item, next) {
obj[next.userAccount] ? '' : (obj[next.userAccount] = true && item.push(next));
return item;
}, []);
return arr;
},
//删除本次新增的用户
deleteAddUser(index) {
let deleteUser = this.addUsers[index];
let deleteUserAccount = deleteUser.userAccount;
let roleCode = deleteUser.roleCode;
//1、用户复选框绑定值同步删除
this.checkedUserAccounts = this.checkedUserAccounts.filter(function(value) {
return value !== deleteUserAccount;
});
//2、最后本次新增的用户删除
this.addUsers.splice(index, 1);
//3、角色复选框绑定值同步变化
this.handleCheckRoleCode();
//4、用户全选状态改变
this.userAndRoleAllCheckStatusChange();
//5、角色选中状态改变,设置已选且有删除用户操作的角色indeterminate为true
this.roleUserCheckStatusChange(roleCode);
}
},
watch: {
queryUsers: {
handler: function(val) {
this.userAndRoleAllCheckStatusChange();
}
}
}
};
</script>
<style scoped lang="less">
.user-row {
.department-user-col {
/deep/ .el-checkbox {
color: #606266;
font-weight: 500;
font-size: 14px;
cursor: pointer;
user-select: none;
margin-right: 30px;
display: block;
}
.detail-btn {
float: right;
margin-left: 20px;
}
}
.user-col {
.user-item {
margin-left: 10px;
}
.delete-icon {
float: right;
margin-right: 20px;
}
}
//滚动条
.scoll-col {
max-height: 300px;
overflow-y: auto;
}
}
</style>
已知问题:某角色先选中,然后删除用户,该角色变为半选,如果该用户通过搜索用户列表的方式来单独勾选或者全选重新加上,该角色的状态仍为半选。因为需要全量判断,性能较差。
2、举例2:例1是从角色跳转到用户,现在再加一层关系,角色跳转到区域(固定的省份),区域再调转到用户:
父组件:这里对角色、区域、区域复选框状态做了一个缓存
<!-- @format -->
<template>
<div>
<div class="container">
<el-form ref="formValidate" :model="formValidate" :rules="ruleValidate" label-position="left" label-width="100px">
<el-form-item :required="true">
<div class="user-div" @click="openSelectUserDialog">
<template v-for="(item, index) in formValidate.receiverList">
<span class="user-item" :title="item" :key="index">{{
item.userName + '(' + item.userAccount + ')'
}}</span></template
>
</div>
</el-form-item>
</el-form>
</div>
<!--弹框-->
<div>
<SelectUser
:selectUserDialogVisible="selectUserDialogVisible"
:initUers="formValidate.receiverList"
:cacheAllRoles="cacheAllRoles"
:cacheAllRegions="cacheAllRegions"
:cacheRoleRegionIndeterminateMap="cacheRoleRegionIndeterminateMap"
v-if="selectUserDialogVisible"
@cancelSelectUser="cancelSelectUser"
@changeSelectUser="changeSelectUser"
></SelectUser>
</div>
</div>
</template>
<script>
import SelectUser from './children/select-user';
export default {
data() {
return {
// 表单数据
formValidate: {
receiverList: []
},
selectUserDialogVisible: false,
//通讯录缓存的角色信息
cacheAllRoles: [],
//通讯录缓存的区域信息
cacheAllRegions: [],
//通讯录缓存的区域复选框状态
cacheRoleRegionIndeterminateMap: {}
};
},
methods: {
//选择用户弹框
openSelectUserDialog() {
this.selectUserDialogVisible = true;
},
//关闭用户选择弹框
cancelSelectUser() {
this.selectUserDialogVisible = false;
},
//选择用户
changeSelectUser(users, cacheAllRoles, cacheAllRegions, cacheRoleRegionIndeterminateMap) {
this.formValidate.receiverList = users;
this.cancelSelectUser();
this.cacheAllRoles = cacheAllRoles;
this.cacheAllRegions = cacheAllRegions;
this.cacheRoleRegionIndeterminateMap = cacheRoleRegionIndeterminateMap;
}
}
},
components: {
SelectUser
}
};
</script>
子组件:右侧用户采用滚动加载
<!-- @format -->
<template>
<div>
<el-dialog title="通讯录" :visible.sync="dialogVisible" width="60%" @close="cancel">
<el-row class="user-row">
<el-col :span="12" class="role-region-user-col scoll-col">
<div class="header-query">
<el-input v-model.trim="userNameOrAccount" placeholder="输入姓名/账号" size="mini"
><i class="el-icon-search" slot="suffix" @click="searchUser"></i
></el-input>
</div>
<div class="role-region-user">
<!--错误提示-->
<template v-if="isNoDataShow">
<p class="no-data">无搜索结果</p>
</template>
<!--正常数据-->
<template v-else>
<!--用户列表复选框-->
<template v-if="queryUsers && queryUsers.length > 0">
<el-row>
<el-col :span="20">
<el-checkbox
:indeterminate="userIsIndeterminate"
@change="handleCheckAllUser"
v-model="userCheckAll"
>全选</el-checkbox
>
<el-checkbox-group v-model="checkedUserAccounts">
<el-checkbox
v-for="user in queryUsers"
:label="user.userAccount"
:key="user.userAccount"
@click.native="handleCheckUser($event, user)"
@change="checkUserChange"
>{{ user.userName + '(' + user.userAccount + ')' }}</el-checkbox
>
</el-checkbox-group></el-col
>
<el-col :span="2" v-if="isFromClickRegion">
<a @click="goBackToRegion($event)" class="goback-to-role"
><svg
t="1628844742588"
class="icon"
viewBox="0 0 1482 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2061"
width="40"
height="40"
>
<path
d="M584.884104 272.714912V0L0 477.152657l584.884104 477.073906V674.817811c406.119203 0 690.568023 108.991464 893.588249 347.528417-81.271091-340.755826-324.926863-681.354149-893.588249-749.631316"
fill="#467CFD"
p-id="2062"
></path></svg
></a>
</el-col>
</el-row>
</template>
<!--角色复选框-->
<template v-else-if="!isRegionListShow">
<el-checkbox :indeterminate="roleIsIndeterminate" @change="handleCheckAllRole" v-model="roleCheckAll"
>全选</el-checkbox
>
<el-checkbox-group v-model="checkedRoleCodes" @change="handleCheckedRoleChange">
<template v-for="(role, index) in allRoles">
<el-checkbox
:label="role.value"
:key="role.value"
@click.native="handleCheckRole($event, role)"
:indeterminate="role.indeterminate"
>{{ role.text }}
<a class="detail-btn" @click="clickRoleToRegionDetail($event, role)" :key="index">详情</a>
</el-checkbox>
</template>
</el-checkbox-group>
</template>
<!--区域复选框-->
<template v-else>
<el-row>
<el-col :span="20">
<el-checkbox
:indeterminate="roleRegionAllIndeterminateMap[currentClickRoleCode]"
v-model="roleRegionAllCheckMap[currentClickRoleCode]"
@change="handleCheckAllRegion"
>全选</el-checkbox
>
<el-checkbox-group v-model="checkedRoleRegionsMap[currentClickRoleCode]">
<template v-for="(item, index) in allRegions">
<el-checkbox
:label="item.value"
:key="item.value"
:indeterminate="roleRegionIndeterminateMap[currentClickRoleCode][item.value]"
@click.native="handleCheckRegion($event, item.value)"
>{{ item.value }}
<a class="detail-btn" :key="index" @click="clickRegionToUserDetail($event, item.value)"
>详情</a
>
</el-checkbox>
</template>
</el-checkbox-group>
</el-col>
<el-col :span="2">
<a @click="goBackToRole($event)" class="goback-to-role"
><svg
t="1628844742588"
class="icon"
viewBox="0 0 1482 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2061"
width="40"
height="40"
>
<path
d="M584.884104 272.714912V0L0 477.152657l584.884104 477.073906V674.817811c406.119203 0 690.568023 108.991464 893.588249 347.528417-81.271091-340.755826-324.926863-681.354149-893.588249-749.631316"
fill="#467CFD"
p-id="2062"
></path></svg
></a>
</el-col>
</el-row>
</template>
</template>
</div>
</el-col>
<!--右侧-->
<el-col :span="12" class="user-col">
<!--选中的用户列表-->
<!-- <div class="user-item" v-for="(user, index) in addUsers" :key="index">
{{ user.userName + '(' + user.userAccount + ')' }}
<a href="javascript:void(0);" @click="deleteAddUser(index)" class="delete-icon">X</a>
</div> -->
<div class="infinite-list-wrapper" style="overflow:auto">
<template>
<p v-if="scrollUserLoading" class="load-user"><i class="el-icon-loading"></i></p>
<ul class="infinite-list" v-infinite-scroll="scrollLoadUser" style="overflow:auto;height:300px">
<li
v-for="i in scrollCount"
class="infinite-list-item"
:key="i"
infinite-scroll-disabled="userScrollDisabled"
>
<div v-if="addUsers[i - 1]">
{{ addUsers[i - 1].userName + '(' + addUsers[i - 1].userAccount + ')' }}
<a href="javascript:void(0);" @click="deleteAddUser(i - 1)" class="delete-icon">X</a>
</div>
</li>
</ul>
</template>
</div>
</el-col>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel()">取 消</el-button>
<el-button type="primary" @click="ok()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
selectUserDialogVisible: {},
//初始化的用户列表
initUers: {},
//缓存的角色列表,包含角色的半选状态
cacheAllRoles: {},
//缓存的区域列表
cacheAllRegions: {},
//缓存的区域复选框状态
cacheRoleRegionIndeterminateMap: {}
},
data() {
return {
dialogVisible: false,
userNameOrAccount: '',
isNoDataShow: false,
//右侧的用户列表
addUsers: [],
//用户列表复选框绑定值
checkedUserAccounts: [],
//左侧用户复选框列表
queryUsers: [],
//用户复选列表全选框状态
userIsIndeterminate: true,
userCheckAll: false,
//角色列表
allRoles: [],
//角色列表复选框绑定值
checkedRoleCodes: [],
//角色复选列表全选框状态
roleIsIndeterminate: false,
roleCheckAll: false,
//区域列表
allRegions: [],
allRegionCodes: [],
//当前点击的角色
currentClickRole: '',
currentClickRoleCode: '',
isRegionListShow: false,
//区域复选列表全选框状态
roleRegionAllIndeterminateMap: {},
roleRegionAllCheckMap: {},
//区域复选框绑定值,map:string->array,如{'管理员':['上海','北京']}
checkedRoleRegionsMap: {},
//区域复选框状态,map:string->map,如{'管理员':{{'上海':true},{'北京':false}}}
roleRegionIndeterminateMap: {},
//用户列表来自区域详情跳转标志
isFromClickRegion: false,
//滚动加载
scrollCount: 0,
scrollUserLoading: false
};
},
created() {
//获取所有角色
this.findRoles().then(res => {
//获取所有区域
this.findRegions();
//初始化数据和勾选状态
this.init();
});
},
computed: {
scrollUserNoMore() {
return this.scrollCount >= this.addUsers.length;
},
userScrollDisabled() {
return this.scrollUserLoading || this.scrollUserNoMore;
}
},
methods: {
scrollLoadUser() {
//一次加载20条
let increaseCount = 20;
let addAllCount = this.addUsers.length;
if (this.scrollCount + increaseCount > addAllCount) {
this.scrollCount = addAllCount;
} else {
this.scrollCount += increaseCount;
}
console.info('加载数据:' + this.scrollCount);
this.scrollUserLoading = false;
},
init() {
this.dialogVisible = this.selectUserDialogVisible;
this.addUsers = this.addUsers.concat(this.initUers);
this.handleCheckedValue();
this.handleCheckedRoleChange(this.checkedRoleCodes);
this.roleRegionIndeterminateMap = this.cacheRoleRegionIndeterminateMap || {};
},
//处理用户、角色、区域复选框绑定值和选择状态
handleCheckedValue() {
let checkedUserAccounts = [];
let checkedRoleCodes = [];
let checkedRoleRegionsMap = {};
this.addUsers.forEach(user => {
let userAccount = user.userAccount;
let roleCode = user.roleCode;
let regionName = user.regionName;
checkedUserAccounts.push(userAccount);
checkedRoleCodes.push(roleCode);
if (!checkedRoleRegionsMap[roleCode]) {
checkedRoleRegionsMap[roleCode] = [];
} else if (checkedRoleRegionsMap[roleCode].indexOf(regionName) === -1) {
checkedRoleRegionsMap[roleCode].push(regionName);
}
});
//用户列表复选框勾选
this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
//角色列表复选框勾选
this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
//角色-区域列表复选框勾选
this.checkedRoleRegionsMap = checkedRoleRegionsMap;
},
handleCheckedUser() {
let checkedUserAccounts = this.addUsers.map(function(item) {
return item.userAccount;
});
this.checkedUserAccounts = Array.from(new Set(checkedUserAccounts));
},
handleCheckedRoleCode() {
let checkedRoleCodes = this.addUsers.map(function(item) {
return item.roleCode;
});
this.checkedRoleCodes = Array.from(new Set(checkedRoleCodes));
},
//处理区域绑定值和勾选状态
handleRegionCheckedAndStatus(deleteRegion) {
//1、处理区域复选框绑定值与全选框状态
//角色选中
if (this.checkedRoleCodes.indexOf(this.currentClickRoleCode) > -1) {
if (!this.currentClickRole.indeterminate) {
//(1)全选状态
this.checkedRoleRegionsMap[this.currentClickRoleCode] = this.allRegionCodes;
this.roleRegionAllCheckMap[this.currentClickRoleCode] = true;
} else {
//(2)半选状态
//获取选择的区域列表
let checkedRegions = this.addUsers.map(user => {
if (user.roleCode === this.currentClickRoleCode) {
return user.regionName;
}
});
if (checkedRegions.length === 0) {
this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
} else {
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
}
this.checkedRoleRegionsMap[this.currentClickRoleCode] = Array.from(new Set(checkedRegions));
}
} else {
this.checkedRoleRegionsMap[this.currentClickRoleCode] = [];
this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
}
//(3)其他情况,赋空值,防止空指针
if (!this.checkedRoleRegionsMap[this.currentClickRoleCode]) {
this.checkedRoleRegionsMap[this.currentClickRoleCode] = new Array();
this.roleRegionAllCheckMap[this.currentClickRoleCode] = false;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
}
//2、处理区域复选框状态
let regionIndeterminateMap = {};
this.allRegionCodes.forEach(regionCode => {
//区域是选中状态且有删除用户操作,则状态置为半选
if (this.checkedRoleRegionsMap[this.currentClickRoleCode].indexOf(regionCode) === -1) {
//没有勾选,为false
regionIndeterminateMap[regionCode] = false;
} else if (deleteRegion && regionCode === deleteRegion) {
//勾选且本次被删除了,为半选状态
console.info('删除' + regionCode);
regionIndeterminateMap[regionCode] = true;
} else if (this.roleRegionIndeterminateMap && this.roleRegionIndeterminateMap[this.currentClickRoleCode]) {
//使用原来的值
regionIndeterminateMap[regionCode] = this.roleRegionIndeterminateMap[this.currentClickRoleCode][regionCode];
} else {
//其他情况
regionIndeterminateMap[regionCode] = false;
}
});
this.roleRegionIndeterminateMap[this.currentClickRoleCode] = regionIndeterminateMap;
},
//获取区域
findRegions() {
if (this.cacheAllRegions && this.cacheAllRegions.length > 0) {
this.allRegions = this.cacheAllRegions;
this.allRegionCodes = this.allRegions.map(function(item) {
return item.value;
});
return;
}
//为空,第一次进入
this.$api['region/getRegions']().then(data => {
this.allRegions = data;
this.allRegionCodes = this.allRegions.map(function(item) {
return item.value;
});
});
},
//获取角色
async findRoles() {
if (this.cacheAllRoles && this.cacheAllRoles.length > 0) {
this.allRoles = this.cacheAllRoles;
return;
}
//为空,第一次进入,查询接口
await this.$api['role/getRoles']().then(data => {
data.forEach(item => {
item.indeterminate = false;
});
this.allRoles = data;
});
},
cancel() {
this.dialogVisible = false;
this.$emit('cancelSelectUser');
},
ok() {
this.dialogVisible = false;
//发送对象 = 初始化的用户+用户列表中选择的用户+角色列表选择的用户
this.$emit('changeSelectUser', this.addUsers, this.allRoles, this.allRegions, this.roleRegionIndeterminateMap);
},
//角色全选/全部取消,全量
handleCheckAllRole(val) {
console.info('全选开始:' + new Date());
if (val) {
//全选
this.scrollUserLoading = true;
//1、处理角色多选
this.checkedRoleCodes = this.allRoles.map(function(item) {
return item.value;
});
this.getUsersByRoles(new Array()).then(users => {
this.addUsers = users;
});
//2、处理用户多选
this.handleCheckedUser();
//3、处理区域多选、全选状态
this.checkedRoleCodes.forEach(roleCode => {
this.checkedRoleRegionsMap[roleCode] = this.allRegionCodes;
this.roleRegionAllCheckMap[roleCode] = true;
this.roleRegionAllIndeterminateMap[roleCode] = false;
});
} else {
//取消全选
//1、处理角色多选
this.checkedRoleCodes = [];
//2、处理用户多选
this.addUsers = [];
this.checkedUserAccounts = [];
//3、处理区域多选、全选状态
this.checkedRoleRegionsMap = {};
this.roleRegionAllCheckMap = {};
this.roleRegionAllIndeterminateMap = {};
}
//4、处理角色复选框状态
this.allRoles.forEach(function(item) {
item.indeterminate = false;
});
//5、处理角色全选框样式
this.roleIsIndeterminate = false;
console.info('全选结束:' + new Date());
},
//角色多选框勾选事件
handleCheckRole(e, role) {
// 因为原生click事件会执行两次,第一次在label标签上,第二次在input标签上,故此处理
if (e.target.tagName === 'INPUT' || e.target.tagName === 'A') return;
let roleCode = role.value;
if (this.checkedRoleCodes.indexOf(roleCode) === -1) {
//选中
//1、处理用户多选
this.getUsersByRoles(new Array(roleCode)).then(users => {
let addUsers = this.addUsers.concat(users);
this.addUsers = this.uniqueUser(addUsers);
});
this.handleCheckedUser();
//2、处理区域多选
this.checkedRoleRegionsMap[roleCode] = this.allRegionCodes;
//3、处理角色-区域全选框状态
this.roleRegionAllCheckMap[roleCode] = true;
this.roleRegionAllIndeterminateMap[roleCode] = false;
} else {
//取消
//1、处理用户多选
this.addUsers = this.addUsers.filter(function(item) {
return item.roleCode !== roleCode;
});
this.handleCheckedUser();
//2、处理区域多选
this.checkedRoleRegionsMap[roleCode] = [];
//3、处理角色复选框状态
role.indeterminate = false;
//4、处理角色-区域全选框状态
this.roleRegionAllCheckMap[roleCode] = false;
this.roleRegionAllIndeterminateMap[roleCode] = true;
}
},
//角色详情单击事件,取A标签的事件
clickRoleToRegionDetail(e, role) {
if (e.target.tagName !== 'A') return;
let roleCode = role.value;
this.currentClickRoleCode = roleCode;
this.currentClickRole = role;
//初始化区域勾选值与勾选状态
this.handleRegionCheckedAndStatus();
this.isRegionListShow = true;
},
//从区域列表返回到角色
goBackToRole(e) {
//this.currentClickRoleCode = '';
this.isRegionListShow = false;
},
//区域全选/全部取消事件
handleCheckAllRegion(val) {
if (val) {
//全选
this.getUsersByRoles(new Array(this.currentClickRoleCode)).then(users => {
//1、处理用户多选
let addUsers = this.addUsers.concat(users);
this.addUsers = this.uniqueUser(addUsers);
this.handleCheckedUser();
//2、处理角色多选
this.handleCheckedRoleCode();
});
//3、处理区域全选
this.checkedRoleRegionsMap[this.currentClickRoleCode] = this.allRegionCodes;
} else {
//取消全选
//3、处理区域多选
this.checkedRoleRegionsMap[this.currentClickRoleCode] = new Array();
this.$forceUpdate();
//1、处理用户多选
let addUsers = this.addUsers.filter(user => {
return user.roleCode !== this.currentClickRoleCode;
});
this.addUsers = addUsers;
this.handleCheckedUser();
//2、处理角色多选
this.checkedRoleCodes = this.checkedRoleCodes.filter(roleCode => {
return roleCode !== this.currentClickRoleCode;
});
}
//4、处理角色全选框样式
this.currentClickRole.indeterminate = false;
this.roleIsIndeterminate = false;
},
//区域勾选事件
handleCheckRegion(e, regionName) {
// 原生click事件会执行两次,第一次在label标签上,第二次在input标签上
if (e.target.tagName !== 'INPUT') return;
let checkRegions = this.checkedRoleRegionsMap[this.currentClickRoleCode];
if (checkRegions.indexOf(regionName) === -1) {
//选中
this.getUsersByRoles(new Array(this.currentClickRoleCode), regionName).then(users => {
//1、处理用户多选
let addUsers = this.addUsers.concat(users);
this.addUsers = this.uniqueUser(addUsers);
this.handleCheckedUser();
//2、处理角色多选
this.handleCheckedRoleCode();
});
//3、处理角色多选状态;处理区域全选状态
if (checkRegions.length === this.allRegionCodes.length - 1) {
//区域全部选中
this.currentClickRole.indeterminate = false;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
} else {
this.currentClickRole.indeterminate = true;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
}
} else {
//取消,强制改变值
checkRegions = checkRegions.filter(item => {
return item !== regionName;
});
this.checkedRoleRegionsMap[this.currentClickRoleCode] = checkRegions;
//1、处理用户多选
let addUsers = this.addUsers.filter(item => {
return !(item.roleCode === this.currentClickRoleCode && item.regionName === regionName);
});
this.addUsers = addUsers;
this.handleCheckedUser();
//2、处理角色多选、多选状态;处理区域全选状态
if (checkRegions.length === 0) {
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = false;
this.checkedRoleCodes = this.checkedRoleCodes.filter(roleCode => {
return roleCode !== this.currentClickRoleCode;
});
} else {
this.currentClickRole.indeterminate = true;
this.roleRegionAllIndeterminateMap[this.currentClickRoleCode] = true;
}
}
},
//区域详情单击事件
clickRegionToUserDetail(e, regionName) {
if (e.target.tagName !== 'A') return;
//阻止选中
e.preventDefault();
this.isFromClickRegion = true;
this.getUsersByRoles(new Array(this.currentClickRoleCode), regionName).then(users => {
this.queryUsers = users;
});
},
//角色选择改变
handleCheckedRoleChange(roleCodes) {
let checkedCount = roleCodes.length;
let totalCount = this.allRoles.length;
this.roleCheckAll = checkedCount === totalCount;
this.roleIsIndeterminate = checkedCount > 0 && checkedCount < totalCount;
},
async getUsersByRoles(roleCodes, regionName) {
let roleCodeStr = '';
if (roleCodes && roleCodes.length > 0) {
roleCodeStr = roleCodes.join(',');
}
let queryUsers = [];
await this.$api['user/getUserByRoleAndRegion']({
roleCodes: roleCodeStr,
region: regionName
}).then(data => {
queryUsers = data;
});
return queryUsers;
},
//搜索用户
searchUser() {
if (this.userNameOrAccount) {
this.$api['user/getByNameOrAccount']({
nameOrAccount: this.userNameOrAccount
}).then(data => {
this.queryUsers = data;
if (data.length === 0) {
this.isNoDataShow = true;
} else {
this.isNoDataShow = false;
}
});
this.isFromClickRegion = false;
} else {
this.isNoDataShow = false;
this.queryUsers = [];
this.isRegionListShow = false;
}
},
//从用户列表返回到区域
goBackToRegion(e) {
this.queryUsers = [];
this.isRegionListShow = true;
this.handleRegionCheckedAndStatus();
},
//用户全选,这里选中的用户是整体用户的子集
handleCheckAllUser(val) {
let queryRoleCodes = this.queryUsers.map(user => {
return user.roleCode;
});
if (val) {
//全选
//1、处理用户多选
let addUsers = this.addUsers.concat(this.queryUsers);
this.addUsers = this.uniqueUser(addUsers);
this.handleCheckedUser();
//2、处理角色多选框状态,新增的角色设为半选
this.allRoles.forEach(role => {
let roleCode = role.value;
if (queryRoleCodes.indexOf(roleCode) >= 0 && this.checkedRoleCodes.indexOf(roleCode) === -1) {
role.indeterminate = true;
}
});
//3、处理角色多选
this.handleCheckedRoleCode();
} else {
//全部取消
//1、处理用户多选
let queryUserAccounts = this.queryUsers.map(function(item) {
return item.userAccount;
});
let addUsers = this.addUsers.filter(function(item) {
return queryUserAccounts.every(function(item1) {
return item.userAccount !== item1;
});
});
this.addUsers = this.uniqueUser(addUsers);
this.handleCheckedUser();
//2、处理角色多选
this.handleCheckedRoleCode();
//3、处理角色多选框状态,取消的角色去除选择状态
this.allRoles.forEach(role => {
let roleCode = role.value;
if (queryRoleCodes.indexOf(roleCode) >= 0 && this.checkedRoleCodes.indexOf(roleCode) >= 0) {
role.indeterminate = true;
} else {
role.indeterminate = false;
}
});
}
//4、用户全选样式改变
this.userIsIndeterminate = false;
//5、点击后回到角色列表页
if (!this.isFromClickRegion) {
this.queryUsers = [];
this.isRegionListShow = false;
}
},
//用户复选框点击事件
handleCheckUser(e, user) {
// 原生click事件防止执行多次
if (e.target.tagName !== 'SPAN') return;
let userAccount = user.userAccount;
let roleCode = user.roleCode;
let regionName = user.regionName;
if (this.checkedUserAccounts.indexOf(userAccount) === -1) {
//选中
//1、处理用户
let addUser = this.queryUsers.find(item => {
return item.userAccount === userAccount;
});
this.addUsers.push(addUser);
this.addUsers = this.uniqueUser(this.addUsers);
//2、处理角色多选、角色复选框选择状态
this.handleCheckedRoleCode();
this.handleCheckedRoleChange(this.checkedRoleCodes);
//3、角色复选框选中状态改变
this.roleCheckStatusChange(roleCode);
} else {
//取消
//1、处理用户
this.addUsers = this.addUsers.filter(function(item) {
return item.userAccount !== userAccount;
});
//2、处理角色多选、角色复选框选择状态
this.handleCheckedRoleCode();
this.handleCheckedRoleChange(this.checkedRoleCodes);
//3、角色复选框选中状态改变
this.roleCheckStatusChange(roleCode);
//4、处理区域复选框
this.handleRegionCheckedAndStatus(regionName);
}
//点击后回到角色列表页
if (!this.isFromClickRegion) {
this.queryUsers = [];
this.isRegionListShow = false;
}
},
checkUserChange(checkedUserAccounts) {
//右侧用户列表包含左侧复选框用户列表,userCheckAll为true,userIsIndeterminate为false
let isUserCheckAll = true;
let isUserCheck = false;
//是否都选中了,有一个没选择则为false
this.queryUsers.forEach(item => {
if (this.checkedUserAccounts.indexOf(item.userAccount) < 0) {
isUserCheckAll = false;
return;
}
});
//是否没选择的,有一个选择则为true
this.queryUsers.forEach(item => {
if (this.checkedUserAccounts.indexOf(item.userAccount) >= 0) {
isUserCheck = true;
return;
}
});
this.userCheckAll = isUserCheckAll;
if (isUserCheck && !isUserCheckAll) {
//有勾选,全选才会存在半选状态
this.userIsIndeterminate = true;
} else {
this.userIsIndeterminate = false;
}
},
//用户、角色全选框选中状态改变
userAndRoleAllCheckStatusChange() {
this.checkUserChange(this.checkedUserAccounts);
//角色复选框选中状态改变
this.handleCheckedRoleChange(this.checkedRoleCodes);
},
//角色复选框选中状态改变
roleCheckStatusChange(roleCode) {
this.allRoles.forEach(item => {
if (item.value === roleCode) {
if (this.checkedRoleCodes.indexOf(roleCode) !== -1) {
item.indeterminate = true;
} else {
item.indeterminate = false;
}
}
});
},
//去重
uniqueUser(arr) {
var obj = {};
arr = arr.reduce(function(item, next) {
obj[next.userAccount] ? '' : (obj[next.userAccount] = true && item.push(next));
return item;
}, []);
return arr;
},
//删除本次新增的用户
deleteAddUser(index) {
let deleteUser = this.addUsers[index];
let deleteUserAccount = deleteUser.userAccount;
let roleCode = deleteUser.roleCode;
let regionName = deleteUser.regionName;
//1、用户复选框绑定值同步删除
this.checkedUserAccounts = this.checkedUserAccounts.filter(function(value) {
return value !== deleteUserAccount;
});
//2、最后本次新增的用户删除
this.addUsers.splice(index, 1);
//3、角色复选框绑定值同步变化
this.handleCheckedRoleCode();
//4、用户全选状态改变
this.userAndRoleAllCheckStatusChange();
//5、角色选中状态改变,设置已选且有删除用户操作的角色indeterminate为true
this.roleCheckStatusChange(roleCode);
//6、区域选择情况
this.handleRegionCheckedAndStatus(regionName);
}
},
watch: {
queryUsers: {
handler: function(val) {
if (val && val.length > 0) {
this.handleCheckedValue();
this.userAndRoleAllCheckStatusChange();
}
}
},
addUsers: {
handler: function(val) {
if (val && val.length > 0) {
this.scrollLoadUser();
}
}
}
}
};
</script>
<style scoped lang="less">
.role-region-user {
.goback-to-role {
//margin-right: 10px;
}
.no-data {
color: red;
}
}
.user-row {
.role-region-user-col {
/deep/ .el-checkbox {
color: #606266;
font-weight: 500;
font-size: 14px;
cursor: pointer;
user-select: none;
margin-right: 30px;
display: block;
}
.detail-btn {
float: right;
margin-left: 20px;
}
}
.user-col {
.user-item {
margin-left: 10px;
}
.delete-icon {
float: right;
margin-right: 20px;
}
.load-user {
text-align: center;
/deep/ .el-icon-loading {
font-size: 30px;
}
}
}
//滚动条
.scoll-col {
max-height: 300px;
overflow-y: auto;
}
}
</style>
从性能角度考虑,已知问题:
(1)左侧用户列表勾选操作,对应的角色不会由半选变为全选:如某角色先选中,再删除右侧某一人员,该角色变为半选状态,再通过左侧用户列表单独勾选或者全选的方式加上该用户,该角色的状态仍为半选;
(2)区域上方的全选框可以区分全选和半选,而每个区域的复选框不能严格区分半选和全选:
如执行用户添加动作,对应的区域均为全选,执行用户删除操作时,所属区域状态变为半选,再次添加上删除的用户,区域仍为半选