提醒自己:
这是之前的逻辑,或许你重新写会有更好的方法,可以参考逻辑!!!
功能介绍
1.有面包屑点击切换
2.有公司、部门、人员
3.单选、多选实现
4.编辑/回显
5.使用随意切换层级和跳转到指定层级回显等功能
效果图:
点击跳转到组件主要内容区域:
数据结构
{
"children":[{}],//子级数据
"type" : 0, // type:0-主企业,2-子企业,1-部门
"comNo" : "1543782809XXXXX",
"teamNo" : null,
"name" : "XXXXXXXX有限公司",
"id" : "1",
"count" : 0,
"parentId" : "",
"contacts": [ {
"name" : "刘XXX",
"icon" : "", // 头像
"memberNo" : "111111111111111111",
"phone" : "17XXXXXXXXX",
"departmentId": [ "1", "62d6591fa965ea000xxxxx"],
"department" : "[["1"],["1","62d6591fa965ea00012xxxxxxx"]
"departmentName" : ""
}
] //人员数据
}
第一级父级:调用UI组件
<basicCompanyInfo @applySubjectData="getApplySubjectData" class="basic-company-info">
js:
// 获取申请公司部门数据
getApplySubjectData(val) {
let { aCompany, aCompanyName, aDepartment, aDepartmentName, name, memberNo } = val
this.dataDTO = {
companyId:aCompany,
companyName:aCompanyName,
departmentName:aDepartmentName,
departmentNo:aDepartment,
userName: name,
userId: memberNo
}
},
第二级需求UI组件:实现交互
<!-- 组织架构选单位/部门/经办人 -->
<template>
<div class="basic-company-info">
<van-cell @click="goOrgChoose" :value="applySubjectData.aCompanyName">
<template #title>
<div class="required-label">申请单位</div>
</template>
<template #right-icon>
<img src="@/assets/img/icon_right.png" alt="" class="icon_right ml10">
</template>
</van-cell>
<van-cell title="申请部门"
:value="!dataState && !applySubjectData.aCompanyName ? '' : (applySubjectData.aDepartmentName ? applySubjectData.aDepartmentName : '该人员未分配部门')" @click="(event) => goOrgChoose(event,2)">
<template #right-icon>
<img src="@/assets/img/icon_right.png" alt="" class="icon_right ml10">
</template>
</van-cell>
<van-cell :value="applySubjectData.name" @click="(event)=> goOrgChoose(event,3)">
<template #title>
<div class="required-label">经办人</div>
</template>
<template #right-icon>
<img src="@/assets/img/icon_right.png" alt="" class="icon_right ml10">
</template>
</van-cell>
<van-cell title="" value="" v-show="$router.path=='/reapply'" />
</div>
</template>
<script>
import eventBus from "@/utils/eventBus";
import apiOrder from "@/api/apiOrder";
export default {
name: "basicCompanyInfo",
data(){
return{
dataState:false,
keyName:1,
checkData:[],
applySubjectData:{},
}
},
props:{
applypropsData:{ // 申请单位/部门/经办人的数据
type:Object,
default:()=>({})
}
},
computed:{
userBaseData(){ // 用户信息
return this.$store.state.user.userInfo;
}
},
watch:{
applypropsData:{
handler(val){
if(val&&this.$route.query.type==1){
this.initapply()
}
},
deep:true
}
},
created() {
eventBus.$off(`corporateDepartment${this.keyName}`)
eventBus.$on(`corporateDepartment${this.keyName}`, function(data){ // 接收组织架构的数据
this.setOrderBaseData(data);
}.bind(this));
},
mounted() {
if (this.$route.query.type==1) {
this.initapply()
}else{
this.getCheckData()
}
},
methods:{
initapply(){
this.applySubjectData=this.applypropsData
this.applySubjectData.name=this.applypropsData.aPersonName
this.applySubjectData.managerId=this.applypropsData.aPerson
},
// 赋值选中的数据
async getCheckData(){
if(this.applySubjectData.aCompany){ // 有选中公司部门的情况回显
this.checkData = [this.applySubjectData];
}else {// 第一次进来默认登录信息
let userInfo;
let res = await apiOrder.findDefaultDept(); // 获取默认部门
if (res.code == 200) {
let defaultDept = res.data;
userInfo = {
companyId: defaultDept.id,
departmentName: defaultDept.departmentName,
departmentNo: defaultDept.departmentNo
}
}
let userBaseData = {...this.userBaseData, ...userInfo};
this.initBase(userBaseData)
}
},
// 初始化数据-取自state用户信息
async initBase(data){
// console.log("初始化数据-取自state用户信息",data)
let list = {
aCompany:data.companyInfo?.no, // 用户信息的公司id与组织架构的公司id不一致,所以按组织架构为准:一级公司id:1
aCompanyName:data.companyInfo?.name,
aDepartment:data.departmentNo,
aDepartmentName:data.departmentName,
memberNo:data.personNo,
icon:data.icon,
name:data.realName,
phone:data.telPhone,
};
this.setOrderBaseData([list])
this.checkData = [list];
},
// 去选择组织架构
goOrgChoose(ev,type){ // 1-企业,2-部门,3-人员
this.$emit('changeData')
// return
this.$store.commit('common/updateOrgStructureSelection', this.checkData); // 改变默认勾选数据
this.$router.push({ path:'/organizationalStructure', query:{ key:this.keyName,levelType:type }})
},
// 公司部门数据获取
setOrderBaseData(data){
let val = data && data[0];
this.dataState = false;
if(val){
this.dataState = true;
this.applySubjectData = {...this.applySubjectData,...val};
this.$emit('applySubjectData',this.applySubjectData)
}
}
}
}
</script>
<style scoped lang="scss">
// css根据需求自定义
</style>
组件主要全部代码:
<!-- 组织架构选人/选公司/选部门-->
<template>
<div class="org-structure">
<div class="org-structure-content topNavPt">
<!-- 导航部分 -->
<topNavigation v-if="isShow" :title="breadCrumbsData.length > 0 ? breadCrumbsData[0].name : navTitle"></topNavigation>
<!-- 面包屑 -->
<div class="bread-crumbs bag-fff" v-if="breadCrumbsData.length > 0">
<div class="bread-crumbs-content" v-for="(item,index) in breadCrumbsData" :key="item.id" @click="goBack(item,index)">
<span :class="index == breadCrumbsData.length - 1 ? 'bread-crumbs-content-company cl969696' : 'bread-crumbs-content-company'">{{ item.name }}</span>
<img src="../../assets/img/icon_right.png" alt="" class="icon_right">
</div>
</div>
<!-- 公司级别/部门级别 -->
<div class="pl15 bag-fff">
<!-- 一级公司 -->
<div v-if="!chooseFirstOrder" class="company-cell-content" @click="chooseOrgOrDepartment(orgList)">
<van-checkbox v-model="checkByDefaultData">{{ orgList.name }}</van-checkbox>
<img src="../../assets/img/icon_right.png" alt="" class="icon_right mr15">
</div>
<!-- 二级及以下公司部门 -->
<div v-else>
<div v-for="item in chooseOrgList" :key="item.id" @click="chooseOrgOrDepartment(item)" class="company-cell-content">
<van-checkbox :class="item.children.length === 0 && item.contacts.length === 0 && item.parentId != 1 ? 'disable-orderBaseCss.scss' : ''" v-model="item.checked">{{ item.name }}
<span>{{ `(${item.count})` }}</span>
</van-checkbox>
<img src="../../assets/img/icon_right.png" alt="" class="icon_right mr15">
</div>
</div>
</div>
<!-- 人员级别 -->
<div v-if="contactsList" class="pl15 bag-fff mt10">
<!-- 单选/多选 -->
<div class="company-cell-content company-personnel" v-for="list in contactsList">
<van-checkbox-group v-model="checkedData" ref="checkboxGroup">
<van-checkbox :name="list.memberNo" checked-color="#5792FD" @click="(event) => handleChecked(event,list,multipleState)">
{{ list.name }}</van-checkbox>
</van-checkbox-group>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="bottom-btn-box flex-ai-jc" :style="checkedFinallyData.length > 0 ? '' : 'background: #f9a39c;'" @click="submit">
<span>提交{{ multipleState && checkedData.length ? `(已选${checkedData.length}人)` : ''}}</span>
</div>
</div>
</template>
<script>
import apiOrder from '@/api/apiOrder'
import eventBus from "@/utils/eventBus";
export default {
name: "organizationalStructure",
components:{
topNavigation:() => import('@/views/shopBus/components/topNavigation')
},
props:{
multipleSelection:{ // 多选/单选
type: Boolean,
default: false
},
navName:{
type: String,
default: "请选择经办人"
},
isShow:{
type: Boolean,
default: true
},
returnState:{ // 标记是否父子级反参-true父子
type: Boolean,
default: false
},
chooseData:{
type:Array,
default:()=>[]
},
levelType:{
type:String,
default:''
}
},
data(){
return{
orgList: [],
chooseOrgList:[],// 组织相关架构
chooseFirstOrder:false, // 是否有一级
breadCrumbsData:[], // 面包屑数据
contactsList:[],// 人员相关数据
checkedData:[], // 勾选数据
checkedFinallyData:[],// 最终传参数据
existData:[],// 之前已存在的值-备份一份
keyName:null,
submitState:false
}
},
computed:{
// 以下数据都是为了区分路由跳转还是父子组件使用
navTitle(){
return this.$route.query && this.$route.query.navName ? this.$route.query.navName : this.navName;
},
multipleState(){
return this.$route.query && this.$route.query.multipleSelection ? this.$route.query.multipleSelection : this.multipleSelection;
},
checkByDefaultData(){
return this.returnState ? this.chooseData : this.$store.state.common.orgStructureSelection && JSON.parse(JSON.stringify(this.$store.state.common.orgStructureSelection))
},
levelState(){ // 1-企业,2-部门,3-人员 --自己定义的
return this.$route.query && this.$route.query.levelType || this.levelType
}
},
created() {
this.keyName = this.$route.query && this.$route.query.key; // 得到唯一key值,便于反参到上一个页面
this.getOrgList();
},
mounted() {
if(this.checkByDefaultData.length > 0){ // 有勾选值的话需要初始化已有的数据
this.checkedData = this.checkByDefaultData.map(item => item.memberNo);
this.existData = this.checkByDefaultData;
}
},
methods:{
// 组织架构数据
async getOrgList(){
let res = await apiOrder.getOrganization();
if(res.code == 200 ){
this.orgList = res.data;
if(this.levelState > 0){ // 有需要跳转到指定层级的情况
this.levelInitShow(this.levelState)
}
}
},
// 点击公司或者部门
chooseOrgOrDepartment(val){
if(val.id == 1){
this.chooseFirstOrder = true;
}
if(!this.breadCrumbsData.find(i => i.id === val.id) && (val.children && val.children.length > 0 || val.contacts && val.contacts.length > 0)){ // 不是重复点击 && 有部门或者有人员
this.breadCrumbsData.push({ id:val.id,name:val.name,type:val.type }); // 面包屑数据 type:0-主企业,2-子企业,1-部门
this.chooseOrgList = [];
// 下一级有数据情况
if(val.children.length > 0){
this.chooseOrgList = val.children; // 组织数据
if(this.checkByDefaultData && this.checkByDefaultData.length > 0){ // 如果有选中的数据,勾选上
this.chooseOrgList = this.chooseOrgList.map(item =>{
let state = this.checkByDefaultData.some(i => (item.type == 2 ? i.aCompany : i.aDepartment) === item.id);
return state ? {...item,checked:true} : {...item,checked:false} // 判断是否需要勾选
})
}
}
// 有人员数据
if(val.contacts.length > 0){
this.contactsList = [...val.contacts]; // 人员数据
if(this.checkByDefaultData && this.checkByDefaultData.length > 0) { // 如果有选中的数据,勾选上
this.contactsList.forEach(per => {
let state = this.checkByDefaultData.some(i => i.memberNo === per.memberNo);
let perState = this.checkedData.some(id => id === per.memberNo); // 判断是否有此人员
if(state && !perState){
this.multipleState ? this.checkedData.push(per.memberNo) : this.checkedData = [per.memberNo];
}
})
}
}
}
},
// 点击面包屑回退
goBack(val,inx){
if(val.id !== this.breadCrumbsData[this.breadCrumbsData.length - 1].id){ // 当前级时不执行筛选
this.breadCrumbsData.splice(inx); // 首先清除面包屑后面的数据
let treeData = this.getItemByIdInTree(this.orgList,val.id);
this.chooseOrgOrDepartment(treeData);
}
},
// 通过某个节点的id,获取该节点的完整信息
getItemByIdInTree(tree,value){
if(tree.id === value){
return tree;
} else {
if(tree.children && tree.children.length > 0){
for(let i = 0; i < tree.children.length; i++){
let resultD = this.getItemByIdInTree(tree.children[i],value);
if(resultD){
return {...resultD};
}
}
}
}
},
// 通过人员id查找相应节点
getMemberNoInTree(tree,id){
if(tree.memberNo === id){
return tree;
} else {
if (tree.contacts && tree.contacts.length > 0) {
for (let i = 0; i < tree.contacts.length; i++) {
let resultD = this.getMemberNoInTree(tree.contacts[i], id);
if (resultD) {
return resultD;
}
}
}
if (tree.children && tree.children.length > 0) {
for (let i = 0; i < tree.children.length; i++) {
let resultD = this.getMemberNoInTree(tree.children[i],id);
if(resultD){
return {...resultD};
}
}
}
}
},
// 根据树子节点ID查找所有父节点 - data:要遍历的数据, target:查找目标, result用于装查找结果的数组
findParent(node, target, result) {
if(node.id === target.id){
if( this.levelState == 3 ){ // 到人员的级别
result.unshift(node);
}
return true;
}
if (node.children && node.children.length > 0) { // 如果当前节点有子节点,则继续遍历子节点
for (const childNode of node.children) {
if (this.findParent(childNode, target, result)) { // 如果在子节点中找到了子节点的父节点,则将当前节点的ID添加到父节点ID数组中,并返回true表示已经找到了子节点
result.unshift(node);
return true;
}
}
}
// for (let i in node) { // 方法二
// let item = node[i]
// if (item.id === target.id) {
// //将查找到的目标数据加入结果数组中
// result.unshift(item)
// return true
// }
// if (item.children && item.children.length > 0) {
// let ok = this.findParent(item.children, target, result)
// if (ok) {
// result.unshift(item)
// return true
// }
// }
// }
//走到这说明没找到目标
return false
},
// 根据type来指定展示到某个级别-例如部门跳转过来就指定到部门级别
levelInitShow(type){ // 1-企业,2-部门,3-人员
let arr = this.checkByDefaultData[0];
if(arr){
let target = { // 企业使用公司id,部门使用部门id(如果没有部门默认打开公司)
id:type == 1 ? arr.aCompany : (arr.aDepartment ? arr.aDepartment : arr.aCompany),
name:type == 1 ? arr.aCompanyName : (arr.aDepartmentName && arr.aDepartmentName ? arr.aDepartmentName : arr.aCompanyName)
}
let result = [];
this.findParent(this.orgList, target, result,arr);
result.forEach(item =>{
this.chooseOrgOrDepartment(item)
})
console.log('指定层级展开:',arr,result,target)
}
},
// 选择人员
handleChecked(ev,val,moreChoose){
let aDepartment,company,per;
if(!moreChoose){ // 单选
this.checkedData = [val.memberNo];
}
this.checkedFinallyData = []; // 初始化
this.checkedData.forEach(user => {
// 通过面包屑数据确定公司和部门
company = this.breadCrumbsData.find(item => item.type == 2); // 0 是主企业 2 是子企业 1 部门
aDepartment = this.breadCrumbsData[this.breadCrumbsData.length - 1];
if(!company){ // 没有查到子公司则使用主企业
company = this.breadCrumbsData.find(item => item.type == 0);
}
// 人员数据
per = this.getMemberNoInTree(this.orgList,user);
let data = {
aCompany:company.id, // 申请单位NO
aCompanyName:company.name, // 申请单位名称
aDepartment:!this.breadCrumbsData.find(item => item.type == 1) ? '' : aDepartment.id, // 申请部门NO - 多级取最后一个部门/排除第一级公司;都没有部门则为空
aDepartmentName:!this.breadCrumbsData.find(item => item.type == 1) ? '' : aDepartment.name, // 申请部门名称
memberNo:per.memberNo,
icon:per.icon,
name:per.name,
phone:per.phone,
per:per,
}
this.checkedFinallyData.push(data);
})
},
// 提交
submit(){
if(this.checkedFinallyData.length > 0){
this.submitState = true; // 是否点击提交
this.$router.back();
if(this.returnState){ // 直接父子组件反参
this.$emit('corporateDepartment',this.checkedFinallyData)
}
}
}
},
beforeDestroy(){
if(!this.returnState && this.submitState){ // 不是父子级反参的情况
eventBus.$emit(`corporateDepartment${this.keyName}`,this.checkedFinallyData,true)
}else if(!this.returnState && !this.submitState){ // 不是父子级反参 && 不是点的提交-反参之前的数据
eventBus.$emit(`corporateDepartment${this.keyName}`,this.existData,false)
}
}
}
</script>
<style scoped lang="scss">
// css自定义
</style>