Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bill-manager-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
赵啸非
bill-manager-ui
Commits
50688879
Commit
50688879
authored
Sep 13, 2024
by
“yiyousong”
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 添加动态菜单
parent
5beea730
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
872 additions
and
409 deletions
+872
-409
admin_2/.env.development
admin_2/.env.development
+2
-1
admin_2/package.json
admin_2/package.json
+1
-0
admin_2/src/api/system.js
admin_2/src/api/system.js
+18
-0
admin_2/src/components/autoRegister/TabMenuBar.vue
admin_2/src/components/autoRegister/TabMenuBar.vue
+44
-0
admin_2/src/directive/index.js
admin_2/src/directive/index.js
+24
-2
admin_2/src/layouts/components/Header.vue
admin_2/src/layouts/components/Header.vue
+84
-30
admin_2/src/pages/engine/Engine.vue
admin_2/src/pages/engine/Engine.vue
+14
-9
admin_2/src/pages/engine/EvaluateSystem.vue
admin_2/src/pages/engine/EvaluateSystem.vue
+7
-0
admin_2/src/pages/engine/QueueUpSystem.vue
admin_2/src/pages/engine/QueueUpSystem.vue
+7
-0
admin_2/src/pages/engine/components/DoubleTable.vue
admin_2/src/pages/engine/components/DoubleTable.vue
+16
-1
admin_2/src/pages/market/EvaluateReport.vue
admin_2/src/pages/market/EvaluateReport.vue
+10
-2
admin_2/src/pages/market/Market.vue
admin_2/src/pages/market/Market.vue
+5
-17
admin_2/src/pages/market/QueueUpReport.vue
admin_2/src/pages/market/QueueUpReport.vue
+10
-2
admin_2/src/pages/sso/Sso.vue
admin_2/src/pages/sso/Sso.vue
+37
-3
admin_2/src/pages/system/System.vue
admin_2/src/pages/system/System.vue
+5
-47
admin_2/src/pages/system/access/components/InputTree.vue
admin_2/src/pages/system/access/components/InputTree.vue
+31
-28
admin_2/src/pages/system/menu/Menu.vue
admin_2/src/pages/system/menu/Menu.vue
+2
-2
admin_2/src/pages/system/menu/components/AddMenu.vue
admin_2/src/pages/system/menu/components/AddMenu.vue
+194
-74
admin_2/src/pages/system/menu/components/IconSelect.vue
admin_2/src/pages/system/menu/components/IconSelect.vue
+1
-7
admin_2/src/router/index.js
admin_2/src/router/index.js
+175
-181
admin_2/src/store/modules/user.js
admin_2/src/store/modules/user.js
+39
-1
admin_2/src/utils/index.js
admin_2/src/utils/index.js
+93
-0
admin_2/yarn.lock
admin_2/yarn.lock
+53
-2
No files found.
admin_2/.env.development
View file @
50688879
#开发环境
NODE_ENV = "development"
VUE_APP_API_BASE_URL=http://192.168.0.98:11078
# VUE_APP_API_BASE_URL=http://192.168.0.98:11078
VUE_APP_API_BASE_URL=http://192.168.0.250:11078
admin_2/package.json
View file @
50688879
...
...
@@ -10,6 +10,7 @@
"dependencies"
:
{
"@ianwalter/vuex-reset"
:
"^4.3.4"
,
"@jiaminghi/data-view"
:
"^2.10.0"
,
"@riophae/vue-treeselect"
:
"^0.4.0"
,
"axios"
:
"^1.4.0"
,
"core-js"
:
"^3.8.3"
,
"crypto-js"
:
"^4.1.1"
,
...
...
admin_2/src/api/system.js
View file @
50688879
...
...
@@ -227,6 +227,15 @@ export const addRoleResource = (data) => {
});
};
// 添加角色菜单
export
const
addRoleMenu
=
(
data
)
=>
{
return
request
({
url
:
`/bill/role/auth/distributionMenu`
,
method
:
"
post
"
,
data
,
});
};
/**
* 用户管理
*/
...
...
@@ -347,3 +356,12 @@ export const changeMenuSort = (data) => {
data
,
});
};
// 获取菜单树列表
export
const
getMenuTreeselect
=
(
data
)
=>
{
return
request
({
url
:
`/bill/menu/treeselect`
,
method
:
"
post
"
,
data
,
});
};
admin_2/src/components/autoRegister/TabMenuBar.vue
0 → 100644
View file @
50688879
<
template
>
<div
class=
"flex h-full w-full flex-col bg-white"
>
<el-tabs
:value=
"activeKey"
@
tab-click=
"changeRouter"
>
<el-tab-pane
v-for=
"v in secondaryRoutes"
:key=
"v.path"
:name=
"v.path"
>
<template
slot=
"label"
>
<i
v-if=
"v.meta.icon"
:class=
"['mr-[5px]', 'primary', v.meta.icon]"
></i>
<span
class=
"tab-label"
>
{{
v
.
meta
.
title
}}
</span>
</
template
>
</el-tab-pane>
</el-tabs>
<div
class=
"flex-1 overflow-y-auto p-[15px]"
>
<router-view></router-view>
</div>
</div>
</template>
<
script
>
import
{
mapGetters
}
from
"
vuex
"
;
export
default
{
name
:
"
TabMenuBar
"
,
data
()
{
return
{
subMenus
:
[],
};
},
computed
:
{
...
mapGetters
(
"
user
"
,
[
"
secondaryRoutes
"
]),
activeKey
()
{
return
this
.
$route
.
path
;
},
},
created
()
{},
methods
:
{
changeRouter
(
e
)
{
this
.
$router
.
push
(
e
.
name
);
},
},
};
</
script
>
<
style
lang=
"less"
scoped
></
style
>
admin_2/src/directive/index.js
View file @
50688879
...
...
@@ -3,8 +3,8 @@ import store from "@/store";
export
const
permission
=
{
inserted
:
function
(
el
,
binding
)
{
const
{
value
}
=
binding
;
const
roles
=
store
.
getters
[
"
user/userI
d
"
]
;
if
(
value
)
{
const
roles
=
store
.
getters
[
"
user/userI
nfo
"
].
id
;
if
(
value
&&
value
instanceof
Array
&&
value
.
length
>
0
)
{
const
permissionRoles
=
value
;
const
hasPermission
=
permissionRoles
.
includes
(
roles
);
if
(
!
hasPermission
)
{
...
...
@@ -15,3 +15,25 @@ export const permission = {
}
},
};
// 按钮鉴权
export
const
hasPermi
=
{
inserted
:
function
(
el
,
binding
)
{
const
{
value
}
=
binding
;
const
permissions
=
store
.
getters
[
"
user/permissions
"
];
if
(
value
&&
value
instanceof
Array
&&
value
.
length
>
0
)
{
const
permissionFlag
=
value
;
const
hasPermissions
=
permissions
.
some
((
permission
)
=>
{
return
permissionFlag
.
includes
(
permission
);
});
if
(
!
hasPermissions
)
{
el
.
remove
();
}
}
else
{
throw
new
Error
(
`请设置操作权限标签值`
);
}
},
};
admin_2/src/layouts/components/Header.vue
View file @
50688879
...
...
@@ -17,8 +17,7 @@
:default-active=
"activeMenu"
mode=
"horizontal"
router
text-color=
"rgba(254, 254, 254, 0.65)"
background-color=
"#0000"
@
select=
"selectMenu"
>
<template
v-for=
"v in menus"
>
<el-submenu
...
...
@@ -55,7 +54,7 @@
<
script
>
import
HeaderSite
from
"
./HeaderSite.vue
"
;
import
{
mapState
}
from
"
vuex
"
;
import
{
mapState
,
mapActions
}
from
"
vuex
"
;
export
default
{
components
:
{
HeaderSite
,
...
...
@@ -75,20 +74,57 @@ export default {
}
return
path
;
},
...
mapState
(
"
user
"
,
[
"
menus
"
,
"
sysName
"
,
"
sysLogo
"
,
"
path
"
]),
...
mapState
(
"
user
"
,
[
"
menus
"
,
"
sysName
"
,
"
sysLogo
"
,
"
path
"
,
"
menus
"
]),
},
created
()
{
document
.
title
=
this
.
sysName
?
this
.
sysName
:
this
.
systemName
;
// 设置项目标题
},
methods
:
{
...
mapActions
(
"
user
"
,
[
"
setSecondaryRoutes
"
]),
selectMenu
(
index
)
{
this
.
setSecondaryRoutes
(
index
);
},
handleGoHome
()
{
this
.
$router
.
push
(
"
/home
"
);
let
path
=
this
.
menus
[
0
].
path
;
this
.
$router
.
push
(
path
);
},
},
};
</
script
>
<
style
lang=
"less"
>
.el-menu--popup {
.el-menu-item {
display: flex;
align-items: center;
&:hover {
color: var(--primary) !important;
i {
color: var(--primary);
}
}
}
.is-active {
color: var(--primary) !important;
}
}
</
style
>
<
style
lang=
"less"
scoped
>
@text-color: #fefefea5;
.mixins(@l,@t) {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: @l;
transform: translateX(@t);
}
.header {
height: 72px;
width: 100%;
...
...
@@ -136,49 +172,67 @@ export default {
:deep(.el-menu) {
height: 100% !important;
border: none !important;
background: #0000;
.el-menu-item {
.el-menu-item
:not(.el-submenu)
{
height: 100%;
font-size: 16px;
color: #fff;
display: flex;
align-items: center;
border: none !important;
letter-spacing: 1px;
color: @text-color;
i {
color: #fff;
// color: #fff;
color: @text-color;
}
&:hover {
background: #0000 !important;
color: @text-color !important;
&::after {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
.mixins(50%,-50%);
}
}
}
.is-active {
.el-submenu {
height: 100%;
font-size: 16px;
.el-submenu__title {
height: 100%;
display: flex;
font-size: 16px;
align-items: center;
border: none !important;
color: @text-color;
&:hover {
background: #0000 !important;
color: #fff !important;
&::after {
.mixins(calc(50% - 20px),-(50% - 20px));
}
}
}
.el-submenu__icon-arrow {
color: @text-color;
}
}
.is-active:not(.el-submenu),
.is-active .el-submenu__title {
color: #fff !important;
background: #0000 !important;
font-weight: 600;
i {
color: #fff;
}
&::after {
.mixins(50%,-50%);
}
}
.is-active .el-submenu__title {
&::after {
content: "";
display: inline-block;
height: 4px;
width: 30%;
background: #ffffff;
border-radius: 2px;
position: absolute;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
left: calc(50% - 20px);
transform: translateX(-(50% - 20px));
}
}
}
...
...
admin_2/src/pages/engine/Engine.vue
View file @
50688879
...
...
@@ -4,19 +4,19 @@
<div
class=
"tab-box flex items-end gap-5"
>
<router-link
:class=
"['tab-item', 'top-radius']"
to=
"/engine/queueupsystem"
v-for=
"item in secondaryRoutes"
:key=
"item.path"
:to=
"item.path"
>
排队取号系统
</router-link>
<router-link
:class=
"['tab-item', 'top-radius']"
to=
"/engine/evaluatesystem"
>
评价系统
<i
v-if=
"item.meta.icon"
:class=
"['mr-2', item.meta.icon]"
></i>
{{
item
.
meta
.
title
}}
</router-link>
</div>
<div
class=
"flex gap-5"
>
<div
class=
"search-box top-radius flex h-full items-center gap-5"
>
<div
class=
"search-box top-radius flex h-full items-center gap-5"
v-hasPermi=
"['engine:query']"
>
<div
class=
"text-[14px] text-[#395EBF]"
>
统计时段:
{{
time
[
0
]
}}
~
{{
time
[
1
]
}}
</div>
...
...
@@ -35,6 +35,7 @@
<div
class=
"engine-btn top-radius"
@
click=
"$router.push('/enginesearch')"
v-hasPermi=
"['engine:enginesearch']"
>
<img
src=
"@/assets/img/engine.png"
class=
"engine-img mr-2 w-[24px]"
/>
数据搜索引擎
...
...
@@ -48,6 +49,7 @@
</
template
>
<
script
>
import
{
mapGetters
}
from
"
vuex
"
;
export
default
{
data
()
{
return
{
...
...
@@ -64,6 +66,9 @@ export default {
});
},
},
computed
:
{
...
mapGetters
(
"
user
"
,
[
"
secondaryRoutes
"
]),
},
created
()
{
this
.
$nextTick
(()
=>
{
this
.
handleDate
();
...
...
admin_2/src/pages/engine/EvaluateSystem.vue
View file @
50688879
...
...
@@ -13,6 +13,7 @@
:loading=
"hallLoading"
type=
"hall"
@
export=
"exportHallEva"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -37,6 +38,8 @@
type=
"pjOption"
@
export=
"exportPjOptionEva"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -61,6 +64,8 @@
type=
"dept"
@
export=
"exportDeptEva"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -85,6 +90,8 @@
type=
"window"
@
export=
"exportWindowEva"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
admin_2/src/pages/engine/QueueUpSystem.vue
View file @
50688879
...
...
@@ -13,6 +13,7 @@
:loading=
"hallLoading"
type=
"hall"
@
export=
"exportHallQueue"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -37,6 +38,8 @@
type=
"business"
@
export=
"exportbusinessQueue"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -61,6 +64,8 @@
type=
"dept"
@
export=
"exportDeptQueue"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
@@ -85,6 +90,8 @@
type=
"window"
@
export=
"exportWindowQueue"
@
search=
"handleSearch"
hasPermiQuery=
"engine:queueupsystem:query"
hasPermiExport=
"engine:queueupsystem:export"
></DoubleTable>
</div>
<Pagination
...
...
admin_2/src/pages/engine/components/DoubleTable.vue
View file @
50688879
...
...
@@ -5,7 +5,11 @@
{{
title
}}
</div>
<div
class=
"flex gap-4"
>
<el-button
type=
"primary"
size=
"small"
@
click=
"handleExport"
<el-button
type=
"primary"
size=
"small"
@
click=
"handleExport"
v-hasPermi=
"[hasPermiExport]"
>
导出
</el-button
>
...
...
@@ -16,6 +20,7 @@
v-model=
"form.pjOption"
placeholder=
"请选择评价选项"
clearable
v-hasPermi=
"[hasPermiQuery]"
>
<el-option
v-for=
"(v, i) in dict.pjOption"
...
...
@@ -32,6 +37,7 @@
v-model=
"form.businessName"
placeholder=
"请选择业务"
clearable
v-hasPermi=
"[hasPermiQuery]"
>
<el-option
v-for=
"(v, i) in getTopKeyList(dict.businessList)"
...
...
@@ -48,6 +54,7 @@
v-model=
"form.deptName"
placeholder=
"请选择部门"
clearable
v-hasPermi=
"[hasPermiQuery]"
>
<el-option
v-for=
"(v, i) in getTopKeyList(dict.sectionNameList)"
...
...
@@ -64,6 +71,7 @@
v-model=
"form.windowNum"
placeholder=
"请选择窗口"
clearable
v-hasPermi=
"[hasPermiQuery]"
>
<el-option
v-for=
"(v, i) in getTopKeyList(dict.windowFromnumList)"
...
...
@@ -78,6 +86,7 @@
size=
"small"
v-if=
"type != 'hall'"
@
click=
"handleSearch"
v-hasPermi=
"[hasPermiQuery]"
>
搜索
</el-button
>
</div>
...
...
@@ -153,6 +162,12 @@ export default {
type
:
Object
,
default
:
()
=>
{},
},
hasPermiQuery
:
{
type
:
String
,
},
hasPermiExport
:
{
type
:
String
,
},
},
data
()
{
return
{
...
...
admin_2/src/pages/market/EvaluateReport.vue
View file @
50688879
...
...
@@ -8,6 +8,7 @@
size=
"small"
:loading=
"exportLoading"
@
click=
"exportExcel"
v-hasPermi=
"['market:evaluatereport:export']"
>
导出
</el-button
>
<div
class=
"text-[#909399]"
>
...
...
@@ -17,7 +18,10 @@
统计时间段:
{{
searchForm
.
time
[
0
]
}}
~
{{
searchForm
.
time
[
1
]
}}
</div>
</div>
<div
class=
"flex items-center"
>
<div
class=
"flex items-center"
v-hasPermi=
"['market:evaluatereport:query']"
>
<el-form
ref=
"searchForm"
inline
size=
"small"
:model=
"searchForm"
>
<el-form-item>
<el-select
style=
"width: 130px"
v-model=
"searchForm.type"
>
...
...
@@ -52,7 +56,11 @@
</el-form-item>
</el-form>
</div>
<el-popover
placement=
"bottom"
trigger=
"click"
>
<el-popover
placement=
"bottom"
trigger=
"click"
v-hasPermi=
"['market:evaluatereport:query']"
>
<div
class=
"w-full"
>
<el-form
ref=
"searchForm2"
inline
size=
"small"
:model=
"searchForm2"
>
<el-form-item>
...
...
admin_2/src/pages/market/Market.vue
View file @
50688879
...
...
@@ -10,7 +10,7 @@
</div>
<div
class=
"flex h-full flex-1 flex-col bg-white"
>
<el-tabs
:value=
"activeKey"
@
tab-click=
"changeRouter"
>
<el-tab-pane
v-for=
"v in s
ubMenu
s"
:key=
"v.path"
:name=
"v.path"
>
<el-tab-pane
v-for=
"v in s
econdaryRoute
s"
:key=
"v.path"
:name=
"v.path"
>
<template
slot=
"label"
>
<i
v-if=
"v.meta.icon"
...
...
@@ -28,37 +28,25 @@
</template>
<
script
>
import
{
findBottomSubarrays
}
from
"
@/utils
"
;
import
{
mapGetters
}
from
"
vuex
"
;
export
default
{
data
()
{
return
{
subMenus
:
[],
curTreeData
:
{},
// 当前选择的站点
};
},
computed
:
{
...
mapGetters
(
"
user
"
,
[
"
secondaryRoutes
"
]),
activeKey
()
{
return
this
.
$route
.
path
;
},
},
created
()
{
this
.
getSubMenus
();
},
created
()
{},
methods
:
{
changeRouter
(
e
)
{
this
.
$router
.
push
(
e
.
name
);
},
// 获取当前顶层路由下的所有子路由
getSubMenus
()
{
let
path
=
this
.
$route
?.
meta
.
activeMenu
?
this
.
$route
.
meta
.
activeMenu
:
this
.
$route
.
path
;
let
options
=
this
.
$router
.
options
.
routes
[
0
].
children
;
let
curRouters
=
options
.
filter
((
v
)
=>
v
.
path
==
path
);
this
.
subMenus
=
findBottomSubarrays
(
curRouters
).
filter
(
(
v
)
=>
!
v
.
meta
.
hidden
);
},
// 改变站点选择
changeSite
(
data
)
{
this
.
curTreeData
=
data
;
...
...
admin_2/src/pages/market/QueueUpReport.vue
View file @
50688879
...
...
@@ -8,6 +8,7 @@
size=
"small"
:loading=
"exportLoading"
@
click=
"exportExcel"
v-hasPermi=
"['market:queueupreport:export']"
>
导出
</el-button
>
<div
class=
"text-[#909399]"
>
...
...
@@ -17,7 +18,10 @@
统计时间段:
{{
searchForm
.
time
[
0
]
}}
~
{{
searchForm
.
time
[
1
]
}}
</div>
</div>
<div
class=
"flex items-center"
>
<div
class=
"flex items-center"
v-hasPermi=
"['market:queueupreport:query']"
>
<el-form
ref=
"searchForm"
inline
size=
"small"
:model=
"searchForm"
>
<el-form-item>
<el-select
style=
"width: 130px"
v-model=
"searchForm.type"
>
...
...
@@ -52,7 +56,11 @@
</el-form-item>
</el-form>
</div>
<el-popover
placement=
"bottom"
trigger=
"click"
>
<el-popover
placement=
"bottom"
trigger=
"click"
v-hasPermi=
"['market:queueupreport:query']"
>
<div
class=
"w-full"
>
<el-form
ref=
"searchForm2"
inline
size=
"small"
:model=
"searchForm2"
>
<!--
<el-form-item>
...
...
admin_2/src/pages/sso/Sso.vue
View file @
50688879
...
...
@@ -7,9 +7,14 @@
<
script
>
import
storage
from
"
@/utils/storage
"
;
import
{
mapMutations
}
from
"
vuex
"
;
import
{
getHomeData
}
from
"
@/api/home
"
;
import
{
generateRoutes
,
filterBtn
}
from
"
@/utils
"
;
import
{
calcMenu
}
from
"
@/router
"
;
export
default
{
data
()
{
return
{};
return
{
menuList
:
[],
};
},
created
()
{
this
.
getToken
();
...
...
@@ -21,9 +26,12 @@ export default {
"
SET_sysLogo
"
,
"
SET_path
"
,
"
SET_userInfo
"
,
"
SET_permissions
"
,
"
SET_routes
"
,
"
SET_menusList
"
,
]),
// 获取token
getToken
()
{
async
getToken
()
{
let
{
token
,
userInfo
,
siteid
,
siteName
,
sysName
,
sysLogo
,
path
}
=
this
.
$route
.
query
;
if
(
token
&&
userInfo
)
{
...
...
@@ -35,7 +43,7 @@ export default {
this
.
SET_path
(
path
);
storage
.
set
(
2
,
"
siteId
"
,
siteid
);
storage
.
set
(
2
,
"
siteName
"
,
siteName
);
this
.
$router
.
push
(
"
/home
"
);
await
this
.
getIndixData
(
);
}
else
{
this
.
$message
.
warning
(
"
跳转失败,请重新登录
"
);
setTimeout
(()
=>
{
...
...
@@ -43,6 +51,32 @@ export default {
},
2000
);
}
},
// 获取菜单列表
async
getIndixData
()
{
let
res
=
await
getHomeData
();
if
(
res
.
data
.
code
==
1
)
{
let
{
menuList
}
=
res
.
data
.
data
;
// 过滤掉按钮
let
menus
=
filterBtn
(
menuList
,
false
);
let
routes
=
generateRoutes
(
menus
);
// this.SET_routes(routes);
this
.
SET_menusList
(
menus
);
this
.
setBtnPermissions
(
menuList
);
calcMenu
();
if
(
routes
.
length
)
{
let
path
=
routes
[
0
].
path
;
this
.
$router
.
push
(
path
);
}
}
},
// 添加按钮权限字符
setBtnPermissions
(
menuList
)
{
let
btnPermissions
=
filterBtn
(
menuList
)
.
filter
((
v
)
=>
v
.
perms
)
.
map
((
v
)
=>
v
.
perms
);
this
.
SET_permissions
(
btnPermissions
);
},
},
};
</
script
>
...
...
admin_2/src/pages/system/System.vue
View file @
50688879
<
template
>
<div
class=
"system flex flex-col bg-white"
>
<el-tabs
:value=
"activeKey"
@
tab-click=
"changeRouter"
>
<el-tab-pane
v-for=
"v in subMenus"
:key=
"v.path"
:name=
"v.path"
>
<template
slot=
"label"
>
<i
v-if=
"v.meta.icon"
:class=
"['mr-[5px]', 'primary', v.meta.icon]"
></i>
<span
class=
"tab-label"
>
{{
v
.
meta
.
title
}}
</span>
</
template
>
</el-tab-pane>
</el-tabs>
<div
class=
"system-out-box flex-1"
>
<router-view></router-view>
</div>
<div
class=
"system"
>
<TabMenuBar></TabMenuBar>
</div>
</
template
>
<
script
>
import
{
findBottomSubarrays
}
from
"
@/utils
"
;
export
default
{
data
()
{
return
{
subMenus
:
[],
};
},
computed
:
{
activeKey
()
{
return
this
.
$route
.
path
;
},
},
created
()
{
this
.
getSubMenus
();
},
methods
:
{
changeRouter
(
e
)
{
this
.
$router
.
push
(
e
.
name
);
},
// 获取当前顶层路由下的所有子路由
getSubMenus
()
{
let
path
=
this
.
$route
?.
meta
.
activeMenu
?
this
.
$route
.
meta
.
activeMenu
:
this
.
$route
.
path
;
let
options
=
this
.
$router
.
options
.
routes
[
0
].
children
;
let
curRouters
=
options
.
filter
((
v
)
=>
v
.
path
==
path
);
this
.
subMenus
=
findBottomSubarrays
(
curRouters
).
filter
(
(
v
)
=>
!
v
.
meta
.
hidden
);
},
},
computed
:
{},
created
()
{},
methods
:
{},
};
</
script
>
<
style
lang=
"less"
scoped
>
// :deep(.el-tabs__nav-scroll) {
// padding-left: 15px;
// }
.system {
width: 100%;
height: 100%;
.system-out-box {
padding: 15px;
overflow-y: auto;
}
}
</
style
>
admin_2/src/pages/system/access/components/InputTree.vue
View file @
50688879
<
template
>
<div>
<el-popover
placement=
"bottom-start"
trigger=
"click"
>
<el-tree
:data=
"treeData"
:props=
"defaultProps"
node-key=
"id"
ref=
"tree"
highlight-current
accordion
:expand-on-click-node=
"false"
:current-node-key=
"value"
@
node-click=
"handleNodeClick"
></el-tree>
<el-input
slot=
"reference"
:value=
"value"
placeholder=
"请选择区域"
clearable
@
clear=
"handleClear"
></el-input>
</el-popover>
</div>
<el-popover
placement=
"bottom-start"
trigger=
"click"
width=
"100%"
>
<el-tree
:data=
"treeData"
:props=
"defaultProps"
node-key=
"id"
ref=
"tree"
highlight-current
accordion
:expand-on-click-node=
"false"
:current-node-key=
"value"
@
node-click=
"handleNodeClick"
></el-tree>
<el-input
slot=
"reference"
:value=
"value"
placeholder=
"请选择区域"
clearable
@
clear=
"handleClear"
></el-input>
</el-popover>
</
template
>
<
script
>
export
default
{
name
:
"
InputTree
"
,
props
:
{
treeData
:
{
type
:
Array
,
...
...
@@ -35,14 +34,18 @@ export default {
value
:
{
default
:
""
,
},
defaultProps
:
{
type
:
Object
,
default
:
()
=>
{
return
{
children
:
"
children
"
,
label
:
"
areaName
"
,
};
},
},
},
data
()
{
return
{
defaultProps
:
{
children
:
"
children
"
,
label
:
"
areaName
"
,
},
};
return
{};
},
methods
:
{
handleClear
()
{
...
...
admin_2/src/pages/system/menu/Menu.vue
View file @
50688879
...
...
@@ -107,7 +107,7 @@ export default {
{
label
:
"
菜单名称
"
,
prop
:
"
name
"
,
align
:
"
center
"
,
//
align: "center",
},
{
label
:
"
ID
"
,
...
...
@@ -242,7 +242,7 @@ export default {
this
.
current
-=
1
;
this
.
getMenuList
();
}
this
.
menuList
=
[...
this
.
menuList
,
...
data
];
this
.
menuList
=
[...
this
.
menuList
,
...
buildTree
(
data
)
];
this
.
tableData
=
buildTree
(
data
);
this
.
total
=
total
;
this
.
dict
=
dict
;
...
...
admin_2/src/pages/system/menu/components/AddMenu.vue
View file @
50688879
...
...
@@ -4,7 +4,7 @@
:title=
"title"
:destroy-on-close=
"true"
:visible.sync=
"Visible"
width=
"6
1
0px"
width=
"6
5
0px"
@
close=
"handleClose"
:close-on-click-modal=
"false"
top=
"10vh"
...
...
@@ -14,31 +14,44 @@
:model=
"form"
:rules=
"rules"
size=
"small"
label-width=
"1
0
0px"
label-width=
"1
3
0px"
>
<el-form-item
label=
"父级菜单"
prop=
"parentId"
>
<treeselect
v-model=
"form.parentId"
:options=
"menuList"
:normalizer=
"normalizer"
:show-count=
"true"
placeholder=
"选择父级菜单"
/>
</el-form-item>
<el-form-item
label=
"菜单类型"
prop=
"menuType"
>
<el-radio-group
v-model=
"form.menuType"
>
<el-radio
v-for=
"(item, key) in dict.menuType"
:key=
"key"
:label=
"Number(key)"
>
{{
item
}}
</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
label=
"菜单名称"
prop=
"name"
>
<el-input
placeholder=
"请输入
系统
名称"
placeholder=
"请输入
菜单
名称"
v-model=
"form.name"
clearable
></el-input>
</el-form-item>
<el-form-item
label=
"父级菜单"
prop=
"parentId"
>
<el-select
clearable
v-model=
"form.parentId"
placeholder=
"请选择父级菜单"
>
<el-option
v-for=
"item in menuList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
</el-option>
</el-select>
<el-form-item
label=
"菜单图标"
prop=
"imgPath"
v-if=
"form.menuType != 2"
>
<IconSelect
v-model=
"form.imgPath"
></IconSelect>
</el-form-item>
<el-form-item
label=
"权限类型"
prop=
"authType"
>
<el-form-item
label=
"权限类型"
prop=
"authType"
v-if=
"form.menuType != 2"
>
<el-select
clearable
v-model=
"form.authType"
...
...
@@ -53,62 +66,135 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"访问地址"
prop=
"url"
>
<el-form-item
prop=
"url"
v-if=
"form.menuType != 2"
>
<span
slot=
"label"
>
<el-tooltip
content=
"访问的路由地址,如:`system`"
placement=
"top"
>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
路由地址
</span>
<el-input
clearable
placeholder=
"请输入菜单
访问
地址"
placeholder=
"请输入菜单
路由
地址"
v-model=
"form.url"
></el-input>
</el-form-item>
<el-form-item
label=
"类型"
prop=
"menuType"
>
<el-radio-group
v-model=
"form.menuType"
>
<el-radio
v-for=
"(item, key) in dict.menuType"
:key=
"key"
:label=
"Number(key)"
>
{{
item
}}
</el-radio
<el-form-item
prop=
"component"
v-if=
"form.menuType != 2"
>
<span
slot=
"label"
>
<el-tooltip
content=
"访问的组件路径,如:`system/menu/Menu`,默认在`pages`目录下"
placement=
"top"
>
</el-radio-group>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
组件路径
</span>
<el-input
clearable
placeholder=
"请输入组件路径"
v-model=
"form.component"
></el-input>
</el-form-item>
<el-form-item
label=
"状态"
prop=
"status"
>
<el-radio-group
v-model=
"form.status"
>
<el-radio
v-for=
"(item, key) in dict.status"
:key=
"key"
:label=
"Number(key)"
>
{{
item
}}
</el-radio
>
</el-radio-group>
<el-form-item
prop=
"activeDir"
v-if=
"form.menuType != 2"
>
<span
slot=
"label"
>
<el-tooltip
content=
"顶部菜单栏激活路由"
placement=
"top"
>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
激活菜单
</span>
<el-input
clearable
placeholder=
"请输入激活菜单地址"
v-model=
"form.activeDir"
></el-input>
</el-form-item>
<el-form-item
label=
"图标"
prop=
"imgPath"
>
<IconSelect
v-model=
"form.imgPath"
></IconSelect>
<!--
<div
class=
"icon-box grid grid-cols-2 gap-1"
>
<div
:class=
"[
'icon-item',
'cursor-pointer',
{ active: form.imgPath == '' },
]"
@click="form.imgPath = ''"
<el-form-item
prop=
"perms"
v-if=
"form.menuType == 2"
>
<span
slot=
"label"
>
<el-tooltip
content=
"控制器中定义的权限字符,如:'system:menu:add'"
placement=
"top"
>
不需要图标
</div>
<div
:class=
"[
'icon-item',
'cursor-pointer',
{ active: form.imgPath == v },
]"
v-for="(v, i) in iconJson"
:key="i"
@click="form.imgPath = v"
>
<i
:class=
"v"
></i>
<span
class=
"ml-2"
>
{{
v
}}
</span>
</div>
</div>
-->
<i
class=
"el-icon-question"
></i>
</el-tooltip>
权限字符
</span>
<el-input
clearable
placeholder=
"请输入权限字符"
v-model=
"form.perms"
></el-input>
</el-form-item>
<el-row>
<el-col
:span=
"12"
v-if=
"form.menuType != 2"
>
<el-form-item
prop=
"visible"
>
<span
slot=
"label"
>
<el-tooltip
content=
"控制路由和子路由是否显示在菜单栏"
placement=
"top"
>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
显示状态
</span>
<el-radio-group
v-model=
"form.visible"
>
<el-radio
v-for=
"(item, key) in dict.visible"
:key=
"key"
:label=
"Number(key)"
>
{{
item
}}
</el-radio
>
</el-radio-group>
</el-form-item>
</el-col>
<el-col
:span=
"12"
v-if=
"form.menuType != 2"
>
<el-form-item
prop=
"cache"
>
<span
slot=
"label"
>
<el-tooltip
content=
"选择是则会被`keep-alive`缓存"
placement=
"top"
>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
是否缓存
</span>
<el-radio-group
v-model=
"form.cache"
>
<el-radio
:label=
"1"
>
是
</el-radio>
<el-radio
:label=
"0"
>
否
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
v-if=
"form.menuType != 2"
>
<el-form-item
prop=
"hideChildrenInMenu"
>
<span
slot=
"label"
>
<el-tooltip
content=
"强制菜单显示为Item而不是SubItem"
placement=
"top"
>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
是否隐藏子菜单
</span>
<el-radio-group
v-model=
"form.hideChildrenInMenu"
>
<el-radio
:label=
"1"
>
是
</el-radio>
<el-radio
:label=
"0"
>
否
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"菜单状态"
prop=
"status"
>
<el-radio-group
v-model=
"form.status"
>
<el-radio
v-for=
"(item, key) in dict.status"
:key=
"key"
:label=
"Number(key)"
>
{{
item
}}
</el-radio
>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span
slot=
"footer"
class=
"dialog-footer"
>
<el-button
size=
"small"
@
click=
"handleRest"
>
重 置
</el-button>
...
...
@@ -124,9 +210,12 @@
import
{
saveMenu
}
from
"
@/api/system
"
;
import
IconSelect
from
"
./IconSelect.vue
"
;
import
iconJson
from
"
@/assets/icon.json
"
;
import
Treeselect
from
"
@riophae/vue-treeselect
"
;
import
"
@riophae/vue-treeselect/dist/vue-treeselect.css
"
;
export
default
{
components
:
{
IconSelect
,
Treeselect
,
},
props
:
{
title
:
{
...
...
@@ -153,20 +242,40 @@ export default {
data
()
{
return
{
iconJson
,
defaultProps
:
{
children
:
"
childList
"
,
label
:
"
name
"
,
},
form
:
{
name
:
""
,
parentId
:
0
,
menuType
:
0
,
status
:
1
,
url
:
""
,
authType
:
""
,
imgPath
:
""
,
name
:
""
,
// 菜单名称
url
:
""
,
// 路由地址
ancestors
:
""
,
// 当前激活根目录
parentId
:
0
,
// 父菜单ID,一级菜单的该字段值为-1
linkType
:
0
,
// 链接方式 (0.普通,1.弹出,2.脚本)
imgPath
:
""
,
// 主菜单图标,主菜单图标的css样式名
buttonImgPath
:
""
,
// 按钮图标,按钮图标的css样式名
imgCommPath
:
""
,
// 常用菜单图标,常用菜单图标的css样式名
commMenu
:
1
,
// 是否常用菜单 (0.非常用,1.常用)
component
:
""
,
// vue组件路径
menuType
:
0
,
// 菜单类型 (0.目录,1.菜单,2.按钮)
authType
:
0
,
// 权限类型 (0.无限制,1.无需登录查看,2.需要登录查看,3.需要角色权限查看)
visible
:
0
,
// 菜单显示状态 (0.显示,1.隐藏)
perms
:
""
,
// 权限标识,多个逗号分割
remark
:
""
,
// 备注信息
orderId
:
""
,
// 排序编号
status
:
1
,
// 菜单状态 (0.停用,1.启用)
cache
:
0
,
// 是否缓存
activeDir
:
""
,
// 激活菜单
hideChildrenInMenu
:
1
,
// 是否隐藏子菜单
},
rules
:
{
name
:
[{
required
:
true
,
message
:
"
请输入菜单名称
"
,
trigger
:
"
blur
"
}],
url
:
[
{
required
:
true
,
message
:
"
请输入菜单访问地址
"
,
trigger
:
"
blur
"
},
],
component
:
[
{
required
:
true
,
message
:
"
请输入组件路径
"
,
trigger
:
"
blur
"
},
],
authType
:
[
{
required
:
true
,
message
:
"
请输入选择权限类型
"
,
trigger
:
"
change
"
},
],
...
...
@@ -218,6 +327,20 @@ export default {
this
.
$resetForm
(
"
form
"
);
this
.
Visible
=
false
;
},
/** 转换菜单数据结构 */
normalizer
(
node
)
{
if
(
node
.
childList
&&
!
node
.
childList
.
length
)
{
delete
node
.
childList
;
}
return
{
id
:
node
.
id
,
label
:
node
.
name
,
children
:
node
.
childList
,
};
},
changeParent
(
row
)
{
console
.
log
(
row
);
},
},
};
</
script
>
...
...
@@ -230,7 +353,4 @@ export default {
:deep(.el-select) {
width: 100%;
}
.active {
color: var(--primary);
}
</
style
>
admin_2/src/pages/system/menu/components/IconSelect.vue
View file @
50688879
...
...
@@ -3,12 +3,6 @@
<div
class=
"content grid max-h-[300px] w-full grid-cols-2 gap-x-4 gap-y-2 overflow-auto"
>
<div
:class=
"['cursor-pointer indent-8',
{ active: value === '' }]"
@click="handleChange('')"
>
不需要图标
</div>
<div
v-for=
"(v, i) in iconJson"
:key=
"i"
>
<div
:class=
"[
...
...
@@ -30,8 +24,8 @@
v-bind=
"$attrs"
v-on=
"$listeners"
:value=
"value"
readonly
:placeholder=
"placeholder"
clearable
>
<i
v-if=
"value"
slot=
"prefix"
:class=
"value"
/>
<i
v-else
slot=
"prefix"
class=
"el-icon-search"
/>
...
...
admin_2/src/router/index.js
View file @
50688879
...
...
@@ -2,6 +2,7 @@ import Vue from "vue";
import
VueRouter
from
"
vue-router
"
;
import
Layouts
from
"
@/layouts/Layouts.vue
"
;
import
store
from
"
@/store
"
;
import
{
generateRoutes
}
from
"
@/utils
"
;
// import local from "@/utils/local";
// 解决重复点击同一个路由报错
const
originalPush
=
VueRouter
.
prototype
.
push
;
...
...
@@ -9,62 +10,53 @@ VueRouter.prototype.push = function (location) {
return
originalPush
.
call
(
this
,
location
).
catch
((
err
)
=>
err
);
};
Vue
.
use
(
VueRouter
);
/**
* Route 对象配置:
* hidden:控制路由是否显示在在菜单
* hideChildrenInMenu:强制菜单显示为Item而不是SubItem
* meta对象配置:
* title:标题
* keepAlive:缓存该路由
* activeMenu:当前的激活路由
* icon:图标
* hidden:控制路由是否显示在在菜单
*/
const
routes
=
[
{
path
:
"
/
"
,
name
:
"
/
"
,
component
:
Layouts
,
redirect
:
"
/sso
"
,
children
:
[
{
path
:
"
/home
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/home/Home
"
),
meta
:
{
title
:
"
数仓工作台
"
,
},
},
{
path
:
"
/engine
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/engine/Engine
"
),
meta
:
{
title
:
"
数据引擎
"
,
},
redirect
:
"
/engine/queueupsystem
"
,
children
:
[
{
path
:
"
/engine/queueupsystem
"
,
hideChildrenInMenu
:
true
,
hidden
:
true
,
component
:
()
=>
import
(
"
@/pages/engine/QueueUpSystem
"
),
meta
:
{
title
:
"
排队取号系统
"
,
activeMenu
:
"
/engine
"
,
},
},
{
path
:
"
/engine/evaluatesystem
"
,
hideChildrenInMenu
:
true
,
hidden
:
true
,
component
:
()
=>
import
(
"
@/pages/engine/EvaluateSystem
"
),
meta
:
{
title
:
"
评价系统
"
,
activeMenu
:
"
/engine
"
,
},
},
],
},
//
{
//
path: "/home",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/home/Home"),
//
meta: {
//
title: "数仓工作台",
//
},
//
},
//
{
//
path: "/engine",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/engine/Engine"),
//
meta: {
//
title: "数据引擎",
//
},
//
redirect: "/engine/queueupsystem",
//
children: [
//
{
//
path: "/engine/queueupsystem",
//
hideChildrenInMenu: true,
//
hidden: true,
//
component: () => import("@/pages/engine/QueueUpSystem"),
//
meta: {
//
title: "排队取号系统",
//
activeMenu: "/engine",
//
},
//
},
//
{
//
path: "/engine/evaluatesystem",
//
hideChildrenInMenu: true,
//
hidden: true,
//
component: () => import("@/pages/engine/EvaluateSystem"),
//
meta: {
//
title: "评价系统",
//
activeMenu: "/engine",
//
},
//
},
//
],
//
},
// 数据搜索引擎
{
path
:
"
/enginesearch
"
,
...
...
@@ -97,133 +89,133 @@ const routes = [
],
},
{
path
:
"
/market
"
,
name
:
"
market
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/market/Market
"
),
meta
:
{
title
:
"
数据集市
"
,
},
redirect
:
"
/market/queueupreport
"
,
children
:
[
{
path
:
"
/market/queueupreport
"
,
name
:
"
queueupreport
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/market/QueueUpReport
"
),
meta
:
{
title
:
"
排队数据报表
"
,
activeMenu
:
"
/market
"
,
icon
:
"
el-icon-guide
"
,
},
},
{
path
:
"
/market/evaluatereport
"
,
name
:
"
evaluatereport
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/market/EvaluateReport
"
),
meta
:
{
title
:
"
评价数据报表
"
,
activeMenu
:
"
/market
"
,
icon
:
"
el-icon-collection
"
,
},
},
],
},
{
path
:
"
/system
"
,
hideChildrenInMenu
:
true
,
component
:
()
=>
import
(
"
@/pages/system/System
"
),
meta
:
{
title
:
"
系统设置
"
,
},
redirect
:
"
/system/access
"
,
children
:
[
{
path
:
"
/system/access
"
,
component
:
()
=>
import
(
"
@/pages/system/access/Access.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
区县接入
"
,
icon
:
"
el-icon-set-up
"
,
},
},
// {
// path: "/system/areasystem",
// component: () => import("@/pages/system/areaSystem/AreaSystem.vue"),
// meta: {
// activeMenu: "/system",
// title: "区县系统",
// icon: "el-icon-monitor",
// },
// },
{
path
:
"
/system/user
"
,
component
:
()
=>
import
(
"
@/pages/system/user/User.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
用户信息
"
,
icon
:
"
el-icon-user
"
,
},
},
{
path
:
"
/system/role
"
,
component
:
()
=>
import
(
"
@/pages/system/role/Role.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
角色信息
"
,
icon
:
"
el-icon-postcard
"
,
},
},
{
path
:
"
/system/resourcemanage
"
,
component
:
()
=>
import
(
"
@/pages/system/resourceManage/ResourceManage.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
资源信息
"
,
icon
:
"
el-icon-box
"
,
},
},
{
path
:
"
/system/menu
"
,
component
:
()
=>
import
(
"
@/pages/system/menu/Menu.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
菜单管理
"
,
icon
:
"
el-icon-guide
"
,
},
},
{
path
:
"
/system/parameter
"
,
component
:
()
=>
import
(
"
@/pages/system/parameter/Parameter.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
系统参数
"
,
icon
:
"
el-icon-cpu
"
,
},
},
{
path
:
"
/system/task
"
,
component
:
()
=>
import
(
"
@/pages/system/task/TaskSet.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
任务信息
"
,
icon
:
"
el-icon-bank-card
"
,
},
},
{
path
:
"
/system/systemlogs
"
,
component
:
()
=>
import
(
"
@/pages/system/systemlogs/SystemLogs.vue
"
),
meta
:
{
activeMenu
:
"
/system
"
,
title
:
"
系统日志
"
,
icon
:
"
el-icon-notebook-1
"
,
},
},
],
},
//
{
//
path: "/market",
//
name: "market",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/market/Market"),
//
meta: {
//
title: "数据集市",
//
},
//
redirect: "/market/queueupreport",
//
children: [
//
{
//
path: "/market/queueupreport",
//
name: "queueupreport",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/market/QueueUpReport"),
//
meta: {
//
title: "排队数据报表",
//
activeMenu: "/market",
//
icon: "el-icon-guide",
//
},
//
},
//
{
//
path: "/market/evaluatereport",
//
name: "evaluatereport",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/market/EvaluateReport"),
//
meta: {
//
title: "评价数据报表",
//
activeMenu: "/market",
//
icon: "el-icon-collection",
//
},
//
},
//
],
//
},
//
{
//
path: "/system",
//
hideChildrenInMenu: true,
//
component: () => import("@/pages/system/System"),
//
meta: {
//
title: "系统设置",
//
},
//
redirect: "/system/access",
//
children: [
//
{
//
path: "/system/access",
//
component: () => import("@/pages/system/access/Access.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "区县接入",
//
icon: "el-icon-set-up",
//
},
//
},
//
// {
//
// path: "/system/areasystem",
//
// component: () => import("@/pages/system/areaSystem/AreaSystem.vue"),
//
// meta: {
//
// activeMenu: "/system",
//
// title: "区县系统",
//
// icon: "el-icon-monitor",
//
// },
//
// },
//
{
//
path: "/system/user",
//
component: () => import("@/pages/system/user/User.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "用户信息",
//
icon: "el-icon-user",
//
},
//
},
//
{
//
path: "/system/role",
//
component: () => import("@/pages/system/role/Role.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "角色信息",
//
icon: "el-icon-postcard",
//
},
//
},
//
{
//
path: "/system/resourcemanage",
//
component: () =>
//
import("@/pages/system/resourceManage/ResourceManage.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "资源信息",
//
icon: "el-icon-box",
//
},
//
},
//
{
//
path: "/system/menu",
//
component: () => import("@/pages/system/menu/Menu.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "菜单管理",
//
icon: "el-icon-guide",
//
},
//
},
//
{
//
path: "/system/parameter",
//
component: () => import("@/pages/system/parameter/Parameter.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "系统参数",
//
icon: "el-icon-cpu",
//
},
//
},
//
{
//
path: "/system/task",
//
component: () => import("@/pages/system/task/TaskSet.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "任务信息",
//
icon: "el-icon-bank-card",
//
},
//
},
//
{
//
path: "/system/systemlogs",
//
component: () => import("@/pages/system/systemlogs/SystemLogs.vue"),
//
meta: {
//
activeMenu: "/system",
//
title: "系统日志",
//
icon: "el-icon-notebook-1",
//
},
//
},
//
],
//
},
],
},
{
...
...
@@ -277,10 +269,12 @@ function menusFilter(arr) {
}
// 动态菜单
export
function
calcMenu
()
{
// dynamicRouter.forEach((v) => {
// router.addRoute(v);
// });
let
menus
=
menusFilter
(
routes
[
0
].
children
);
let
menusList
=
store
.
getters
[
"
user/menusList
"
];
let
dynamicRouter
=
generateRoutes
(
menusList
);
dynamicRouter
.
forEach
((
v
)
=>
{
router
.
addRoute
(
"
/
"
,
v
);
});
let
menus
=
menusFilter
(
dynamicRouter
);
store
.
commit
(
"
user/SET_menus
"
,
menus
);
}
calcMenu
();
...
...
admin_2/src/store/modules/user.js
View file @
50688879
import
{
getSiteBusiness
,
getDepartment
,
getWindow
}
from
"
@/api/site
"
;
import
{
getHomeData
}
from
"
@/api/home
"
;
import
{
findInTree
}
from
"
@/utils
"
;
export
default
{
namespaced
:
true
,
state
:
{
menus
:
[],
// 菜单
menusList
:
[],
// 原始菜单列表
menus
:
[],
// 格式化菜单列表
routes
:
[],
// 路由列表
secondaryRoutes
:
[],
// 二级路由
barList
:
[],
// 登录返回菜单
homeData
:
{},
// 首页数据
token
:
""
,
...
...
@@ -16,6 +20,7 @@ export default {
businessList
:
[],
// 站点业务列表
deptList
:
[],
// 站点部门列表
windowList
:
[],
// 站点窗口列表
permissions
:
[],
// 按钮权限字符列表
},
getters
:
{
siteId
(
state
)
{
...
...
@@ -37,8 +42,35 @@ export default {
let
{
barList
}
=
state
.
homeData
;
return
barList
||
[];
},
routes
(
state
)
{
return
state
.
routes
;
},
menus
(
state
)
{
return
state
.
menus
;
},
permissions
(
state
)
{
return
state
.
permissions
;
},
menusList
(
state
)
{
return
state
.
menusList
;
},
secondaryRoutes
(
state
)
{
return
state
.
secondaryRoutes
;
},
},
mutations
:
{
SET_menusList
(
state
,
menusList
)
{
state
.
menusList
=
menusList
;
},
SET_routes
(
state
,
routes
)
{
state
.
routes
=
routes
;
},
SET_permissions
(
state
,
permissions
)
{
state
.
permissions
=
permissions
;
},
SET_secondaryRoutes
(
state
,
secondaryRoutes
)
{
state
.
secondaryRoutes
=
secondaryRoutes
;
},
SET_path
(
state
,
path
)
{
state
.
path
=
path
;
},
...
...
@@ -127,5 +159,11 @@ export default {
context
.
commit
(
"
SET_windowList
"
,
data
);
}
},
// 设置二级路由
setSecondaryRoutes
(
context
,
value
)
{
let
routes
=
findInTree
(
context
.
state
.
menus
,
"
path
"
,
value
);
let
secondaryRoutes
=
routes
.
children
||
[];
context
.
commit
(
"
SET_secondaryRoutes
"
,
secondaryRoutes
);
},
},
};
admin_2/src/utils/index.js
View file @
50688879
import
Vue
from
"
vue
"
;
import
CryptoJS
from
"
crypto-js
"
;
import
moment
from
"
moment
"
;
import
{
find
,
get
}
from
"
lodash-es
"
;
// 加密数据
export
let
encrypt
=
(
str
,
keyStr
,
ivStr
)
=>
{
...
...
@@ -205,3 +206,95 @@ export const getFieldFromArray = (arr, field, treeField) => {
return
result
;
};
// 生成路由
export
const
generateRoutes
=
(
menuList
)
=>
{
let
routers
=
menuList
.
map
((
item
)
=>
{
// 构造符合要求的结构
let
path
=
item
.
url
.
charAt
(
0
)
===
"
/
"
?
item
.
url
:
"
/
"
+
item
.
url
;
let
name
=
item
.
url
.
charAt
(
0
)
===
"
/
"
?
item
.
url
.
slice
(
1
)
:
item
.
url
;
let
activeMenu
=
item
.
activeDir
?
item
.
activeDir
.
charAt
(
0
)
===
"
/
"
?
item
.
activeDir
:
"
/
"
+
item
.
activeDir
:
""
;
let
component
=
item
.
component
?
item
.
component
.
charAt
(
0
)
===
"
/
"
?
item
.
component
:
"
/
"
+
item
.
component
:
null
;
const
newItem
=
{
path
,
name
,
hidden
:
!!
item
.
visible
,
hideChildrenInMenu
:
!!
item
.
hideChildrenInMenu
,
component
:
()
=>
import
(
`@/pages
${
component
}
`
),
meta
:
{
title
:
item
.
name
,
icon
:
item
.
imgPath
,
keepAlive
:
!!
item
.
cache
,
activeMenu
,
},
};
// 递归处理子节点
if
(
item
.
children
&&
item
.
children
.
length
>
0
)
{
newItem
.
children
=
generateRoutes
(
item
.
children
);
}
return
newItem
;
});
routers
.
forEach
((
v
)
=>
{
if
(
v
.
children
&&
v
.
children
.
length
)
{
v
.
redirect
=
v
.
children
[
0
].
path
;
}
});
return
routers
;
};
/**
* 过滤菜单按钮项并提取 menuType = 2 的项
* @param {Array} menuList - 菜单列表
* @param {Boolean} menuType - true 获取 menuType = 2 的项并返回为一维数组, false 剔除 menuType = 2 的项
* @param {Array} btnItems - 用于存储 menuType = 2 的项(递归使用)
* @returns {Array} - 返回提取到的 menuType = 2 的项(如果 menuType 为 true)或剔除 menuType = 2 的菜单
*/
export
const
filterBtn
=
(
menuList
,
menuType
=
true
,
btnItems
=
[])
=>
{
const
result
=
menuList
.
map
((
menu
)
=>
{
// 深拷贝对象,避免修改原数据
const
newMenu
=
{
...
menu
};
if
(
newMenu
.
children
&&
newMenu
.
children
.
length
>
0
)
{
newMenu
.
children
=
filterBtn
(
newMenu
.
children
,
menuType
,
btnItems
);
}
const
btnItem
=
newMenu
.
menuType
==
2
;
if
(
menuType
)
{
if
(
btnItem
)
{
btnItems
.
push
(
newMenu
);
}
return
newMenu
;
}
else
{
// 剔除 menuType = 2 的项
return
!
btnItem
?
newMenu
:
null
;
}
})
.
filter
((
menu
)
=>
menu
!==
null
);
// 过滤掉 null 项
return
menuType
?
btnItems
:
result
;
};
export
function
findInTree
(
data
,
key
,
value
)
{
// 递归遍历树形结构
function
recursiveSearch
(
nodes
)
{
return
find
(
nodes
,
(
node
)
=>
{
if
(
get
(
node
,
key
)
===
value
)
{
return
true
;
}
if
(
node
.
children
)
{
return
recursiveSearch
(
node
.
children
);
}
return
false
;
});
}
return
recursiveSearch
(
data
);
}
admin_2/yarn.lock
View file @
50688879
...
...
@@ -989,6 +989,13 @@
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.3.1":
version "7.25.6"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2"
integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.22.5":
version "7.22.5"
resolved "https://registry.npmmirror.com/@babel/template/-/template-7.22.5.tgz"
...
...
@@ -1222,6 +1229,20 @@
resolved "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.21.tgz"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@riophae/vue-treeselect@^0.4.0":
version "0.4.0"
resolved "https://registry.npmmirror.com/@riophae/vue-treeselect/-/vue-treeselect-0.4.0.tgz#0baed5a794cffc580b63591f35c125e51c0df241"
integrity sha512-J4atYmBqXQmiPFK/0B5sXKjtnGc21mBJEiyKIDZwk0Q9XuynVFX6IJ4EpaLmUgL5Tve7HAS7wkiGGSti6Uaxcg==
dependencies:
"@babel/runtime" "^7.3.1"
babel-helper-vue-jsx-merge-props "^2.0.3"
easings-css "^1.0.0"
fuzzysearch "^1.0.3"
is-promise "^2.1.0"
lodash "^4.0.0"
material-colors "^1.2.6"
watch-size "^2.0.0"
"@sideway/address@^4.1.3":
version "4.1.4"
resolved "https://registry.npmmirror.com/@sideway/address/-/address-4.1.4.tgz"
...
...
@@ -2140,7 +2161,7 @@ axios@^1.4.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
babel-helper-vue-jsx-merge-props@^2.0.0:
babel-helper-vue-jsx-merge-props@^2.0.0
, babel-helper-vue-jsx-merge-props@^2.0.3
:
version "2.0.3"
resolved "https://registry.npmmirror.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==
...
...
@@ -3104,6 +3125,11 @@ duplexer@^0.1.2:
resolved "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
easings-css@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/easings-css/-/easings-css-1.0.0.tgz#dde569003bb7a4a0c0b77878f5db3e0be5679c81"
integrity sha512-7Uq7NdazNfVtr0RNmPAys8it0zKCuaqxJStYKEl72D3j4gbvXhhaM7iWNbqhA4C94ygCye6VuyhzBRQC4szeBg==
easy-stack@1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/easy-stack/-/easy-stack-1.0.1.tgz"
...
...
@@ -3684,6 +3710,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==
fuzzysearch@^1.0.3:
version "1.0.3"
resolved "https://registry.npmmirror.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008"
integrity sha512-s+kNWQuI3mo9OALw0HJ6YGmMbLqEufCh2nX/zzV5CrICQ/y4AwPxM+6TIiF9ItFCHXFCyM/BfCCmN57NTIJuPg==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz"
...
...
@@ -4173,6 +4204,11 @@ is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"
is-promise@^2.1.0:
version "2.2.2"
resolved "https://registry.npmmirror.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz"
...
...
@@ -4485,7 +4521,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
lodash@^4.17.14, lodash@^4.17.20, lodash@^4.17.21:
lodash@^4.
0.0, lodash@^4.
17.14, lodash@^4.17.20, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
...
...
@@ -4556,6 +4592,11 @@ make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
material-colors@^1.2.6:
version "1.2.6"
resolved "https://registry.npmmirror.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz"
...
...
@@ -5714,6 +5755,11 @@ regenerator-runtime@^0.13.11:
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
regenerator-runtime@^0.14.0:
version "0.14.1"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
regenerator-transform@^0.15.1:
version "0.15.1"
resolved "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz"
...
...
@@ -6688,6 +6734,11 @@ vuex@^3.6.2:
resolved "https://registry.npmmirror.com/vuex/-/vuex-3.6.2.tgz"
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
watch-size@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/watch-size/-/watch-size-2.0.0.tgz#096ee28d0365bd7ea03d9c8bf1f2f50a73be1474"
integrity sha512-M92R89dNoTPWyCD+HuUEDdhaDnh9jxPGOwlDc0u51jAgmjUvzqaEMynXSr3BaWs+QdHYk4KzibPy1TFtjLmOZQ==
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz"
...
...
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