Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
02fa679d
authored
Dec 24, 2024
by
zhuguojian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:菜单列表改为虚拟化树形控件实现
parent
ecfe1b61
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
220 additions
and
56 deletions
+220
-56
src/views/system/menu/index.vue
+220
-56
No files found.
src/views/system/menu/index.vue
View file @
02fa679d
...
@@ -67,65 +67,87 @@
...
@@ -67,65 +67,87 @@
<!-- 列表 -->
<!-- 列表 -->
<ContentWrap>
<ContentWrap>
<el-t
able
<el-t
ree-v2
v-if=
"refreshTable"
v-if=
"refreshTable"
v-loading=
"loading"
v-loading=
"loading"
:data=
"list"
:data=
"list"
:default-expand-all=
"isExpandAll"
:props=
"
{
row-key=
"id"
label: 'name',
children: 'children'
}"
:default-expanded-keys="isExpandAll ? list.map(item => item.id) : []"
:height="600"
:item-size="40"
:virtual-scroll-horizontal="true"
:highlight-current="true"
@current-change="handleCurrentChange"
>
>
<el-table-column
:show-overflow-tooltip=
"true"
label=
"菜单名称"
prop=
"name"
width=
"250"
/>
<template
#
default=
"
{ data }">
<el-table-column
align=
"center"
label=
"图标"
prop=
"icon"
width=
"100"
>
<div
<template
#
default=
"scope"
>
class=
"custom-tree-node"
<Icon
:icon=
"scope.row.icon"
/>
:class=
"
{ 'menu-item': true }"
</
template
>
>
</el-table-column>
<div
class=
"node-content"
>
<el-table-column
label=
"排序"
prop=
"sort"
width=
"60"
/>
<span
class=
"label"
>
{{
data
.
name
}}
</span>
<el-table-column
:show-overflow-tooltip=
"true"
label=
"权限标识"
prop=
"permission"
/>
<div
v-if=
"currentNode === data"
class=
"menu-info"
>
<el-table-column
:show-overflow-tooltip=
"true"
label=
"组件路径"
prop=
"component"
/>
<span
class=
"info-item"
v-if=
"data.icon"
>
<el-table-column
:show-overflow-tooltip=
"true"
label=
"组件名称"
prop=
"componentName"
/>
<span
class=
"info-label"
>
图标:
</span>
<el-table-column
label=
"状态"
prop=
"status"
>
<span
class=
"icon-preview"
>
<
template
#
default=
"scope"
>
<Icon
:icon=
"data.icon"
/>
<el-switch
<span
class=
"icon-name"
>
{{
data
.
icon
}}
</span>
class=
"ml-4px"
</span>
v-model=
"scope.row.status"
</span>
v-hasPermi=
"['system:menu:update']"
<span
class=
"info-item"
>
:active-value=
"CommonStatusEnum.ENABLE"
<span
class=
"info-label"
>
排序:
</span>
:inactive-value=
"CommonStatusEnum.DISABLE"
<span
class=
"info-value"
>
{{
data
.
sort
}}
</span>
:loading=
"menuStatusUpdating[scope.row.id]"
</span>
@
change=
"(val) => handleStatusChanged(scope.row, val as number)"
<span
class=
"info-item"
v-if=
"data.permission"
>
/>
<span
class=
"info-label"
>
权限标识:
</span>
</
template
>
<span
class=
"info-value"
>
{{
data
.
permission
}}
</span>
</el-table-column>
</span>
<el-table-column
align=
"center"
label=
"操作"
>
<span
class=
"info-item"
v-if=
"data.path"
>
<
template
#
default=
"scope"
>
<span
class=
"info-label"
>
路由地址:
</span>
<el-button
<span
class=
"info-value"
>
{{
data
.
path
}}
</span>
v-hasPermi=
"['system:menu:update']"
</span>
link
<span
class=
"info-item"
v-if=
"data.component"
>
type=
"primary"
<span
class=
"info-label"
>
组件路径:
</span>
@
click=
"openForm('update', scope.row.id)"
<span
class=
"info-value"
>
{{
data
.
component
}}
</span>
>
</span>
修改
<span
class=
"info-item"
v-if=
"data.componentName"
>
</el-button>
<span
class=
"info-label"
>
组件名称:
</span>
<el-button
<span
class=
"info-value"
>
{{
data
.
componentName
}}
</span>
v-hasPermi=
"['system:menu:create']"
</span>
link
</div>
type=
"primary"
</div>
@
click=
"openForm('create', undefined, scope.row.id)"
<div
v-show=
"currentNode === data"
class=
"operations"
>
>
<el-button
新增
v-hasPermi=
"['system:menu:update']"
</el-button>
link
<el-button
type=
"primary"
v-hasPermi=
"['system:menu:delete']"
@
click
.
stop=
"openForm('update', data.id)"
link
>
type=
"danger"
修改
@
click=
"handleDelete(scope.row.id)"
</el-button>
>
<el-button
删除
v-hasPermi=
"['system:menu:create']"
</el-button>
link
</
template
>
type=
"primary"
</el-table-column>
@
click
.
stop=
"openForm('create', undefined, data.id)"
</el-table>
>
新增
</el-button>
<el-button
v-hasPermi=
"['system:menu:delete']"
link
type=
"danger"
@
click
.
stop=
"handleDelete(data.id)"
>
删除
</el-button>
</div>
</div>
</
template
>
</el-tree-v2>
</ContentWrap>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<!-- 表单弹窗:添加/修改 -->
...
@@ -155,13 +177,26 @@ const queryParams = reactive({
...
@@ -155,13 +177,26 @@ const queryParams = reactive({
const
queryFormRef
=
ref
()
// 搜索的表单
const
queryFormRef
=
ref
()
// 搜索的表单
const
isExpandAll
=
ref
(
false
)
// 是否展开,默认全部折叠
const
isExpandAll
=
ref
(
false
)
// 是否展开,默认全部折叠
const
refreshTable
=
ref
(
true
)
// 重新渲染表格状态
const
refreshTable
=
ref
(
true
)
// 重新渲染表格状态
const
currentNode
=
ref
<
any
>
(
null
)
// 当前选中节点
/** 查询列表 */
/** 查询列表 */
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
loading
.
value
=
true
loading
.
value
=
true
try
{
try
{
const
data
=
await
MenuApi
.
getMenuList
(
queryParams
)
const
data
=
await
MenuApi
.
getMenuList
(
queryParams
)
list
.
value
=
handleTree
(
data
)
// 为每个节点添加 showInfo 属性和样式对象
const
addProps
=
(
items
:
any
[])
=>
{
items
.
forEach
(
item
=>
{
item
.
showInfo
=
false
item
.
popupStyle
=
{}
if
(
item
.
children
&&
item
.
children
.
length
>
0
)
{
addProps
(
item
.
children
)
}
})
}
const
processedData
=
handleTree
(
data
)
addProps
(
processedData
)
list
.
value
=
processedData
}
finally
{
}
finally
{
loading
.
value
=
false
loading
.
value
=
false
}
}
...
@@ -233,8 +268,136 @@ const handleStatusChanged = async (menu: MenuVO, val: number) => {
...
@@ -233,8 +268,136 @@ const handleStatusChanged = async (menu: MenuVO, val: number) => {
}
}
}
}
const
handleCurrentChange
=
(
data
:
any
)
=>
{
currentNode
.
value
=
data
// 关闭所有信息面板
list
.
value
.
forEach
((
item
:
any
)
=>
{
item
.
showInfo
=
false
})
}
// 添加点击外部关闭弹出层的处理
onMounted
(()
=>
{
document
.
addEventListener
(
'click'
,
(
event
:
MouseEvent
)
=>
{
const
target
=
event
.
target
as
HTMLElement
if
(
!
target
.
closest
(
'.menu-info-popup'
)
&&
!
target
.
closest
(
'.info-button'
))
{
list
.
value
.
forEach
((
item
:
any
)
=>
{
item
.
showInfo
=
false
})
}
})
})
/** 初始化 **/
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
getList
()
getList
()
})
})
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
:deep
(
.el-tree-node.is-current
>
.el-tree-node__content
)
{
background-color
:
var
(
--el-color-primary-light-7
)
!important
;
.custom-tree-node
{
background-color
:
var
(
--el-color-primary-light-7
);
.operations
{
background-color
:
var
(
--el-color-primary-light-7
);
}
}
}
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
padding
:
0
8px
;
height
:
40px
;
position
:
relative
;
border-bottom
:
1px
solid
var
(
--el-border-color-lighter
);
min-width
:
800px
;
transition
:
background-color
0.3s
;
.node-content
{
display
:
flex
;
align-items
:
center
;
gap
:
12px
;
height
:
100%
;
flex
:
1
;
min-width
:
0
;
.label
{
flex-shrink
:
0
;
}
.menu-info
{
display
:
flex
;
align-items
:
center
;
gap
:
16px
;
overflow-x
:
auto
;
flex
:
1
;
margin-right
:
16px
;
padding
:
0
4px
;
&::-webkit-scrollbar
{
height
:
6px
;
}
&
::-webkit-scrollbar-thumb
{
background
:
var
(
--el-border-color
);
border-radius
:
3px
;
}
&
::-webkit-scrollbar-track
{
background
:
transparent
;
}
}
.info-item
{
flex-shrink
:
0
;
display
:
flex
;
align-items
:
center
;
gap
:
4px
;
.info-label
{
color
:
var
(
--el-text-color-secondary
);
font-size
:
13px
;
}
.info-value
{
color
:
var
(
--el-text-color-primary
);
font-size
:
13px
;
}
.icon-preview
{
display
:
flex
;
align-items
:
center
;
gap
:
4px
;
padding
:
0
8px
;
height
:
24px
;
border-radius
:
4px
;
border
:
1px
solid
var
(
--el-border-color-lighter
);
background-color
:
var
(
--el-bg-color
);
.icon-name
{
font-size
:
13px
;
color
:
var
(
--el-text-color-regular
);
}
}
}
}
.operations
{
display
:
flex
;
gap
:
8px
;
height
:
100%
;
align-items
:
center
;
flex-shrink
:
0
;
position
:
sticky
;
right
:
8px
;
padding-left
:
8px
;
transition
:
background-color
0.3s
;
}
}
</
style
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment