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

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