123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- <template>
- <div class="hc-project-wbs-log relative h-full">
- <div v-loading="isLoading" class="hc-flex-center relative mb-14px">
- <span>选择WBS:</span>
- <el-select v-model="wbsId" placeholder="请选择WBS" class="w-500px" size="large" :disabled="isDisabled" @change="wbsChange">
- <el-option-group v-for="group in wbsTreeList" :key="group.label" :label="group.label">
- <el-option v-for="item in group.data" :key="item.value" :label="item.label" :value="item.value" />
- </el-option-group>
- </el-select>
- </div>
- <div class="wbs-template-body">
- <div v-loading="leftLoading" class="left">
- <hc-card-item scrollbar :title="`${leftNum}项`">
- <template #extra>
- <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 :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>
- </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 () => {
- isLoading.value = true
- const { data } = await mainApi.findLogWbsTreeList()
- // 格式化数据
- let arr = [{ label: '公有库', data: [] }], res = getArrValue(data)
- // 公有库
- res.forEach((item) => {
- item.value = item.id
- item.label = item.wbsName
- })
- arr[0].data = res
- wbsTreeList.value = arr
- //处理选中
- const form = getObjValue(formModel.value)
- let refId = form.referenceLogWbsTemplateId
- if (isNullES(refId) || refId <= 0 || Number(form.wbsType) <= 0) {
- wbsId.value = ''
- isLoading.value = false
- return
- }
- wbsId.value = refId
- isLoading.value = false
- await getLeftTreeData()
- await getRightTreeApi()
- setRightTree()
- }
- //左边树
- const leftLoading = ref(false)
- const leftTreeData = ref([])
- const getLeftTreeData = async () => {
- if (isNullES(wbsId.value)) return
- leftLoading.value = true
- const { tenant_id } = getObjValue(userInfo.value)
- const { data } = await treeApi.getAlltree({
- tenantId: tenant_id,
- type: '1',
- wbsId: wbsId.value,
- })
- leftTreeData.value = getArrValue(data)
- leftLoading.value = false
- }
- //切换wbs树
- const isDisabled = ref(false)
- const wbsChange = () => {
- getLeftTreeData()
- }
- //获取右边数据
- const rightLoading = ref(false)
- const rightTreeData = ref([])
- const getRightTreeApi = async () => {
- if (isNullES(wbsId.value)) return
- rightLoading.value = true
- const form = getObjValue(formModel.value)
- const { data } = await mainApi.findProjectTree({
- projectId: form.id,
- wbsId: wbsId.value,
- })
- rightTreeData.value = getArrValue(data)
- 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 <= 0) {
- //直接把左边勾选的树复制到右侧
- let allTree = deepClone(leftTreeData.value)
- const halfKeys = right.getHalfCheckedKeys()
- const keys = right.getCheckedKeys().concat(halfKeys)
- getRightTree(allTree, keys)
- rightTreeData.value = allTree
- } 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()
- }
- 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 = async (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++) {
- await getIds(ids, tree.data[i])
- }
- return ids.join(',')
- }
- const getIds = async (ids, data) => {
- ids.push(data.id)
- if (data.children && data.children.length) {
- for (let i = 0; i < data.children.length; i++) {
- await getIds(ids, data.children[i])
- }
- }
- }
- const setCheckTreeChange = () => {
- console.log('默认全部启用')
- }
- const getTreeObj = async () => {
- const form = getObjValue(formModel.value)
- const ids = await getTreeAllId('right')
- return {
- wbsId: wbsId.value,
- projectId: form.id,
- wbsType: '4',
- wbsTreeIds: ids,
- }
- }
- defineExpose({
- getTreeObj,
- })
- </script>
- <style lang="scss">
- @import './style/log';
- </style>
|