123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- <template>
- <div class="hc-contract-info-wbs relative h-full">
- <div class="wbs-template-body">
- <div v-loading="leftLoading" class="left">
- <hc-card-item scrollbar :title="`${leftNum}项`">
- <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="btn-action">
- <div class="relative">
- <div class="relative">
- <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 :type="rightNum <= 0 ? '' : 'primary'" :disabled="rightNum <= 0" @click="delTreeClick">
- <i class="i-ri-arrow-left-line" />
- </el-button>
- </div>
- </div>
- </div>
- <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>
- <div class="action">
- <el-button hc-btn class="mr-4" :loading="submitLoading" @click="saveAndExit">保存并退出</el-button>
- <el-button hc-btn type="primary" :loading="submitLoading" @click="saveAndNextStep">保存并进入下一步</el-button>
- </div>
- </div>
- </template>
- <script setup>
- import { nextTick, onMounted, ref, watch } from 'vue'
- import { useAppStore } from '~src/store'
- import { deepClone, getArrValue, getObjValue, isNullES } from 'js-fast-way'
- import mainApi from '~api/project/project'
- import treeApi from '~api/wbs/tree'
- //缓存
- const store = useAppStore()
- //双向绑定
- const modelData = defineModel('modelValue', {
- default: {},
- })
- //监听数据
- const formModel = ref({})
- watch(() => modelData.value, (data) => {
- formModel.value = data
- }, { immediate: true, deep: true })
- //监听
- const userInfo = ref(store.getUserInfo)
- watch(() => store.getUserInfo, (info) => {
- userInfo.value = info
- }, { immediate: true, deep: true })
- //渲染完成
- onMounted(() => {
- getWbsTreeList()
- })
- //树配置
- const leftTreeRef = ref(null)
- const rightTreeRef = ref(null)
- const treeProps = {
- children: 'children',
- label: 'title',
- }
- //获取WBS树列表
- const wbsId = ref('')
- const wbsTreeList = ref([])
- const isLoading = ref(false)
- const getWbsTreeList = async () => {
- }
- //左边树
- const leftLoading = ref(false)
- const leftTreeData = ref([])
- //获取右边数据
- const rightLoading = ref(false)
- const rightTreeData = ref([])
- const getRightTreeApi = async () => {
- }
- //左边树被展开
- 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
- } else {
- //只增加右侧树没有的节点,不会覆盖右侧树多余的节点
- let checkNodes = left.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()
- }
- //保存并退出
- const saveAndExit = async () => {
- /*const isRes = await saveDataApi()
- if (!isRes) return
- emit('close', dataInfo.value)*/
- }
- //保存并进入下一步
- const saveAndNextStep = async () => {
- /*const isRes = await saveDataApi()
- if (!isRes) return
- emit('next', dataInfo.value)*/
- }
- const submitLoading = ref(false)
- </script>
- <style lang="scss">
- @import './style/wbs';
- </style>
|