6b5f7a517b
角色名称添加长度(2-50)校验,角色标识添加长度和格式校验, 排序使用 VALIDATION 常量的 initialValue 和 rules。
209 lines
6.8 KiB
TypeScript
209 lines
6.8 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import { Table, Button, Modal, Form, Input, InputNumber, Select, Tag, Space, message, Popconfirm, TreeSelect } from 'antd'
|
|
import { PlusOutlined, EditOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons'
|
|
import type { ColumnsType } from 'antd/es/table'
|
|
import { roleApi } from '@/api/role.api'
|
|
import type { Role, CreateRoleRequest, UpdateRoleRequest, RolePageRequest, Permission } from '@/api/role.api'
|
|
import type { PageResponse } from '@/api/user.api'
|
|
import { RoleStatus, roleStatusMap } from '@/constants/status'
|
|
import { VALIDATION } from '@/constants/validation-rules'
|
|
import PermissionGuard from '@/components/PermissionGuard'
|
|
|
|
export default function RoleManagement() {
|
|
const [roles, setRoles] = useState<Role[]>([])
|
|
const [loading, setLoading] = useState(false)
|
|
const [modalOpen, setModalOpen] = useState(false)
|
|
const [editingRole, setEditingRole] = useState<Role | null>(null)
|
|
const [permissions, setPermissions] = useState<Permission[]>([])
|
|
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 })
|
|
const [form] = Form.useForm()
|
|
|
|
useEffect(() => {
|
|
loadRoles()
|
|
loadPermissions()
|
|
}, [])
|
|
|
|
async function loadRoles() {
|
|
setLoading(true)
|
|
try {
|
|
const params: RolePageRequest = { page: pagination.current - 1, size: pagination.pageSize }
|
|
const res = await roleApi.getPage(params)
|
|
const data = res as unknown as PageResponse<Role>
|
|
setRoles(data.content)
|
|
setPagination((prev) => ({ ...prev, total: data.totalElements }))
|
|
} catch {
|
|
message.error('加载角色列表失败')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
async function loadPermissions() {
|
|
try {
|
|
const res = await roleApi.getAllPermissions()
|
|
setPermissions(Array.isArray(res) ? res : [])
|
|
} catch { /* ignored */ }
|
|
}
|
|
|
|
function handleAdd() {
|
|
setEditingRole(null)
|
|
form.resetFields()
|
|
setModalOpen(true)
|
|
}
|
|
|
|
function handleEdit(record: Role) {
|
|
setEditingRole(record)
|
|
form.setFieldsValue({
|
|
roleName: record.roleName,
|
|
roleKey: record.roleKey,
|
|
roleSort: record.roleSort,
|
|
status: record.status,
|
|
permissions: record.permissions?.map((p) => p.id),
|
|
})
|
|
setModalOpen(true)
|
|
}
|
|
|
|
async function handleDelete(id: number) {
|
|
try {
|
|
await roleApi.delete(id)
|
|
message.success('删除成功')
|
|
loadRoles()
|
|
} catch {
|
|
message.error('删除失败')
|
|
}
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
try {
|
|
const values = await form.validateFields()
|
|
if (editingRole) {
|
|
const data: UpdateRoleRequest = { ...values }
|
|
await roleApi.update(editingRole.id, data)
|
|
message.success('更新成功')
|
|
} else {
|
|
const data: CreateRoleRequest = { ...values }
|
|
await roleApi.create(data)
|
|
message.success('创建成功')
|
|
}
|
|
setModalOpen(false)
|
|
loadRoles()
|
|
} catch { /* ignored */ }
|
|
}
|
|
|
|
const permissionTreeData = buildPermissionTree(permissions)
|
|
|
|
const columns: ColumnsType<Role> = [
|
|
{ title: '角色名称', dataIndex: 'roleName', key: 'roleName' },
|
|
{ title: '角色标识', dataIndex: 'roleKey', key: 'roleKey' },
|
|
{ title: '排序', dataIndex: 'roleSort', key: 'roleSort', width: 80 },
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'status',
|
|
key: 'status',
|
|
render: (status: RoleStatus) => {
|
|
const info = roleStatusMap[status]
|
|
return <Tag color={info?.color || 'default'}>{info?.label || status}</Tag>
|
|
},
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'action',
|
|
render: (_, record) => (
|
|
<Space>
|
|
<PermissionGuard permission="system:role:edit">
|
|
<Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record)} />
|
|
</PermissionGuard>
|
|
<PermissionGuard permission="system:role:delete">
|
|
<Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}>
|
|
<Button type="link" danger icon={<DeleteOutlined />} />
|
|
</Popconfirm>
|
|
</PermissionGuard>
|
|
</Space>
|
|
),
|
|
},
|
|
]
|
|
|
|
return (
|
|
<div style={{ padding: 24 }}>
|
|
<div style={{ marginBottom: 16 }}>
|
|
<Space>
|
|
<PermissionGuard permission="system:role:add">
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>新增角色</Button>
|
|
</PermissionGuard>
|
|
<Button icon={<ReloadOutlined />} onClick={loadRoles}>刷新</Button>
|
|
</Space>
|
|
</div>
|
|
|
|
<Table<Role>
|
|
rowKey="id"
|
|
columns={columns}
|
|
dataSource={roles}
|
|
loading={loading}
|
|
pagination={{
|
|
...pagination,
|
|
showSizeChanger: true,
|
|
showTotal: (total) => `共 ${total} 条`,
|
|
onChange: (page, pageSize) => {
|
|
setPagination((prev) => ({ ...prev, current: page, pageSize }))
|
|
setTimeout(loadRoles, 0)
|
|
},
|
|
}}
|
|
/>
|
|
|
|
<Modal
|
|
title={editingRole ? '编辑角色' : '新增角色'}
|
|
open={modalOpen}
|
|
onOk={handleSubmit}
|
|
onCancel={() => setModalOpen(false)}
|
|
destroyOnHidden
|
|
width={600}
|
|
>
|
|
<Form form={form} layout="vertical">
|
|
<Form.Item name="roleName" label="角色名称" rules={VALIDATION.roleName.rules}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="roleKey" label="角色标识" rules={VALIDATION.roleKey.rules}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="roleSort" label="排序" initialValue={VALIDATION.roleSort.initialValue} rules={VALIDATION.roleSort.rules}>
|
|
<InputNumber min={1} style={{ width: '100%' }} />
|
|
</Form.Item>
|
|
<Form.Item name="status" label="状态" initialValue={RoleStatus.ACTIVE}>
|
|
<Select options={Object.entries(roleStatusMap).map(([value, info]) => ({ label: info.label, value }))} />
|
|
</Form.Item>
|
|
<Form.Item name="permissions" label="权限">
|
|
<TreeSelect
|
|
treeData={permissionTreeData}
|
|
multiple
|
|
treeCheckable
|
|
showCheckedStrategy={TreeSelect.SHOW_CHILD}
|
|
placeholder="请选择权限"
|
|
style={{ width: '100%' }}
|
|
/>
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function buildPermissionTree(permissions: Permission[]) {
|
|
const grouped: Record<string, Permission[]> = {}
|
|
for (const p of permissions) {
|
|
const key = p.resource
|
|
if (!grouped[key]) grouped[key] = []
|
|
grouped[key].push(p)
|
|
}
|
|
|
|
return Object.entries(grouped).map(([resource, items]) => ({
|
|
title: resource,
|
|
value: `resource-${resource}`,
|
|
key: `resource-${resource}`,
|
|
children: items.map((item) => ({
|
|
title: `${item.name} (${item.action})`,
|
|
value: item.id,
|
|
key: item.id,
|
|
})),
|
|
}))
|
|
}
|