<template> <div class="outer-layer"> <div> <tm-navbar :hideBack="false" hideHome title="群管理员"> </tm-navbar> </div> <div class="root"> <div class="w-full h-[1134rpx] mb-[20rpx] pl-[32rpx] pr-[32rpx] pb-[20rpx] overflow-y-auto" > <div class="pl-[16rpx] pr-[16rpx] pt-[22rpx] pb-[24rpx] bg-[#FFFFFF]"> <tm-input placeholder="请输入…" color="#F9F9FD" :round="1" prefix="tmicon-search" prefixColor="#46299D" searchBgColor="#F9F9FD" focusColor="#F9F9FD" v-model="searchVal" ></tm-input> <div v-if="crumbs.length" class="w-full overflow-x-auto mt-[22rpx] leading-[48rpx] text-[#2F2F2F] flex items-center no-scrollbar" ref="crumbsContainer" > <div v-for="(item, index) in crumbs" class="flex items-center text-[28rpx] leading-[48rpx] whitespace-nowrap" :class="[ index === crumbsIndex ? 'text-[#747474]' : 'text-[#46299D]', index === 0 ? '' : 'ml-[12rpx]', ]" @click="handleCrumbsClick(index)" > <div>{{ item.name }}</div> <div v-if="index !== crumbs.length - 1" class="ml-[20rpx] flex items-center mb-[2rpx]" > <tm-icon name="tmicon-angle-right" :font-size="20" :color="index !== crumbs.length - 1 ? '#7A58DE' : '#C1B4EA'" ></tm-icon> </div> </div> </div> </div> <!-- <div class="pl-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center" @click="()=>allCheck(allCheckStatus)" > <div> <checkBox :disabled="currentCrumbs?.sons?.length === 0" :modelValue="allCheckStatus" ></checkBox> </div> <div class="font-bold text-[28rpx] leading-[54rpx] ml-[20rpx]"> 全选 </div> </div> --> <div v-if="currentCrumbs?.sons?.length" v-for="item in currentCrumbs?.sons" class="pl-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center" > <div class="w-full flex items-center justify-between"> <div class="flex items-center" > <div> <!-- <checkBox :disabled="!item?.sons?.length" v-model="item.checkStatus" @change="(val) => checkItemChange(item, val)" ></checkBox> --> </div> <div class="font-bold text-[28rpx] leading-[54rpx] ml-[20rpx]"> {{ item.name }} </div> </div> <div class="flex items-center mr-[32rpx]"> <div class="vDivider mr-[32rpx]"></div> <div @click="() => toNextLevel(item)" class="flex items-center"> <div class="mr-[12rpx]"> <tm-image :width="26" :height="26" :src="item.checkStatus !== 'checked' ? downDep : downDepDis" ></tm-image> </div> <div class="text-[28rpx] leading-[54rpx] font-bold" :class=" item.checkStatus !== 'checked' ? 'text-[#46299D]' : 'text-[#C1B4EA]' " > 下级 </div> </div> </div> </div> </div> <div v-if="currentCrumbs?.positions?.length" v-for="item in currentCrumbs?.positions" class="pl-[32rpx] bg-[#FFFFFF] mt-[20rpx] h-[110rpx] flex items-center" > <div class="w-full flex items-center justify-between"> <div class="flex items-center" > <div> <checkBox :disabled="!item?.sons?.length" :modelValue="choosePostList.find(v=>v.ID === item.ID)?'checked':'noChecked'" @change="(val) => checkItemChange(item, val)" ></checkBox> </div> <div class="font-bold text-[28rpx] leading-[54rpx] ml-[20rpx]"> {{ item.name }} </div> </div> </div> </div> </div> <div class="h-[162rpx] pl-[32rpx] pr-[32rpx] bg-[#FFFFFF]"> <div class="mt-[14rpx] flex justify-between"> <div class="flex flex-col"> <div @click="openDrawer" class="flex items-center text-[28rpx] leading-[60rpx] text-[#000000] font-bold"> <div>已选择岗位数:</div> <div>{{ choosePostList.length }}</div> <div class="ml-[28rpx]"> <tm-icon :fontSize="24" color="#46299D" name="tmicon-angle-up"></tm-icon> </div> </div> <div class="text-[24rpx] leading-[24rpx] text-[#7A58DE] w-[280rpx] truncate"> {{ choosePostList.map(v=>v.name).toString() }} </div> </div> <div class="btnBox"> <tm-button @click="handleConfirm" color="#46299D" :disabled="!choosePostList.length" disabledColor="#E6E6E6" :margin="[0]" :shadow="0" :width="264" :height="76" size="large" label="确定" > </tm-button> </div> </div> </div> </div> <tm-drawer placement="bottom" v-model:show="showWin" :height="800" :hideHeader="true" :round="5" > <div class="flex flex-col w-full h-full pt-[36rpx] pl-[32rpx] pr-[32rpx] leading-[60rpx]" > <div class="text-[32rpx] font-bold flex items-center justify-between" > <div class="flex items-center ml-[10rpx]"> <div>已选择岗位数:</div> <div>{{ choosePostList.length }}</div> </div> <div class="text-[#7A58DE] mr-[10rpx]" @click="()=>showWin = false" > 确定 </div> </div> <div class="flex-1 pb-[20rpx] overflow-y-auto pt-[30rpx]" > <div v-for="(item,index) in choosePostList" class="flex flex-col" > <div v-if="index ===0" class="divider" ></div> <div class="flex items-center justify-between mt-[36rpx] font-bold text-[#000000] leading-[54rpx] mb-[34rpx]" > <div class="text-[28rpx] ml-[10rpx]">{{ item.departmentName }}-{{ item.name }}</div> <div class="diyBtn"> <tm-button @click="()=>deleteNode(item)" :disabled="userDepIds.includes(item.ID)" :margin="[10]" :shadow="0" text size="small" :width="106" :height="50" outlined label="移除"></tm-button> </div> </div> <div class="divider" ></div> </div> </div> </div> </tm-drawer> </div> </template> <script setup> import { ref, watch, computed, onMounted,nextTick } from "vue"; import { onShow, onLoad } from "@dcloudio/uni-app"; import { useChatList } from "@/store/chatList/index.js"; import { useAuth } from "@/store/auth"; import { useTalkStore, useUserStore } from "@/store"; import { useGroupTypeStore } from "@/store/groupType"; import downDep from "@/static/image/chatList/downDep.png"; import downDepDis from "@/static/image/chatList/downDepDis.png"; import checkBox from "@/components/checkBox/index.vue"; import lodash from 'lodash' const { groupActiveIndex, getPositionsTree, postTreeList, crumbs, crumbsIndex, depCheckedKeys, groupAdmins, } = useGroupTypeStore(); const userStore = useUserStore() // 1 groupAdmin 2 groupMember const pageType = ref(1); const searchVal = ref(""); const crumbsContainer = ref(null); const showWin = ref(false); const choosePostList = ref([]) const getAllCheckedNodes = (node, checkedNodes = []) => { if (node.checkStatus === 'checked') { checkedNodes.push(node); } if (node.sons && Array.isArray(node.sons)) { node.sons.forEach(son => getAllCheckedNodes(son, checkedNodes)); } return checkedNodes; }; const userDepIds = computed(() => { return userStore.deps.map(v=>v.dept_id); }); const currentCrumbs = computed(() => { if (crumbs.value[crumbsIndex.value] ) { if (searchVal.value && searchVal.value !== "") { let filterSons = crumbs.value[crumbsIndex.value].sons.filter((item) => item.name.includes(searchVal.value) ); return { ...crumbs.value[crumbsIndex.value], sons: filterSons, }; } console.log("allCheckedList", crumbs.value[crumbsIndex.value]); return crumbs.value[crumbsIndex.value]; } return {} }); // const allCheckStatus = computed(() => { // if (!currentCrumbs.value.sons) { // return "noChecked"; // } // const allChecked = currentCrumbs.value.sons.every((son) => son.checkStatus === "checked"); // const someChecked =currentCrumbs.value.sons.some( // (son) => // son.checkStatus === "checked" || son.checkStatus === "halfChecked" // ); // if (allChecked) { // return "checked"; // } else if (someChecked) { // return "halfChecked"; // } else { // return "noChecked"; // } // }) const findNodeById = (node, targetId) => { if (node.ID === targetId) { return node; } if (node.sons && Array.isArray(node.sons)) { for (const son of node.sons) { const found = findNodeById(son, targetId); if (found) { return found; } } } return null; }; const findParentNode = (node, targetId) => { if (!node.sons || !Array.isArray(node.sons)) return null; for (const son of node.sons) { if (son.ID === targetId) { return node; } const parent = findParentNode(son, targetId); if (parent) { return parent; } } return null; }; // 检查并更新父节点的状态 const updateParentStatus = (node) => { const parent = findParentNode(postTreeList.value[0], node.ID); if (!parent) return; if (parent.checkStatus !== "checked"){ const allChecked = parent.sons && Array.isArray(parent.sons) && parent.sons.every((son) => son.checkStatus === "checked"); const someChecked = parent.sons && Array.isArray(parent.sons) && parent.sons.some( (son) => son.checkStatus === "checked" || son.checkStatus === "halfChecked" ); if (allChecked) { parent.checkStatus = "halfChecked"; } else if (someChecked) { parent.checkStatus = "halfChecked"; } else { parent.checkStatus = "noChecked"; } } updateParentStatus(parent); }; //根据子节点状态更新当前节点状态 const updateNodeStatus = (node) => { if (!node.sons || !Array.isArray(node.sons)) return; const allChecked = node.sons.every(son => son.checkStatus === 'checked'); const someChecked = node.sons.some(son => son.checkStatus === 'checked' || son.checkStatus === 'halfChecked'); if (allChecked) { node.checkStatus = 'halfChecked'; } else if (someChecked) { node.checkStatus = 'halfChecked'; } else { node.checkStatus = 'noChecked'; } }; // 更新当前节点及其所有子节点的状态 const updateCheckStatus = (node, status) => { node.checkStatus = status; if (node.sons && Array.isArray(node.sons) && node.sons.length > 0) { node.sons.forEach((son) => updateCheckStatus(son, status)); } }; const checkItemChange = (item, val) => { if (val === 'checked') { let depItem = findNodeById(postTreeList.value[0],item.departmentID) choosePostList.value.push({ ...item, departmentName:depItem.name, }) }else{ choosePostList.value = choosePostList.value.filter(v=>v.ID !== item.ID) } }; const deleteNode = (item) => { choosePostList.value = choosePostList.value.filter(v=>v.ID !== item.ID) }; const toNextLevel = async (item) => { if (item.checkStatus !== "checked") { crumbs.value.push(item); crumbsIndex.value++; await nextTick(); if (crumbsContainer.value) { crumbsContainer.value.scrollLeft = crumbsContainer.value.scrollWidth; } } }; const handleCrumbsClick = (index) => { crumbsIndex.value = index; crumbs.value = crumbs.value.slice(0, index + 1); }; // const allCheck = (status) => { // let statusT = 'noChecked'; // if (status === "checked") { // statusT = "noChecked"; // } else { // statusT = "checked"; // } // currentCrumbs.value.sons.forEach((item) => { // const itemT = findNodeById(postTreeList.value[0], item.ID) // if (!itemT) return; // checkItemChange(itemT, statusT); // }); // }; const openDrawer = () => { showWin.value = true; if (allCheckedList.length>0) { } }; watch(() => postTreeList.value, (newValue, oldValue) => { console.log("postTreeList", newValue); }, { deep: true }); // watch(() => searchVal.value, (newValue, oldValue) => { // console.log("searchVal", newValue); // }); const handleConfirm = () => { groupAdmins.value = lodash.cloneDeep(choosePostList.value) console.log("groupAdmins", groupAdmins.value); uni.navigateBack(); } const initCheckedKeys = () => { choosePostList.value = groupAdmins.value }; const init = async () => { crumbsIndex.value = 0; await getPositionsTree(); crumbs.value = postTreeList.value.length ? [postTreeList.value[0]] : []; initCheckedKeys(); }; onMounted(() => { init(); }); </script> <style scoped lang="scss"> uni-page-body, page { height: 100%; } .outer-layer { overflow-y: auto; flex: 1; background-image: url("@/static/image/clockIn/z3280@3x.png"); background-size: cover; padding-bottom: 0; display: flex; flex-direction: column; } .root { flex: 1; display: flex; flex-direction: column; justify-content: space-between; padding-top: 18rpx; overflow: hidden; } .divider { height: 1rpx; background-color: #707070; opacity: 0.1; } .vDivider { width: 1rpx; height: 48rpx; background-color: #b4b4b4; } .avatar-placeholder { width: 192rpx; height: 192rpx; background-color: #e0e0e0; border-radius: 50%; margin-bottom: 40rpx; } .groupCard { height: 272rpx; width: 100%; background-size: cover; background-position: center; background-repeat: no-repeat; border-radius: 12rpx; &.firstPanel { background-image: url("@/static/image/chatList/zu6033@2x.png"); } &.secondPanel { background-image: url("@/static/image/chatList/zu6031@2x.png"); margin-top: 28rpx; margin-bottom: 28rpx; } &.thirdPanel { background-image: url("@/static/image/chatList/zu6032@2x.png"); } &.activePanel { box-shadow: 0 0 0 3rpx #46299d; } } .btnBox { :deep(uni-button[disabled="true"]) { color: #bebebe !important; } } .no-scrollbar { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } .no-scrollbar::-webkit-scrollbar { display: none; /* Chrome, Safari, and Opera */ } .diyBtn { :deep(uni-button) { color: #191919 !important; border: 1rpx solid #D6D6D8 !important; background-color: #FFFFFF !important; &[disabled="true"] { color: #BEBEBE !important; border: 1rpx solid #E6E6E6 !important; background-color: #E6E6E6 !important; } } } </style>