style: 完善角色管理

This commit is contained in:
kailong321200875 2023-08-06 08:27:40 +08:00
parent 47016a535f
commit c4576bd57b
4 changed files with 498 additions and 66 deletions

View File

@ -1,7 +1,6 @@
import config from '@/config/axios/config' import config from '@/config/axios/config'
import { MockMethod } from 'vite-plugin-mock' import { MockMethod } from 'vite-plugin-mock'
import Mock from 'mockjs' import Mock from 'mockjs'
import { toAnyString } from '@/utils'
const { code } = config const { code } = config
@ -25,7 +24,7 @@ export default [
redirect: '/dashboard/analysis', redirect: '/dashboard/analysis',
name: 'Dashboard', name: 'Dashboard',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 1,
meta: { meta: {
title: '首页', title: '首页',
icon: 'ant-design:dashboard-filled', icon: 'ant-design:dashboard-filled',
@ -37,7 +36,7 @@ export default [
component: 'views/Dashboard/Analysis', component: 'views/Dashboard/Analysis',
name: 'Analysis', name: 'Analysis',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 2,
meta: { meta: {
title: '分析页', title: '分析页',
noCache: true noCache: true
@ -48,7 +47,7 @@ export default [
component: 'views/Dashboard/Workplace', component: 'views/Dashboard/Workplace',
name: 'Workplace', name: 'Workplace',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 3,
meta: { meta: {
title: '工作台', title: '工作台',
noCache: true noCache: true
@ -65,13 +64,13 @@ export default [
}, },
name: 'ExternalLink', name: 'ExternalLink',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 4,
children: [ children: [
{ {
path: 'https://element-plus-admin-doc.cn/', path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink', name: 'DocumentLink',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 5,
meta: { meta: {
title: '文档' title: '文档'
} }
@ -84,7 +83,7 @@ export default [
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level', name: 'Level',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 6,
meta: { meta: {
title: '菜单', title: '菜单',
icon: 'carbon:skill-level-advanced' icon: 'carbon:skill-level-advanced'
@ -95,7 +94,7 @@ export default [
name: 'Menu1', name: 'Menu1',
component: '##', component: '##',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 7,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
title: '菜单1' title: '菜单1'
@ -106,7 +105,7 @@ export default [
name: 'Menu11', name: 'Menu11',
component: '##', component: '##',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 8,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
title: '菜单1-1', title: '菜单1-1',
@ -118,10 +117,10 @@ export default [
name: 'Menu111', name: 'Menu111',
component: 'views/Level/Menu111', component: 'views/Level/Menu111',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 9,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '菜单1-1-1', title: '菜单1-1-1'
permission: ['edit', 'add']
} }
} }
] ]
@ -131,10 +130,10 @@ export default [
name: 'Menu12', name: 'Menu12',
component: 'views/Level/Menu12', component: 'views/Level/Menu12',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 10,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '菜单1-2', title: '菜单1-2'
permission: ['edit', 'add']
} }
} }
] ]
@ -144,10 +143,10 @@ export default [
name: 'Menu2Demo', name: 'Menu2Demo',
component: 'views/Level/Menu2', component: 'views/Level/Menu2',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 11,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '菜单2', title: '菜单2'
permission: ['edit', 'add']
} }
} }
] ]
@ -158,7 +157,7 @@ export default [
redirect: '/example/example-dialog', redirect: '/example/example-dialog',
name: 'Example', name: 'Example',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 12,
meta: { meta: {
title: '综合示例', title: '综合示例',
icon: 'ep:management', icon: 'ep:management',
@ -170,11 +169,11 @@ export default [
component: 'views/Example/Dialog/ExampleDialog', component: 'views/Example/Dialog/ExampleDialog',
name: 'ExampleDialog', name: 'ExampleDialog',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 13,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '综合示例-弹窗', title: '综合示例-弹窗',
currentPermission: ['edit', 'add'], permission: ['edit', 'add']
permission: ['edit', 'add', 'delete']
} }
}, },
{ {
@ -182,11 +181,11 @@ export default [
component: 'views/Example/Page/ExamplePage', component: 'views/Example/Page/ExamplePage',
name: 'ExamplePage', name: 'ExamplePage',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 14,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '综合示例-页面', title: '综合示例-页面',
currentPermission: ['edit', 'add'], permission: ['edit', 'add']
permission: ['edit', 'add', 'delete']
} }
}, },
{ {
@ -194,7 +193,8 @@ export default [
component: 'views/Example/Page/ExampleAdd', component: 'views/Example/Page/ExampleAdd',
name: 'ExampleAdd', name: 'ExampleAdd',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 15,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '综合示例-新增', title: '综合示例-新增',
noTagsView: true, noTagsView: true,
@ -202,8 +202,7 @@ export default [
hidden: true, hidden: true,
showMainRoute: true, showMainRoute: true,
activeMenu: '/example/example-page', activeMenu: '/example/example-page',
currentPermission: ['delete', 'add'], permission: ['delete', 'add']
permission: ['edit', 'add', 'delete']
} }
}, },
{ {
@ -211,7 +210,8 @@ export default [
component: 'views/Example/Page/ExampleEdit', component: 'views/Example/Page/ExampleEdit',
name: 'ExampleEdit', name: 'ExampleEdit',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 16,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '综合示例-编辑', title: '综合示例-编辑',
noTagsView: true, noTagsView: true,
@ -219,8 +219,7 @@ export default [
hidden: true, hidden: true,
showMainRoute: true, showMainRoute: true,
activeMenu: '/example/example-page', activeMenu: '/example/example-page',
currentPermission: ['delete', 'add'], permission: ['delete', 'add']
permission: ['edit', 'add', 'delete']
} }
}, },
{ {
@ -228,7 +227,8 @@ export default [
component: 'views/Example/Page/ExampleDetail', component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail', name: 'ExampleDetail',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
id: toAnyString(), id: 17,
permission: ['edit', 'add', 'delete'],
meta: { meta: {
title: '综合示例-详情', title: '综合示例-详情',
noTagsView: true, noTagsView: true,
@ -236,8 +236,7 @@ export default [
hidden: true, hidden: true,
showMainRoute: true, showMainRoute: true,
activeMenu: '/example/example-page', activeMenu: '/example/example-page',
currentPermission: ['delete', 'edit'], permission: ['delete', 'edit']
permission: ['edit', 'add', 'delete']
} }
} }
] ]

View File

@ -531,9 +531,413 @@ const testList: string[] = [
const List: any[] = [] const List: any[] = []
const roleNames = ['超级管理员', '管理员', '普通用户', '游客', '测试用户'] const roleNames = ['超级管理员', '管理员', '普通用户', '游客']
const menus = [
[
{
path: '/dashboard',
component: '#',
redirect: '/dashboard/analysis',
name: 'Dashboard',
status: Mock.Random.integer(0, 1),
id: 1,
meta: {
title: '首页',
icon: 'ant-design:dashboard-filled',
alwaysShow: true
},
children: [
{
path: 'analysis',
component: 'views/Dashboard/Analysis',
name: 'Analysis',
status: Mock.Random.integer(0, 1),
id: 2,
meta: {
title: '分析页',
noCache: true
}
},
{
path: 'workplace',
component: 'views/Dashboard/Workplace',
name: 'Workplace',
status: Mock.Random.integer(0, 1),
id: 3,
meta: {
title: '工作台',
noCache: true
}
}
]
},
{
path: '/external-link',
component: '#',
meta: {
title: '文档',
icon: 'clarity:document-solid'
},
name: 'ExternalLink',
status: Mock.Random.integer(0, 1),
id: 4,
children: [
{
path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink',
status: Mock.Random.integer(0, 1),
id: 5,
meta: {
title: '文档'
}
}
]
},
{
path: '/level',
component: '#',
redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level',
status: Mock.Random.integer(0, 1),
id: 6,
meta: {
title: '菜单',
icon: 'carbon:skill-level-advanced'
},
children: [
{
path: 'menu1',
name: 'Menu1',
component: '##',
status: Mock.Random.integer(0, 1),
id: 7,
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: '菜单1'
},
children: [
{
path: 'menu1-1',
name: 'Menu11',
component: '##',
status: Mock.Random.integer(0, 1),
id: 8,
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: '菜单1-1',
alwaysShow: true
},
children: [
{
path: 'menu1-1-1',
name: 'Menu111',
component: 'views/Level/Menu111',
status: Mock.Random.integer(0, 1),
id: 9,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单1-1-1',
permission: ['edit', 'add', 'delete']
}
}
]
},
{
path: 'menu1-2',
name: 'Menu12',
component: 'views/Level/Menu12',
status: Mock.Random.integer(0, 1),
id: 10,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单1-2',
permission: ['edit', 'add', 'delete']
}
}
]
},
{
path: 'menu2',
name: 'Menu2Demo',
component: 'views/Level/Menu2',
status: Mock.Random.integer(0, 1),
id: 11,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单2',
permission: ['edit', 'add', 'delete']
}
}
]
},
{
path: '/example',
component: '#',
redirect: '/example/example-dialog',
name: 'Example',
status: Mock.Random.integer(0, 1),
id: 12,
meta: {
title: '综合示例',
icon: 'ep:management',
alwaysShow: true
},
children: [
{
path: 'example-dialog',
component: 'views/Example/Dialog/ExampleDialog',
name: 'ExampleDialog',
status: Mock.Random.integer(0, 1),
id: 13,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-弹窗',
permission: ['edit', 'add', 'delete']
}
},
{
path: 'example-page',
component: 'views/Example/Page/ExamplePage',
name: 'ExamplePage',
status: Mock.Random.integer(0, 1),
id: 14,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-页面',
permission: ['edit', 'add', 'delete']
}
},
{
path: 'example-add',
component: 'views/Example/Page/ExampleAdd',
name: 'ExampleAdd',
status: Mock.Random.integer(0, 1),
id: 15,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-新增',
noTagsView: true,
noCache: true,
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
permission: ['edit', 'add', 'delete']
}
},
{
path: 'example-edit',
component: 'views/Example/Page/ExampleEdit',
name: 'ExampleEdit',
status: Mock.Random.integer(0, 1),
id: 16,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-编辑',
noTagsView: true,
noCache: true,
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
permission: ['edit', 'add', 'delete']
}
},
{
path: 'example-detail',
component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail',
status: Mock.Random.integer(0, 1),
id: 17,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-详情',
noTagsView: true,
noCache: true,
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
permission: ['edit', 'add', 'delete']
}
}
]
}
],
[
{
path: '/dashboard',
component: '#',
redirect: '/dashboard/analysis',
name: 'Dashboard',
status: Mock.Random.integer(0, 1),
id: 1,
meta: {
title: '首页',
icon: 'ant-design:dashboard-filled',
alwaysShow: true
},
children: [
{
path: 'analysis',
component: 'views/Dashboard/Analysis',
name: 'Analysis',
status: Mock.Random.integer(0, 1),
id: 2,
meta: {
title: '分析页',
noCache: true
}
},
{
path: 'workplace',
component: 'views/Dashboard/Workplace',
name: 'Workplace',
status: Mock.Random.integer(0, 1),
id: 3,
meta: {
title: '工作台',
noCache: true
}
}
]
}
],
[
{
path: '/external-link',
component: '#',
meta: {
title: '文档',
icon: 'clarity:document-solid'
},
name: 'ExternalLink',
status: Mock.Random.integer(0, 1),
id: 4,
children: [
{
path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink',
status: Mock.Random.integer(0, 1),
id: 5,
meta: {
title: '文档'
}
}
]
},
{
path: '/level',
component: '#',
redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level',
status: Mock.Random.integer(0, 1),
id: 6,
meta: {
title: '菜单',
icon: 'carbon:skill-level-advanced'
},
children: [
{
path: 'menu1',
name: 'Menu1',
component: '##',
status: Mock.Random.integer(0, 1),
id: 7,
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: '菜单1'
},
children: [
{
path: 'menu1-1',
name: 'Menu11',
component: '##',
status: Mock.Random.integer(0, 1),
id: 8,
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
title: '菜单1-1',
alwaysShow: true
},
children: [
{
path: 'menu1-1-1',
name: 'Menu111',
component: 'views/Level/Menu111',
status: Mock.Random.integer(0, 1),
id: 9,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单1-1-1',
permission: ['edit', 'add', 'delete']
}
}
]
},
{
path: 'menu1-2',
name: 'Menu12',
component: 'views/Level/Menu12',
status: Mock.Random.integer(0, 1),
id: 10,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单1-2',
permission: ['edit', 'add', 'delete']
}
}
]
},
{
path: 'menu2',
name: 'Menu2Demo',
component: 'views/Level/Menu2',
status: Mock.Random.integer(0, 1),
id: 11,
permission: ['edit', 'add', 'delete'],
meta: {
title: '菜单2',
permission: ['edit', 'add', 'delete']
}
}
]
}
],
[
{
path: '/example',
component: '#',
redirect: '/example/example-dialog',
name: 'Example',
status: Mock.Random.integer(0, 1),
id: 12,
meta: {
title: '综合示例',
icon: 'ep:management',
alwaysShow: true
},
children: [
{
path: 'example-detail',
component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail',
status: Mock.Random.integer(0, 1),
id: 17,
permission: ['edit', 'add', 'delete'],
meta: {
title: '综合示例-详情',
noTagsView: true,
noCache: true,
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
permission: ['edit', 'add', 'delete']
}
}
]
}
]
]
for (let i = 0; i < 5; i++) { for (let i = 0; i < 4; i++) {
List.push( List.push(
Mock.mock({ Mock.mock({
id: toAnyString(), id: toAnyString(),
@ -542,7 +946,8 @@ for (let i = 0; i < 5; i++) {
role: '@first', role: '@first',
status: Mock.Random.integer(0, 1), status: Mock.Random.integer(0, 1),
createTime: '@datetime', createTime: '@datetime',
remark: '@cword(10, 15)' remark: '@cword(10, 15)',
menu: menus[i]
}) })
) )
} }
@ -573,7 +978,7 @@ export default [
code: code, code: code,
data: { data: {
list: List, list: List,
total: 5 total: 4
} }
} }
} }

