You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
7.2 KiB
244 lines
7.2 KiB
import Switch from '@/components/switch'
|
|
import { usePageStoreOptions } from '@/store'
|
|
import { IMenu } from '@/types/menus'
|
|
import {
|
|
ActionType,
|
|
PageContainer,
|
|
ProColumns,
|
|
ProTable,
|
|
BetaSchemaForm, ProFormColumnsType,
|
|
} from '@ant-design/pro-components'
|
|
import { useStyle } from './style.ts'
|
|
import { memo, useEffect, useMemo, useRef, useState } from 'react'
|
|
import { useAtom, useAtomValue } from 'jotai'
|
|
import {
|
|
deleteRoleAtom,
|
|
pageAtom,
|
|
roleAtom,
|
|
roleIdsAtom,
|
|
rolesAtom,
|
|
saveOrUpdateRoleAtom,
|
|
searchAtom
|
|
} from '@/store/role.ts'
|
|
import { useTranslation } from '@/i18n.ts'
|
|
import { Button, Form, Space, Spin, Table, Tree, Popconfirm } from 'antd'
|
|
import { PlusOutlined } from '@ant-design/icons'
|
|
import { menuDataAtom } from '@/store/menu.ts'
|
|
import { getTreeCheckedStatus } from '@/utils/tree.ts'
|
|
|
|
const MenuTree = (props: any) => {
|
|
const { data: menuList, isLoading: menuLoading } = useAtomValue(menuDataAtom)
|
|
const { value, onChange, form, id, mode } = props
|
|
|
|
const onCheck = (checkedKeys: any, info: any) => {
|
|
if (onChange) {
|
|
onChange([ ...checkedKeys, ...info.halfCheckedKeys ])
|
|
} else {
|
|
form.setFieldsValue({ [id]: [ ...checkedKeys, ...info.halfCheckedKeys ] })
|
|
}
|
|
}
|
|
if (menuLoading) {
|
|
return <Spin spinning={true} size={'small'}/>
|
|
}
|
|
return <Tree treeData={menuList}
|
|
fieldNames={{ title: 'title', key: 'id' }}
|
|
disabled={mode !== 'edit'} checkable={true} onCheck={onCheck}
|
|
checkedKeys={getTreeCheckedStatus<IMenu>(menuList!, value)}/>
|
|
|
|
|
|
}
|
|
|
|
const Roles = memo(() => {
|
|
|
|
const { t } = useTranslation()
|
|
const { styles } = useStyle()
|
|
const [ form ] = Form.useForm()
|
|
const actionRef = useRef<ActionType>()
|
|
const [ page, setPage ] = useAtom(pageAtom, usePageStoreOptions())
|
|
const [ search, setSearch ] = useAtom(searchAtom, usePageStoreOptions())
|
|
const [ roleIds, setRoleIds ] = useAtom(roleIdsAtom, usePageStoreOptions())
|
|
const { data, isLoading, isFetching, refetch } = useAtomValue(rolesAtom, usePageStoreOptions())
|
|
const { isPending, mutate, isSuccess } = useAtomValue(saveOrUpdateRoleAtom, usePageStoreOptions())
|
|
const { mutate: deleteRole, isPending: isDeleting } = useAtomValue(deleteRoleAtom, usePageStoreOptions())
|
|
const [ , setRole ] = useAtom(roleAtom, usePageStoreOptions())
|
|
const [ open, setOpen ] = useState(false)
|
|
|
|
const columns = useMemo(() => {
|
|
|
|
return [
|
|
{
|
|
title: 'id', dataIndex: 'id',
|
|
hideInTable: true,
|
|
hideInSearch: true,
|
|
formItemProps: {
|
|
hidden: true
|
|
}
|
|
},
|
|
{
|
|
title: t('system.roles.columns.name'), dataIndex: 'name', valueType: 'text',
|
|
formItemProps: {
|
|
rules: [ { required: true, message: t('message.required') } ]
|
|
}
|
|
},
|
|
{
|
|
title: t('system.roles.columns.code'), dataIndex: 'code', valueType: 'text',
|
|
formItemProps: {
|
|
rules: [ { required: true, message: t('message.required') } ]
|
|
}
|
|
},
|
|
{
|
|
title: t('system.roles.columns.status'), dataIndex: 'status', valueType: 'switch',
|
|
render: (text) => {
|
|
return <Switch value={!!text} size={'small'}/>
|
|
}
|
|
},
|
|
{
|
|
title: t('system.roles.columns.sort'), dataIndex: 'sort', valueType: 'digit',
|
|
},
|
|
{ title: t('system.roles.columns.description'), dataIndex: 'description', valueType: 'textarea' },
|
|
{
|
|
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: t('system.roles.columns.option'), valueType: 'option',
|
|
key: 'option',
|
|
render: (_, record) => [
|
|
<a key="editable"
|
|
onClick={() => {
|
|
setRole(record)
|
|
setOpen(true)
|
|
form.setFieldsValue(record)
|
|
}}
|
|
>
|
|
{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[]
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (isSuccess) {
|
|
setOpen(false)
|
|
}
|
|
}, [ isSuccess ])
|
|
|
|
|
|
return (
|
|
<PageContainer breadcrumbRender={false} title={false} className={styles.container}>
|
|
<ProTable
|
|
rowKey={'id'}
|
|
actionRef={actionRef}
|
|
headerTitle={t('system.roles.title', '角色管理')}
|
|
columns={columns}
|
|
loading={isLoading || isFetching}
|
|
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}>
|
|
<Popconfirm
|
|
onConfirm={() => {
|
|
deleteRole(roleIds)
|
|
}}
|
|
title={t('message.batchDelete')}>
|
|
<Button type={'link'} loading={isDeleting}>{t('actions.batchDel')}</Button>
|
|
</Popconfirm>
|
|
</Space>
|
|
)
|
|
}}
|
|
options={{
|
|
reload: () => {
|
|
refetch()
|
|
},
|
|
}}
|
|
toolbar={{
|
|
search: {
|
|
loading: isFetching && !!search.key,
|
|
onSearch: (value: string) => {
|
|
setSearch({ key: value })
|
|
},
|
|
placeholder: t('system.roles.search.placeholder')
|
|
},
|
|
actions: [
|
|
<Button
|
|
key="button"
|
|
icon={<PlusOutlined/>}
|
|
onClick={() => {
|
|
form.resetFields()
|
|
form.setFieldsValue({
|
|
id: 0,
|
|
})
|
|
setOpen(true)
|
|
}}
|
|
type="primary"
|
|
>
|
|
{t('actions.add', '添加')}
|
|
</Button>,
|
|
]
|
|
}}
|
|
pagination={{
|
|
total: data?.total,
|
|
current: page.page,
|
|
pageSize: page.pageSize,
|
|
onChange: (page) => {
|
|
|
|
setPage((prev) => {
|
|
return { ...prev, page }
|
|
})
|
|
}
|
|
}}
|
|
/>
|
|
<BetaSchemaForm
|
|
width={600}
|
|
form={form}
|
|
layout={'horizontal'}
|
|
title={t('system.roles.edit.title', '角色编辑')}
|
|
colProps={{ span: 24 }}
|
|
labelCol={{ span: 6 }}
|
|
wrapperCol={{ span: 16 }}
|
|
layoutType={'ModalForm'}
|
|
open={open}
|
|
modalProps={{
|
|
maskClosable: false,
|
|
}}
|
|
onOpenChange={(open) => {
|
|
setOpen(open)
|
|
}}
|
|
loading={isPending}
|
|
onFinish={async (values) => {
|
|
// console.log('values', values)
|
|
mutate(values)
|
|
return true
|
|
}}
|
|
columns={columns as ProFormColumnsType[]}/>
|
|
</PageContainer>
|
|
)
|
|
})
|
|
|
|
export default Roles
|