瀏覽代碼

创建项目

ZaiZai 10 月之前
父節點
當前提交
2dd09db241
共有 2 個文件被更改,包括 210 次插入12 次删除
  1. 3 0
      src/views/project/info/style/template.scss
  2. 207 12
      src/views/project/info/template.vue

+ 3 - 0
src/views/project/info/style/template.scss

@@ -38,6 +38,9 @@
             align-items: center;
             justify-content: center;
             padding: 0 14px;
+            .el-button[hc-btn] {
+                border-radius: 3px
+            }
         }
         .right {
             position: relative;

+ 207 - 12
src/views/project/info/template.vue

@@ -12,31 +12,39 @@
             </el-select>
         </div>
         <div class="wbs-template-body">
-            <div class="left">
-                <hc-card-item scrollbar title="7020项">
+            <div v-loading="leftLoading" class="left">
+                <hc-card-item scrollbar :title="`${leftNum}项`">
                     <template #extra>
-                        <el-checkbox v-model="allChecked" label="默认全部引用" size="large" />
+                        <el-checkbox v-model="allChecked" label="默认全部引用" size="large" @change="checkChang" />
                     </template>
-                    内容区域
+                    <el-tree
+                        ref="leftTreeRef" :data="leftTreeData" show-checkbox node-key="id" :props="treeProps"
+                        highlight-current :expand-on-click-node="false" @node-expand="nodeLeftTreeExpand"
+                        @check-change="checkLeftTreeChange"
+                    />
                 </hc-card-item>
             </div>
             <div class="action">
                 <div class="relative">
                     <div class="relative">
-                        <el-button hc-btn style="border-radius: 3px">
+                        <el-button hc-btn :type="leftNum <= 0 ? '' : 'primary'" :disabled="leftNum <= 0" @click="addTreeClick">
                             <i class="i-ri-arrow-right-line" />
                         </el-button>
                     </div>
                     <div class="relative mt-14px">
-                        <el-button hc-btn style="border-radius: 3px">
+                        <el-button hc-btn :type="rightNum <= 0 ? '' : 'primary'" :disabled="rightNum <= 0" @click="delTreeClick">
                             <i class="i-ri-arrow-left-line" />
                         </el-button>
                     </div>
                 </div>
             </div>
-            <div class="right">
-                <hc-card-item scrollbar title="0项">
-                    内容区域
+            <div v-loading="rightLoading" class="right">
+                <hc-card-item scrollbar :title="`${rightNum}项`">
+                    <el-tree
+                        ref="rightTreeRef" :data="rightTreeData" show-checkbox node-key="id" :props="treeProps"
+                        highlight-current :expand-on-click-node="false" :default-expanded-keys="rightExpands"
+                        @check-change="checkRightTreeChange"
+                    />
                 </hc-card-item>
             </div>
         </div>
@@ -44,9 +52,9 @@
 </template>
 
 <script setup>
-import { onMounted, ref, watch } from 'vue'
+import { nextTick, onMounted, ref, watch } from 'vue'
 import { useAppStore } from '~src/store'
-import { getArrValue, getObjValue, isNullES } from 'js-fast-way'
+import { deepClone, getArrValue, getObjValue, isNullES } from 'js-fast-way'
 import mainApi from '~api/project/project'
 import treeApi from '~api/wbs/tree'
 
@@ -82,6 +90,14 @@ const templateTypeData = [
     { value: 3, label: '计量' }, { value: 5, label: '征拆' },
 ]
 
+//树配置
+const leftTreeRef = ref(null)
+const rightTreeRef = ref(null)
+const treeProps = {
+    children: 'children',
+    label: 'title',
+}
+
 //获取WBS树列表
 const wbsId = ref('')
 const wbsTreeList = ref([])
@@ -167,7 +183,7 @@ const rightLoading = ref(false)
 const rightTreeData = ref([])
 const getRightTreeApi = async () => {
     rightLoading.value = true
-    //isDisabled.value = true
+    isDisabled.value = true
     let refId = referenceWbsId.value
     if (isNullES(refId)) {
         isDisabled.value = false
@@ -212,10 +228,189 @@ const getRightTreeApi = async () => {
     const projectTree = getArrValue(data)
     isDisabled.value = projectTree.length > 0
     rightTreeData.value = projectTree
+    setRightTree()
     rightLoading.value = false
 }
 
+//默认全部引用
 const allChecked = ref(false)
+const checkChang = () => {
+    setCheckTreeChange()
+}
+
+//左边树被展开
+const rightExpands = ref([])
+const nodeLeftTreeExpand = (data) => {
+    rightExpands.value = rightExpands.value.concat([data.id])
+}
+
+//左边树复选框被点击
+const leftNum = ref(0)
+const checkLeftTreeChange = () => {
+    const e = leftTreeRef.value
+    let checkNum = e.getCheckedKeys().length
+    let halfNum = e.getHalfCheckedKeys().length
+    leftNum.value = checkNum + halfNum
+}
+
+//右边树复选框被点击
+const rightNum = ref(0)
+const checkRightTreeChange = () => {
+    const e = rightTreeRef.value
+    let checkNum = e.getCheckedKeys().length
+    let halfNum = e.getHalfCheckedKeys().length
+    rightNum.value = checkNum + halfNum
+}
+
+//左边树新增到右边
+const addTreeClick = () => {
+    const left = leftTreeRef.value, right = rightTreeRef.value
+    if (rightTreeData.value.length < 1) {
+        //直接把左边勾选的树复制到右侧
+        let allTree = deepClone(leftTreeData.value)
+        const halfKeys = right.getHalfCheckedKeys()
+        const keys = right.getCheckedKeys().concat(halfKeys)
+        getRightTree(allTree, keys)
+        rightTreeData.value = allTree
+        setCheckTreeChange(rightTreeData.value)
+    } else {
+        //只增加右侧树没有的节点,不会覆盖右侧树多余的节点
+        let checkNodes = right.getCheckedNodes(false, true)
+
+        let rIdMap = new Map()
+        checkNodes.forEach((data) => {
+            rIdMap.set(data.id, data)
+        })
+
+        let lIdSet = new Set()
+        getRightTreeData(lIdSet, rightTreeData.value)
+
+        //在右侧id减去左侧有的id,剩下的就是新增的id
+        lIdSet.forEach((id) => {
+            rIdMap.delete(id)
+        })
+
+        let addMap = new Map()
+        rIdMap.forEach((data) => {
+            if (data.parentId !== '0' && data.parentId !== 0) {
+                //在左侧树能找到父节点的,新增
+                let lNode = right.getNode(data.parentId)
+                if (lNode) addMap.set(data, lNode.data.id)
+            }
+        })
+
+        //把半选和选中的数组key合并
+        const halfKeys = left.getHalfCheckedKeys()
+        const keys = left.getCheckedKeys().concat(halfKeys)
+        const myArray = Array.from(addMap.keys())
+        let myright = deepClone(myArray)
+        getRightTree(myright, keys)
+        myright.forEach((data) => {
+            right.append(data, data.parentId)
+        })
+    }
+}
+
+//获取右边树
+const getRightTree = (arr, keys) => {
+    //对比所有的node和选中的key
+    for (let i = arr.length - 1; i >= 0; i--) {
+        let isIn = false
+        for (let j = keys.length - 1; j >= 0; j--) {
+            if (keys[j] === arr[i].id) {
+                isIn = true
+                //已经匹配到的key移除,节省性能
+                keys.splice(j, 1)
+                break
+            }
+        }
+        if (isIn) {
+            //包含在选中的节点,如果有childer继续递归判断
+            if (arr[i].children && arr[i].children.length) {
+                getRightTree(arr[i].children, keys)
+            }
+        } else {
+            //不包含在选中key的node删除
+            arr.splice(i, 1)
+        }
+    }
+}
+
+const getRightTreeData = (set, arr) => {
+    arr.forEach((data) => {
+        set.add(data.id)
+        if (data.children && data.children.length) {
+            getRightTreeData(set, data.children)
+        }
+    })
+}
+
+//右边树移除
+const delTreeClick = () => {
+    const left = leftTreeRef.value, right = rightTreeRef.value
+    let delNodes = right.getCheckedNodes()
+    //只把选中的节点移除
+    delNodes.forEach((node) => {
+        right.remove(node)
+        left.setChecked(node.id, false)
+    })
+    checkLeftTreeChange()
+    checkRightTreeChange()
+    setCheckTreeChange(delNodes)
+}
+
+const setRightTree = () => {
+    let ids = []
+    const data = rightTreeData.value
+    for (let i = 0; i < data.length; i++) {
+        getLeafIds(ids, data[i])
+    }
+    //在左边把右边的节点勾选上
+    const e = leftTreeRef.value
+    nextTick(() => {
+        e.setCheckedKeys(ids, true)
+    })
+}
+
+const getLeafIds = (ids, data) => {
+    if (data.children && data.children.length) {
+        for (let i = 0; i < data.children.length; i++) {
+            getLeafIds(ids, data.children[i])
+        }
+    } else {
+        ids.push(data.id)
+    }
+}
+
+const getTreeAllId = (name) => {
+    let tree
+    if (name === 'left') {
+        tree = leftTreeRef.value
+    } else if (name === 'right') {
+        tree = rightTreeRef.value
+    }
+    if (allChecked.value) {
+        tree = leftTreeRef.value
+    }
+    let ids = []
+    for (let i = 0; i < tree.data.length; i++) {
+        getIds(ids, tree.data[i])
+    }
+    return ids.join(',')
+}
+
+const getIds = (ids, data) => {
+    ids.push(data.id)
+    if (data.children && data.children.length) {
+        for (let i = 0; i < data.children.length; i++) {
+            getIds(ids, data.children[i])
+        }
+    }
+}
+
+const setCheckTreeChange = () => {
+
+}
 </script>
 
 <style lang="scss">