Browse Source

完善角色页

main
dark 5 months ago
parent
commit
3dcd447d8f
  1. 6
      src/layout/RootLayout.tsx
  2. 6
      src/layout/style.ts
  3. 4
      src/locales/lang/en-US.ts
  4. 16
      src/locales/lang/pages/system/roles/en-US.ts
  5. 17
      src/locales/lang/pages/system/roles/zh-CN.ts
  6. 4
      src/locales/lang/zh-CN.ts
  7. 75
      src/pages/system/roles/index.tsx
  8. 21
      src/pages/system/roles/store.ts

6
src/layout/RootLayout.tsx

@ -2,7 +2,6 @@ import Avatar from '@/components/avatar'
import PageBreadcrumb from '@/components/breadcrumb'
import ErrorPage from '@/components/error/error.tsx'
import SelectLang from '@/components/select-lang'
import { useTranslation } from '@/i18n.ts'
import { appAtom } from '@/store/system.ts'
import { userMenuDataAtom } from '@/store/user.ts'
import { MenuItem } from '@/types'
@ -42,7 +41,6 @@ const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => {
export default () => {
const { styles } = useStyle()
const { t } = useTranslation()
const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom)
const { language } = useAtomValue(appAtom)
const items = getBreadcrumbData(menuData, location.pathname)
@ -116,14 +114,14 @@ export default () => {
</span>
)}
menuItemRender={(item, dom) => {
return <div style={{ userSelect: 'none' }} onClick={() => {
return <span style={{ userSelect: 'none' }} onClick={() => {
setPathname(item.path || '/dashboard')
}}
>
<Link to={item.path} target={item.type === 'url' ? '_blank' : '_self'}>
{dom}
</Link>
</div>
</span>
}}
{...{
'layout': 'mix',

6
src/layout/style.ts

@ -9,6 +9,11 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
.ant-pro-layout-bg-list {
user-select: none;
}
.ant-menu-inline-collapsed >.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item{
padding-inline-start: 0;
}
`,
}
@ -20,6 +25,7 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
.ant-pro-base-menu-inline-group .ant-menu-item-group-title .anticon {
margin-inline-end: 0;
}
`
return {

4
src/locales/lang/en-US.ts

@ -1,6 +1,6 @@
import antdEN from 'antd/locale/en_US'
import menus from './pages/system/menus/en-US'
import roles from './pages/system/roles/en-US'
export default {
...antdEN,
@ -42,11 +42,13 @@ export default {
},
system: {
menus,
roles,
},
actions: {
news: 'Add newly',
add: 'Add',
cancel: 'Cancel',
edit: 'Edit',
delete: 'Delete',
batchDel: 'Batch Delete',
reset: 'Reset',

16
src/locales/lang/pages/system/roles/en-US.ts

@ -0,0 +1,16 @@
export default {
title: 'Role Management',
columns: {
name: 'Name',
menu_ids: 'Permissions',
status: 'Status',
code: 'Alias',
icon: 'Icon',
sort: 'Sort',
description: 'Remarks',
option: 'Operation',
},
edit: {
title: 'Edit Role',
},
};

17
src/locales/lang/pages/system/roles/zh-CN.ts

@ -0,0 +1,17 @@
export default {
title: '角色管理',
columns: {
name: '名称',
menu_ids: '权限',
status: '状态',
code: '别名',
icon: '图标',
sort: '排序',
description: '备注',
option: '操作',
},
edit:{
title: '编辑角色',
},
}

4
src/locales/lang/zh-CN.ts

@ -1,6 +1,6 @@
import antdZh from 'antd/locale/zh_CN'
import menus from './pages/system/menus/zh-CN.ts'
import roles from './pages/system/roles/zh-CN.ts'
export default {
...antdZh,
@ -42,10 +42,12 @@ export default {
system: {
menus,
roles
},
actions: {
news: '新增加',
add: '添加',
edit: '编辑',
cancel: '取消',
delete: '删除',
batchDel: '批量删除',

75
src/pages/system/roles/index.tsx

@ -9,9 +9,17 @@ import { createLazyFileRoute } from '@tanstack/react-router'
import { useStyle } from './style.ts'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { pageAtom, roleAtom, rolesAtom, saveOrUpdateRoleAtom, searchAtom } from './store.ts'
import {
deleteRoleAtom,
pageAtom,
roleAtom,
roleIdsAtom,
rolesAtom,
saveOrUpdateRoleAtom,
searchAtom
} from './store.ts'
import { useTranslation } from '@/i18n.ts'
import { Button, Form, Space, Spin, Table, Tree } from 'antd'
import { Button, Form, Space, Spin, Table, Tree, Popconfirm } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { menuDataAtom } from '@/pages/system/menus/store.ts'
import { getTreeCheckedStatus } from '@/utils/tree.ts'
@ -46,8 +54,10 @@ const Roles = memo(() => {
const actionRef = useRef<ActionType>()
const [ page, setPage ] = useAtom(pageAtom)
const setSearch = useSetAtom(searchAtom)
const [ roleIds, setRoleIds ] = useAtom(roleIdsAtom)
const { data, isLoading, isFetching, refetch } = useAtomValue(rolesAtom)
const { isPending, mutate, isSuccess } = useAtomValue(saveOrUpdateRoleAtom)
const { mutate: deleteRole, isPending: isDeleteing } = useAtomValue(deleteRoleAtom)
const [ , setRole ] = useAtom(roleAtom)
const [ open, setOpen ] = useState(false)
@ -58,49 +68,61 @@ const Roles = memo(() => {
title: 'id', dataIndex: 'id',
hideInTable: true,
hideInSearch: true,
// hideInForm: true,
formItemProps: {
hidden: true
}
},
{
title: '名称', dataIndex: 'name', valueType: 'text',
title: t('system.roles.columns.name'), dataIndex: 'name', valueType: 'text',
formItemProps: {
rules: [ { required: true, message: '请输入角色名称' } ]
rules: [ { required: true, message: t('message.required') } ]
}
},
{
title: '别名', dataIndex: 'code', valueType: 'text',
title: t('system.roles.columns.code'), dataIndex: 'code', valueType: 'text',
formItemProps: {
rules: [ { required: true, message: '请输入别名' } ]
rules: [ { required: true, message: t('message.required') } ]
}
},
{ title: '状态', dataIndex: 'status', valueType: 'switch', },
{ title: t('system.roles.columns.status'), dataIndex: 'status', valueType: 'switch', },
{
title: '排序', dataIndex: 'sort', valueType: 'digit',
title: t('system.roles.columns.sort'), dataIndex: 'sort', valueType: 'digit',
},
{ title: '备注', dataIndex: 'description', valueType: 'textarea' },
{ title: t('system.roles.columns.description'), dataIndex: 'description', valueType: 'textarea' },
{
title: '权限', dataIndex: 'menu_ids',
title: t('system.roles.columns.menu_ids'),
hideInTable: true,
hideInSearch: true,
dataIndex: 'menu_ids',
valueType: 'text',
renderFormItem: (item, config, form) => {
return <MenuTree {...config} form={form} {...item.fieldProps} />
}
},
{
title: '操作', valueType: 'option',
title: t('system.roles.columns.option'), valueType: 'option',
key: 'option',
render: (text, record, _, action) => [
<a
key="editable"
<a key="editable"
onClick={() => {
setRole(record)
setOpen(true)
form.setFieldsValue(record)
}}
>
</a>,
<a href={record.url} target="_blank" rel="noopener noreferrer" key="del">
{t('actions.edit', '编辑')}
</a>,
<Popconfirm
key={'del_confirm'}
onConfirm={()=>{
deleteRole([ record.id ])
}}
title={t('message.deleteConfirm')}>
<a key="del" >
{t('actions.delete', '删除')}
</a>
</Popconfirm>
,
],
},
] as ProColumns[]
@ -112,6 +134,7 @@ const Roles = memo(() => {
}
}, [ isSuccess ])
return (
<PageContainer breadcrumbRender={false} title={false} className={styles.container}>
<ProTable
@ -123,12 +146,22 @@ const Roles = memo(() => {
dataSource={data?.rows}
search={false}
rowSelection={{
onChange: (selectedRowKeys) => {
setRoleIds(selectedRowKeys as number[])
},
selectedRowKeys: roleIds,
selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT ],
}}
tableAlertOptionRender={() => {
return (
<Space size={16}>
<a></a>
<Popconfirm
onConfirm={() => {
deleteRole(roleIds)
}}
title={t('message.batchDelete')}>
<Button type={'link'} loading={isDeleteing}>{t('actions.batchDel')}</Button>
</Popconfirm>
</Space>
)
}}
@ -140,7 +173,7 @@ const Roles = memo(() => {
toolbar={{
search: {
onSearch: (value: string) => {
setSearch({ name: value })
setSearch({ key: value })
},
},
actions: [
@ -156,7 +189,7 @@ const Roles = memo(() => {
}}
type="primary"
>
{t('actions.add', '添加')}
</Button>,
]
}}

21
src/pages/system/roles/store.ts

@ -6,11 +6,13 @@ import systemServ from '@/service/system.ts'
import { message } from 'antd'
import { t } from '@/i18n.ts'
type SearchParams = IPage & IRole
type SearchParams = IPage & {
key?: string
}
export const idAtom = atom(0)
export const IdsAtom = atom([])
export const roleIdsAtom = atom<number[]>([])
export const roleAtom = atom<IRole>(undefined as unknown as IRole)
@ -55,3 +57,18 @@ export const saveOrUpdateRoleAtom = atomWithMutation<IApiResult<IRole>>((get) =>
}
}
})
export const deleteRoleAtom = atomWithMutation((get) => {
return {
mutationKey: [ 'deleteMenu' ],
mutationFn: async (ids: number[]) => {
return await systemServ.role.batchDelete(ids ?? get(roleIdsAtom))
},
onSuccess: (res) => {
message.success('删除成功')
//更新列表
get(queryClientAtom).invalidateQueries({ queryKey: [ 'roles', get(searchAtom) ] })
return res
}
}
})
Loading…
Cancel
Save