【机构】左侧树加入虚拟滚动,优化业务授权机构逻辑

This commit is contained in:
俞宝山
2026-02-11 00:32:26 +08:00
parent 62eeabfdb4
commit 1c086d5b52
8 changed files with 299 additions and 103 deletions

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -116,6 +119,7 @@
<script setup name="bizOrg">
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import bizOrgApi from '@/api/biz/bizOrgApi'
import Form from './form.vue'
import CopyForm from './copyForm.vue'
@@ -168,10 +172,31 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
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 对象
const loadData = (parameter) => {
loadTreeData()
return bizOrgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
@@ -200,10 +225,11 @@
}
})
}
loadTreeData()
// 懒加载子节点
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
resolve()
return
}
@@ -218,7 +244,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
})

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -107,6 +110,7 @@
<script setup name="bizPosition">
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import bizPositionApi from '@/api/biz/bizPositionApi'
import bizOrgApi from '@/api/biz/bizOrgApi'
import Form from './form.vue'
@@ -159,6 +163,28 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
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 对象
const loadData = (parameter) => {
@@ -210,7 +236,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
.catch(() => {

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -169,6 +172,7 @@
<script setup name="bizUser">
import { message, Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import tool from '@/utils/tool'
import downloadUtil from '@/utils/downloadUtil'
import bizUserApi from '@/api/biz/bizUserApi'
@@ -235,6 +239,28 @@
const RoleSelectorPlusRef = ref()
const selectedRecord = ref({})
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 对象
const loadData = (parameter) => {
return bizUserApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
@@ -285,7 +311,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
.catch(() => {

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -115,6 +118,7 @@
<script setup name="sysOrg">
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
import CopyForm from './copyForm.vue'
@@ -165,10 +169,31 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
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 对象
const loadData = (parameter) => {
loadTreeData()
return orgApi.orgPage(Object.assign(parameter, searchFormState.value)).then((res) => {
return res
})
@@ -197,10 +222,11 @@
}
})
}
loadTreeData()
// 懒加载子节点
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
resolve()
return
}
@@ -215,7 +241,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
})

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -107,6 +110,7 @@
<script setup name="sysPosition">
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import positionApi from '@/api/sys/positionApi'
import orgApi from '@/api/sys/orgApi'
import Form from './form.vue'
@@ -156,6 +160,28 @@
const treeData = ref([])
// 替换treeNode 中 title,key,children
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 对象
const loadData = (parameter) => {
@@ -188,7 +214,7 @@
// 懒加载子节点
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
resolve()
return
}
@@ -203,7 +229,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
})

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -144,6 +147,7 @@
<script setup name="sysRole">
import { Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import roleApi from '@/api/sys/roleApi'
import orgApi from '@/api/sys/orgApi'
import GrantResourceForm from './grantResourceForm.vue'
@@ -202,6 +206,28 @@
const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
// 记录数据
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 对象
const loadData = (parameter) => {
@@ -268,7 +294,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
.catch(() => {

View File

@@ -1,15 +1,18 @@
<template>
<XnResizablePanel direction="row" :initial-size="300" :min-size="200" :max-size="500" :md="0">
<template #left>
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<div ref="treeContainerRef" style="height: 100%">
<a-tree
v-if="treeData.length > 0"
v-model:expandedKeys="defaultExpandedKeys"
:tree-data="treeData"
:field-names="treeFieldNames"
:load-data="onLoadData"
:height="treeHeight"
@select="treeSelect"
/>
<a-empty v-else :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</template>
<template #right>
<a-form ref="searchFormRef" :model="searchFormState">
@@ -187,6 +190,7 @@
<script setup name="sysUser">
import { message, Empty } from 'ant-design-vue'
import { isEmpty } from 'lodash-es'
import { triggerRef, onMounted, onActivated, onUnmounted } from 'vue'
import tool from '@/utils/tool'
import downloadUtil from '@/utils/downloadUtil'
import userApi from '@/api/sys/userApi'
@@ -256,6 +260,28 @@
const ImpExpRef = ref()
const grantResourceFormRef = 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 对象
const loadData = (parameter) => {
return userApi.userPage(Object.assign(parameter, searchFormState.value)).then((res) => {
@@ -282,7 +308,7 @@
// 懒加载子节点
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
if (treeNode.dataRef.children || treeNode.dataRef.isLeaf) {
resolve()
return
}
@@ -297,7 +323,7 @@
isLeaf: item.isLeaf === undefined ? false : item.isLeaf
}
})
treeData.value = [...treeData.value]
triggerRef(treeData)
resolve()
})
})