思路
- 数据是个树状形结构,每一个层级有部门和人员组合,当勾选部门后,该部门都被选中,且无法点击下一级。当只选人时,那么该人员就会被选中。
- 交互层面,选中的会被置灰,部门选中,置灰后不可进入下级。
- 选中部门时,虽然已选区域显示的部门,但是实际上选择的还是该部门下的人,且选的是当时部门下的所有人
- 当再次添加人员时,根据业务不同,有两种方式:
-
- 业务功能本身具有移除已选中的人。此时再次选人时,未选区域会回显出之前已经选中过的人,并且会置灰显示不可取消勾选;已选区域不会回显之前选中的人,而是每次进来只会显示当前已选的人或部门。
-
- 业务功能没有移除已选中的人。此时再次选人时,未选区域同样会回显之前已经选中过的人,但是不会置灰,可以取消勾选;已选区域会回显之前选中的人。
-
组件封装
主要利用两个概念理论:
- 地址引用
- 树状递归
第一步:接口数据格式分析:
children中存储的是部门相关,stadds存储的是人员。
第二步:需求分析:
需求中需要实现勾选和半勾选、全选的状态,需要在树状数据结构中添加isChecked属性,用来标记选中状态。
代码实现
第一步:定义几个存储变量:
const membersDataObj = ref({children:[]}) // 存储所有数据
const membersDataQueryList = ref([]) // 只存储所有人员,用于搜索
const searchStaffs = ref([]) //通过搜索条件,模糊查询得出的结果
const currentMembersAndDepartments = ref({children:[],staffs:[]})
const levelDatas = ref([]) // 存储层级菜单面包屑
cosnt isCheckedItems = ref([]) // 存储已选中的对象
第二步:转换数据,加装属性isChecked,层级level
const switchOrganiseData = (obj, level) => {
obj.level += 1;
if (obj.staffs && obj.staffs.length > 0) {
obj.staffs.forEach((staff) => {
staff.isChecked = false;
});
}
if (obj.children && obj.children.length > 0) {
obj.children.forEach((child) => {
child.isChecked = false;
switchOrganiseData(child, obj.level);
});
}
};
第三步:递归获取所有成员,存储到membersDataQueryList变量数组中,用于模糊查询的数据
// 递归获取所有成员
const getStaffs = (arr, staffArr) => {
arr.map((item) => {
if (item.staffs && item.staffs.length > 0) {
staffArr = staffArr.concat(item.staffs);
if (item.children && item.children.length > 0) {
staffArr = staffArr.concat(getStaffs(item.children, staffArr));
}
}
});
return staffArr;
};
部门下的成员,可能存在于多个部门下,需要去重,使用map函数
// 去重人员
const arrayNonRepeatfy = (staffArr) => {
const map = new Map();
staffArr.forEach((element) => {
if (!map.has(element.idStaff)) {
map.set(element.idStaff, element);
}
});
return Array.from(map.values());
};