feat: 角色管理

This commit is contained in:
kailong321200875 2023-08-05 20:34:55 +08:00
parent c72b3a33aa
commit 47016a535f
13 changed files with 398 additions and 106 deletions

View File

@ -173,6 +173,7 @@ export default [
id: toAnyString(),
meta: {
title: '综合示例-弹窗',
currentPermission: ['edit', 'add'],
permission: ['edit', 'add', 'delete']
}
},
@ -184,6 +185,7 @@ export default [
id: toAnyString(),
meta: {
title: '综合示例-页面',
currentPermission: ['edit', 'add'],
permission: ['edit', 'add', 'delete']
}
},
@ -200,6 +202,7 @@ export default [
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
currentPermission: ['delete', 'add'],
permission: ['edit', 'add', 'delete']
}
},
@ -216,6 +219,7 @@ export default [
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
currentPermission: ['delete', 'add'],
permission: ['edit', 'add', 'delete']
}
},
@ -232,6 +236,7 @@ export default [
hidden: true,
showMainRoute: true,
activeMenu: '/example/example-page',
currentPermission: ['delete', 'edit'],
permission: ['edit', 'add', 'delete']
}
}

View File

@ -1,5 +1,7 @@
import config from '@/config/axios/config'
import { MockMethod } from 'vite-plugin-mock'
import Mock from 'mockjs'
import { toAnyString } from '@/utils'
const { code } = config
@ -527,6 +529,24 @@ const testList: string[] = [
'/error/500-demo'
]
const List: any[] = []
const roleNames = ['超级管理员', '管理员', '普通用户', '游客', '测试用户']
for (let i = 0; i < 5; i++) {
List.push(
Mock.mock({
id: toAnyString(),
// timestamp: +Mock.Random.date('T'),
roleName: roleNames[i],
role: '@first',
status: Mock.Random.integer(0, 1),
createTime: '@datetime',
remark: '@cword(10, 15)'
})
)
}
export default [
// 列表接口
{
@ -542,5 +562,21 @@ export default [
}
}
}
},
{
url: '/role/table',
method: 'get',
timeout,
response: () => {
return {
data: {
code: code,
data: {
list: List,
total: 5
}
}
}
}
}
] as MockMethod[]

5
src/api/role/index.ts Normal file
View File

@ -0,0 +1,5 @@
import request from '@/config/axios'
export const getRoleListApi = () => {
return request.get({ url: '/role/table' })
}

View File

