mirror of
https://gitee.com/xiaonuobase/snowy.git
synced 2026-03-22 02:37:16 +08:00
【机构】左侧树加入虚拟滚动,优化业务授权机构逻辑
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -116,6 +119,7 @@
|
|||||||
<script setup name="bizOrg">
|
<script setup name="bizOrg">
|
||||||
import { Empty } from 'ant-design-vue'
|
import { Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import bizOrgApi from '@/api/biz/bizOrgApi'
|
import bizOrgApi from '@/api/biz/bizOrgApi'
|
||||||
import Form from './form.vue'
|
import Form from './form.vue'
|
||||||
import CopyForm from './copyForm.vue'
|
import CopyForm from './copyForm.vue'
|
||||||
@@ -168,10 +172,31 @@
|
|||||||
const treeData = ref([])
|
const treeData = ref([])
|
||||||
// 替换treeNode 中 title,key,children
|
// 替换treeNode 中 title,key,children
|
||||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
loadTreeData()
|
|
||||||
return bizOrgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
return bizOrgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
@@ -200,10 +225,11 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
loadTreeData()
|
||||||
// 懒加载子节点
|
// 懒加载子节点
|
||||||
const onLoadData = (treeNode) => {
|
const onLoadData = (treeNode) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (treeNode.dataRef.children) {
|
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
|
||||||
resolve()
|
resolve()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -218,7 +244,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -107,6 +110,7 @@
|
|||||||
<script setup name="bizPosition">
|
<script setup name="bizPosition">
|
||||||
import { Empty } from 'ant-design-vue'
|
import { Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import bizPositionApi from '@/api/biz/bizPositionApi'
|
import bizPositionApi from '@/api/biz/bizPositionApi'
|
||||||
import bizOrgApi from '@/api/biz/bizOrgApi'
|
import bizOrgApi from '@/api/biz/bizOrgApi'
|
||||||
import Form from './form.vue'
|
import Form from './form.vue'
|
||||||
@@ -159,6 +163,28 @@
|
|||||||
const treeData = ref([])
|
const treeData = ref([])
|
||||||
// 替换treeNode 中 title,key,children
|
// 替换treeNode 中 title,key,children
|
||||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
@@ -210,7 +236,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -169,6 +172,7 @@
|
|||||||
<script setup name="bizUser">
|
<script setup name="bizUser">
|
||||||
import { message, Empty } from 'ant-design-vue'
|
import { message, Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
import downloadUtil from '@/utils/downloadUtil'
|
import downloadUtil from '@/utils/downloadUtil'
|
||||||
import bizUserApi from '@/api/biz/bizUserApi'
|
import bizUserApi from '@/api/biz/bizUserApi'
|
||||||
@@ -235,6 +239,28 @@
|
|||||||
const RoleSelectorPlusRef = ref()
|
const RoleSelectorPlusRef = ref()
|
||||||
const selectedRecord = ref({})
|
const selectedRecord = ref({})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
return bizUserApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
return bizUserApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||||
@@ -285,7 +311,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -115,6 +118,7 @@
|
|||||||
<script setup name="sysOrg">
|
<script setup name="sysOrg">
|
||||||
import { Empty } from 'ant-design-vue'
|
import { Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import orgApi from '@/api/sys/orgApi'
|
import orgApi from '@/api/sys/orgApi'
|
||||||
import Form from './form.vue'
|
import Form from './form.vue'
|
||||||
import CopyForm from './copyForm.vue'
|
import CopyForm from './copyForm.vue'
|
||||||
@@ -165,10 +169,31 @@
|
|||||||
const treeData = ref([])
|
const treeData = ref([])
|
||||||
// 替换treeNode 中 title,key,children
|
// 替换treeNode 中 title,key,children
|
||||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
loadTreeData()
|
|
||||||
return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
@@ -197,10 +222,11 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
loadTreeData()
|
||||||
// 懒加载子节点
|
// 懒加载子节点
|
||||||
const onLoadData = (treeNode) => {
|
const onLoadData = (treeNode) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (treeNode.dataRef.children) {
|
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
|
||||||
resolve()
|
resolve()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -215,7 +241,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -107,6 +110,7 @@
|
|||||||
<script setup name="sysPosition">
|
<script setup name="sysPosition">
|
||||||
import { Empty } from 'ant-design-vue'
|
import { Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import positionApi from '@/api/sys/positionApi'
|
import positionApi from '@/api/sys/positionApi'
|
||||||
import orgApi from '@/api/sys/orgApi'
|
import orgApi from '@/api/sys/orgApi'
|
||||||
import Form from './form.vue'
|
import Form from './form.vue'
|
||||||
@@ -156,6 +160,28 @@
|
|||||||
const treeData = ref([])
|
const treeData = ref([])
|
||||||
// 替换treeNode 中 title,key,children
|
// 替换treeNode 中 title,key,children
|
||||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
@@ -188,7 +214,7 @@
|
|||||||
// 懒加载子节点
|
// 懒加载子节点
|
||||||
const onLoadData = (treeNode) => {
|
const onLoadData = (treeNode) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (treeNode.dataRef.children) {
|
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
|
||||||
resolve()
|
resolve()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -203,7 +229,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -144,6 +147,7 @@
|
|||||||
<script setup name="sysRole">
|
<script setup name="sysRole">
|
||||||
import { Empty } from 'ant-design-vue'
|
import { Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import roleApi from '@/api/sys/roleApi'
|
import roleApi from '@/api/sys/roleApi'
|
||||||
import orgApi from '@/api/sys/orgApi'
|
import orgApi from '@/api/sys/orgApi'
|
||||||
import GrantResourceForm from './grantResourceForm.vue'
|
import GrantResourceForm from './grantResourceForm.vue'
|
||||||
@@ -202,6 +206,28 @@
|
|||||||
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
|
||||||
// 记录数据
|
// 记录数据
|
||||||
const recordCacheData = ref({})
|
const recordCacheData = ref({})
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
@@ -268,7 +294,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
|
||||||
<template #left>
|
<template #left>
|
||||||
<a-tree
|
<div ref="treeContainerRef" style="height: 100%">
|
||||||
v-if="treeData.length > 0"
|
<a-tree
|
||||||
v-model:expandedKeys="defaultExpandedKeys"
|
v-if="treeData.length > 0"
|
||||||
:tree-data="treeData"
|
v-model:expandedKeys="defaultExpandedKeys"
|
||||||
:field-names="treeFieldNames"
|
:tree-data="treeData"
|
||||||
:load-data="onLoadData"
|
:field-names="treeFieldNames"
|
||||||
@select="treeSelect"
|
:load-data="onLoadData"
|
||||||
/>
|
:height="treeHeight"
|
||||||
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
@select="treeSelect"
|
||||||
|
/>
|
||||||
|
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #right>
|
<template #right>
|
||||||
<a-form ref="searchFormRef" :model="searchFormState">
|
<a-form ref="searchFormRef" :model="searchFormState">
|
||||||
@@ -187,6 +190,7 @@
|
|||||||
<script setup name="sysUser">
|
<script setup name="sysUser">
|
||||||
import { message, Empty } from 'ant-design-vue'
|
import { message, Empty } from 'ant-design-vue'
|
||||||
import { isEmpty } from 'lodash-es'
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
|
||||||
import tool from '@/utils/tool'
|
import tool from '@/utils/tool'
|
||||||
import downloadUtil from '@/utils/downloadUtil'
|
import downloadUtil from '@/utils/downloadUtil'
|
||||||
import userApi from '@/api/sys/userApi'
|
import userApi from '@/api/sys/userApi'
|
||||||
@@ -256,6 +260,28 @@
|
|||||||
const ImpExpRef = ref()
|
const ImpExpRef = ref()
|
||||||
const grantResourceFormRef = ref()
|
const grantResourceFormRef = ref()
|
||||||
const grantPermissionFormRef = ref()
|
const grantPermissionFormRef = ref()
|
||||||
|
// 树容器高度自适应
|
||||||
|
const treeContainerRef = ref(null)
|
||||||
|
const treeHeight = ref(0)
|
||||||
|
let resizeObserver = null
|
||||||
|
const calcTreeHeight = () => {
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
treeHeight.value = treeContainerRef.value.clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
calcTreeHeight()
|
||||||
|
if (treeContainerRef.value) {
|
||||||
|
resizeObserver = new ResizeObserver(calcTreeHeight)
|
||||||
|
resizeObserver.observe(treeContainerRef.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
onActivated(calcTreeHeight)
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
// 表格查询 返回 Promise 对象
|
// 表格查询 返回 Promise 对象
|
||||||
const loadData = (parameter) => {
|
const loadData = (parameter) => {
|
||||||
return userApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
return userApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||||
@@ -282,7 +308,7 @@
|
|||||||
// 懒加载子节点
|
// 懒加载子节点
|
||||||
const onLoadData = (treeNode) => {
|
const onLoadData = (treeNode) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (treeNode.dataRef.children) {
|
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
|
||||||
resolve()
|
resolve()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -297,7 +323,7 @@
|
|||||||
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
treeData.value = [...treeData.value]
|
triggerRef(treeData)
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -139,38 +139,52 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
|
|||||||
@Override
|
@Override
|
||||||
public List<JSONObject> treeLazy(BizOrgTreeLazyParam bizOrgTreeLazyParam) {
|
public List<JSONObject> treeLazy(BizOrgTreeLazyParam bizOrgTreeLazyParam) {
|
||||||
String parentId = ObjectUtil.isNotEmpty(bizOrgTreeLazyParam.getParentId()) ? bizOrgTreeLazyParam.getParentId() : "0";
|
String parentId = ObjectUtil.isNotEmpty(bizOrgTreeLazyParam.getParentId()) ? bizOrgTreeLazyParam.getParentId() : "0";
|
||||||
|
// 校验数据范围
|
||||||
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
|
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
|
||||||
|
if (ObjectUtil.isEmpty(loginUserDataScope)) {
|
||||||
// 获取所有机构
|
|
||||||
List<BizOrg> allOrgList = this.getAllOrgList();
|
|
||||||
Set<String> visibleOrgIds = null;
|
|
||||||
|
|
||||||
// 如果数据范围不为空,则计算可见机构ID集合(包含自身及其所有父级)
|
|
||||||
if (ObjectUtil.isNotEmpty(loginUserDataScope)) {
|
|
||||||
Set<BizOrg> bizOrgSet = CollectionUtil.newHashSet();
|
|
||||||
loginUserDataScope.forEach(orgId -> bizOrgSet.addAll(this.getParentListById(allOrgList, orgId, true)));
|
|
||||||
visibleOrgIds = bizOrgSet.stream().map(BizOrg::getId).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤出当前父级下的可见子级
|
|
||||||
final Set<String> finalVisibleOrgIds = visibleOrgIds;
|
|
||||||
List<BizOrg> sysOrgList = allOrgList.stream()
|
|
||||||
.filter(bizOrg -> bizOrg.getParentId().equals(parentId))
|
|
||||||
.filter(bizOrg -> finalVisibleOrgIds == null || finalVisibleOrgIds.contains(bizOrg.getId()))
|
|
||||||
.sorted(Comparator.comparingInt(BizOrg::getSortCode).thenComparing(BizOrg::getId))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (ObjectUtil.isEmpty(sysOrgList)) {
|
|
||||||
return CollectionUtil.newArrayList();
|
return CollectionUtil.newArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断这些机构是否还有可见子机构
|
// 获取所有机构
|
||||||
return sysOrgList.stream().map(bizOrg -> {
|
List<BizOrg> allOrgList = this.getAllOrgList();
|
||||||
|
|
||||||
|
// 构建索引,避免重复线性遍历(O(N) 一次性构建)
|
||||||
|
Map<String, BizOrg> orgById = allOrgList.stream()
|
||||||
|
.collect(Collectors.toMap(BizOrg::getId, org -> org, (a, b) -> a));
|
||||||
|
Map<String, List<BizOrg>> childrenByParentId = allOrgList.stream()
|
||||||
|
.collect(Collectors.groupingBy(BizOrg::getParentId));
|
||||||
|
|
||||||
|
// 计算可见机构ID集合(包含自身及其所有父级),使用索引将复杂度从 O(M*N*D) 降至 O(M*D)
|
||||||
|
Set<String> visibleOrgIds = new HashSet<>();
|
||||||
|
for (String orgId : loginUserDataScope) {
|
||||||
|
if (orgById.containsKey(orgId)) {
|
||||||
|
visibleOrgIds.add(orgId);
|
||||||
|
// 向上遍历添加所有父级
|
||||||
|
String currentId = orgById.get(orgId).getParentId();
|
||||||
|
while (ObjectUtil.isNotEmpty(currentId) && !"0".equals(currentId) && orgById.containsKey(currentId)) {
|
||||||
|
if (!visibleOrgIds.add(currentId)) {
|
||||||
|
break; // 已经添加过,停止遍历
|
||||||
|
}
|
||||||
|
currentId = orgById.get(currentId).getParentId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤出当前父级下的可见子级(使用 parentId 索引,O(K) 而非 O(N))
|
||||||
|
List<BizOrg> childList = childrenByParentId.getOrDefault(parentId, Collections.emptyList()).stream()
|
||||||
|
.filter(bizOrg -> visibleOrgIds.contains(bizOrg.getId()))
|
||||||
|
.sorted(Comparator.comparingInt(BizOrg::getSortCode).thenComparing(BizOrg::getId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (ObjectUtil.isEmpty(childList)) {
|
||||||
|
return CollectionUtil.newArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断这些机构是否还有可见子机构(使用 parentId 索引,O(1) 查找子节点列表)
|
||||||
|
return childList.stream().map(bizOrg -> {
|
||||||
JSONObject jsonObject = JSONUtil.parseObj(bizOrg);
|
JSONObject jsonObject = JSONUtil.parseObj(bizOrg);
|
||||||
// 计算是否有可见的子节点
|
List<BizOrg> subChildren = childrenByParentId.getOrDefault(bizOrg.getId(), Collections.emptyList());
|
||||||
boolean hasChildren = allOrgList.stream()
|
boolean hasChildren = subChildren.stream().anyMatch(item -> visibleOrgIds.contains(item.getId()));
|
||||||
.anyMatch(item -> item.getParentId().equals(bizOrg.getId()) && (finalVisibleOrgIds == null || finalVisibleOrgIds.contains(item.getId())));
|
|
||||||
|
|
||||||
jsonObject.set("isLeaf", !hasChildren);
|
jsonObject.set("isLeaf", !hasChildren);
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|||||||
Reference in New Issue
Block a user