Browse Source

完善角色页

main
dark 7 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. 85
      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 PageBreadcrumb from '@/components/breadcrumb'
import ErrorPage from '@/components/error/error.tsx' import ErrorPage from '@/components/error/error.tsx'
import SelectLang from '@/components/select-lang' import SelectLang from '@/components/select-lang'
import { useTranslation } from '@/i18n.ts'
import { appAtom } from '@/store/system.ts' import { appAtom } from '@/store/system.ts'
import { userMenuDataAtom } from '@/store/user.ts' import { userMenuDataAtom } from '@/store/user.ts'
import { MenuItem } from '@/types' import { MenuItem } from '@/types'
@ -42,7 +41,6 @@ const getBreadcrumbData = (menuData: MenuItem[], pathname: string) => {
export default () => { export default () => {
const { styles } = useStyle() const { styles } = useStyle()
const { t } = useTranslation()
const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom) const { data: menuData = [], isLoading } = useAtomValue(userMenuDataAtom)
const { language } = useAtomValue(appAtom) const { language } = useAtomValue(appAtom)
const items = getBreadcrumbData(menuData, location.pathname) const items = getBreadcrumbData(menuData, location.pathname)
@ -116,14 +114,14 @@ export default () => {
</span> </span>
)} )}
menuItemRender={(item, dom) => { menuItemRender={(item, dom) => {
return <div style={{ userSelect: 'none' }} onClick={() => {
return <span style={{ userSelect: 'none' }} onClick={() => {
setPathname(item.path || '/dashboard') setPathname(item.path || '/dashboard')
}} }}
> >
<Link to={item.path} target={item.type === 'url' ? '_blank' : '_self'}> <Link to={item.path} target={item.type === 'url' ? '_blank' : '_self'}>
{dom} {dom}
</Link> </Link>
</div>
</span>
}} }}
{...{ {...{
'layout': 'mix', '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 { .ant-pro-layout-bg-list {
user-select: none; 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 { .ant-pro-base-menu-inline-group .ant-menu-item-group-title .anticon {
margin-inline-end: 0; margin-inline-end: 0;
} }
` `
return { return {

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

@ -1,6 +1,6 @@
import antdEN from 'antd/locale/en_US' import antdEN from 'antd/locale/en_US'
import menus from './pages/system/menus/en-US' import menus from './pages/system/menus/en-US'
import roles from './pages/system/roles/en-US'
export default { export default {
...antdEN, ...antdEN,
@ -42,11 +42,13 @@ export default {
}, },
system: { system: {
menus, menus,
roles,
}, },
actions: { actions: {
news: 'Add newly', news: 'Add newly',
add: 'Add', add: 'Add',
cancel: 'Cancel', cancel: 'Cancel',
edit: 'Edit',
delete: 'Delete', delete: 'Delete',
batchDel: 'Batch Delete', batchDel: 'Batch Delete',
reset: 'Reset', 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 antdZh from 'antd/locale/zh_CN'
import menus from './pages/system/menus/zh-CN.ts' import menus from './pages/system/menus/zh-CN.ts'
import roles from './pages/system/roles/zh-CN.ts'
export default { export default {
...antdZh, ...antdZh,
@ -42,10 +42,12 @@ export default {
system: { system: {
menus, menus,
roles
}, },
actions: { actions: {
news: '新增加', news: '新增加',
add: '添加', add: '添加',
edit: '编辑',
cancel: '取消', cancel: '取消',
delete: '删除', delete: '删除',
batchDel: '批量删除', batchDel: '批量删除',

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

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

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

@ -6,11 +6,13 @@ import systemServ from '@/service/system.ts'
import { message } from 'antd' import { message } from 'antd'
import { t } from '@/i18n.ts' import { t } from '@/i18n.ts'
type SearchParams = IPage & IRole
type SearchParams = IPage & {
key?: string
}
export const idAtom = atom(0) export const idAtom = atom(0)
export const IdsAtom = atom([])
export const roleIdsAtom = atom<number[]>([])
export const roleAtom = atom<IRole>(undefined as unknown as IRole) 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