@ -146,7 +146,7 @@ export const initModel = (schema: FormSchema[], formModel: Recordable) => {
schema.map((v) => {
if (v.remove) {
delete model[v.field]
} else if (v.component && v.component !== 'Divider') {
} else if (v.component !== 'Divider') {
// const hasField = Reflect.has(model, v.field)
const hasField = get(model, v.field)
// 如果先前已经有值存在,则不进行重新赋值,而是采用现有的值

View File

@ -523,6 +523,12 @@ export default {
canTo: 'Can to',
name: 'Name'
},
role: {
roleName: 'Role name',
role: 'Role',
// 菜单分配
menu: 'Menu allocation'
},
inputPasswordDemo: {
title: 'InputPassword',
inputPasswordDes: 'Secondary packaging of Input components based on ElementPlus'

View File

@ -517,6 +517,11 @@ export default {
canTo: '是否可跳转',
name: '组件名称'
},
role: {
roleName: '角色名称',
role: '角色',
menu: '菜单分配'
},
inputPasswordDemo: {
title: '密码输入框',
inputPasswordDes: '基于 ElementPlus 的 Input 组件二次封装'

View File

@ -34,7 +34,7 @@ const submit = async () => {
console.log(err)
})
if (valid) {
const formData = getFormData()
const formData = await getFormData()
return formData
}
}

View File

@ -64,27 +64,27 @@ const formSchema = reactive<FormSchema[]>([
label: t('menu.activeMenu'),
component: 'Input'
},
{
field: 'meta.permission',
label: t('menu.permission'),
component: 'CheckboxGroup',
componentProps: {
options: [
{
label: 'add',
value: 'add'
},
{
label: 'edit',
value: 'edit'
},
{
label: 'delete',
value: 'delete'
}
]
}
},
// {
// field: 'meta.permission',
// label: t('menu.permission'),
// component: 'CheckboxGroup',
// componentProps: {
// options: [
// {
// label: 'add',
// value: 'add'
// },
// {
// label: 'edit',
// value: 'edit'
// },
// {
// label: 'delete',
// value: 'delete'
// }
// ]
// }
// },
{
field: 'meta.hidden',
label: t('menu.hidden'),
@ -137,7 +137,7 @@ const submit = async () => {
console.log(err)
})
if (valid) {
const formData = getFormData()
const formData = await getFormData()
return formData
}
}

View File

@ -1,91 +1,166 @@
<script setup lang="ts">
// import { ContentWrap } from '@/components/ContentWrap'
// import { useI18n } from '@/hooks/web/useI18n'
// import { Table } from '@/components/Table'
// import { getUserListApi } from '@/api/login'
// import { UserType } from '@/api/login/types'
// import { ref, h } from 'vue'
// import { ElButton } from 'element-plus'
// import { TableColumn, TableSlotDefault } from '@/types/table'
<script setup lang="tsx">
import { reactive, ref, unref } from 'vue'
import { getRoleListApi } from '@/api/role'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n'
import { Table, TableColumn } from '@/components/Table'
import { ElButton, ElTag } from 'element-plus'
import { Search } from '@/components/Search'
import { FormSchema } from '@/components/Form'
import { ContentWrap } from '@/components/ContentWrap'
import Write from './components/Write.vue'
import { Dialog } from '@/components/Dialog'
// interface Params {
// pageIndex?: number
// pageSize?: number
// }
const { t } = useI18n()
// const { t } = useI18n()
const { tableRegister, tableState, tableMethods } = useTable({
fetchDataApi: async () => {
const res = await getRoleListApi()
return {
list: res.data.list || [],
total: res.data.total
}
}
})
// const columns: TableColumn[] = [
// {
// field: 'index',
// label: t('userDemo.index'),
// type: 'index'
// },
// {
// field: 'username',
// label: t('userDemo.username')
// },
// {
// field: 'password',
// label: t('userDemo.password')
// },
// {
// field: 'role',
// label: t('userDemo.role')
// },
// {
// field: 'remark',
// label: t('userDemo.remark'),
// formatter: (row: UserType) => {
// return h(
// 'span',
// row.username === 'admin' ? t('userDemo.remarkMessage1') : t('userDemo.remarkMessage2')
// )
// }
// },
// {
// field: 'action',
// label: t('userDemo.action')
// }
// ]
const { dataList, loading, total } = tableState
const { getList } = tableMethods
// const loading = ref(true)
const tableColumns = reactive<TableColumn[]>([
{
field: 'index',
label: t('userDemo.index'),
type: 'index'
},
{
field: 'roleName',
label: t('role.roleName')
},
{
field: 'role',
label: t('role.role')
},
{
field: 'status',
label: t('menu.status'),
slots: {
default: (data: any) => {
return (
<>
<ElTag type={data[0].row.status === 0 ? 'danger' : 'success'}>
{data[0].row.status === 1 ? t('userDemo.enable') : t('userDemo.disable')}
</ElTag>
</>
)
}
}
},
{
field: 'createTime',
label: t('tableDemo.displayTime')
},
{
field: 'remark',
label: t('userDemo.remark')
},
{
field: 'action',
label: t('userDemo.action'),
width: 240,
slots: {
default: (data: any) => {
const row = data[0].row
return (
<>
<ElButton type="primary" onClick={() => action(row, 'edit')}>
{t('exampleDemo.edit')}
</ElButton>
<ElButton type="danger">{t('exampleDemo.del')}</ElButton>
</>
)
}
}
}
])
// let tableDataList = ref<UserType[]>([])
const searchSchema = reactive<FormSchema[]>([
{
field: 'roleName',
label: t('role.roleName'),
component: 'Input'
}
])
// const getTableList = async (params?: Params) => {
// const res = await getUserListApi({
// params: params || {
// pageIndex: 1,
// pageSize: 10
// }
// })
// // .catch(() => {})
// // .finally(() => {
// // loading.value = false
// // })
// if (res) {
// tableDataList.value = res.data.list
// loading.value = false
// }
// }
const searchParams = ref({})
const setSearchParams = (data: any) => {
searchParams.value = data
getList()
}
// getTableList()
const dialogVisible = ref(false)
const dialogTitle = ref('')
// const actionFn = (data: TableSlotDefault) => {
// console.log(data)
// }
const currentRow = ref()
const actionType = ref('')
const writeRef = ref<ComponentRef<typeof Write>>()
const saveLoading = ref(false)
const action = (row: any, type: string) => {
dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail')
actionType.value = type
currentRow.value = row
dialogVisible.value = true
}
const AddAction = () => {
dialogTitle.value = t('exampleDemo.add')
currentRow.value = undefined
dialogVisible.value = true
actionType.value = ''
}
const save = async () => {
const write = unref(writeRef)
const formData = await write?.submit()
if (formData) {
saveLoading.value = true
setTimeout(() => {
saveLoading.value = false
dialogVisible.value = false
}, 1000)
}
}
</script>
<template>
<div>role</div>
<!-- <ContentWrap :title="t('userDemo.title')" :message="t('userDemo.message')">
<Table :columns="columns" :data="tableDataList" :loading="loading" :selection="false">
<template #action="data">
<ElButton type="primary" @click="actionFn(data as TableSlotDefault)">
{{ t('tableDemo.action') }}
<ContentWrap>
<Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
<div class="mb-10px">
<ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
</div>
<Table
:columns="tableColumns"
default-expand-all
node-key="id"
:data="dataList"
:loading="loading"
:pagination="{
total
}"
@register="tableRegister"
/>
</ContentWrap>
<Dialog v-model="dialogVisible" :title="dialogTitle">
<Write v-if="actionType !== 'detail'" ref="writeRef" :current-row="currentRow" />
<template #footer>
<ElButton v-if="actionType !== 'detail'" type="primary" :loading="saveLoading" @click="save">
{{ t('exampleDemo.save') }}
</ElButton>
<ElButton @click="dialogVisible = false">{{ t('dialogDemo.close') }}</ElButton>
</template>
</Table>
</ContentWrap> -->
</Dialog>
</template>

View File

@ -0,0 +1,160 @@
<script setup lang="tsx">
import { Form, FormSchema } from '@/components/Form'
import { useForm } from '@/hooks/web/useForm'
import { PropType, reactive, watch, ref, unref } from 'vue'
import { useValidator } from '@/hooks/web/useValidator'
import { useI18n } from '@/hooks/web/useI18n'
import { ElTree, ElCheckboxGroup, ElCheckbox } from 'element-plus'
import { getMenuListApi } from '@/api/menu'
import { filter } from '@/utils/tree'
const { t } = useI18n()
const { required } = useValidator()
const props = defineProps({
currentRow: {
type: Object as PropType<any>,
default: () => null
}
})
const treeRef = ref<typeof ElTree>()
const formSchema = ref<FormSchema[]>([
{
field: 'roleName',
label: t('role.roleName'),
component: 'Input'
},
{
field: 'role',
label: t('role.role'),
component: 'Input'
},
{
field: 'status',
label: t('menu.status'),
component: 'Select',
componentProps: {
options: [
{
label: t('userDemo.disable'),
value: 0
},
{
label: t('userDemo.enable'),
value: 1
}
]
}
},
{
field: 'menu',
label: t('role.menu'),
colProps: {
span: 24
},
formItemProps: {
slots: {
default: (formData: any) => {
console.log(formData)
return (
<>
<div class="flex w-full">
<div class="flex-1">
<ElTree
ref={treeRef}
show-checkbox
node-key="id"
highlight-current
data={treeData.value}
onNode-click={nodeClick}
>
{{
default: (data) => {
return <span>{data.data.meta.title}</span>
}
}}
</ElTree>
</div>
<div class="flex-1">
{unref(currentTreeData) && unref(currentTreeData)?.meta?.permission ? (
<ElCheckboxGroup v-model={unref(currentTreeData).meta.currentPermission}>
{unref(currentTreeData)?.meta?.permission.map((v: string) => {
return <ElCheckbox label={v} />
})}
</ElCheckboxGroup>
) : null}
</div>
</div>
</>
)
}
}
}
}
])
const currentTreeData = ref()
const nodeClick = (treeData: any) => {
currentTreeData.value = treeData
}
const rules = reactive({
roleName: [required()],
role: [required()],
status: [required()]
})
const { formRegister, formMethods } = useForm()
const { setValues, getFormData, getElFormExpose } = formMethods
const treeData = ref([])
const getMenuList = async () => {
const res = await getMenuListApi()
if (res) {
treeData.value = res.data.list
}
}
getMenuList()
const submit = async () => {
const elForm = await getElFormExpose()
const valid = await elForm?.validate().catch((err) => {
console.log(err)
})
if (valid) {
const formData = await getFormData()
const checkedKeys = [
...(unref(treeRef)?.getCheckedKeys() || []),
...(unref(treeRef)?.getHalfCheckedKeys() || [])
]
const data = filter(unref(treeData), (item: any) => {
return checkedKeys.includes(item.id)
})
formData.menu = data || []
return formData
}
}
watch(
() => props.currentRow,
(currentRow) => {
if (!currentRow) return
setValues(currentRow)
},
{
deep: true,
immediate: true
}
)
defineExpose({
submit
})
</script>
<template>
<Form :rules="rules" @register="formRegister" :schema="formSchema" />
</template>

View File

@ -36,7 +36,7 @@ const submit = async () => {
console.log(err)
})
if (valid) {
const formData = getFormData()
const formData = await getFormData()
return formData
}
}

View File

@ -36,7 +36,7 @@ const submit = async () => {
console.log(err)
})
if (valid) {
const formData = getFormData()
const formData = await getFormData()
return formData
}
}

View File

@ -120,7 +120,7 @@ const submit = async () => {
console.log(err)
})
if (valid) {
const formData = getFormData()
const formData = await getFormData()
return formData
}
}