View File

@ -64,27 +64,27 @@ const formSchema = reactive<FormSchema[]>([
label: t('menu.activeMenu'), label: t('menu.activeMenu'),
component: 'Input' component: 'Input'
}, },
// { {
// field: 'meta.permission', field: 'permission',
// label: t('menu.permission'), label: t('menu.permission'),
// component: 'CheckboxGroup', component: 'CheckboxGroup',
// componentProps: { componentProps: {
// options: [ options: [
// { {
// label: 'add', label: 'add',
// value: 'add' value: 'add'
// }, },
// { {
// label: 'edit', label: 'edit',
// value: 'edit' value: 'edit'
// }, },
// { {
// label: 'delete', label: 'delete',
// value: 'delete' value: 'delete'
// } }
// ] ]
// } }
// }, },
{ {
field: 'meta.hidden', field: 'meta.hidden',
label: t('menu.hidden'), label: t('menu.hidden'),

View File

@ -1,12 +1,13 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { Form, FormSchema } from '@/components/Form' import { Form, FormSchema } from '@/components/Form'
import { useForm } from '@/hooks/web/useForm' import { useForm } from '@/hooks/web/useForm'
import { PropType, reactive, watch, ref, unref } from 'vue' import { PropType, reactive, watch, ref, unref, nextTick } from 'vue'
import { useValidator } from '@/hooks/web/useValidator' import { useValidator } from '@/hooks/web/useValidator'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { ElTree, ElCheckboxGroup, ElCheckbox } from 'element-plus' import { ElTree, ElCheckboxGroup, ElCheckbox } from 'element-plus'
import { getMenuListApi } from '@/api/menu' import { getMenuListApi } from '@/api/menu'
import { filter } from '@/utils/tree' import { filter, eachTree } from '@/utils/tree'
import { findIndex } from '@/utils'
const { t } = useI18n() const { t } = useI18n()
@ -57,8 +58,7 @@ const formSchema = ref<FormSchema[]>([
}, },
formItemProps: { formItemProps: {
slots: { slots: {
default: (formData: any) => { default: () => {
console.log(formData)
return ( return (
<> <>
<div class="flex w-full"> <div class="flex w-full">
@ -68,6 +68,7 @@ const formSchema = ref<FormSchema[]>([
show-checkbox show-checkbox
node-key="id" node-key="id"
highlight-current highlight-current
expand-on-click-node={false}
data={treeData.value} data={treeData.value}
onNode-click={nodeClick} onNode-click={nodeClick}
> >
@ -79,9 +80,9 @@ const formSchema = ref<FormSchema[]>([
</ElTree> </ElTree>
</div> </div>
<div class="flex-1"> <div class="flex-1">
{unref(currentTreeData) && unref(currentTreeData)?.meta?.permission ? ( {unref(currentTreeData) && unref(currentTreeData)?.permission ? (
<ElCheckboxGroup v-model={unref(currentTreeData).meta.currentPermission}> <ElCheckboxGroup v-model={unref(currentTreeData).meta.permission}>
{unref(currentTreeData)?.meta?.permission.map((v: string) => { {unref(currentTreeData)?.permission.map((v: string) => {
return <ElCheckbox label={v} /> return <ElCheckbox label={v} />
})} })}
</ElCheckboxGroup> </ElCheckboxGroup>
@ -115,6 +116,32 @@ const getMenuList = async () => {
const res = await getMenuListApi() const res = await getMenuListApi()
if (res) { if (res) {
treeData.value = res.data.list treeData.value = res.data.list
if (!props.currentRow) return
await nextTick()
const checked: any[] = []
eachTree(props.currentRow.menu, (v) => {
checked.push({
id: v.id,
permission: v.meta?.permission || []
})
})
eachTree(treeData.value, (v) => {
const index = findIndex(checked, (item) => {
return item.id === v.id
})
if (index > -1) {
const meta = { ...(v.meta || {}) }
meta.permission = checked[index].permission
v.meta = meta
}
})
for (const item of checked) {
unref(treeRef)?.setChecked(item.id, true, false)
}
// unref(treeRef)?.setCheckedKeys(
// checked.map((v) => v.id),
// false
// )
} }
} }
getMenuList() getMenuList()
@ -134,6 +161,7 @@ const submit = async () => {
return checkedKeys.includes(item.id) return checkedKeys.includes(item.id)
}) })
formData.menu = data || [] formData.menu = data || []
console.log(formData)
return formData return formData
} }
} }