Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
V
vue-quasar-admin-dev
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
吴超
vue-quasar-admin-dev
Commits
b5ffdbbe
Commit
b5ffdbbe
authored
Jan 10, 2026
by
周海峰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
no message
parent
f0e1db21
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
124 行增加
和
77 行删除
+124
-77
src/components/organization-ant.vue
+124
-77
没有找到文件。
src/components/organization-ant.vue
View file @
b5ffdbbe
<
template
>
<
template
>
<div
style=
"padding:1vh;"
>
<div
style=
"position: relative;"
>
<div
v-show=
"getTreeData.length > 0"
>
<!-- Loading遮罩层 - 覆盖整个组件 -->
<div
class=
"component-loading-overlay"
:style=
"
{ display: checkLoading ? 'flex' : 'none' }"
>
处理中...
</div>
<div
v-show=
"treeData.length > 0"
>
<div
class=
"search-container"
>
<div
class=
"search-container"
>
<div
class=
"search-wrapper"
>
<div
class=
"search-wrapper"
>
<q-input
<q-input
...
@@ -83,21 +91,16 @@
...
@@ -83,21 +91,16 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
style=
"padding-top: 6vh"
>
<div
style=
"padding-top: 6vh
;
"
>
<Tree
<Tree
v-if=
"
getT
reeData.length > 0"
v-if=
"
t
reeData.length > 0"
ref=
"tree"
ref=
"tree"
checkable
checkable
:checkedKeys=
"checkedKeys"
@
expand=
"onExpand"
:expandedKeys=
"expandedKeys"
:autoExpandParent=
"autoExpandParent"
:treeData=
"getTreeData"
:defaultExpandedKeys=
"defaultExpandedKeys"
:defaultExpandedKeys=
"defaultExpandedKeys"
:checkedKeys=
"checkedKeys"
:treeData=
"treeData"
@
check=
"onCheck"
@
check=
"onCheck"
@
select=
"onSelect"
>
>
<
template
slot=
"title"
slot-scope=
"node"
>
<
template
slot=
"title"
slot-scope=
"node"
>
<span
style=
"color: rgb(33, 186, 69);"
v-if=
"checkedKeys.indexOf(node.key)>-1"
>
√
</span>
<span
style=
"color: rgb(33, 186, 69);"
v-if=
"checkedKeys.indexOf(node.key)>-1"
>
√
</span>
<span
v-if=
"node.title.indexOf(searchValue) > -1"
>
<span
v-if=
"node.title.indexOf(searchValue) > -1"
>
...
@@ -114,7 +117,7 @@
...
@@ -114,7 +117,7 @@
</Tree>
</Tree>
</div>
</div>
</div>
</div>
<div
v-show=
"!
getT
reeData.length > 0"
>
<div
v-show=
"!
t
reeData.length > 0"
>
正在加载组织机构组件...
正在加载组织机构组件...
</div>
</div>
</div>
</div>
...
@@ -186,7 +189,11 @@
...
@@ -186,7 +189,11 @@
nodeCache
:
null
,
nodeCache
:
null
,
// 搜索相关
// 搜索相关
searchOptions
:
[],
searchOptions
:
[],
showSearchMenu
:
false
showSearchMenu
:
false
,
// 勾选操作loading状态
checkLoading
:
false
,
// 保存body原始样式
originalBodyStyle
:
null
};
};
},
},
props
:
{
props
:
{
...
@@ -236,33 +243,76 @@
...
@@ -236,33 +243,76 @@
onCheck
(
checkedKeys
,
e
)
{
onCheck
(
checkedKeys
,
e
)
{
console
.
log
(
'onCheck'
,
checkedKeys
,
e
);
console
.
log
(
'onCheck'
,
checkedKeys
,
e
);
let
finalCheckedKeys
=
[...
checkedKeys
];
// 显示loading
this
.
checkLoading
=
true
;
console
.
log
(
'Loading set to true:'
,
this
.
checkLoading
);
// 当勾选父节点时,自动勾选所有叶子节点
// 防止页面滚动
if
(
e
.
checked
&&
e
.
node
.
children
&&
e
.
node
.
children
.
length
>
0
)
{
this
.
preventBodyScroll
();
const
leafKeys
=
this
.
getAllLeafKeys
(
e
.
node
.
children
);
finalCheckedKeys
=
[...
new
Set
([...
finalCheckedKeys
,
...
leafKeys
])];
}
// 当取消勾选父节点时,取消勾选所有叶子节点
// 强制Vue重新渲染
if
(
!
e
.
checked
&&
e
.
node
.
children
&&
e
.
node
.
children
.
length
>
0
)
{
this
.
$forceUpdate
();
const
leafKeys
=
this
.
getAllLeafKeys
(
e
.
node
.
children
);
finalCheckedKeys
=
finalCheckedKeys
.
filter
(
key
=>
!
leafKeys
.
includes
(
key
));
}
// 只在最终结果不同时才更新,避免不必要的触发
// 使用setTimeout强制分离到下一个事件循环,确保loading先显示
if
(
JSON
.
stringify
(
finalCheckedKeys
)
!==
JSON
.
stringify
(
this
.
checkedKeys
))
{
setTimeout
(()
=>
{
this
.
checkedKeys
=
finalCheckedKeys
;
console
.
log
(
'Processing check operation...'
);
this
.
processCheckOperation
(
checkedKeys
,
e
);
},
0
);
},
// 分离的处理逻辑
processCheckOperation
(
checkedKeys
,
e
)
{
try
{
// 更新本地状态
this
.
checkedKeys
=
checkedKeys
;
// 更新选中的人员列表
// 更新选中的人员列表
this
.
updateSelectedStaff
();
this
.
updateSelectedStaff
();
// 双向绑定会通过watch自动处理
// 处理完成后,延迟一点时间再隐藏loading,确保用户能看到
setTimeout
(()
=>
{
this
.
checkLoading
=
false
;
// 恢复页面滚动
this
.
restoreBodyScroll
();
},
200
);
// 最少显示200ms,让用户看到反馈
}
catch
(
error
)
{
console
.
error
(
'勾选处理出错:'
,
error
);
this
.
checkLoading
=
false
;
// 出错时也要隐藏loading
this
.
restoreBodyScroll
();
// 恢复页面滚动
}
},
// 防止body滚动
preventBodyScroll
()
{
// 保存原始样式
if
(
!
this
.
originalBodyStyle
)
{
this
.
originalBodyStyle
=
{
overflow
:
document
.
body
.
style
.
overflow
,
position
:
document
.
body
.
style
.
position
};
}
// 防止滚动
document
.
body
.
style
.
overflow
=
'hidden'
;
document
.
body
.
style
.
position
=
'fixed'
;
document
.
body
.
style
.
width
=
'100%'
;
},
// 恢复body滚动
restoreBodyScroll
()
{
// 恢复原始样式
if
(
this
.
originalBodyStyle
)
{
document
.
body
.
style
.
overflow
=
this
.
originalBodyStyle
.
overflow
||
''
;
document
.
body
.
style
.
position
=
this
.
originalBodyStyle
.
position
||
''
;
document
.
body
.
style
.
width
=
''
;
this
.
originalBodyStyle
=
null
;
}
}
},
},
onSelect
(
selectedKeys
,
info
)
{
onSelect
(
selectedKeys
,
info
)
{
// 在复选模式下,onSelect 可以用来处理一些辅助功能,比如展开/折叠
// 在复选模式下,onSelect 可以用来处理一些辅助功能,比如展开/折叠
// console.log('onSelect', selectedKeys, info);
// console.log('onSelect', selectedKeys, info);
},
},
// 搜索输入处理
// 搜索输入处理
onSearchInput
(
value
)
{
onSearchInput
(
value
)
{
this
.
searchValue
=
value
||
''
;
this
.
searchValue
=
value
||
''
;
...
@@ -285,14 +335,12 @@
...
@@ -285,14 +335,12 @@
this
.
showSearchMenu
=
false
;
this
.
showSearchMenu
=
false
;
}
}
},
},
// 手动搜索
// 手动搜索
manualSearch
()
{
manualSearch
()
{
if
(
this
.
searchText
&&
this
.
searchText
.
length
>
0
)
{
if
(
this
.
searchText
&&
this
.
searchText
.
length
>
0
)
{
this
.
onSearchInput
(
this
.
searchText
);
this
.
onSearchInput
(
this
.
searchText
);
}
}
},
},
// 隐藏搜索菜单
// 隐藏搜索菜单
hideSearchMenu
()
{
hideSearchMenu
()
{
// 延迟隐藏,以便点击选项时能正常触发
// 延迟隐藏,以便点击选项时能正常触发
...
@@ -300,25 +348,27 @@
...
@@ -300,25 +348,27 @@
this
.
showSearchMenu
=
false
;
this
.
showSearchMenu
=
false
;
},
500
);
},
500
);
},
},
// 选择搜索选项
// 选择搜索选项
selectSearchOption
(
option
)
{
selectSearchOption
(
option
)
{
this
.
checkLoading
=
true
;
// 强制Vue重新渲染
this
.
$forceUpdate
();
console
.
log
(
option
,
'selectSearchOption======='
)
console
.
log
(
option
,
'selectSearchOption======='
)
// 勾选选中的节点
// 清空搜索状态
if
(
!
this
.
checkedKeys
.
includes
(
option
.
key
))
{
this
.
checkedKeys
=
[...
this
.
checkedKeys
,
option
.
key
];
this
.
updateSelectedStaff
();
}
// 展开到选中节点的路径
const
parentKeys
=
this
.
getParentKeys
(
option
.
key
,
this
.
treeData
);
this
.
expandedKeys
=
[...
new
Set
([...
this
.
expandedKeys
,
...
parentKeys
])];
this
.
autoExpandParent
=
false
;
// 清空搜索状态
this
.
searchText
=
''
;
this
.
searchText
=
''
;
this
.
searchOptions
=
[];
this
.
searchOptions
=
[];
this
.
showSearchMenu
=
false
;
this
.
showSearchMenu
=
false
;
setTimeout
(()
=>
{
// 勾选选中的节点
if
(
!
this
.
checkedKeys
.
includes
(
option
.
key
))
{
this
.
checkedKeys
=
[
option
.
key
,
...
this
.
checkedKeys
];
}
else
{
//根据 key 移除
this
.
checkedKeys
=
this
.
checkedKeys
.
filter
(
item
=>
item
!==
option
.
key
);
}
this
.
updateSelectedStaff
();
this
.
checkLoading
=
false
;
},
0
);
},
},
// 获取节点到根节点的路径
// 获取节点到根节点的路径
...
@@ -346,17 +396,17 @@
...
@@ -346,17 +396,17 @@
this
.
searchValue
=
value
;
this
.
searchValue
=
value
;
// 展开包含搜索结果的节点
// 展开包含搜索结果的节点
const
expandedKeys
=
dataList
.
map
((
item
)
=>
{
//
const expandedKeys = dataList.map((item) => {
if
(
item
.
title
.
indexOf
(
value
)
>
-
1
)
{
//
if (item.title.indexOf(value) > -1) {
return
getParentKey
(
item
.
key
,
this
.
getTreeData
)
//
return getParentKey(item.key, this.getTreeData)
}
//
}
return
null
//
return null
}).
filter
((
item
,
i
,
self
)
=>
item
&&
self
.
indexOf
(
item
)
===
i
)
//
}).filter((item, i, self) => item && self.indexOf(item) === i)
if
(
expandedKeys
.
length
>
0
)
{
//
if (expandedKeys.length > 0) {
this
.
expandedKeys
=
[...
new
Set
([...
this
.
expandedKeys
,
...
expandedKeys
])];
//
this.expandedKeys = [...new Set([...this.expandedKeys, ...expandedKeys])];
this
.
autoExpandParent
=
true
;
//
this.autoExpandParent = true;
}
//
}
},
},
// 获取节点下的所有叶子节点key
// 获取节点下的所有叶子节点key
getAllLeafKeys
(
nodes
)
{
getAllLeafKeys
(
nodes
)
{
...
@@ -377,27 +427,7 @@
...
@@ -377,27 +427,7 @@
// 更新选中的人员列表
// 更新选中的人员列表
updateSelectedStaff
()
{
updateSelectedStaff
()
{
this
.
checkedPeople
=
[];
this
.
checkedPeople
=
dataList
.
filter
(
node
=>
node
.
key
<
1000000
&&
this
.
checkedKeys
.
includes
(
node
.
key
))
this
.
checkedDepartment
=
[];
// 使用 Map 缓存节点查找结果,避免重复遍历
if
(
!
this
.
nodeCache
)
{
this
.
nodeCache
=
new
Map
();
this
.
buildNodeCache
(
this
.
treeData
);
}
// 遍历所有选中的key,区分人员和部门
this
.
checkedKeys
.
forEach
(
key
=>
{
const
node
=
this
.
nodeCache
.
get
(
key
);
if
(
node
)
{
if
(
key
<
1000000
)
{
// 人员
this
.
checkedPeople
.
push
(
node
);
}
else
{
// 部门
this
.
checkedDepartment
.
push
(
node
);
}
}
});
// 向父组件发送选中的人员列表
// 向父组件发送选中的人员列表
this
.
$emit
(
'staffNode'
,
this
.
checkedPeople
);
this
.
$emit
(
'staffNode'
,
this
.
checkedPeople
);
},
},
...
@@ -467,7 +497,7 @@
...
@@ -467,7 +497,7 @@
position
:
fixed
;
position
:
fixed
;
width
:
17vw
;
width
:
17vw
;
z-index
:
9999
;
z-index
:
9999
;
padding
:
1vh
;
padding
:
0
1vh
;
}
}
.search-wrapper
{
.search-wrapper
{
...
@@ -684,6 +714,23 @@
...
@@ -684,6 +714,23 @@
background
:
rgba
(
0
,
0
,
0
,
0.3
);
background
:
rgba
(
0
,
0
,
0
,
0.3
);
}
}
/* 组件Loading遮罩层样式 - 覆盖整个组件 */
.component-loading-overlay
{
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background-color
:
rgba
(
255
,
255
,
255
,
0.9
);
backdrop-filter
:
blur
(
3px
);
z-index
:
1000
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
border-radius
:
8px
;
overflow
:
hidden
;
/* 防止遮罩层内部滚动 */
}
/* 响应式设计 */
/* 响应式设计 */
@media
(
max-width
:
768px
)
{
@media
(
max-width
:
768px
)
{
.search-container
{
.search-container
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论